it
This commit is contained in:
102
core/scanner.py
102
core/scanner.py
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user