mirror of
https://github.com/Horizontal42/netsleuth.git
synced 2026-11-10 22:42:03 +03:00
Refactor cli.py to fix PLR0915 Too many statements
Extracted `_run_phase_2`, `_run_phase_3bc`, `_interpret_findings`, and `_export_report` from `diagnose`. Extracted `_build_options` and `_setup_interface` from `run`. This reduces the cyclomatic complexity and statement counts of these orchestration functions while preserving behavior. Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com>
This commit is contained in:
parent
8c99ac78b7
commit
935b23456d
1 changed files with 230 additions and 119 deletions
|
|
@ -50,6 +50,7 @@ from netsleuth.interpret import (
|
||||||
from netsleuth.ip_geo import dual_stack_mismatch, gather_identity
|
from netsleuth.ip_geo import dual_stack_mismatch, gather_identity
|
||||||
from netsleuth.metrics import collect_metrics, render_csv, render_prometheus
|
from netsleuth.metrics import collect_metrics, render_csv, render_prometheus
|
||||||
from netsleuth.models import (
|
from netsleuth.models import (
|
||||||
|
Capabilities,
|
||||||
BindTarget,
|
BindTarget,
|
||||||
CaptivePortal,
|
CaptivePortal,
|
||||||
Finding,
|
Finding,
|
||||||
|
|
@ -621,48 +622,7 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
asn = geo.asn if options.target_kind != "asn" else options.target_value
|
asn = geo.asn if options.target_kind != "asn" else options.target_value
|
||||||
|
|
||||||
# Phase 2 — bgp || reputation || dns_leak || dns_advanced || path_diversity
|
# Phase 2 — bgp || reputation || dns_leak || dns_advanced || path_diversity
|
||||||
bgp_result, rep_result, dns_result, dns_advanced_result, path_diversity_result = await gather_modules(
|
await _run_phase_2(modules, client, settings, options, local, geo, bundle, asn, raw, timeouts, flags)
|
||||||
run_module("bgp", _bgp_section(client, settings, asn, raw), timeout=timeouts.module_seconds),
|
|
||||||
run_module(
|
|
||||||
"reputation", _reputation_section(client, settings, options, geo, raw), timeout=timeouts.module_seconds
|
|
||||||
),
|
|
||||||
run_module(
|
|
||||||
"dns_leak",
|
|
||||||
collect_dns_leak(local, asn, settings.providers.cymru_origin_zone, timeouts.dns_seconds),
|
|
||||||
timeout=timeouts.module_seconds,
|
|
||||||
),
|
|
||||||
run_module("dns_advanced", _dns_advanced_section(client, settings, options), timeout=timeouts.module_seconds),
|
|
||||||
run_module(
|
|
||||||
"path_diversity",
|
|
||||||
_path_diversity_section(client, settings, options, geo.country_code),
|
|
||||||
timeout=timeouts.module_seconds,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
modules["bgp"], modules["reputation"] = bgp_result, rep_result
|
|
||||||
modules["dns_advanced"], modules["path_diversity"] = dns_advanced_result, path_diversity_result
|
|
||||||
ctx = VpnContext(
|
|
||||||
local=local,
|
|
||||||
geo=geo,
|
|
||||||
cf=bundle.get("cf_trace"),
|
|
||||||
dns_leak=dns_result.data,
|
|
||||||
pdb_info_type=getattr(bgp_result.data, "pdb_info_type", None),
|
|
||||||
os_timezone=_os_timezone(),
|
|
||||||
provider_flags=flags,
|
|
||||||
)
|
|
||||||
signals = gather_vpn_signals(ctx)
|
|
||||||
modules["vpn_assessment"] = ModuleResult(
|
|
||||||
name="vpn_assessment",
|
|
||||||
status="ok" if dns_result.status == "ok" else "partial",
|
|
||||||
data=assess_vpn(
|
|
||||||
signals,
|
|
||||||
settings.thresholds.vpn_confidence,
|
|
||||||
tunnel_iface=local.iface_name if is_tunnel_iface(local.iface_name or "") else None,
|
|
||||||
dns_leak=dns_result.data,
|
|
||||||
),
|
|
||||||
errors=dns_result.errors,
|
|
||||||
started_at=dns_result.started_at,
|
|
||||||
duration_ms=dns_result.duration_ms,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Phase 3 — latency || traceroute, both bounded
|
# Phase 3 — latency || traceroute, both bounded
|
||||||
hosts = [(h.label, h.host) for h in settings.probing.reference_hosts]
|
hosts = [(h.label, h.host) for h in settings.probing.reference_hosts]
|
||||||
|
|
@ -710,42 +670,8 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
modules["latency"].data = (modules["latency"].data or []) + (v6_result.data or [])
|
modules["latency"].data = (modules["latency"].data or []) + (v6_result.data or [])
|
||||||
modules["latency"].warnings += v6_result.warnings
|
modules["latency"].warnings += v6_result.warnings
|
||||||
|
|
||||||
# Phase 3b — prefix benchmark and DPI check, opt-in and exclusive: each is a
|
# Phase 3b & 3c
|
||||||
# single-target/self-scoped probe that should not share the wire with the
|
await _run_phase_3bc(modules, caps, settings, options, local, timeouts, cycles)
|
||||||
# reference-host latency fanout above.
|
|
||||||
modules["prefix_benchmark"] = await run_module(
|
|
||||||
"prefix_benchmark",
|
|
||||||
_prefix_bench_section(caps, settings, options, bgp_result.data),
|
|
||||||
timeout=timeouts.subprocess_seconds,
|
|
||||||
)
|
|
||||||
modules["dpi_check"] = await run_module(
|
|
||||||
"dpi_check", _dpi_section(settings, options), timeout=timeouts.module_seconds
|
|
||||||
)
|
|
||||||
modules["ecmp"] = await run_module(
|
|
||||||
"ecmp", _ecmp_section(caps, settings, options, cycles), timeout=timeouts.subprocess_seconds
|
|
||||||
)
|
|
||||||
modules["pmtud"] = await run_module(
|
|
||||||
"pmtud", _pmtud_section(settings, options, local.iface_mtu), timeout=timeouts.subprocess_seconds
|
|
||||||
)
|
|
||||||
modules["quic"] = await run_module(
|
|
||||||
"quic", _quic_section(settings, options), timeout=timeouts.module_seconds
|
|
||||||
)
|
|
||||||
|
|
||||||
# Phase 3c — per-hop ASN/AS-name/country enrichment. Mutates the trace hops
|
|
||||||
# in place; a lookup failure must never downgrade the trace itself, so only
|
|
||||||
# its warnings (not its status) get folded into modules["path"].
|
|
||||||
enrich_result = await run_module(
|
|
||||||
"path_enrich",
|
|
||||||
enrich_hops(
|
|
||||||
modules["path"].data or [],
|
|
||||||
origin_zone=settings.providers.cymru_origin_zone,
|
|
||||||
origin6_zone=settings.providers.cymru_origin6_zone,
|
|
||||||
asn_zone=settings.providers.cymru_asn_zone,
|
|
||||||
timeout=timeouts.dns_seconds,
|
|
||||||
),
|
|
||||||
timeout=timeouts.module_seconds,
|
|
||||||
)
|
|
||||||
modules["path"].warnings.extend(enrich_result.warnings)
|
|
||||||
|
|
||||||
# Phase 4 — speed, exclusive: nothing else is in flight at this point.
|
# Phase 4 — speed, exclusive: nothing else is in flight at this point.
|
||||||
pings = modules["latency"].data or []
|
pings = modules["latency"].data or []
|
||||||
|
|
@ -763,6 +689,127 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
)
|
)
|
||||||
|
|
||||||
# Phase 5 — interpret
|
# Phase 5 — interpret
|
||||||
|
findings = _interpret_findings(modules, settings, local, geo, bundle)
|
||||||
|
|
||||||
|
# Phase 6 — export
|
||||||
|
return _export_report(
|
||||||
|
modules, findings, raw, settings, options, started_at, caps, local, asn
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def _run_phase_3bc(
|
||||||
|
modules: dict[str, ModuleResult],
|
||||||
|
caps: Capabilities,
|
||||||
|
settings: Settings,
|
||||||
|
options: Options,
|
||||||
|
local: LocalNet,
|
||||||
|
timeouts: Any,
|
||||||
|
cycles: int,
|
||||||
|
) -> None:
|
||||||
|
# Phase 3b — prefix benchmark and DPI check, opt-in and exclusive: each is a
|
||||||
|
# single-target/self-scoped probe that should not share the wire with the
|
||||||
|
# reference-host latency fanout above.
|
||||||
|
modules["prefix_benchmark"] = await run_module(
|
||||||
|
"prefix_benchmark",
|
||||||
|
_prefix_bench_section(caps, settings, options, modules.get("bgp", ModuleResult(name="", status="")).data),
|
||||||
|
timeout=timeouts.subprocess_seconds,
|
||||||
|
)
|
||||||
|
modules["dpi_check"] = await run_module(
|
||||||
|
"dpi_check", _dpi_section(settings, options), timeout=timeouts.module_seconds
|
||||||
|
)
|
||||||
|
modules["ecmp"] = await run_module(
|
||||||
|
"ecmp", _ecmp_section(caps, settings, options, cycles), timeout=timeouts.subprocess_seconds
|
||||||
|
)
|
||||||
|
modules["pmtud"] = await run_module(
|
||||||
|
"pmtud", _pmtud_section(settings, options, local.iface_mtu), timeout=timeouts.subprocess_seconds
|
||||||
|
)
|
||||||
|
modules["quic"] = await run_module(
|
||||||
|
"quic", _quic_section(settings, options), timeout=timeouts.module_seconds
|
||||||
|
)
|
||||||
|
|
||||||
|
# Phase 3c — per-hop ASN/AS-name/country enrichment. Mutates the trace hops
|
||||||
|
# in place; a lookup failure must never downgrade the trace itself, so only
|
||||||
|
# its warnings (not its status) get folded into modules["path"].
|
||||||
|
enrich_result = await run_module(
|
||||||
|
"path_enrich",
|
||||||
|
enrich_hops(
|
||||||
|
modules["path"].data or [],
|
||||||
|
origin_zone=settings.providers.cymru_origin_zone,
|
||||||
|
origin6_zone=settings.providers.cymru_origin6_zone,
|
||||||
|
asn_zone=settings.providers.cymru_asn_zone,
|
||||||
|
timeout=timeouts.dns_seconds,
|
||||||
|
),
|
||||||
|
timeout=timeouts.module_seconds,
|
||||||
|
)
|
||||||
|
modules["path"].warnings.extend(enrich_result.warnings)
|
||||||
|
|
||||||
|
|
||||||
|
async def _run_phase_2(
|
||||||
|
modules: dict[str, ModuleResult],
|
||||||
|
client: httpx.AsyncClient,
|
||||||
|
settings: Settings,
|
||||||
|
options: Options,
|
||||||
|
local: LocalNet,
|
||||||
|
geo: IpGeo,
|
||||||
|
bundle: dict,
|
||||||
|
asn: str | None,
|
||||||
|
raw: dict[str, Any],
|
||||||
|
timeouts: Any,
|
||||||
|
flags: dict,
|
||||||
|
) -> None:
|
||||||
|
bgp_result, rep_result, dns_result, dns_advanced_result, path_diversity_result = await gather_modules(
|
||||||
|
run_module("bgp", _bgp_section(client, settings, asn, raw), timeout=timeouts.module_seconds),
|
||||||
|
run_module(
|
||||||
|
"reputation", _reputation_section(client, settings, options, geo, raw), timeout=timeouts.module_seconds
|
||||||
|
),
|
||||||
|
run_module(
|
||||||
|
"dns_leak",
|
||||||
|
collect_dns_leak(local, asn, settings.providers.cymru_origin_zone, timeouts.dns_seconds),
|
||||||
|
timeout=timeouts.module_seconds,
|
||||||
|
),
|
||||||
|
run_module("dns_advanced", _dns_advanced_section(client, settings, options), timeout=timeouts.module_seconds),
|
||||||
|
run_module(
|
||||||
|
"path_diversity",
|
||||||
|
_path_diversity_section(client, settings, options, geo.country_code),
|
||||||
|
timeout=timeouts.module_seconds,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
modules["bgp"], modules["reputation"] = bgp_result, rep_result
|
||||||
|
modules["dns_advanced"], modules["path_diversity"] = dns_advanced_result, path_diversity_result
|
||||||
|
ctx = VpnContext(
|
||||||
|
local=local,
|
||||||
|
geo=geo,
|
||||||
|
cf=bundle.get("cf_trace"),
|
||||||
|
dns_leak=dns_result.data,
|
||||||
|
pdb_info_type=getattr(bgp_result.data, "pdb_info_type", None),
|
||||||
|
os_timezone=_os_timezone(),
|
||||||
|
provider_flags=flags,
|
||||||
|
)
|
||||||
|
signals = gather_vpn_signals(ctx)
|
||||||
|
modules["vpn_assessment"] = ModuleResult(
|
||||||
|
name="vpn_assessment",
|
||||||
|
status="ok" if dns_result.status == "ok" else "partial",
|
||||||
|
data=assess_vpn(
|
||||||
|
signals,
|
||||||
|
settings.thresholds.vpn_confidence,
|
||||||
|
tunnel_iface=local.iface_name if is_tunnel_iface(local.iface_name or "") else None,
|
||||||
|
dns_leak=dns_result.data,
|
||||||
|
),
|
||||||
|
errors=dns_result.errors,
|
||||||
|
started_at=dns_result.started_at,
|
||||||
|
duration_ms=dns_result.duration_ms,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _interpret_findings(
|
||||||
|
modules: dict[str, ModuleResult],
|
||||||
|
settings: Settings,
|
||||||
|
local: LocalNet,
|
||||||
|
geo: IpGeo,
|
||||||
|
bundle: dict,
|
||||||
|
) -> list[Finding]:
|
||||||
speed = modules["speed"].data or SpeedResult()
|
speed = modules["speed"].data or SpeedResult()
|
||||||
l7_findings: list[Finding] = list(tls_findings(modules["tls"].data or [], settings.thresholds))
|
l7_findings: list[Finding] = list(tls_findings(modules["tls"].data or [], settings.thresholds))
|
||||||
if modules["prefix_benchmark"].data is not None:
|
if modules["prefix_benchmark"].data is not None:
|
||||||
|
|
@ -776,8 +823,8 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
if modules["quic"].data is not None:
|
if modules["quic"].data is not None:
|
||||||
l7_findings += quic_findings(modules["quic"].data, settings.thresholds)
|
l7_findings += quic_findings(modules["quic"].data, settings.thresholds)
|
||||||
traces = modules["path"].data or []
|
traces = modules["path"].data or []
|
||||||
findings = _dedupe(
|
return _dedupe(
|
||||||
latency_findings(pings, settings.thresholds)
|
latency_findings(modules["latency"].data or [], settings.thresholds)
|
||||||
+ [f for trace in traces for f in path_findings(trace, local, settings.thresholds)]
|
+ [f for trace in traces for f in path_findings(trace, local, settings.thresholds)]
|
||||||
+ [f for trace in traces for f in path_asn_findings(trace, geo.country_code)]
|
+ [f for trace in traces for f in path_asn_findings(trace, geo.country_code)]
|
||||||
+ speed_findings(speed, settings.thresholds.bufferbloat_ms, geo.country)
|
+ speed_findings(speed, settings.thresholds.bufferbloat_ms, geo.country)
|
||||||
|
|
@ -787,10 +834,21 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
+ captive_portal_findings(modules["captive_portal"].data or CaptivePortal())
|
+ captive_portal_findings(modules["captive_portal"].data or CaptivePortal())
|
||||||
+ [f for report in (modules["ecmp"].data or []) for f in ecmp_findings(report)]
|
+ [f for report in (modules["ecmp"].data or []) for f in ecmp_findings(report)]
|
||||||
+ [f for result in (modules["pmtud"].data or []) for f in pmtud_findings(result)]
|
+ [f for result in (modules["pmtud"].data or []) for f in pmtud_findings(result)]
|
||||||
+ dual_family_findings(pings)
|
+ dual_family_findings(modules["latency"].data or [])
|
||||||
)
|
)
|
||||||
|
|
||||||
# Phase 6 — export
|
|
||||||
|
def _export_report(
|
||||||
|
modules: dict[str, ModuleResult],
|
||||||
|
findings: list[Finding],
|
||||||
|
raw: dict[str, Any],
|
||||||
|
settings: Settings,
|
||||||
|
options: Options,
|
||||||
|
started_at: str,
|
||||||
|
caps: Capabilities,
|
||||||
|
local: LocalNet,
|
||||||
|
asn: str | None,
|
||||||
|
) -> tuple[dict, list[Path]]:
|
||||||
meta = {
|
meta = {
|
||||||
"run_id": uuid.uuid4().hex[:12],
|
"run_id": uuid.uuid4().hex[:12],
|
||||||
"started_at": started_at,
|
"started_at": started_at,
|
||||||
|
|
@ -829,9 +887,9 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
"dropped_backends": dropped,
|
"dropped_backends": dropped,
|
||||||
}
|
}
|
||||||
report = build_report(meta, modules, findings, raw)
|
report = build_report(meta, modules, findings, raw)
|
||||||
asn = meta.get("target") or egress_asn(report)
|
actual_asn = meta.get("target") or egress_asn(report)
|
||||||
md_name = report_filename(asn, started_at, "md")
|
md_name = report_filename(actual_asn, started_at, "md")
|
||||||
ru_md_name = report_filename(asn, started_at, "ru.md")
|
ru_md_name = report_filename(actual_asn, started_at, "ru.md")
|
||||||
sibling_for_md, sibling_for_ru = format_siblings(options.formats, md_name, ru_md_name)
|
sibling_for_md, sibling_for_ru = format_siblings(options.formats, md_name, ru_md_name)
|
||||||
artifacts: dict[str, str] = {}
|
artifacts: dict[str, str] = {}
|
||||||
if "md" in options.formats:
|
if "md" in options.formats:
|
||||||
|
|
@ -850,7 +908,7 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
if settings.history.auto_diff:
|
if settings.history.auto_diff:
|
||||||
if "json" in options.formats:
|
if "json" in options.formats:
|
||||||
try:
|
try:
|
||||||
key = report.get("meta", {}).get("target") or asn
|
key = report.get("meta", {}).get("target") or actual_asn
|
||||||
previous = history.find_previous(settings.output.logs_dir, key or "unknown", limit=1) if key else []
|
previous = history.find_previous(settings.output.logs_dir, key or "unknown", limit=1) if key else []
|
||||||
if previous:
|
if previous:
|
||||||
previous_report = load_report(previous[0])
|
previous_report = load_report(previous[0])
|
||||||
|
|
@ -866,7 +924,6 @@ async def diagnose(settings: Settings, options: Options) -> tuple[dict, list[Pat
|
||||||
paths = write_report(report, artifacts, Path(settings.output.logs_dir))
|
paths = write_report(report, artifacts, Path(settings.output.logs_dir))
|
||||||
return report, paths
|
return report, paths
|
||||||
|
|
||||||
|
|
||||||
def _check_ndt7_consent(settings: Settings) -> bool:
|
def _check_ndt7_consent(settings: Settings) -> bool:
|
||||||
consent_marker = Path(settings.output.cache_dir) / "ndt7_consent"
|
consent_marker = Path(settings.output.cache_dir) / "ndt7_consent"
|
||||||
if consent_marker.exists():
|
if consent_marker.exists():
|
||||||
|
|
@ -884,6 +941,81 @@ def _check_ndt7_consent(settings: Settings) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _build_options(
|
||||||
|
target: str | None,
|
||||||
|
kind: str | None,
|
||||||
|
value: str | None,
|
||||||
|
quick: bool,
|
||||||
|
full: bool,
|
||||||
|
target_host: str | None,
|
||||||
|
speedtest_server: str | None,
|
||||||
|
dnsbl: bool,
|
||||||
|
ndt7: bool,
|
||||||
|
tcp_trace: bool,
|
||||||
|
tls: bool,
|
||||||
|
dns_advanced: bool,
|
||||||
|
path_diversity: bool,
|
||||||
|
prefix_bench: bool,
|
||||||
|
ecmp: bool,
|
||||||
|
pmtud: bool,
|
||||||
|
quic: bool,
|
||||||
|
ipv6: bool | None,
|
||||||
|
my_server: str | None,
|
||||||
|
formats: frozenset[str],
|
||||||
|
webhook: str | None,
|
||||||
|
) -> Options:
|
||||||
|
return Options(
|
||||||
|
mode="target" if target else "auto",
|
||||||
|
target_kind=kind,
|
||||||
|
target_value=value,
|
||||||
|
quick=quick and not full,
|
||||||
|
full=full,
|
||||||
|
extra_host=target_host,
|
||||||
|
speedtest_server=speedtest_server,
|
||||||
|
dnsbl=dnsbl,
|
||||||
|
ndt7=ndt7,
|
||||||
|
tcp_trace=tcp_trace,
|
||||||
|
tls=tls or full,
|
||||||
|
dns_advanced=dns_advanced or full,
|
||||||
|
path_diversity=path_diversity or full,
|
||||||
|
prefix_bench=prefix_bench,
|
||||||
|
ecmp=ecmp,
|
||||||
|
pmtud=pmtud,
|
||||||
|
quic=quic,
|
||||||
|
ipv6=ipv6,
|
||||||
|
dpi_target=my_server,
|
||||||
|
formats=formats,
|
||||||
|
webhook=webhook,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_interface(interface: str, options: Options) -> None:
|
||||||
|
addrs_by_iface = {
|
||||||
|
name: [(a.family, a.address.split("%")[0]) for a in addrs]
|
||||||
|
for name, addrs in psutil.net_if_addrs().items()
|
||||||
|
}
|
||||||
|
up_by_iface = {name: stats.isup for name, stats in psutil.net_if_stats().items()}
|
||||||
|
bind = resolve_bind_target(interface, addrs_by_iface, up_by_iface)
|
||||||
|
if bind.error:
|
||||||
|
raise typer.BadParameter(bind.error, param_hint="--interface")
|
||||||
|
options.interface = interface
|
||||||
|
options.bind = bind
|
||||||
|
if bind.ipv4:
|
||||||
|
probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
try:
|
||||||
|
probe.bind((bind.ipv4, 0))
|
||||||
|
probe.connect(("1.1.1.1", 53))
|
||||||
|
except OSError:
|
||||||
|
console.print(
|
||||||
|
f"[yellow]--interface {bind.iface_name}: no route to the internet from this "
|
||||||
|
"address yet — continuing, this run may show every module as unreachable.[/yellow]"
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
probe.close()
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def run(
|
def run(
|
||||||
full: bool = typer.Option(False, "--full", help="Full run: speedtest and full MTR cycles."),
|
full: bool = typer.Option(False, "--full", help="Full run: speedtest and full MTR cycles."),
|
||||||
|
|
@ -999,52 +1131,31 @@ def run(
|
||||||
)
|
)
|
||||||
kind, value = parse_target(target) if target else (None, None)
|
kind, value = parse_target(target) if target else (None, None)
|
||||||
formats = parse_formats(format_, ru=ru, json_flag=json_flag, default=frozenset(settings.output.formats))
|
formats = parse_formats(format_, ru=ru, json_flag=json_flag, default=frozenset(settings.output.formats))
|
||||||
options = Options(
|
options = _build_options(
|
||||||
mode="target" if target else "auto",
|
target=target,
|
||||||
target_kind=kind,
|
kind=kind,
|
||||||
target_value=value,
|
value=value,
|
||||||
quick=quick and not full,
|
quick=quick,
|
||||||
full=full,
|
full=full,
|
||||||
extra_host=target_host,
|
target_host=target_host,
|
||||||
speedtest_server=speedtest_server,
|
speedtest_server=speedtest_server,
|
||||||
dnsbl=dnsbl,
|
dnsbl=dnsbl,
|
||||||
ndt7=ndt7,
|
ndt7=ndt7,
|
||||||
tcp_trace=tcp_trace,
|
tcp_trace=tcp_trace,
|
||||||
tls=tls or full,
|
tls=tls,
|
||||||
dns_advanced=dns_advanced or full,
|
dns_advanced=dns_advanced,
|
||||||
path_diversity=path_diversity or full,
|
path_diversity=path_diversity,
|
||||||
prefix_bench=prefix_bench,
|
prefix_bench=prefix_bench,
|
||||||
ecmp=ecmp,
|
ecmp=ecmp,
|
||||||
pmtud=pmtud,
|
pmtud=pmtud,
|
||||||
quic=quic,
|
quic=quic,
|
||||||
ipv6=ipv6,
|
ipv6=ipv6,
|
||||||
dpi_target=my_server,
|
my_server=my_server,
|
||||||
formats=formats,
|
formats=formats,
|
||||||
webhook=webhook,
|
webhook=webhook,
|
||||||
)
|
)
|
||||||
if interface:
|
if interface:
|
||||||
addrs_by_iface = {
|
_setup_interface(interface, options)
|
||||||
name: [(a.family, a.address.split("%")[0]) for a in addrs]
|
|
||||||
for name, addrs in psutil.net_if_addrs().items()
|
|
||||||
}
|
|
||||||
up_by_iface = {name: stats.isup for name, stats in psutil.net_if_stats().items()}
|
|
||||||
bind = resolve_bind_target(interface, addrs_by_iface, up_by_iface)
|
|
||||||
if bind.error:
|
|
||||||
raise typer.BadParameter(bind.error, param_hint="--interface")
|
|
||||||
options.interface = interface
|
|
||||||
options.bind = bind
|
|
||||||
if bind.ipv4:
|
|
||||||
probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
try:
|
|
||||||
probe.bind((bind.ipv4, 0))
|
|
||||||
probe.connect(("1.1.1.1", 53))
|
|
||||||
except OSError:
|
|
||||||
console.print(
|
|
||||||
f"[yellow]--interface {bind.iface_name}: no route to the internet from this "
|
|
||||||
"address yet — continuing, this run may show every module as unreachable.[/yellow]"
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
probe.close()
|
|
||||||
if ndt7:
|
if ndt7:
|
||||||
options.ndt7 = _check_ndt7_consent(settings)
|
options.ndt7 = _check_ndt7_consent(settings)
|
||||||
if tcp_trace:
|
if tcp_trace:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue