This commit is contained in:
overcuriousity
2025-09-11 21:38:04 +02:00
parent b47e679992
commit 646b569ced
4 changed files with 163 additions and 91 deletions

View File

@@ -145,44 +145,36 @@ class Scanner:
def start_scan(self, target_domain: str, max_depth: int = 2, clear_graph: bool = True) -> bool:
"""
Start a new reconnaissance scan with concurrent processing.
Enhanced with better debugging and state validation.
Args:
target_domain: Initial domain to investigate
max_depth: Maximum recursion depth
Returns:
bool: True if scan started successfully
Start a new reconnaissance scan.
Forcefully cleans up any previous scan thread before starting.
"""
print(f"=== STARTING SCAN IN SCANNER {id(self)} ===")
print(f"Scanner status: {self.status}")
print(f"Target domain: '{target_domain}', Max depth: {max_depth}")
print(f"Available providers: {len(self.providers) if hasattr(self, 'providers') else 0}")
try:
if self.status == ScanStatus.RUNNING:
print(f"ERROR: Scan already running in scanner {id(self)}, rejecting new scan")
print(f"Current target: {self.current_target}")
print(f"Current depth: {self.current_depth}")
return False
print(f"Initial scanner status: {self.status}")
# If a thread is still alive from a previous scan, we must wait for it to die.
if self.scan_thread and self.scan_thread.is_alive():
print("A previous scan thread is still alive. Sending termination signal and waiting...")
self.stop_scan()
self.scan_thread.join(10.0) # Wait up to 10 seconds
if self.scan_thread.is_alive():
print("ERROR: The previous scan thread is unresponsive and could not be stopped. Please restart the application.")
self.status = ScanStatus.FAILED
return False
print("Previous scan thread terminated successfully.")
# Reset state for the new scan
self.status = ScanStatus.IDLE
print(f"Scanner state is now clean for a new scan.")
try:
# Check if we have any providers
if not hasattr(self, 'providers') or not self.providers:
print(f"ERROR: No providers available in scanner {id(self)}, cannot start scan")
return False
print(f"Scanner {id(self)} validation passed, providers available: {[p.get_name() for p in self.providers]}")
# Stop any existing scan thread
if self.scan_thread and self.scan_thread.is_alive():
print(f"Stopping existing scan thread in scanner {id(self)}...")
self.stop_event.set()
self.scan_thread.join(timeout=5.0)
if self.scan_thread.is_alive():
print(f"WARNING: Could not stop existing thread in scanner {id(self)}")
return False
if clear_graph:
self.graph.clear()
self.current_target = target_domain.lower().strip()
@@ -212,6 +204,7 @@ class Scanner:
except Exception as e:
print(f"ERROR: Exception in start_scan for scanner {id(self)}: {e}")
traceback.print_exc()
self.status = ScanStatus.FAILED
return False
def _execute_scan(self, target_domain: str, max_depth: int) -> None:
@@ -525,7 +518,13 @@ class Scanner:
"""
print(f"Large number of {rel_type.name} relationships for {source}. Creating a large entity node.")
entity_name = f"Large collection of {rel_type.name} for {source}"
self.graph.add_node(entity_name, NodeType.LARGE_ENTITY, metadata={"count": len(targets)})
node_type = 'unknown'
if targets:
if _is_valid_domain(targets[0]):
node_type = 'domain'
elif _is_valid_ip(targets[0]):
node_type = 'ip'
self.graph.add_node(entity_name, NodeType.LARGE_ENTITY, metadata={"count": len(targets), "nodes": targets, "node_type": node_type})
self.graph.add_edge(source, entity_name, rel_type, 0.9, provider_name, {"info": "Aggregated node"})
def _safe_provider_query(self, provider, target: str, is_ip: bool) -> List[Tuple[str, str, RelationshipType, float, Dict[str, Any]]]:
@@ -543,32 +542,27 @@ class Scanner:
def stop_scan(self) -> bool:
"""
Request immediate scan termination with aggressive cancellation.
Request immediate scan termination.
Acts on the thread's liveness, not just the 'RUNNING' status.
"""
try:
if self.status == ScanStatus.RUNNING:
print("=== INITIATING IMMEDIATE SCAN TERMINATION ===")
self.stop_event.set()
for provider in self.providers:
try:
if hasattr(provider, 'session'):
provider.session.close()
print(f"Closed HTTP session for provider: {provider.get_name()}")
except Exception as e:
print(f"Error closing session for {provider.get_name()}: {e}")
if self.executor:
print("Shutting down executor with immediate cancellation...")
self.executor.shutdown(wait=False, cancel_futures=True)
threading.Timer(2.0, self._force_stop_completion).start()
print("Immediate termination requested - ongoing requests will be cancelled")
return True
print("No active scan to stop")
return False
if not self.scan_thread or not self.scan_thread.is_alive():
print("No active scan thread to stop.")
# Cleanup state if inconsistent
if self.status == ScanStatus.RUNNING:
self.status = ScanStatus.STOPPED
return False
print("=== INITIATING IMMEDIATE SCAN TERMINATION ===")
self.status = ScanStatus.STOPPED
self.stop_event.set()
if self.executor:
print("Shutting down executor with immediate cancellation...")
self.executor.shutdown(wait=False, cancel_futures=True)
print("Termination signal sent. The scan thread will stop shortly.")
return True
except Exception as e:
print(f"ERROR: Exception in stop_scan: {e}")
traceback.print_exc()