|
""" |
|
Main ISP Application |
|
|
|
Integrates all core modules and provides the main application entry point |
|
""" |
|
|
|
import os |
|
import sys |
|
import json |
|
import threading |
|
import time |
|
from flask import Flask |
|
from flask_cors import CORS |
|
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) |
|
|
|
|
|
from src.routes.isp_api import isp_api, init_engines |
|
|
|
|
|
def load_config(): |
|
"""Load configuration from file or use defaults""" |
|
config_file = os.path.join(os.path.dirname(__file__), 'config.json') |
|
|
|
default_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, |
|
"host_ip": "0.0.0.0" |
|
}, |
|
"firewall": { |
|
"default_policy": "ACCEPT", |
|
"log_blocked": True, |
|
"log_accepted": False, |
|
"max_log_entries": 10000, |
|
"rules": [ |
|
{ |
|
"rule_id": "allow_dhcp", |
|
"priority": 1, |
|
"action": "ACCEPT", |
|
"direction": "BOTH", |
|
"dest_port": "67,68", |
|
"protocol": "UDP", |
|
"description": "Allow DHCP traffic", |
|
"enabled": True |
|
}, |
|
{ |
|
"rule_id": "allow_dns", |
|
"priority": 2, |
|
"action": "ACCEPT", |
|
"direction": "BOTH", |
|
"dest_port": "53", |
|
"protocol": "UDP", |
|
"description": "Allow DNS traffic", |
|
"enabled": True |
|
} |
|
] |
|
}, |
|
"tcp": { |
|
"initial_window": 65535, |
|
"max_retries": 3, |
|
"timeout": 300, |
|
"time_wait_timeout": 120, |
|
"mss": 1460 |
|
}, |
|
"router": { |
|
"router_id": "virtual-isp-router", |
|
"default_gateway": "10.0.0.1", |
|
"interfaces": [ |
|
{ |
|
"name": "virtual0", |
|
"ip_address": "10.0.0.1", |
|
"netmask": "255.255.255.0", |
|
"enabled": True, |
|
"mtu": 1500 |
|
} |
|
], |
|
"static_routes": [] |
|
}, |
|
"socket_translator": { |
|
"connect_timeout": 10, |
|
"read_timeout": 30, |
|
"max_connections": 1000, |
|
"buffer_size": 8192 |
|
}, |
|
"packet_bridge": { |
|
"websocket_host": "0.0.0.0", |
|
"websocket_port": 8765, |
|
"tcp_host": "0.0.0.0", |
|
"tcp_port": 8766, |
|
"max_clients": 100, |
|
"client_timeout": 300 |
|
}, |
|
"session_tracker": { |
|
"max_sessions": 10000, |
|
"session_timeout": 3600, |
|
"cleanup_interval": 300, |
|
"metrics_retention": 86400 |
|
}, |
|
"logger": { |
|
"log_level": "INFO", |
|
"log_to_file": True, |
|
"log_file_path": "/tmp/virtual_isp.log", |
|
"log_file_max_size": 10485760, |
|
"log_file_backup_count": 5, |
|
"log_to_console": True, |
|
"structured_logging": True, |
|
"max_memory_logs": 10000 |
|
}, |
|
"openvpn": { |
|
"server_config_path": "/etc/openvpn/server/server.conf", |
|
"ca_cert_path": "/home/ubuntu/openvpn-ca/pki/ca.crt", |
|
"server_cert_path": "/home/ubuntu/openvpn-ca/pki/issued/server.crt", |
|
"server_key_path": "/home/ubuntu/openvpn-ca/pki/private/server.key", |
|
"dh_path": "/home/ubuntu/openvpn-ca/pki/dh.pem", |
|
"vpn_network": "10.8.0.0/24", |
|
"vpn_server_ip": "10.8.0.1", |
|
"vpn_port": 1194, |
|
"protocol": "udp", |
|
"auto_start": False, |
|
"client_to_client": False, |
|
"push_routes": [ |
|
"redirect-gateway def1 bypass-dhcp", |
|
"dhcp-option DNS 8.8.8.8", |
|
"dhcp-option DNS 8.8.4.4" |
|
] |
|
} |
|
} |
|
|
|
if os.path.exists(config_file): |
|
try: |
|
with open(config_file, 'r') as f: |
|
file_config = json.load(f) |
|
|
|
|
|
def merge_config(default, override): |
|
result = default.copy() |
|
for key, value in override.items(): |
|
if key in result and isinstance(result[key], dict) and isinstance(value, dict): |
|
result[key] = merge_config(result[key], value) |
|
else: |
|
result[key] = value |
|
return result |
|
|
|
return merge_config(default_config, file_config) |
|
|
|
except Exception as e: |
|
print(f"Error loading config file: {e}") |
|
print("Using default configuration") |
|
return default_config |
|
else: |
|
|
|
try: |
|
with open(config_file, 'w') as f: |
|
json.dump(default_config, f, indent=2) |
|
print(f"Created default configuration file: {config_file}") |
|
except Exception as e: |
|
print(f"Could not save default config: {e}") |
|
|
|
return default_config |
|
|
|
|
|
def create_app(): |
|
"""Create and configure Flask application""" |
|
app = Flask(__name__, static_folder=os.path.join(os.path.dirname(__file__), 'static')) |
|
|
|
|
|
CORS(app, origins="*", allow_headers=["Content-Type", "Authorization"]) |
|
|
|
|
|
config = load_config() |
|
app.config['ISP_CONFIG'] = config |
|
|
|
|
|
app.register_blueprint(isp_api, url_prefix='/api') |
|
|
|
|
|
init_engines(config) |
|
|
|
|
|
@app.route('/', defaults={'path': ''}) |
|
@app.route('/<path:path>') |
|
def serve_static(path): |
|
static_folder_path = app.static_folder |
|
if static_folder_path is None: |
|
return "Static folder not configured", 404 |
|
|
|
if path != "" and os.path.exists(os.path.join(static_folder_path, path)): |
|
return app.send_static_file(path) |
|
else: |
|
index_path = os.path.join(static_folder_path, 'index.html') |
|
if os.path.exists(index_path): |
|
return app.send_static_file('index.html') |
|
else: |
|
return """ |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>Virtual ISP Stack</title> |
|
<style> |
|
body { font-family: Arial, sans-serif; margin: 40px; } |
|
.container { max-width: 800px; margin: 0 auto; } |
|
.status { background: #f0f0f0; padding: 20px; border-radius: 5px; } |
|
.api-link { color: #0066cc; text-decoration: none; } |
|
.api-link:hover { text-decoration: underline; } |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<h1>Virtual ISP Stack</h1> |
|
<div class="status"> |
|
<h2>System Status</h2> |
|
<p>The Virtual ISP Stack is running successfully!</p> |
|
<p><strong>API Endpoint:</strong> <a href="/api/status" class="api-link">/api/status</a></p> |
|
<p><strong>System Stats:</strong> <a href="/api/stats" class="api-link">/api/stats</a></p> |
|
</div> |
|
|
|
<h2>Available API Endpoints</h2> |
|
<ul> |
|
<li><a href="/api/config" class="api-link">GET /api/config</a> - System configuration</li> |
|
<li><a href="/api/status" class="api-link">GET /api/status</a> - System status</li> |
|
<li><a href="/api/stats" class="api-link">GET /api/stats</a> - System statistics</li> |
|
<li><a href="/api/dhcp/leases" class="api-link">GET /api/dhcp/leases</a> - DHCP leases</li> |
|
<li><a href="/api/nat/sessions" class="api-link">GET /api/nat/sessions</a> - NAT sessions</li> |
|
<li><a href="/api/firewall/rules" class="api-link">GET /api/firewall/rules</a> - Firewall rules</li> |
|
<li><a href="/api/tcp/connections" class="api-link">GET /api/tcp/connections</a> - TCP connections</li> |
|
<li><a href="/api/router/routes" class="api-link">GET /api/router/routes</a> - Routing table</li> |
|
<li><a href="/api/bridge/clients" class="api-link">GET /api/bridge/clients</a> - Bridge clients</li> |
|
<li><a href="/api/sessions" class="api-link">GET /api/sessions</a> - Session tracking</li> |
|
<li><a href="/api/logs" class="api-link">GET /api/logs</a> - System logs</li> |
|
</ul> |
|
|
|
<h2>WebSocket Bridge</h2> |
|
<p>WebSocket server running on port 8765 for packet bridge connections.</p> |
|
<p>TCP server running on port 8766 for packet bridge connections.</p> |
|
</div> |
|
</body> |
|
</html> |
|
""", 200 |
|
|
|
return app |
|
|
|
|
|
def main(): |
|
"""Main application entry point""" |
|
print("Starting Virtual ISP Stack...") |
|
|
|
|
|
app = create_app() |
|
|
|
|
|
print("Virtual ISP Stack started successfully!") |
|
print("API available at: http://0.0.0.0:5000/api/") |
|
print("WebSocket bridge at: ws://0.0.0.0:8765") |
|
print("TCP bridge at: tcp://0.0.0.0:8766") |
|
|
|
|
|
app.run(host='0.0.0.0', port=5000, debug=False, threaded=True) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |
|
|
|
|