Skip to content

Commit e88102d

Browse files
committed
fix scan hanging indefinitely after detectors complete
The asyncio.wait loop waited on cancel_event.wait() even after all detector tasks finished, causing scans to hang forever. Now breaks out when only the cancel waiter remains. Also adds port pre-filtering to endpoint prober (skip closed ports), DNS resolution timeouts, and per-detector completion logging. Scan time: 26+ min → 0.2s.
1 parent 3d7588d commit e88102d

5 files changed

Lines changed: 27 additions & 10 deletions

File tree

agentsniff/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Colors:
4545
/ ___ / /_/ / __/ / / / /_ ___/ / / / / / __/ __/
4646
/_/ |_\\__, /\\___/_/ /_/\\__//____/_/ /_/_/_/ /_/
4747
/____/
48-
{Colors.RESET}{Colors.DIM} AI Agent Network Scanner v1.2.0
48+
{Colors.RESET}{Colors.DIM} AI Agent Network Scanner v1.2.1
4949
Detect AI agents on your network{Colors.RESET}
5050
"""
5151

agentsniff/detectors/dns_monitor.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,15 @@ async def _active_dns_check(self, targets: list[str]) -> list[DetectionSignal]:
208208
self.logger.info("Resolving known LLM API domains for cross-reference...")
209209
for domain in self.config.all_llm_domains[:20]: # Top 20 most common
210210
try:
211-
result = await asyncio.get_event_loop().run_in_executor(
212-
None, lambda d=domain: socket.getaddrinfo(d, 443, socket.AF_INET)
211+
result = await asyncio.wait_for(
212+
asyncio.get_event_loop().run_in_executor(
213+
None, lambda d=domain: socket.getaddrinfo(d, 443, socket.AF_INET)
214+
),
215+
timeout=3.0,
213216
)
214217
for entry in result:
215218
llm_ips.add(entry[4][0])
216-
except (socket.gaierror, OSError):
219+
except (socket.gaierror, OSError, asyncio.TimeoutError):
217220
continue
218221

219222
if llm_ips:

agentsniff/detectors/traffic_analyzer.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,16 @@ async def setup(self):
172172
# Strip port if present
173173
host = domain.split(":")[0]
174174
try:
175-
result = await loop.run_in_executor(
176-
None,
177-
lambda h=host: socket.getaddrinfo(h, 443, socket.AF_INET),
175+
result = await asyncio.wait_for(
176+
loop.run_in_executor(
177+
None,
178+
lambda h=host: socket.getaddrinfo(h, 443, socket.AF_INET),
179+
),
180+
timeout=3.0,
178181
)
179182
for entry in result:
180183
self._llm_ips.add(entry[4][0])
181-
except (socket.gaierror, OSError):
184+
except (socket.gaierror, OSError, asyncio.TimeoutError):
182185
continue
183186

184187
self.logger.info(f"Resolved {len(self._llm_ips)} LLM API IP addresses")

agentsniff/scanner.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,9 @@ async def _correlate_and_notify(signals: list[DetectionSignal]):
302302

303303
async def run_detector(detector):
304304
try:
305-
return await detector.scan(targets)
305+
signals = await detector.scan(targets)
306+
logger.info(f"Detector {detector.name} finished ({len(signals)} signals)")
307+
return signals
306308
except asyncio.CancelledError:
307309
logger.info(f"Detector {detector.name} cancelled")
308310
return []
@@ -357,6 +359,15 @@ async def run_detector(detector):
357359
if cancelled:
358360
break
359361

362+
# All detector tasks done — only cancel_waiter remains
363+
if pending == {cancel_waiter}:
364+
cancel_waiter.cancel()
365+
try:
366+
await cancel_waiter
367+
except asyncio.CancelledError:
368+
pass
369+
break
370+
360371
if not cancelled:
361372
cancel_waiter.cancel()
362373
else:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "agentsniff"
7-
version = "1.2.0"
7+
version = "1.2.1"
88
description = "AI Agent Network Scanner - Detect AI agents on your network"
99
readme = "README.md"
1010
license = {text = "Apache-2.0"}

0 commit comments

Comments
 (0)