"""Defense category routes — landing page, Linux defense, Windows defense, Threat Monitor.""" import re import subprocess import platform import socket import json from flask import Blueprint, render_template, request, jsonify, Response, stream_with_context from web.auth import login_required defense_bp = Blueprint('defense', __name__, url_prefix='/defense') def _run_cmd(cmd, timeout=10): try: result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout) return result.returncode == 0, result.stdout.strip() except Exception: return False, "" # ==================== LANDING PAGE ==================== @defense_bp.route('/') @login_required def index(): from core.menu import MainMenu menu = MainMenu() menu.load_modules() modules = {k: v for k, v in menu.modules.items() if v.category == 'defense'} # Gather system info for the landing page sys_info = { 'platform': platform.system(), 'hostname': socket.gethostname(), 'os_version': platform.platform(), } try: sys_info['ip'] = socket.gethostbyname(socket.gethostname()) except Exception: sys_info['ip'] = '127.0.0.1' return render_template('defense.html', modules=modules, sys_info=sys_info) # ==================== LINUX DEFENSE ==================== @defense_bp.route('/linux') @login_required def linux_index(): from core.menu import MainMenu menu = MainMenu() menu.load_modules() modules = {k: v for k, v in menu.modules.items() if v.category == 'defense'} return render_template('defense_linux.html', modules=modules) @defense_bp.route('/linux/audit', methods=['POST']) @login_required def linux_audit(): """Run full Linux security audit.""" from modules.defender import Defender d = Defender() d.check_firewall() d.check_ssh_config() d.check_open_ports() d.check_users() d.check_permissions() d.check_services() d.check_fail2ban() d.check_selinux() passed = sum(1 for r in d.results if r['passed']) total = len(d.results) score = int((passed / total) * 100) if total > 0 else 0 return jsonify({ 'score': score, 'passed': passed, 'total': total, 'checks': d.results }) @defense_bp.route('/linux/check/', methods=['POST']) @login_required def linux_check(check_name): """Run individual Linux security check.""" from modules.defender import Defender d = Defender() checks_map = { 'firewall': d.check_firewall, 'ssh': d.check_ssh_config, 'ports': d.check_open_ports, 'users': d.check_users, 'permissions': d.check_permissions, 'services': d.check_services, 'fail2ban': d.check_fail2ban, 'selinux': d.check_selinux, } func = checks_map.get(check_name) if not func: return jsonify({'error': f'Unknown check: {check_name}'}), 400 func() return jsonify({'checks': d.results}) @defense_bp.route('/linux/firewall/rules') @login_required def linux_firewall_rules(): """Get current iptables rules.""" success, output = _run_cmd("sudo iptables -L -n --line-numbers 2>/dev/null") if success: return jsonify({'rules': output}) return jsonify({'rules': 'Could not read iptables rules (need sudo privileges)'}) @defense_bp.route('/linux/firewall/block', methods=['POST']) @login_required def linux_firewall_block(): """Block an IP address via iptables.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) success, _ = _run_cmd(f"sudo iptables -A INPUT -s {ip} -j DROP") if success: return jsonify({'message': f'Blocked {ip}', 'success': True}) return jsonify({'error': f'Failed to block {ip} (need sudo)', 'success': False}) @defense_bp.route('/linux/firewall/unblock', methods=['POST']) @login_required def linux_firewall_unblock(): """Unblock an IP address via iptables.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) success, _ = _run_cmd(f"sudo iptables -D INPUT -s {ip} -j DROP") if success: return jsonify({'message': f'Unblocked {ip}', 'success': True}) return jsonify({'error': f'Failed to unblock {ip}', 'success': False}) @defense_bp.route('/linux/logs/analyze', methods=['POST']) @login_required def linux_logs_analyze(): """Analyze auth and web logs (Linux).""" from modules.defender import Defender d = Defender() auth_results = d._analyze_auth_log() web_results = d._analyze_web_logs() return jsonify({ 'auth_results': auth_results[:20], 'web_results': web_results[:20], }) # ==================== WINDOWS DEFENSE ==================== @defense_bp.route('/windows') @login_required def windows_index(): """Windows defense sub-page.""" return render_template('defense_windows.html') @defense_bp.route('/windows/audit', methods=['POST']) @login_required def windows_audit(): """Run full Windows security audit.""" from modules.defender_windows import WindowsDefender d = WindowsDefender() d.check_firewall() d.check_ssh_config() d.check_open_ports() d.check_updates() d.check_users() d.check_permissions() d.check_services() d.check_defender() d.check_uac() passed = sum(1 for r in d.results if r['passed']) total = len(d.results) score = int((passed / total) * 100) if total > 0 else 0 return jsonify({ 'score': score, 'passed': passed, 'total': total, 'checks': d.results }) @defense_bp.route('/windows/check/', methods=['POST']) @login_required def windows_check(check_name): """Run individual Windows security check.""" from modules.defender_windows import WindowsDefender d = WindowsDefender() checks_map = { 'firewall': d.check_firewall, 'ssh': d.check_ssh_config, 'ports': d.check_open_ports, 'updates': d.check_updates, 'users': d.check_users, 'permissions': d.check_permissions, 'services': d.check_services, 'defender': d.check_defender, 'uac': d.check_uac, } func = checks_map.get(check_name) if not func: return jsonify({'error': f'Unknown check: {check_name}'}), 400 func() return jsonify({'checks': d.results}) @defense_bp.route('/windows/firewall/rules') @login_required def windows_firewall_rules(): """Get Windows Firewall rules.""" from modules.defender_windows import WindowsDefender d = WindowsDefender() success, output = d.get_firewall_rules() if success: return jsonify({'rules': output}) return jsonify({'rules': 'Could not read Windows Firewall rules (need admin privileges)'}) @defense_bp.route('/windows/firewall/block', methods=['POST']) @login_required def windows_firewall_block(): """Block an IP via Windows Firewall.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) from modules.defender_windows import WindowsDefender d = WindowsDefender() success, message = d.block_ip(ip) return jsonify({'message': message, 'success': success}) @defense_bp.route('/windows/firewall/unblock', methods=['POST']) @login_required def windows_firewall_unblock(): """Unblock an IP via Windows Firewall.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) from modules.defender_windows import WindowsDefender d = WindowsDefender() success, message = d.unblock_ip(ip) return jsonify({'message': message, 'success': success}) @defense_bp.route('/windows/logs/analyze', methods=['POST']) @login_required def windows_logs_analyze(): """Analyze Windows Event Logs.""" from modules.defender_windows import WindowsDefender d = WindowsDefender() auth_results, system_results = d.analyze_event_logs() return jsonify({ 'auth_results': auth_results[:20], 'system_results': system_results[:20], }) # ==================== THREAT MONITOR ==================== def _get_monitor(): """Get singleton ThreatMonitor instance.""" from modules.defender_monitor import get_threat_monitor return get_threat_monitor() @defense_bp.route('/monitor') @login_required def monitor_index(): """Threat Monitor sub-page.""" return render_template('defense_monitor.html') @defense_bp.route('/monitor/stream') @login_required def monitor_stream(): """SSE stream of real-time threat data.""" return Response(stream_with_context(_get_monitor().monitor_stream()), mimetype='text/event-stream', headers={'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no'}) @defense_bp.route('/monitor/connections', methods=['POST']) @login_required def monitor_connections(): """Get current network connections.""" m = _get_monitor() connections = m.get_connections() return jsonify({'connections': connections, 'total': len(connections)}) @defense_bp.route('/monitor/processes', methods=['POST']) @login_required def monitor_processes(): """Get suspicious processes.""" m = _get_monitor() processes = m.get_suspicious_processes() return jsonify({'processes': processes, 'total': len(processes)}) @defense_bp.route('/monitor/threats', methods=['POST']) @login_required def monitor_threats(): """Get threat score and summary.""" m = _get_monitor() report = m.generate_threat_report() return jsonify(report) @defense_bp.route('/monitor/block-ip', methods=['POST']) @login_required def monitor_block_ip(): """Counter-attack: block an IP.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) success, message = _get_monitor().auto_block_ip(ip) return jsonify({'message': message, 'success': success}) @defense_bp.route('/monitor/kill-process', methods=['POST']) @login_required def monitor_kill_process(): """Counter-attack: kill a process.""" data = request.get_json(silent=True) or {} pid = data.get('pid') if not pid: return jsonify({'error': 'No PID provided', 'success': False}) success, message = _get_monitor().kill_process(pid) return jsonify({'message': message, 'success': success}) @defense_bp.route('/monitor/block-port', methods=['POST']) @login_required def monitor_block_port(): """Counter-attack: block a port.""" data = request.get_json(silent=True) or {} port = data.get('port') direction = data.get('direction', 'in') if not port: return jsonify({'error': 'No port provided', 'success': False}) success, message = _get_monitor().block_port(port, direction) return jsonify({'message': message, 'success': success}) @defense_bp.route('/monitor/blocklist') @login_required def monitor_blocklist_get(): """Get persistent blocklist.""" return jsonify({'blocked_ips': _get_monitor().get_blocklist()}) @defense_bp.route('/monitor/blocklist', methods=['POST']) @login_required def monitor_blocklist_add(): """Add IP to persistent blocklist.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) blocklist = _get_monitor().add_to_blocklist(ip) return jsonify({'blocked_ips': blocklist, 'success': True}) @defense_bp.route('/monitor/blocklist/remove', methods=['POST']) @login_required def monitor_blocklist_remove(): """Remove IP from persistent blocklist.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip: return jsonify({'error': 'No IP provided', 'success': False}) blocklist = _get_monitor().remove_from_blocklist(ip) return jsonify({'blocked_ips': blocklist, 'success': True}) # ==================== MONITORING: BANDWIDTH, ARP, PORTS, GEOIP, CONN RATE ==================== @defense_bp.route('/monitor/bandwidth', methods=['POST']) @login_required def monitor_bandwidth(): """Get bandwidth stats per interface.""" return jsonify({'interfaces': _get_monitor().get_bandwidth()}) @defense_bp.route('/monitor/arp-check', methods=['POST']) @login_required def monitor_arp_check(): """Check for ARP spoofing.""" alerts = _get_monitor().check_arp_spoofing() return jsonify({'alerts': alerts, 'total': len(alerts)}) @defense_bp.route('/monitor/new-ports', methods=['POST']) @login_required def monitor_new_ports(): """Check for new listening ports.""" ports = _get_monitor().check_new_listening_ports() return jsonify({'new_ports': ports, 'total': len(ports)}) @defense_bp.route('/monitor/geoip', methods=['POST']) @login_required def monitor_geoip(): """GeoIP lookup for an IP.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip: return jsonify({'error': 'No IP provided'}), 400 result = _get_monitor().geoip_lookup(ip) if result: return jsonify(result) return jsonify({'ip': ip, 'error': 'Private IP or lookup failed'}) @defense_bp.route('/monitor/connections-geo', methods=['POST']) @login_required def monitor_connections_geo(): """Get connections enriched with GeoIP data.""" connections = _get_monitor().get_connections_with_geoip() return jsonify({'connections': connections, 'total': len(connections)}) @defense_bp.route('/monitor/connection-rate', methods=['POST']) @login_required def monitor_connection_rate(): """Get connection rate stats.""" return jsonify(_get_monitor().get_connection_rate()) # ==================== PACKET CAPTURE (via WiresharkManager) ==================== @defense_bp.route('/monitor/capture/interfaces') @login_required def monitor_capture_interfaces(): """Get available network interfaces for capture.""" from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() return jsonify({'interfaces': wm.list_interfaces()}) @defense_bp.route('/monitor/capture/start', methods=['POST']) @login_required def monitor_capture_start(): """Start packet capture.""" data = request.get_json(silent=True) or {} from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() result = wm.start_capture( interface=data.get('interface', ''), bpf_filter=data.get('filter', ''), duration=int(data.get('duration', 30)), ) return jsonify(result) @defense_bp.route('/monitor/capture/stop', methods=['POST']) @login_required def monitor_capture_stop(): """Stop packet capture.""" from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() result = wm.stop_capture() return jsonify(result) @defense_bp.route('/monitor/capture/stats') @login_required def monitor_capture_stats(): """Get capture statistics.""" from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() return jsonify(wm.get_capture_stats()) @defense_bp.route('/monitor/capture/stream') @login_required def monitor_capture_stream(): """SSE stream of captured packets.""" import time as _time from core.wireshark import get_wireshark_manager mgr = get_wireshark_manager() def generate(): last_count = 0 while mgr._capture_running: stats = mgr.get_capture_stats() count = stats.get('packet_count', 0) if count > last_count: new_packets = mgr._capture_packets[last_count:count] for pkt in new_packets: yield f'data: {json.dumps({"type": "packet", **pkt})}\n\n' last_count = count yield f'data: {json.dumps({"type": "stats", "packet_count": count, "running": True})}\n\n' _time.sleep(0.5) stats = mgr.get_capture_stats() yield f'data: {json.dumps({"type": "done", **stats})}\n\n' return Response(stream_with_context(generate()), mimetype='text/event-stream', headers={'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no'}) @defense_bp.route('/monitor/capture/protocols', methods=['POST']) @login_required def monitor_capture_protocols(): """Get protocol distribution from captured packets.""" from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() return jsonify({'protocols': wm.get_protocol_hierarchy()}) @defense_bp.route('/monitor/capture/conversations', methods=['POST']) @login_required def monitor_capture_conversations(): """Get top conversations from captured packets.""" from core.wireshark import get_wireshark_manager wm = get_wireshark_manager() return jsonify({'conversations': wm.extract_conversations()}) # ==================== DDOS MITIGATION ==================== @defense_bp.route('/monitor/ddos/detect', methods=['POST']) @login_required def monitor_ddos_detect(): """Detect DDoS/DoS attack patterns.""" return jsonify(_get_monitor().detect_ddos()) @defense_bp.route('/monitor/ddos/top-talkers', methods=['POST']) @login_required def monitor_ddos_top_talkers(): """Get top source IPs by connection count.""" data = request.get_json(silent=True) or {} limit = int(data.get('limit', 20)) return jsonify({'talkers': _get_monitor().get_top_talkers(limit)}) @defense_bp.route('/monitor/ddos/rate-limit', methods=['POST']) @login_required def monitor_ddos_rate_limit(): """Apply rate limit to an IP.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() rate = data.get('rate', '25/min') if not ip or not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip): return jsonify({'error': 'Invalid IP address', 'success': False}) success, msg = _get_monitor().apply_rate_limit(ip, rate) return jsonify({'message': msg, 'success': success}) @defense_bp.route('/monitor/ddos/rate-limit/remove', methods=['POST']) @login_required def monitor_ddos_rate_limit_remove(): """Remove rate limit from an IP.""" data = request.get_json(silent=True) or {} ip = data.get('ip', '').strip() if not ip: return jsonify({'error': 'No IP provided', 'success': False}) success, msg = _get_monitor().remove_rate_limit(ip) return jsonify({'message': msg, 'success': success}) @defense_bp.route('/monitor/ddos/syn-status') @login_required def monitor_ddos_syn_status(): """Check SYN flood protection status.""" return jsonify(_get_monitor().get_syn_protection_status()) @defense_bp.route('/monitor/ddos/syn-enable', methods=['POST']) @login_required def monitor_ddos_syn_enable(): """Enable SYN flood protection.""" success, msg = _get_monitor().enable_syn_protection() return jsonify({'message': msg, 'success': success}) @defense_bp.route('/monitor/ddos/syn-disable', methods=['POST']) @login_required def monitor_ddos_syn_disable(): """Disable SYN flood protection.""" success, msg = _get_monitor().disable_syn_protection() return jsonify({'message': msg, 'success': success}) @defense_bp.route('/monitor/ddos/config') @login_required def monitor_ddos_config_get(): """Get DDoS auto-mitigation config.""" return jsonify(_get_monitor().get_ddos_config()) @defense_bp.route('/monitor/ddos/config', methods=['POST']) @login_required def monitor_ddos_config_save(): """Save DDoS auto-mitigation config.""" data = request.get_json(silent=True) or {} config = _get_monitor().save_ddos_config(data) return jsonify({'config': config, 'success': True}) @defense_bp.route('/monitor/ddos/auto-mitigate', methods=['POST']) @login_required def monitor_ddos_auto_mitigate(): """Run auto-mitigation.""" result = _get_monitor().auto_mitigate() return jsonify(result) @defense_bp.route('/monitor/ddos/history') @login_required def monitor_ddos_history(): """Get mitigation history.""" return jsonify({'history': _get_monitor().get_mitigation_history()}) @defense_bp.route('/monitor/ddos/history/clear', methods=['POST']) @login_required def monitor_ddos_history_clear(): """Clear mitigation history.""" _get_monitor().clear_mitigation_history() return jsonify({'success': True})