""" ISP API Routes Flask routes for the Virtual ISP Stack API endpoints """ from flask import Blueprint, jsonify, request, Response from flask_cors import cross_origin import json import time from typing import Dict, Any # Import core modules from core.dhcp_server import DHCPServer from core.nat_engine import NATEngine from core.firewall import FirewallEngine, FirewallRule, FirewallRuleBuilder, FirewallAction, FirewallDirection from core.tcp_engine import TCPEngine from core.virtual_router import VirtualRouter from core.socket_translator import SocketTranslator from core.packet_bridge import PacketBridge from core.session_tracker import SessionTracker, SessionType, SessionState from core.logger import VirtualISPLogger, LogLevel, LogCategory, LogFilter from core.openvpn_manager import OpenVPNManager, initialize_openvpn_manager, get_openvpn_manager # Create blueprint isp_api = Blueprint('isp_api', __name__) # Global instances (will be initialized by main app) dhcp_server: DHCPServer = None nat_engine: NATEngine = None firewall_engine: FirewallEngine = None tcp_engine: TCPEngine = None virtual_router: VirtualRouter = None socket_translator: SocketTranslator = None packet_bridge: PacketBridge = None session_tracker: SessionTracker = None logger: VirtualISPLogger = None openvpn_manager: OpenVPNManager = None def init_engines(config: Dict[str, Any]): """Initialize all engines with configuration""" global dhcp_server, nat_engine, firewall_engine, tcp_engine global virtual_router, socket_translator, packet_bridge, session_tracker, logger, openvpn_manager # Initialize logger first logger = VirtualISPLogger(config.get('logger', {})) logger.start() # Initialize core engines dhcp_server = DHCPServer(config.get('dhcp', {})) nat_engine = NATEngine(config.get('nat', {})) firewall_engine = FirewallEngine(config.get('firewall', {})) tcp_engine = TCPEngine(config.get('tcp', {})) virtual_router = VirtualRouter(config.get('router', {})) socket_translator = SocketTranslator(config.get('socket_translator', {})) packet_bridge = PacketBridge(config.get('packet_bridge', {})) session_tracker = SessionTracker(config.get('session_tracker', {})) # Initialize OpenVPN manager openvpn_manager = initialize_openvpn_manager(config.get('openvpn', {})) openvpn_manager.set_isp_components( dhcp_server=dhcp_server, nat_engine=nat_engine, firewall=firewall_engine, router=virtual_router ) # Start engines dhcp_server.start() nat_engine.start() tcp_engine.start() socket_translator.start() session_tracker.start() packet_bridge.start() logger.info(LogCategory.SYSTEM, 'api', 'All engines initialized and started') # Configuration endpoints @isp_api.route('/config', methods=['GET']) @cross_origin() def get_config(): """Get current system configuration""" try: config = { 'dhcp': { 'network': '10.0.0.0/24', 'range_start': '10.0.0.10', 'range_end': '10.0.0.100', 'lease_time': 3600, 'gateway': '10.0.0.1', 'dns_servers': ['8.8.8.8', '8.8.4.4'] }, 'nat': { 'port_range_start': 10000, 'port_range_end': 65535, 'session_timeout': 300 }, 'firewall': { 'default_policy': 'ACCEPT', 'log_blocked': True }, 'tcp': { 'initial_window': 65535, 'max_retries': 3, 'timeout': 30 } } return jsonify({ 'status': 'success', 'config': config }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/config', methods=['POST']) @cross_origin() def update_config(): """Update system configuration""" try: config_data = request.get_json() # Here you would update the actual configuration # For now, just return success if logger: logger.info(LogCategory.SYSTEM, 'api', 'Configuration updated', metadata=config_data) return jsonify({ 'status': 'success', 'message': 'Configuration updated successfully' }) except Exception as e: if logger: logger.error(LogCategory.SYSTEM, 'api', f'Configuration update failed: {str(e)}') return jsonify({ 'status': 'error', 'message': str(e) }), 500 # DHCP endpoints @isp_api.route('/dhcp/leases', methods=['GET']) @cross_origin() def get_dhcp_leases(): """Get DHCP lease table""" try: if not dhcp_server: return jsonify({'status': 'error', 'message': 'DHCP server not initialized'}), 500 leases = dhcp_server.get_leases() return jsonify({ 'status': 'success', 'leases': leases, 'count': len(leases) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/dhcp/leases/', methods=['DELETE']) @cross_origin() def release_dhcp_lease(mac_address): """Release DHCP lease""" try: if not dhcp_server: return jsonify({'status': 'error', 'message': 'DHCP server not initialized'}), 500 success = dhcp_server.release_lease(mac_address) if success: if logger: logger.info(LogCategory.DHCP, 'api', f'Released DHCP lease for {mac_address}') return jsonify({ 'status': 'success', 'message': f'Lease for {mac_address} released' }) else: return jsonify({ 'status': 'error', 'message': f'Lease for {mac_address} not found' }), 404 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # NAT endpoints @isp_api.route('/nat/sessions', methods=['GET']) @cross_origin() def get_nat_sessions(): """Get NAT session table""" try: if not nat_engine: return jsonify({'status': 'error', 'message': 'NAT engine not initialized'}), 500 sessions = nat_engine.get_sessions() return jsonify({ 'status': 'success', 'sessions': sessions, 'count': len(sessions) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/nat/stats', methods=['GET']) @cross_origin() def get_nat_stats(): """Get NAT statistics""" try: if not nat_engine: return jsonify({'status': 'error', 'message': 'NAT engine not initialized'}), 500 stats = nat_engine.get_stats() return jsonify({ 'status': 'success', 'stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # Firewall endpoints @isp_api.route('/firewall/rules', methods=['GET']) @cross_origin() def get_firewall_rules(): """Get firewall rules""" try: if not firewall_engine: return jsonify({'status': 'error', 'message': 'Firewall engine not initialized'}), 500 rules = firewall_engine.get_rules() return jsonify({ 'status': 'success', 'rules': rules, 'count': len(rules) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/firewall/rules', methods=['POST']) @cross_origin() def add_firewall_rule(): """Add firewall rule""" try: if not firewall_engine: return jsonify({'status': 'error', 'message': 'Firewall engine not initialized'}), 500 rule_data = request.get_json() # Build rule using builder builder = FirewallRuleBuilder(rule_data['rule_id']) builder.set_priority(rule_data.get('priority', 100)) builder.set_action(rule_data['action']) builder.set_direction(rule_data.get('direction', 'BOTH')) if 'source_ip' in rule_data: builder.set_source_ip(rule_data['source_ip']) if 'dest_ip' in rule_data: builder.set_dest_ip(rule_data['dest_ip']) if 'source_port' in rule_data: builder.set_source_port(rule_data['source_port']) if 'dest_port' in rule_data: builder.set_dest_port(rule_data['dest_port']) if 'protocol' in rule_data: builder.set_protocol(rule_data['protocol']) if 'description' in rule_data: builder.set_description(rule_data['description']) rule = builder.build() success = firewall_engine.add_rule(rule) if success: if logger: logger.info(LogCategory.FIREWALL, 'api', f'Added firewall rule: {rule.rule_id}') return jsonify({ 'status': 'success', 'message': f'Rule {rule.rule_id} added successfully' }) else: return jsonify({ 'status': 'error', 'message': f'Rule {rule.rule_id} already exists' }), 400 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/firewall/rules/', methods=['DELETE']) @cross_origin() def delete_firewall_rule(rule_id): """Delete firewall rule""" try: if not firewall_engine: return jsonify({'status': 'error', 'message': 'Firewall engine not initialized'}), 500 success = firewall_engine.remove_rule(rule_id) if success: if logger: logger.info(LogCategory.FIREWALL, 'api', f'Deleted firewall rule: {rule_id}') return jsonify({ 'status': 'success', 'message': f'Rule {rule_id} deleted successfully' }) else: return jsonify({ 'status': 'error', 'message': f'Rule {rule_id} not found' }), 404 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/firewall/logs', methods=['GET']) @cross_origin() def get_firewall_logs(): """Get firewall logs""" try: if not firewall_engine: return jsonify({'status': 'error', 'message': 'Firewall engine not initialized'}), 500 limit = request.args.get('limit', 100, type=int) filter_action = request.args.get('action') logs = firewall_engine.get_logs(limit=limit, filter_action=filter_action) return jsonify({ 'status': 'success', 'logs': logs, 'count': len(logs) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/firewall/stats', methods=['GET']) @cross_origin() def get_firewall_stats(): """Get firewall statistics""" try: if not firewall_engine: return jsonify({'status': 'error', 'message': 'Firewall engine not initialized'}), 500 stats = firewall_engine.get_stats() return jsonify({ 'status': 'success', 'stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # TCP connections endpoints @isp_api.route('/tcp/connections', methods=['GET']) @cross_origin() def get_tcp_connections(): """Get TCP connections""" try: if not tcp_engine: return jsonify({'status': 'error', 'message': 'TCP engine not initialized'}), 500 connections = tcp_engine.get_connections() return jsonify({ 'status': 'success', 'connections': connections, 'count': len(connections) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # Router endpoints @isp_api.route('/router/routes', methods=['GET']) @cross_origin() def get_routing_table(): """Get routing table""" try: if not virtual_router: return jsonify({'status': 'error', 'message': 'Virtual router not initialized'}), 500 routes = virtual_router.get_routing_table() return jsonify({ 'status': 'success', 'routes': routes, 'count': len(routes) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/router/interfaces', methods=['GET']) @cross_origin() def get_router_interfaces(): """Get router interfaces""" try: if not virtual_router: return jsonify({'status': 'error', 'message': 'Virtual router not initialized'}), 500 interfaces = virtual_router.get_interfaces() return jsonify({ 'status': 'success', 'interfaces': interfaces, 'count': len(interfaces) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/router/arp', methods=['GET']) @cross_origin() def get_arp_table(): """Get ARP table""" try: if not virtual_router: return jsonify({'status': 'error', 'message': 'Virtual router not initialized'}), 500 arp_table = virtual_router.get_arp_table() return jsonify({ 'status': 'success', 'arp_table': arp_table, 'count': len(arp_table) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/router/stats', methods=['GET']) @cross_origin() def get_router_stats(): """Get router statistics""" try: if not virtual_router: return jsonify({'status': 'error', 'message': 'Virtual router not initialized'}), 500 stats = virtual_router.get_stats() return jsonify({ 'status': 'success', 'stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # Bridge endpoints @isp_api.route('/bridge/clients', methods=['GET']) @cross_origin() def get_bridge_clients(): """Get bridge clients""" try: if not packet_bridge: return jsonify({'status': 'error', 'message': 'Packet bridge not initialized'}), 500 clients = packet_bridge.get_clients() return jsonify({ 'status': 'success', 'clients': clients, 'count': len(clients) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/bridge/stats', methods=['GET']) @cross_origin() def get_bridge_stats(): """Get bridge statistics""" try: if not packet_bridge: return jsonify({'status': 'error', 'message': 'Packet bridge not initialized'}), 500 stats = packet_bridge.get_stats() return jsonify({ 'status': 'success', 'stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # Session tracking endpoints @isp_api.route('/sessions', methods=['GET']) @cross_origin() def get_sessions(): """Get sessions""" try: if not session_tracker: return jsonify({'status': 'error', 'message': 'Session tracker not initialized'}), 500 limit = request.args.get('limit', 100, type=int) offset = request.args.get('offset', 0, type=int) sessions = session_tracker.get_sessions(limit=limit, offset=offset) return jsonify({ 'status': 'success', 'sessions': sessions, 'count': len(sessions) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/sessions/summary', methods=['GET']) @cross_origin() def get_session_summary(): """Get session summary""" try: if not session_tracker: return jsonify({'status': 'error', 'message': 'Session tracker not initialized'}), 500 summary = session_tracker.get_session_summary() return jsonify({ 'status': 'success', 'summary': summary }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # Logging endpoints @isp_api.route('/logs', methods=['GET']) @cross_origin() def get_logs(): """Get system logs""" try: if not logger: return jsonify({'status': 'error', 'message': 'Logger not initialized'}), 500 limit = request.args.get('limit', 100, type=int) offset = request.args.get('offset', 0, type=int) level = request.args.get('level') category = request.args.get('category') search = request.args.get('search') if search: logs = logger.search_logs(search, limit=limit) else: log_filter = LogFilter() if level: log_filter.level_filter = LogLevel(level.upper()) if category: log_filter.category_filter = LogCategory(category.upper()) logs = logger.get_logs(limit=limit, offset=offset, log_filter=log_filter) return jsonify({ 'status': 'success', 'logs': logs, 'count': len(logs) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/logs/errors', methods=['GET']) @cross_origin() def get_error_logs(): """Get recent error logs""" try: if not logger: return jsonify({'status': 'error', 'message': 'Logger not initialized'}), 500 limit = request.args.get('limit', 50, type=int) errors = logger.get_recent_errors(limit=limit) return jsonify({ 'status': 'success', 'errors': errors, 'count': len(errors) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 # System status endpoints @isp_api.route('/status', methods=['GET']) @cross_origin() def get_system_status(): """Get overall system status""" try: status = { 'timestamp': time.time(), 'uptime': time.time() - (time.time() - 3600), # Placeholder 'components': { 'dhcp_server': dhcp_server is not None and dhcp_server.running, 'nat_engine': nat_engine is not None and nat_engine.running, 'firewall_engine': firewall_engine is not None, 'tcp_engine': tcp_engine is not None and tcp_engine.running, 'virtual_router': virtual_router is not None, 'socket_translator': socket_translator is not None and socket_translator.running, 'packet_bridge': packet_bridge is not None and packet_bridge.running, 'session_tracker': session_tracker is not None and session_tracker.running, 'logger': logger is not None and logger.running }, 'stats': {} } # Collect stats from each component if dhcp_server: status['stats']['dhcp_leases'] = len(dhcp_server.get_leases()) if nat_engine: nat_stats = nat_engine.get_stats() status['stats']['nat_sessions'] = nat_stats.get('active_sessions', 0) if firewall_engine: fw_stats = firewall_engine.get_stats() status['stats']['firewall_rules'] = fw_stats.get('total_rules', 0) if tcp_engine: tcp_connections = tcp_engine.get_connections() status['stats']['tcp_connections'] = len(tcp_connections) if packet_bridge: bridge_stats = packet_bridge.get_stats() status['stats']['bridge_clients'] = bridge_stats.get('active_clients', 0) if session_tracker: session_stats = session_tracker.get_stats() status['stats']['total_sessions'] = session_stats.get('active_sessions', 0) return jsonify({ 'status': 'success', 'system_status': status }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/stats', methods=['GET']) @cross_origin() def get_system_stats(): """Get comprehensive system statistics""" try: stats = { 'timestamp': time.time(), 'dhcp': dhcp_server.get_leases() if dhcp_server else {}, 'nat': nat_engine.get_stats() if nat_engine else {}, 'firewall': firewall_engine.get_stats() if firewall_engine else {}, 'router': virtual_router.get_stats() if virtual_router else {}, 'bridge': packet_bridge.get_stats() if packet_bridge else {}, 'sessions': session_tracker.get_stats() if session_tracker else {}, 'logger': logger.get_stats() if logger else {} } return jsonify({ 'status': 'success', 'stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 packet_bridge.start() # OpenVPN endpoints @isp_api.route('/openvpn/status', methods=['GET']) @cross_origin() def get_openvpn_status(): """Get OpenVPN server status""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 status = openvpn_manager.get_server_status() return jsonify({ 'status': 'success', 'openvpn_status': { 'is_running': status.is_running, 'connected_clients': status.connected_clients, 'total_bytes_received': status.total_bytes_received, 'total_bytes_sent': status.total_bytes_sent, 'uptime': status.uptime, 'server_ip': status.server_ip, 'server_port': status.server_port } }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/start', methods=['POST']) @cross_origin() def start_openvpn_server(): """Start OpenVPN server""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 success = openvpn_manager.start_server() if success: return jsonify({ 'status': 'success', 'message': 'OpenVPN server started successfully' }) else: return jsonify({ 'status': 'error', 'message': 'Failed to start OpenVPN server' }), 500 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/stop', methods=['POST']) @cross_origin() def stop_openvpn_server(): """Stop OpenVPN server""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 success = openvpn_manager.stop_server() if success: return jsonify({ 'status': 'success', 'message': 'OpenVPN server stopped successfully' }) else: return jsonify({ 'status': 'error', 'message': 'Failed to stop OpenVPN server' }), 500 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/clients', methods=['GET']) @cross_origin() def get_openvpn_clients(): """Get connected OpenVPN clients""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 clients = openvpn_manager.get_connected_clients() return jsonify({ 'status': 'success', 'clients': clients }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/clients//disconnect', methods=['POST']) @cross_origin() def disconnect_openvpn_client(client_id): """Disconnect a specific OpenVPN client""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 success = openvpn_manager.disconnect_client(client_id) if success: return jsonify({ 'status': 'success', 'message': f'Client {client_id} disconnected successfully' }) else: return jsonify({ 'status': 'error', 'message': f'Failed to disconnect client {client_id}' }), 500 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/config/', methods=['GET']) @cross_origin() def get_client_config(client_name): """Generate client configuration file""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 # Get server IP from request or use default server_ip = request.args.get('server_ip', '127.0.0.1') config = openvpn_manager.generate_client_config(client_name, server_ip) if config: return Response( config, mimetype='text/plain', headers={'Content-Disposition': f'attachment; filename={client_name}.ovpn'} ) else: return jsonify({ 'status': 'error', 'message': 'Failed to generate client configuration' }), 500 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/stats', methods=['GET']) @cross_origin() def get_openvpn_stats(): """Get comprehensive OpenVPN statistics""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 stats = openvpn_manager.get_statistics() return jsonify({ 'status': 'success', 'openvpn_stats': stats }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/configs', methods=['GET']) @cross_origin() def list_client_configs(): """List all stored client configurations""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 configs = openvpn_manager.list_client_configs() return jsonify({ 'status': 'success', 'configs': configs, 'count': len(configs) }) except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/configs/', methods=['GET']) @cross_origin() def get_stored_client_config(client_name): """Get stored client configuration""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 config_content = openvpn_manager.load_client_config(client_name) if config_content: return Response( config_content, mimetype='text/plain', headers={'Content-Disposition': f'attachment; filename={client_name}.ovpn'} ) else: return jsonify({ 'status': 'error', 'message': f'Configuration for {client_name} not found' }), 404 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/configs/', methods=['DELETE']) @cross_origin() def delete_stored_client_config(client_name): """Delete stored client configuration""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 success = openvpn_manager.delete_client_config(client_name) if success: return jsonify({ 'status': 'success', 'message': f'Configuration for {client_name} deleted successfully' }) else: return jsonify({ 'status': 'error', 'message': f'Configuration for {client_name} not found' }), 404 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500 @isp_api.route('/openvpn/configs//generate', methods=['POST']) @cross_origin() def generate_and_save_client_config(client_name): """Generate and save client configuration""" try: if not openvpn_manager: return jsonify({ 'status': 'error', 'message': 'OpenVPN manager not initialized' }), 500 # Get server IP from request or use default server_ip = request.args.get('server_ip', '127.0.0.1') config_content = openvpn_manager.generate_and_save_client_config(client_name, server_ip) if config_content: return jsonify({ 'status': 'success', 'message': f'Configuration for {client_name} generated and saved successfully' }) else: return jsonify({ 'status': 'error', 'message': f'Failed to generate configuration for {client_name}' }), 500 except Exception as e: return jsonify({ 'status': 'error', 'message': str(e) }), 500