#!/usr/bin/env python3 """ Complete Network Scanner with pfSense Integration Combines network scanning with pfSense-specific features """ import json import logging import argparse from datetime import datetime from network_scanner import NetworkScanner, NetworkSegment from pfsense_scanner import PfSenseScanner logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) class IntegratedNetworkScanner: """Enhanced network scanner with pfSense integration""" def __init__(self, config: dict): self.config = config self.base_scanner = NetworkScanner(config) self.pfsense_devices = [] def scan_all(self): """Perform complete network scan including pfSense devices""" logger.info("Starting integrated network scan...") # Run base network scan self.base_scanner.scan_all() # Identify and enhance pfSense devices self._scan_pfsense_devices() logger.info("Integrated scan complete") def _scan_pfsense_devices(self): """Find and deeply scan pfSense devices""" logger.info("Looking for pfSense devices...") # Check configured special devices special_devices = self.config.get('special_devices', {}) for segment in self.base_scanner.segments: for device in segment.devices: is_pfsense = False # Check if device is marked as pfSense in config if device.ip in special_devices: if special_devices[device.ip].get('type') == 'firewall' or \ special_devices[device.ip].get('os') == 'pfSense': is_pfsense = True # Check if hostname contains pfsense if device.hostname and 'pfsense' in device.hostname.lower(): is_pfsense = True # Check if device looks like a pfSense (has many routes and ports 80/443) if device.routes and len(device.routes) > 3 and \ 80 in device.open_ports and 443 in device.open_ports: is_pfsense = True if is_pfsense and device.ssh_accessible: logger.info(f"Enhanced scanning pfSense device: {device.ip}") self._enhance_pfsense_device(device) def _enhance_pfsense_device(self, device): """Enhance device info with pfSense-specific data""" try: scanner = PfSenseScanner( device.ip, self.config.get('ssh_user', 'root'), self.config.get('ssh_key_path') ) pfsense_info = scanner.get_full_info() # Merge pfSense-specific info into device device.device_type = 'firewall' device.os_type = 'pfSense (FreeBSD)' # Store additional pfSense data if not hasattr(device, 'pfsense_info'): device.__dict__['pfsense_info'] = pfsense_info # Add DHCP leases to known devices dhcp_leases = pfsense_info.get('dhcp_leases', []) if dhcp_leases: logger.info(f"Found {len(dhcp_leases)} DHCP leases on {device.ip}") # Add VPN info vpn_info = pfsense_info.get('vpn', {}) wireguard = vpn_info.get('wireguard', []) if wireguard: logger.info(f"Found {len(wireguard)} WireGuard tunnels on {device.ip}") self.pfsense_devices.append(device) except Exception as e: logger.error(f"Error enhancing pfSense device {device.ip}: {e}") def export_json(self, filename: str): """Export enhanced results to JSON""" data = { 'scan_timestamp': datetime.now().isoformat(), 'segments': [] } for segment in self.base_scanner.segments: segment_data = { 'name': segment.name, 'cidr': segment.cidr, 'gateway': segment.gateway, 'is_vpn': segment.is_vpn, 'devices': [] } for device in segment.devices: device_data = { 'ip': device.ip, 'hostname': device.hostname, 'mac': device.mac, 'manufacturer': device.manufacturer, 'os_type': device.os_type, 'os_version': device.os_version, 'device_type': device.device_type, 'open_ports': device.open_ports, 'ssh_accessible': device.ssh_accessible, 'services': device.services, 'routes': device.routes, 'interfaces': device.interfaces } # Add pfSense-specific info if available if hasattr(device, 'pfsense_info'): device_data['pfsense_info'] = device.__dict__['pfsense_info'] segment_data['devices'].append(device_data) data['segments'].append(segment_data) with open(filename, 'w') as f: json.dump(data, f, indent=2) logger.info(f"Exported results to {filename}") def print_summary(self): """Print enhanced summary""" print("\n" + "="*80) print("INTEGRATED NETWORK SCAN SUMMARY") print("="*80) total_devices = sum(len(seg.devices) for seg in self.base_scanner.segments) print(f"\nTotal Segments: {len(self.base_scanner.segments)}") print(f"Total Devices: {total_devices}") print(f"pfSense Devices: {len(self.pfsense_devices)}") for segment in self.base_scanner.segments: print(f"\n{'='*80}") print(f"šŸ“” Network: {segment.name} ({segment.cidr})") if segment.is_vpn: print(" šŸ” VPN Network") print(f" Devices: {len(segment.devices)}") for device in segment.devices: icon = self._get_device_icon(device.device_type) print(f"\n {icon} {device.ip}") if device.hostname: print(f" Hostname: {device.hostname}") if device.mac: print(f" MAC: {device.mac}") if device.device_type: print(f" Type: {device.device_type}") if device.os_type: print(f" OS: {device.os_type} {device.os_version or ''}") if device.open_ports: print(f" Ports: {', '.join(map(str, device.open_ports))}") if device.ssh_accessible: print(f" āœ“ SSH Accessible") # Show pfSense-specific info if hasattr(device, 'pfsense_info'): pfsense = device.__dict__['pfsense_info'] print(f" šŸ›”ļø pfSense Firewall:") print(f" Interfaces: {len(pfsense.get('interfaces', []))}") print(f" Routes: {len(pfsense.get('routes', []))}") print(f" DHCP Leases: {len(pfsense.get('dhcp_leases', []))}") vpn = pfsense.get('vpn', {}) wg_count = len(vpn.get('wireguard', [])) ovpn_count = len(vpn.get('openvpn', [])) if wg_count: print(f" WireGuard Tunnels: {wg_count}") if ovpn_count: print(f" OpenVPN Connections: {ovpn_count}") if device.routes and len(device.routes) > 0: print(f" šŸ“‹ Routing Table ({len(device.routes)} routes):") for route in device.routes[:3]: # Show first 3 dest = route.get('destination', 'unknown') gw = route.get('gateway', 'direct') print(f" → {dest} via {gw}") if len(device.routes) > 3: print(f" ... and {len(device.routes) - 3} more") print("\n" + "="*80) def _get_device_icon(self, device_type): """Get emoji icon for device type""" icons = { 'router': 'šŸ”€', 'firewall': 'šŸ›”ļø', 'switch': 'šŸ”Œ', 'server': 'šŸ–„ļø', 'linux_server': '🐧', 'windows_client': 'šŸ’»', 'client': 'šŸ’»' } return icons.get(device_type, 'ā“') def main(): parser = argparse.ArgumentParser( description='Integrated Network Scanner with pfSense Support' ) parser.add_argument('-c', '--config', default='config.json', help='Configuration file (default: config.json)') parser.add_argument('-o', '--output', default='network_scan.json', help='Output JSON file (default: network_scan.json)') parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') parser.add_argument('--generate-svg', action='store_true', help='Automatically generate SVG diagram after scan') args = parser.parse_args() if args.verbose: logging.getLogger().setLevel(logging.DEBUG) # Load configuration try: with open(args.config, 'r') as f: config = json.load(f) logger.info(f"Loaded configuration from {args.config}") except FileNotFoundError: logger.warning(f"Config file {args.config} not found, using defaults") config = {} # Run integrated scanner scanner = IntegratedNetworkScanner(config) scanner.scan_all() # Print summary scanner.print_summary() # Export results scanner.export_json(args.output) print(f"\nāœ“ Scan complete! Results saved to {args.output}") # Generate SVG if requested if args.generate_svg: try: from svg_generator import NetworkDiagramGenerator with open(args.output, 'r') as f: scan_data = json.load(f) svg_file = args.output.replace('.json', '.svg') generator = NetworkDiagramGenerator(scan_data) generator.generate_svg(svg_file) print(f"āœ“ SVG diagram generated: {svg_file}") except Exception as e: logger.error(f"Error generating SVG: {e}") if __name__ == '__main__': main()