This commit is contained in:
Andrew Pimenov 2026-10-07 06:57:33 +03:00 • committed by GitHub
commit 02fa94e6c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 41 additions and 31 deletions

View file

@ -71,7 +71,7 @@ from netsleuth.probes.dns_leak import collect_dns_leak
from netsleuth.probes.hop_asn import enrich_hops
from netsleuth.probes.latency import ping_fanout, tcp_connect_rtt
from netsleuth.probes.nat64 import detect_nat64
from netsleuth.probes.traceroute import filter_trace_tiers, tier_order, traceroute
from netsleuth.probes.traceroute import TracerouteOptions, filter_trace_tiers, tier_order, traceroute
from netsleuth.speed import NDT7_CONSENT_NOTICE
if sys.platform == "win32":
@ -476,13 +476,15 @@ async def _ecmp_section(caps, settings: Settings, options: Options, cycles: int)
*(
traceroute(
host,
caps,
max_hops=settings.probing.max_hops,
cycles=cycles,
timeout=settings.timeouts.subprocess_seconds,
semaphore=semaphore,
tcp_trace=options.tcp_trace,
source_ip=options.bind.ipv4 if options.bind else None,
TracerouteOptions(
caps=caps,
max_hops=settings.probing.max_hops,
cycles=cycles,
timeout=settings.timeouts.subprocess_seconds,
semaphore=semaphore,
tcp_trace=options.tcp_trace,
source_ip=options.bind.ipv4 if options.bind else None,
)
)
for _ in range(cfg.runs)
)
@ -498,13 +500,15 @@ async def _traces(hosts, caps, settings: Settings, cycles: int, options: Options
*(
traceroute(
host,
caps,
max_hops=settings.probing.max_hops,
cycles=cycles,
timeout=settings.timeouts.subprocess_seconds,
semaphore=semaphore,
tcp_trace=options.tcp_trace,
source_ip=options.bind.ipv4 if options.bind else None,
TracerouteOptions(
caps=caps,
max_hops=settings.probing.max_hops,
cycles=cycles,
timeout=settings.timeouts.subprocess_seconds,
semaphore=semaphore,
tcp_trace=options.tcp_trace,
source_ip=options.bind.ipv4 if options.bind else None,
)
)
for _label, host in hosts
)

View file

@ -7,6 +7,7 @@ import platform
import shutil
import threading
from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import TypeVar
from netsleuth.models import Capabilities, TraceConfig, TraceHop, TraceResult
@ -16,6 +17,17 @@ from netsleuth.traceparse import build_trace_result, finalize_hop
_T = TypeVar("_T")
@dataclass(frozen=True)
class TracerouteOptions:
caps: Capabilities
max_hops: int
cycles: int
timeout: float
semaphore: asyncio.Semaphore | None = None
tcp_trace: bool = False
source_ip: str | None = None
def _run_in_daemon_thread(func: Callable[..., _T], *args: object) -> asyncio.Future[_T]:
# asyncio.to_thread()/loop.run_in_executor(None, ...) queue work onto the
# ThreadPoolExecutor-backed default executor, whose worker threads are non-daemon
@ -256,29 +268,23 @@ async def _tier_tcp_trace(
async def traceroute(
target: str,
caps: Capabilities,
max_hops: int,
cycles: int,
timeout: float,
semaphore: asyncio.Semaphore | None = None,
tcp_trace: bool = False,
source_ip: str | None = None,
options: TracerouteOptions,
) -> TraceResult:
builders = {
"tcp_trace": lambda: _tier_tcp_trace(target, max_hops, timeout, source_ip=source_ip),
"tcp_trace": lambda: _tier_tcp_trace(target, options.max_hops, options.timeout, source_ip=options.source_ip),
"mtr_json": lambda: _tier_mtr(
target, caps.mtr_binary or shutil.which("mtr") or "mtr", cycles, max_hops, timeout, source_ip
target, options.caps.mtr_binary or shutil.which("mtr") or "mtr", options.cycles, options.max_hops, options.timeout, options.source_ip
),
"icmp_win": lambda: _tier_icmp_win(target, max_hops, timeout, source_ip),
"icmplib": lambda: _tier_icmplib(target, max_hops, timeout, source_ip=source_ip),
"icmp_win": lambda: _tier_icmp_win(target, options.max_hops, options.timeout, options.source_ip),
"icmplib": lambda: _tier_icmplib(target, options.max_hops, options.timeout, source_ip=options.source_ip),
"system_traceroute": lambda: _tier_system(
target, caps.traceroute_binary or "traceroute", max_hops, timeout, source_ip
target, options.caps.traceroute_binary or "traceroute", options.max_hops, options.timeout, options.source_ip
),
}
order = tier_order(caps, tcp_trace)
order, _dropped = filter_trace_tiers(order, caps.os_name, forced_v4=bool(source_ip))
order = tier_order(options.caps, options.tcp_trace)
order, _dropped = filter_trace_tiers(order, options.caps.os_name, forced_v4=bool(options.source_ip))
tiers = [(name, builders[name]) for name in order]
if semaphore is None:
if options.semaphore is None:
return await run_cascade(tiers)
async with semaphore:
async with options.semaphore:
return await run_cascade(tiers)