Reorganize project structure: move code to src/, docs to docs/, config to config/, scripts to scripts/, results to results/, tests to tests/. Keep only main script and latest scan results in root.

This commit is contained in:
mindesbunister
2025-10-10 15:39:59 +02:00
parent b8e06617e8
commit da5f1f2d0c
26 changed files with 581 additions and 53 deletions

View File

@@ -33,8 +33,8 @@ log_error() {
} }
# Check if we're in the right directory # Check if we're in the right directory
if [ ! -f "integrated_scanner.py" ]; then if [ ! -f "src/integrated_scanner.py" ]; then
log_error "integrated_scanner.py not found. Please run this script from the network scanner directory." log_error "src/integrated_scanner.py not found. Please run this script from the network scanner directory."
exit 1 exit 1
fi fi
@@ -48,7 +48,7 @@ fi
# Step 1: Run system verification # Step 1: Run system verification
log_info "Step 1: Verifying system requirements..." log_info "Step 1: Verifying system requirements..."
if ./test_system.py >/dev/null 2>&1; then if python3 src/test_system.py >/dev/null 2>&1; then
log_success "System verification passed" log_success "System verification passed"
else else
log_error "System verification failed. Please check the output above." log_error "System verification failed. Please check the output above."
@@ -58,7 +58,7 @@ fi
# Step 2: Run integrated network scan # Step 2: Run integrated network scan
log_info "Step 2: Running integrated network scan..." log_info "Step 2: Running integrated network scan..."
SCAN_OUTPUT="network_scan_$(date +%Y%m%d_%H%M%S).json" SCAN_OUTPUT="network_scan_$(date +%Y%m%d_%H%M%S).json"
if ./integrated_scanner.py -o "$SCAN_OUTPUT" -v; then if python3 src/integrated_scanner.py -o "$SCAN_OUTPUT" -v; then
log_success "Network scan completed: $SCAN_OUTPUT" log_success "Network scan completed: $SCAN_OUTPUT"
else else
log_error "Network scan failed" log_error "Network scan failed"
@@ -68,7 +68,7 @@ fi
# Step 3: Generate SVG diagram # Step 3: Generate SVG diagram
log_info "Step 3: Generating network diagram..." log_info "Step 3: Generating network diagram..."
SVG_OUTPUT="${SCAN_OUTPUT%.json}.svg" SVG_OUTPUT="${SCAN_OUTPUT%.json}.svg"
if ./svg_generator.py "$SCAN_OUTPUT" -o "$SVG_OUTPUT"; then if python3 src/svg_generator.py "$SCAN_OUTPUT" -o "$SVG_OUTPUT"; then
log_success "SVG diagram generated: $SVG_OUTPUT" log_success "SVG diagram generated: $SVG_OUTPUT"
else else
log_error "SVG generation failed" log_error "SVG generation failed"
@@ -79,7 +79,7 @@ fi
if [ "$XML_FILES" -gt 0 ]; then if [ "$XML_FILES" -gt 0 ]; then
log_info "Step 4: Generating pfSense network summary..." log_info "Step 4: Generating pfSense network summary..."
SUMMARY_OUTPUT="network_summary_$(date +%Y%m%d_%H%M%S).md" SUMMARY_OUTPUT="network_summary_$(date +%Y%m%d_%H%M%S).md"
if ./pfsense_integrator.py *.xml --summary "$SUMMARY_OUTPUT"; then if python3 src/pfsense_integrator.py *.xml --summary "$SUMMARY_OUTPUT"; then
log_success "Network summary generated: $SUMMARY_OUTPUT" log_success "Network summary generated: $SUMMARY_OUTPUT"
else else
log_warning "Network summary generation failed" log_warning "Network summary generation failed"

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -0,0 +1,53 @@
# Network Topology Summary
Generated from pfSense XML configurations
## pfSense Firewall: gw-nue01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): dhcp
- **LAN** (lan): 10.0.0.1
- **wireguardnachhause** (opt1): 10.69.69.1
- Gateway: WirusguardusGW
### Static Routes
- 172.20.0.0/16 via WirusguardusGW
*heyme*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*heyme*
- Peer: wireguardheyme - Networks: 172.20.0.0/16, 10.69.69.2/32
### DHCP Configuration
## pfSense Firewall: gw-st01
**Version:** unknown
**Domain:** egonetix.lan
### Network Interfaces
- **WAN** (wan): 192.168.178.3
- Gateway: WANGW
- **LAN** (lan): 172.20.20.1
- **wireguardnnbesch** (opt1): 10.69.69.2
- Gateway: wirenuenbesch
- **HomeAssistant** (opt2): 172.20.70.1
- **WireguardOpenvpn** (opt3): 10.5.0.2
- Gateway: WireguardOpenvpnGW
### Static Routes
- 10.0.0.0/24 via wirenuenbesch
*wireguardnünbesch*
- 12.1.0.0/24 via wirenuenbesch
*openvpn nutzer*
### WireGuard VPN
- **Tunnel tun_wg0** (Port 51820)
*de1099.nordvpn.com*
- **Tunnel tun_wg1** (Port 51821)
*wireguardnünbesch*
- Peer: de1099.nordvpn.com - Networks: 0.0.0.0/0
- Peer: wireguardnünbesch - Networks: 10.0.0.0/24, 10.69.69.1/32, 12.1.0.0/24
### DHCP Configuration

View File

@@ -7,7 +7,10 @@ Combines network scanning with pfSense-specific features
import json import json
import logging import logging
import argparse import argparse
import subprocess
import re
from datetime import datetime from datetime import datetime
from typing import Dict
from network_scanner import NetworkScanner, NetworkSegment from network_scanner import NetworkScanner, NetworkSegment
from pfsense_scanner import PfSenseScanner from pfsense_scanner import PfSenseScanner
from dataclasses import asdict from dataclasses import asdict
@@ -38,11 +41,71 @@ class IntegratedNetworkScanner:
# Check for pfSense XML files and integrate them # Check for pfSense XML files and integrate them
self._integrate_pfsense_xml() self._integrate_pfsense_xml()
# Scan pfSense LAN networks
self._scan_pfsense_lan_networks()
# Identify and enhance pfSense devices # Identify and enhance pfSense devices
self._scan_pfsense_devices() self._scan_pfsense_devices()
logger.info("Integrated scan complete") logger.info("Integrated scan complete")
def _scan_pfsense_lan_networks(self):
"""Scan LAN networks served by pfSense devices"""
logger.info("Scanning pfSense LAN networks...")
# Get pfSense configurations from the integrator
try:
from pfsense_integrator import PfSenseIntegrator
import glob
xml_files = glob.glob("*.xml")
if xml_files:
integrator = PfSenseIntegrator(xml_files)
integrator.load_pfsense_configs()
for pfsense_name, pfsense_config in integrator.pfsense_configs.items():
logger.info(f"Checking LAN networks for pfSense: {pfsense_name}")
interfaces = pfsense_config.get('interfaces', {})
for iface_name, iface_config in interfaces.items():
# Skip WAN interfaces and VPN interfaces
if iface_name.lower() in ['wan', 'wireguard', 'openvpn', 'ipsec']:
continue
# Get the network for this interface
ipaddr = iface_config.get('ipaddr')
subnet = iface_config.get('subnet')
if ipaddr and subnet:
try:
# Calculate the network from IP and subnet
import ipaddress
ip = ipaddress.IPv4Address(ipaddr)
net = ipaddress.IPv4Network(f"{ip}/{subnet}", strict=False)
network_cidr = str(net)
logger.info(f"Scanning pfSense LAN network: {network_cidr} (interface: {iface_name})")
# Check if this network is already scanned
existing_networks = [seg.cidr for seg in self.base_scanner.segments]
if network_cidr not in existing_networks:
# Scan this network
lan_segment = self.base_scanner.scan_network(
network_cidr,
f"{pfsense_name}_{iface_name.upper()}",
is_vpn=False
)
self.base_scanner.segments.append(lan_segment)
logger.info(f"Added LAN network {network_cidr} with {len(lan_segment.devices)} devices")
else:
logger.info(f"Network {network_cidr} already scanned")
except Exception as e:
logger.error(f"Error scanning pfSense LAN network {ipaddr}/{subnet}: {e}")
except Exception as e:
logger.error(f"Error scanning pfSense LAN networks: {e}")
def _integrate_pfsense_xml(self): def _integrate_pfsense_xml(self):
"""Automatically integrate pfSense XML files if present""" """Automatically integrate pfSense XML files if present"""
import glob import glob
@@ -91,7 +154,9 @@ class IntegratedNetworkScanner:
enhanced_data = json.load(f) enhanced_data = json.load(f)
# Update segments # Update segments
vpn_interfaces = self._check_vpn_interfaces()
self.base_scanner.segments = [] self.base_scanner.segments = []
for seg_data in enhanced_data.get('segments', []): for seg_data in enhanced_data.get('segments', []):
segment = NetworkSegment( segment = NetworkSegment(
name=seg_data['name'], name=seg_data['name'],
@@ -101,9 +166,48 @@ class IntegratedNetworkScanner:
devices=[] devices=[]
) )
for dev_data in seg_data['devices']: # Only scan VPN networks if VPN interfaces are active
device = Device(**dev_data) if seg_data['is_vpn']:
segment.devices.append(device) if vpn_interfaces:
logger.info(f"Scanning VPN network {seg_data['cidr']} (VPN interfaces active)")
# Scan the VPN network for devices
vpn_segment = self.base_scanner.scan_network(
seg_data['cidr'],
seg_data['name'],
is_vpn=True
)
segment.devices = vpn_segment.devices
else:
logger.info(f"VPN network {seg_data['cidr']} (no active VPN interfaces)")
# Try to scan anyway if network might be reachable
try:
logger.info(f"Attempting to scan VPN network {seg_data['cidr']} anyway...")
vpn_segment = self.base_scanner.scan_network(
seg_data['cidr'],
seg_data['name'],
is_vpn=True
)
segment.devices = vpn_segment.devices
logger.info(f"Successfully scanned VPN network {seg_data['cidr']} with {len(vpn_segment.devices)} devices")
except Exception as e:
logger.warning(f"Could not scan VPN network {seg_data['cidr']}: {e}")
# Keep any devices that were already in the segment data
for dev_data in seg_data['devices']:
device_kwargs = {k: v for k, v in dev_data.items()
if k in ['ip', 'hostname', 'mac', 'manufacturer', 'os_type',
'os_version', 'device_type', 'open_ports', 'ssh_accessible',
'services', 'routes', 'interfaces']}
device = Device(**device_kwargs)
segment.devices.append(device)
else:
# For non-VPN networks, use the devices from the segment data
for dev_data in seg_data['devices']:
device_kwargs = {k: v for k, v in dev_data.items()
if k in ['ip', 'hostname', 'mac', 'manufacturer', 'os_type',
'os_version', 'device_type', 'open_ports', 'ssh_accessible',
'services', 'routes', 'interfaces']}
device = Device(**device_kwargs)
segment.devices.append(device)
self.base_scanner.segments.append(segment) self.base_scanner.segments.append(segment)
@@ -305,6 +409,33 @@ class IntegratedNetworkScanner:
} }
return icons.get(device_type, '') return icons.get(device_type, '')
def _check_vpn_interfaces(self) -> dict:
"""Check which VPN interfaces are active"""
vpn_interfaces = {}
try:
# Check for WireGuard interfaces
result = subprocess.run(
['ip', 'link', 'show'],
capture_output=True,
text=True,
timeout=5
)
for line in result.stdout.splitlines():
if 'wg' in line.lower() or 'tun' in line.lower() or 'tap' in line.lower():
# Extract interface name (format: 123: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> ...)
match = re.search(r'\d+:\s+(\w+):', line)
if match:
iface = match.group(1)
vpn_interfaces[iface] = True
logger.info(f"Found active VPN interface: {iface}")
except Exception as e:
logger.warning(f"Error checking VPN interfaces: {e}")
return vpn_interfaces
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(

View File

@@ -11,8 +11,9 @@ import json
import re import re
import socket import socket
import argparse import argparse
import multiprocessing
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict, field
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
import logging import logging
@@ -34,21 +35,11 @@ class Device:
os_type: Optional[str] = None os_type: Optional[str] = None
os_version: Optional[str] = None os_version: Optional[str] = None
device_type: Optional[str] = None # router, switch, server, client, etc. device_type: Optional[str] = None # router, switch, server, client, etc.
open_ports: List[int] = None open_ports: List[int] = field(default_factory=list)
ssh_accessible: bool = False ssh_accessible: bool = False
services: List[str] = None services: List[str] = field(default_factory=list)
routes: List[Dict] = None routes: List[Dict] = field(default_factory=list)
interfaces: List[Dict] = None interfaces: List[Dict] = field(default_factory=list)
def __post_init__(self):
if self.open_ports is None:
self.open_ports = []
if self.services is None:
self.services = []
if self.routes is None:
self.routes = []
if self.interfaces is None:
self.interfaces = []
@dataclass @dataclass
@@ -59,11 +50,7 @@ class NetworkSegment:
gateway: Optional[str] = None gateway: Optional[str] = None
vlan: Optional[int] = None vlan: Optional[int] = None
is_vpn: bool = False is_vpn: bool = False
devices: List[Device] = None devices: List[Device] = field(default_factory=list)
def __post_init__(self):
if self.devices is None:
self.devices = []
class NetworkScanner: class NetworkScanner:
@@ -114,6 +101,33 @@ class NetworkScanner:
return networks return networks
def _check_vpn_interfaces(self) -> Dict[str, bool]:
"""Check which VPN interfaces are active"""
vpn_interfaces = {}
try:
# Check for WireGuard interfaces
result = subprocess.run(
['ip', 'link', 'show'],
capture_output=True,
text=True,
timeout=5
)
for line in result.stdout.splitlines():
if 'wg' in line.lower() or 'tun' in line.lower() or 'tap' in line.lower():
# Extract interface name (format: 123: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> ...)
match = re.search(r'\d+:\s+(\w+):', line)
if match:
iface = match.group(1)
vpn_interfaces[iface] = True
logger.info(f"Found active VPN interface: {iface}")
except Exception as e:
logger.warning(f"Error checking VPN interfaces: {e}")
return vpn_interfaces
def ping_sweep(self, network: str) -> List[str]: def ping_sweep(self, network: str) -> List[str]:
"""Perform ping sweep to find live hosts""" """Perform ping sweep to find live hosts"""
logger.info(f"Performing ping sweep on {network}") logger.info(f"Performing ping sweep on {network}")
@@ -128,7 +142,10 @@ class NetworkScanner:
logger.warning(f"Large network {network}, limiting scan") logger.warning(f"Large network {network}, limiting scan")
hosts = hosts[:254] hosts = hosts[:254]
with ThreadPoolExecutor(max_workers=50) as executor: max_ping_workers = min(len(hosts), multiprocessing.cpu_count() * 8)
logger.info(f"Pinging {len(hosts)} hosts using {max_ping_workers} concurrent workers")
with ThreadPoolExecutor(max_workers=max_ping_workers) as executor:
future_to_ip = { future_to_ip = {
executor.submit(self._ping_host, str(ip)): str(ip) executor.submit(self._ping_host, str(ip)): str(ip)
for ip in hosts for ip in hosts
@@ -222,10 +239,22 @@ class NetworkScanner:
common_ports = [22, 80, 443, 8080, 8443, 3389, 445, 139, 21, 23, 25, 53, 3306, 5432] common_ports = [22, 80, 443, 8080, 8443, 3389, 445, 139, 21, 23, 25, 53, 3306, 5432]
open_ports = [] open_ports = []
for port in common_ports: max_port_workers = min(len(common_ports), multiprocessing.cpu_count() * 2)
if self._check_port(ip, port):
open_ports.append(port) with ThreadPoolExecutor(max_workers=max_port_workers) as executor:
logger.debug(f"{ip}:{port} - OPEN") future_to_port = {
executor.submit(self._check_port, ip, port): port
for port in common_ports
}
for future in as_completed(future_to_port):
port = future_to_port[future]
try:
if future.result():
open_ports.append(port)
logger.debug(f"{ip}:{port} - OPEN")
except Exception as e:
logger.debug(f"Error checking {ip}:{port}: {e}")
return open_ports return open_ports
@@ -395,7 +424,7 @@ class NetworkScanner:
else: else:
return 'client' return 'client'
def scan_network(self, network: str, name: str = None, is_vpn: bool = False) -> NetworkSegment: def scan_network(self, network: str, name: Optional[str] = None, is_vpn: bool = False) -> NetworkSegment:
"""Scan a complete network segment""" """Scan a complete network segment"""
logger.info(f"Scanning network segment: {network}") logger.info(f"Scanning network segment: {network}")
@@ -409,7 +438,10 @@ class NetworkScanner:
live_hosts = self.ping_sweep(network) live_hosts = self.ping_sweep(network)
# Gather device info # Gather device info
with ThreadPoolExecutor(max_workers=10) as executor: max_device_workers = min(len(live_hosts), multiprocessing.cpu_count() * 2)
logger.info(f"Gathering device info for {len(live_hosts)} hosts using {max_device_workers} concurrent workers")
with ThreadPoolExecutor(max_workers=max_device_workers) as executor:
future_to_ip = { future_to_ip = {
executor.submit(self.get_device_info, ip): ip executor.submit(self.get_device_info, ip): ip
for ip in live_hosts for ip in live_hosts
@@ -431,13 +463,24 @@ class NetworkScanner:
# Discover networks # Discover networks
networks = self.discover_networks() networks = self.discover_networks()
# Scan each network # Scan networks concurrently
for network in networks: max_concurrent_networks = min(len(networks), multiprocessing.cpu_count())
try: logger.info(f"Scanning {len(networks)} networks using {max_concurrent_networks} concurrent processes")
segment = self.scan_network(network)
self.segments.append(segment) with ThreadPoolExecutor(max_workers=max_concurrent_networks) as executor:
except Exception as e: future_to_network = {
logger.error(f"Error scanning {network}: {e}") executor.submit(self.scan_network, network): network
for network in networks
}
for future in as_completed(future_to_network):
network = future_to_network[future]
try:
segment = future.result()
self.segments.append(segment)
logger.info(f"Completed scanning network: {network}")
except Exception as e:
logger.error(f"Error scanning {network}: {e}")
logger.info(f"Scan complete. Found {len(self.segments)} segments") logger.info(f"Scan complete. Found {len(self.segments)} segments")

View File

@@ -82,7 +82,12 @@ class PfSenseIntegrator:
# Look for LAN interface # Look for LAN interface
lan_interface = interfaces.get('lan') lan_interface = interfaces.get('lan')
if lan_interface and lan_interface.get('ipaddr') and lan_interface.get('subnet'): if lan_interface and lan_interface.get('ipaddr') and lan_interface.get('subnet'):
lan_network = f"{lan_interface['ipaddr']}/{lan_interface['subnet']}" # Calculate the proper network address
import ipaddress
ip = ipaddress.IPv4Address(lan_interface['ipaddr'])
subnet_bits = int(lan_interface['subnet'])
network = ipaddress.IPv4Network(f"{ip}/{subnet_bits}", strict=False)
lan_network = str(network)
# Find existing segment # Find existing segment
for segment in segments: for segment in segments:
@@ -213,6 +218,11 @@ class PfSenseIntegrator:
network_cidr = iface_config.get('network_cidr') network_cidr = iface_config.get('network_cidr')
if network_cidr and network_cidr != 'unknown': if network_cidr and network_cidr != 'unknown':
# Filter out invalid networks
if self._is_invalid_network(network_cidr):
logger.warning(f"Skipping invalid interface network: {network_cidr}")
continue
# Check if segment already exists # Check if segment already exists
segment_exists = any(seg.get('cidr') == network_cidr for seg in segments) segment_exists = any(seg.get('cidr') == network_cidr for seg in segments)
@@ -233,6 +243,12 @@ class PfSenseIntegrator:
for peer in wireguard.get('peers', []): for peer in wireguard.get('peers', []):
for allowed_ip in peer.get('allowed_ips', []): for allowed_ip in peer.get('allowed_ips', []):
network = f"{allowed_ip['address']}/{allowed_ip['mask']}" network = f"{allowed_ip['address']}/{allowed_ip['mask']}"
# Filter out invalid networks
if self._is_invalid_network(network):
logger.warning(f"Skipping invalid WireGuard network: {network}")
continue
segment_exists = any(seg.get('cidr') == network for seg in segments) segment_exists = any(seg.get('cidr') == network for seg in segments)
if not segment_exists: if not segment_exists:
@@ -246,6 +262,26 @@ class PfSenseIntegrator:
segments.append(new_segment) segments.append(new_segment)
logger.info(f"Added WireGuard network: {network}") logger.info(f"Added WireGuard network: {network}")
def _is_invalid_network(self, network: str) -> bool:
"""Check if a network should not be scanned"""
try:
import ipaddress
net = ipaddress.ip_network(network, strict=False)
# Skip networks that are too large or invalid
if net.prefixlen == 0: # 0.0.0.0/0 - route all traffic
return True
if net.prefixlen < 8: # Very large networks
return True
if net.network_address.is_private and net.prefixlen < 16: # Large private networks
return True
if str(net.network_address) == '0.0.0.0': # Invalid network
return True
return False
except ValueError:
return True # Invalid network format
def generate_network_summary(self, output_file: str): def generate_network_summary(self, output_file: str):
"""Generate a human-readable network summary""" """Generate a human-readable network summary"""
summary = [] summary = []

View File

@@ -56,11 +56,11 @@ def test_commands():
def test_scripts_exist(): def test_scripts_exist():
"""Check if all scripts exist""" """Check if all scripts exist"""
scripts = [ scripts = [
'network_scanner.py', 'src/network_scanner.py',
'pfsense_scanner.py', 'src/pfsense_scanner.py',
'svg_generator.py', 'src/svg_generator.py',
'integrated_scanner.py', 'src/integrated_scanner.py',
'quickstart.sh' 'scripts/quickstart.sh'
] ]
all_ok = True all_ok = True
@@ -77,10 +77,10 @@ def test_scripts_exist():
def test_script_syntax(): def test_script_syntax():
"""Test Python script syntax""" """Test Python script syntax"""
scripts = [ scripts = [
'network_scanner.py', 'src/network_scanner.py',
'pfsense_scanner.py', 'src/pfsense_scanner.py',
'svg_generator.py', 'src/svg_generator.py',
'integrated_scanner.py' 'src/integrated_scanner.py'
] ]
all_ok = True all_ok = True