Initial commit — SETEC LABS Manager (Setec_CDM)

Flask-based VPS management panel with SSH remote command execution.
Includes E2E encrypted SSH tunnel (AES-256-GCM + Go agent), setup wizard,
security hardening tools, DNS management, firewall configs, monitoring,
backup, and .sec patch update system.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DigiJ
2026-03-13 12:39:02 -07:00
commit 9e839ee826
62 changed files with 14605 additions and 0 deletions

View File

@@ -0,0 +1,990 @@
{% extends "base.html" %}
{% block title %}Firewall{% endblock %}
{% block content %}
<h1>[|] Firewall Manager</h1>
<!-- Tab navigation -->
<div class="toolbar" id="tabs">
<button class="btn" onclick="showTab('dashboard')" id="tab-dashboard">Dashboard</button>
<button class="btn" onclick="showTab('ufw')" id="tab-ufw">UFW</button>
<button class="btn" onclick="showTab('iptables')" id="tab-iptables">iptables</button>
<button class="btn" onclick="showTab('nftables')" id="tab-nftables">nftables</button>
<button class="btn" onclick="showTab('firewalld')" id="tab-firewalld">firewalld</button>
<button class="btn" onclick="showTab('csf')" id="tab-csf">CSF</button>
<button class="btn" onclick="showTab('ufw2ip')" id="tab-ufw2ip">UFW → IP</button>
<button class="btn" onclick="showTab('ip2ufw')" id="tab-ip2ufw">IP → UFW</button>
</div>
<!-- ═══════════════════════ DASHBOARD TAB ═══════════════════════ -->
<div class="tab-content" id="panel-dashboard">
<div class="grid grid-2">
<div class="card">
<div class="card-title">Firewall Detection</div>
<div id="fw-detect" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwDetect()">Detect Firewalls</button>
</div>
<div class="card">
<div class="card-title">Open Ports</div>
<div id="fw-ports" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwPorts()">Scan Ports</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Active Connections</div>
<div id="fw-conns" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwConns()">Refresh</button>
</div>
<div class="card">
<div class="card-title">Connection Stats by State</div>
<div id="fw-connstats" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwConnStats()">Refresh</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Top Connections by IP</div>
<div id="fw-topip" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwTopIPs()">Refresh</button>
</div>
<div class="card">
<div class="card-title">Recent Blocked / Dropped</div>
<div id="fw-blocked" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwBlocked()">Refresh</button>
</div>
</div>
<div class="card">
<div class="card-title">Firewall Log</div>
<div id="fw-log" class="output" style="max-height:400px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwLog()">Load Log</button>
</div>
</div>
<!-- ═══════════════════════ UFW TAB ═══════════════════════ -->
<div class="tab-content" id="panel-ufw" style="display:none;">
<div class="card">
<div class="card-title">UFW Status</div>
<div id="ufw-status" class="output" style="max-height:400px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="ufwStatus()">Refresh</button>
<button class="btn btn-warn" onclick="ufwEnable()">Enable UFW</button>
<button class="btn btn-danger" onclick="ufwDisable()">Disable UFW</button>
<button class="btn" onclick="ufwNumbered()">Numbered Rules</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Add Rule</div>
<label>Rule (e.g. "allow 8080/tcp", "deny from 1.2.3.4")</label>
<input type="text" id="ufw-rule" placeholder="allow 443/tcp" style="width:100%;">
<button class="btn" onclick="ufwAdd()" style="margin-top:8px;">Add Rule</button>
</div>
<div class="card">
<div class="card-title">Delete Rule</div>
<label>Rule to delete (e.g. "allow 8080/tcp")</label>
<input type="text" id="ufw-del-rule" placeholder="allow 8080/tcp" style="width:100%;">
<button class="btn btn-danger" onclick="ufwDel()" style="margin-top:8px;">Delete Rule</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Presets</div>
<button class="btn" onclick="ufwPreset('webserver')">Web Server (80, 443)</button>
<button class="btn" onclick="ufwPreset('mailserver')">Mail Server (25, 465, 587, 993)</button>
<button class="btn btn-danger" onclick="ufwPreset('lockdown')">Lockdown (SSH only)</button>
</div>
<div class="card">
<div class="card-title">Defaults</div>
<div id="ufw-defaults" class="output" style="max-height:150px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="ufwDefault('deny','incoming')">Default Deny In</button>
<button class="btn" onclick="ufwDefault('allow','outgoing')">Default Allow Out</button>
<button class="btn btn-danger" onclick="ufwDefault('deny','outgoing')">Default Deny Out</button>
</div>
</div>
</div>
<div class="card">
<div class="card-title">UFW Application Profiles</div>
<div id="ufw-apps" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="ufwAppList()">List App Profiles</button>
</div>
<div class="card">
<div class="card-title">UFW Log</div>
<div id="ufw-log" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="ufwLog()">View Log</button>
<button class="btn" onclick="ufwLogLevel('on')">Logging On</button>
<button class="btn" onclick="ufwLogLevel('high')">Logging High</button>
<button class="btn btn-danger" onclick="ufwLogLevel('off')">Logging Off</button>
</div>
</div>
</div>
<!-- ═══════════════════════ IPTABLES TAB ═══════════════════════ -->
<div class="tab-content" id="panel-iptables" style="display:none;">
<div id="ipt-not-installed" style="display:none;">
<div class="card">
<div class="card-title">iptables</div>
<p style="color:#888;margin-bottom:10px;">iptables is the traditional Linux packet filter. It is usually pre-installed.</p>
<div id="ipt-install-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<button class="btn btn-warn" onclick="iptInstall()">Install iptables</button>
</div>
</div>
<div id="ipt-main">
<div class="card">
<div class="card-title">iptables Rules (filter)</div>
<div id="ipt-rules" class="output" style="max-height:500px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="iptList()">Filter Table</button>
<button class="btn" onclick="iptListNat()">NAT Table</button>
<button class="btn" onclick="iptListMangle()">Mangle Table</button>
<button class="btn" onclick="iptCounters()">Counters</button>
<button class="btn" onclick="iptIp6()">IPv6 Rules</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Add Rule</div>
<label>Chain</label>
<select id="ipt-chain" style="width:120px;">
<option>INPUT</option>
<option>OUTPUT</option>
<option>FORWARD</option>
</select>
<label>Rule (e.g. "-p tcp --dport 80 -j ACCEPT")</label>
<input type="text" id="ipt-rule" placeholder="-p tcp --dport 80 -j ACCEPT" style="width:100%;">
<div style="margin-top:8px;">
<button class="btn" onclick="iptAdd()">Append Rule</button>
<label style="display:inline;">Position</label>
<input type="number" id="ipt-pos" value="1" style="width:50px;">
<button class="btn" onclick="iptInsert()">Insert at Position</button>
</div>
</div>
<div class="card">
<div class="card-title">Delete Rule</div>
<label>Chain</label>
<select id="ipt-del-chain" style="width:120px;">
<option>INPUT</option>
<option>OUTPUT</option>
<option>FORWARD</option>
</select>
<label>Rule Number</label>
<input type="number" id="ipt-del-num" value="1" style="width:80px;">
<button class="btn btn-danger" onclick="iptDelete()" style="margin-top:8px;">Delete Rule</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Chain Policy</div>
<label>Chain</label>
<select id="ipt-pol-chain" style="width:120px;">
<option>INPUT</option>
<option>OUTPUT</option>
<option>FORWARD</option>
</select>
<label>Policy</label>
<select id="ipt-pol-target" style="width:120px;">
<option>ACCEPT</option>
<option>DROP</option>
</select>
<button class="btn btn-warn" onclick="iptPolicy()" style="margin-top:8px;">Set Policy</button>
</div>
<div class="card">
<div class="card-title">Quick Actions</div>
<div style="margin-bottom:8px;">
<label>IP Address</label>
<input type="text" id="ipt-ip" placeholder="1.2.3.4" style="width:160px;">
</div>
<div class="toolbar">
<button class="btn btn-danger" onclick="iptBlockIP()">Block IP</button>
<button class="btn" onclick="iptUnblockIP()">Unblock IP</button>
<button class="btn" onclick="iptListBlocked()">Show Blocked</button>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Persistence</div>
<div id="ipt-persist" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn btn-warn" onclick="iptSave()">Save Rules</button>
<button class="btn" onclick="iptRestore()">Restore Saved</button>
</div>
</div>
<div class="card">
<div class="card-title">Flush</div>
<div id="ipt-flush-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn btn-danger" onclick="iptFlush()">Flush All Rules</button>
<button class="btn" onclick="iptZero()">Zero Counters</button>
</div>
</div>
</div>
<div class="card">
<div class="card-title">iptables Log</div>
<div id="ipt-log" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="iptLog()">View Log</button>
</div>
</div>
</div>
<!-- ═══════════════════════ NFTABLES TAB ═══════════════════════ -->
<div class="tab-content" id="panel-nftables" style="display:none;">
<div id="nft-not-installed" style="display:none;">
<div class="card">
<div class="card-title">nftables</div>
<p style="color:#888;margin-bottom:10px;">nftables is the modern replacement for iptables. Provides better performance and a cleaner syntax.</p>
<div id="nft-install-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<button class="btn btn-warn" onclick="nftInstall()">Install nftables</button>
</div>
</div>
<div id="nft-main">
<div class="card">
<div class="card-title">nftables Ruleset</div>
<div id="nft-rules" class="output" style="max-height:500px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="nftList()">Full Ruleset</button>
<button class="btn" onclick="nftTables()">Tables</button>
<button class="btn" onclick="nftCounters()">Counters</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">List Chains</div>
<div id="nft-chains" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<label>Table (e.g. "inet filter")</label>
<input type="text" id="nft-table" value="inet filter" style="width:200px;">
<button class="btn" onclick="nftChains()" style="margin-top:8px;">List Chains</button>
</div>
<div class="card">
<div class="card-title">Add Rule</div>
<label>Table</label>
<input type="text" id="nft-add-table" value="inet filter" style="width:180px;">
<label>Chain</label>
<input type="text" id="nft-add-chain" value="input" style="width:180px;">
<label>Rule (e.g. "tcp dport 80 accept")</label>
<input type="text" id="nft-add-rule" placeholder="tcp dport 80 accept" style="width:100%;">
<button class="btn" onclick="nftAddRule()" style="margin-top:8px;">Add Rule</button>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Delete Rule</div>
<label>Table</label>
<input type="text" id="nft-del-table" value="inet filter" style="width:180px;">
<label>Chain</label>
<input type="text" id="nft-del-chain" value="input" style="width:180px;">
<label>Handle Number</label>
<input type="number" id="nft-del-handle" style="width:80px;">
<button class="btn btn-danger" onclick="nftDelRule()" style="margin-top:8px;">Delete Rule</button>
</div>
<div class="card">
<div class="card-title">Create Table / Chain</div>
<label>Family</label>
<select id="nft-family" style="width:100px;">
<option>inet</option>
<option>ip</option>
<option>ip6</option>
<option>bridge</option>
</select>
<label>Table Name</label>
<input type="text" id="nft-new-table" placeholder="mytable" style="width:150px;">
<button class="btn" onclick="nftCreateTable()" style="margin-top:8px;">Create Table</button>
<div style="margin-top:10px;border-top:1px solid #333;padding-top:8px;">
<label>Chain Name</label>
<input type="text" id="nft-new-chain" placeholder="mychain" style="width:150px;">
<label>Hook</label>
<select id="nft-hook" style="width:100px;">
<option>input</option>
<option>output</option>
<option>forward</option>
<option>prerouting</option>
<option>postrouting</option>
</select>
<button class="btn" onclick="nftCreateChain()" style="margin-top:8px;">Create Chain</button>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Persistence</div>
<div id="nft-persist" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn btn-warn" onclick="nftSave()">Save Ruleset</button>
<button class="btn" onclick="nftRestore()">Restore Saved</button>
<button class="btn" onclick="nftConfig()">View Config File</button>
</div>
</div>
<div class="card">
<div class="card-title">Flush</div>
<div id="nft-flush-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<button class="btn btn-danger" onclick="nftFlush()">Flush All</button>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════ FIREWALLD TAB ═══════════════════════ -->
<div class="tab-content" id="panel-firewalld" style="display:none;">
<div id="fwd-not-installed" style="display:none;">
<div class="card">
<div class="card-title">firewalld</div>
<p style="color:#888;margin-bottom:10px;">firewalld is a zone-based firewall manager. Common on RHEL/CentOS but also available on Debian/Ubuntu.</p>
<div id="fwd-install-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<button class="btn btn-warn" onclick="fwdInstall()">Install firewalld</button>
</div>
</div>
<div id="fwd-main">
<div class="grid grid-2">
<div class="card">
<div class="card-title">firewalld Status</div>
<div id="fwd-status" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="fwdStatus()">Refresh</button>
<button class="btn btn-warn" onclick="fwdReload()">Reload</button>
<button class="btn btn-danger" onclick="fwdPanicOn()">Panic On</button>
<button class="btn" onclick="fwdPanicOff()">Panic Off</button>
</div>
</div>
<div class="card">
<div class="card-title">Zones</div>
<div id="fwd-zones" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwdZones()">List Zones</button>
<div style="margin-top:8px;">
<label>Zone</label>
<input type="text" id="fwd-zone" value="public" style="width:120px;">
<button class="btn" onclick="fwdZoneInfo()">Zone Info</button>
<button class="btn btn-warn" onclick="fwdSetDefault()">Set as Default</button>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Services</div>
<div id="fwd-services" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<label>Service (e.g. http, https, ssh, smtp)</label>
<input type="text" id="fwd-service" placeholder="http" style="width:150px;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn" onclick="fwdServicesList()">List Available</button>
<button class="btn btn-warn" onclick="fwdAddService()">Add Service</button>
<button class="btn btn-danger" onclick="fwdRemoveService()">Remove Service</button>
</div>
</div>
<div class="card">
<div class="card-title">Ports</div>
<div id="fwd-ports" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<label>Port (e.g. 8080/tcp)</label>
<input type="text" id="fwd-port" placeholder="8080/tcp" style="width:150px;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn btn-warn" onclick="fwdAddPort()">Add Port</button>
<button class="btn btn-danger" onclick="fwdRemovePort()">Remove Port</button>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Rich Rules</div>
<div id="fwd-rich" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<label>Rich Rule</label>
<input type="text" id="fwd-rich-rule" placeholder='rule family="ipv4" source address="1.2.3.4" drop' style="width:100%;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn btn-warn" onclick="fwdAddRich()">Add Rich Rule</button>
<button class="btn btn-danger" onclick="fwdRemoveRich()">Remove Rich Rule</button>
</div>
</div>
<div class="card">
<div class="card-title">Block / Unblock IP</div>
<div id="fwd-block" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<label>IP Address</label>
<input type="text" id="fwd-ip" placeholder="1.2.3.4" style="width:160px;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn btn-danger" onclick="fwdBlockIP()">Block IP</button>
<button class="btn" onclick="fwdUnblockIP()">Unblock IP</button>
</div>
</div>
</div>
<div class="card">
<div class="card-title">firewalld Log</div>
<div id="fwd-log" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="fwdLog()">View Log</button>
</div>
</div>
</div>
<!-- ═══════════════════════ CSF TAB ═══════════════════════ -->
<div class="tab-content" id="panel-csf" style="display:none;">
<div id="csf-not-installed" style="display:none;">
<div class="card">
<div class="card-title">CSF (ConfigServer Security & Firewall)</div>
<p style="color:#888;margin-bottom:10px;">CSF is a stateful packet inspection firewall with login/intrusion detection (LFD). Popular on cPanel servers but works standalone.</p>
<div id="csf-install-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<button class="btn btn-warn" onclick="csfInstall()">Install CSF</button>
</div>
</div>
<div id="csf-main">
<div class="grid grid-2">
<div class="card">
<div class="card-title">CSF Status</div>
<div id="csf-status" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="csfStatus()">Refresh</button>
<button class="btn btn-warn" onclick="csfStart()">Start</button>
<button class="btn btn-danger" onclick="csfStop()">Stop (Flush)</button>
<button class="btn" onclick="csfRestart()">Restart</button>
</div>
</div>
<div class="card">
<div class="card-title">Test iptables Modules</div>
<div id="csf-test" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="csfTest()">Run Test</button>
</div>
</div>
<div class="card">
<div class="card-title">Rules</div>
<div id="csf-rules" class="output" style="max-height:500px;margin-bottom:10px;"></div>
<button class="btn" onclick="csfList()">List All Rules</button>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Allow / Deny IP</div>
<div id="csf-ip-out" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<label>IP Address</label>
<input type="text" id="csf-ip" placeholder="1.2.3.4" style="width:160px;">
<label>Comment</label>
<input type="text" id="csf-comment" placeholder="reason" style="width:200px;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn" onclick="csfAllow()">Allow</button>
<button class="btn btn-danger" onclick="csfDeny()">Deny</button>
<button class="btn" onclick="csfRemove()">Remove</button>
<button class="btn" onclick="csfGrep()">Search IP</button>
</div>
</div>
<div class="card">
<div class="card-title">Temporary Rules</div>
<div id="csf-temp" class="output" style="max-height:200px;margin-bottom:10px;"></div>
<label>TTL (seconds)</label>
<input type="number" id="csf-ttl" value="3600" style="width:100px;">
<div class="toolbar" style="margin-top:8px;">
<button class="btn" onclick="csfTempAllow()">Temp Allow</button>
<button class="btn btn-danger" onclick="csfTempDeny()">Temp Deny</button>
<button class="btn" onclick="csfTempList()">List Temp Rules</button>
</div>
</div>
</div>
<div class="grid grid-2">
<div class="card">
<div class="card-title">Configuration</div>
<div id="csf-config" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="csfConfig()">View Key Settings</button>
</div>
<div class="card">
<div class="card-title">LFD Log</div>
<div id="csf-log" class="output" style="max-height:300px;margin-bottom:10px;"></div>
<button class="btn" onclick="csfLog()">View Log</button>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════ UFW → IPTABLES TAB ═══════════════════════ -->
<div class="tab-content" id="panel-ufw2ip" style="display:none;">
<div class="card">
<div class="card-title">Migrate: UFW → iptables</div>
<p style="color:#888;margin-bottom:15px;">
This will disable UFW and switch to raw iptables management. Your existing firewall rules
(which UFW manages via iptables under the hood) will be preserved and saved to
<code>/etc/iptables/rules.v4</code>. iptables-persistent will be installed to ensure
rules survive reboots.
</p>
<div style="margin-bottom:15px;padding:10px;border:1px solid #ffaa00;color:#ffaa00;">
<strong>What happens:</strong><br>
1. Current UFW/iptables state is backed up<br>
2. UFW is disabled and its service stopped<br>
3. The iptables rules that UFW generated are saved<br>
4. iptables-persistent is installed for persistence<br>
5. You manage rules directly via the iptables tab
</div>
<div id="m-ufw2ip-out" class="output" style="max-height:500px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="previewUfw2Ip()">Preview Current Rules</button>
<button class="btn btn-danger" onclick="runUfw2Ip()">Migrate UFW → iptables</button>
</div>
</div>
</div>
<!-- ═══════════════════════ IPTABLES → UFW TAB ═══════════════════════ -->
<div class="tab-content" id="panel-ip2ufw" style="display:none;">
<div class="card">
<div class="card-title">Migrate: iptables → UFW</div>
<p style="color:#888;margin-bottom:15px;">
This will convert your iptables rules to UFW and enable UFW as the primary firewall frontend.
Your current iptables rules are backed up before any changes. TCP/UDP ACCEPT rules on INPUT
are automatically converted to UFW allow rules.
</p>
<div style="margin-bottom:15px;padding:10px;border:1px solid #ffaa00;color:#ffaa00;">
<strong>What happens:</strong><br>
1. Current iptables rules are backed up<br>
2. UFW is installed (if not present) and reset<br>
3. Default deny incoming / allow outgoing is set<br>
4. iptables ACCEPT rules are converted to UFW allow rules<br>
5. UFW is enabled, iptables-persistent is disabled<br>
6. You manage rules via the UFW tab
</div>
<div id="m-ip2ufw-out" class="output" style="max-height:500px;margin-bottom:10px;"></div>
<div class="toolbar">
<button class="btn" onclick="previewIp2Ufw()">Preview Current Rules</button>
<button class="btn btn-danger" onclick="runIp2Ufw()">Migrate iptables → UFW</button>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
// ── Tab switching ──
function showTab(name) {
document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
document.querySelectorAll('#tabs .btn').forEach(el => el.style.background = '');
document.getElementById('panel-' + name).style.display = 'block';
document.getElementById('tab-' + name).style.background = '#1a2a1a';
}
showTab('dashboard');
// ── Dashboard ──
async function fwDetect() {
const r = await apiGet('/api/firewall/detect');
showResult(r, 'fw-detect');
}
async function fwPorts() {
const r = await apiGet('/api/firewall/ports');
showResult(r, 'fw-ports');
}
async function fwConns() {
const r = await apiGet('/api/firewall/connections');
showResult(r, 'fw-conns');
}
async function fwConnStats() {
const r = await apiGet('/api/firewall/connection-stats');
showResult(r, 'fw-connstats');
}
async function fwTopIPs() {
const r = await apiGet('/api/firewall/top-ips');
showResult(r, 'fw-topip');
}
async function fwBlocked() {
const r = await apiGet('/api/firewall/blocked');
showResult(r, 'fw-blocked');
}
async function fwLog() {
const r = await apiGet('/api/firewall/log');
showResult(r, 'fw-log');
}
// ── UFW ──
async function ufwStatus() {
const r = await apiGet('/api/security/firewall/status');
showResult(r, 'ufw-status');
}
async function ufwNumbered() {
const r = await apiGet('/api/firewall/ufw/numbered');
showResult(r, 'ufw-status');
}
async function ufwEnable() {
const r = await apiPost('/api/security/firewall/enable');
showResult(r, 'ufw-status');
}
async function ufwDisable() {
if (!confirm('Disable UFW?')) return;
const r = await apiPost('/api/security/firewall/disable');
showResult(r, 'ufw-status');
}
async function ufwAdd() {
const rule = document.getElementById('ufw-rule').value;
const r = await apiPost('/api/security/firewall/add', {rule});
showResult(r, 'ufw-status');
}
async function ufwDel() {
const rule = document.getElementById('ufw-del-rule').value;
const r = await apiPost('/api/security/firewall/delete', {rule});
showResult(r, 'ufw-status');
}
async function ufwPreset(name) {
if (!confirm('Apply ' + name + ' firewall preset?')) return;
const r = await apiPost('/api/security/firewall/preset', {preset: name});
showResult(r, 'ufw-status');
}
async function ufwDefault(policy, direction) {
const r = await apiPost('/api/firewall/ufw/default', {policy, direction});
showResult(r, 'ufw-defaults');
}
async function ufwAppList() {
const r = await apiGet('/api/firewall/ufw/app-list');
showResult(r, 'ufw-apps');
}
async function ufwLog() {
const r = await apiGet('/api/firewall/ufw/log');
showResult(r, 'ufw-log');
}
async function ufwLogLevel(level) {
const r = await apiPost('/api/firewall/ufw/log-level', {level});
showResult(r, 'ufw-log');
}
// ── iptables ──
async function iptList() {
const r = await apiGet('/api/firewall/iptables/list');
showResult(r, 'ipt-rules');
}
async function iptListNat() {
const r = await apiGet('/api/firewall/iptables/list-nat');
showResult(r, 'ipt-rules');
}
async function iptListMangle() {
const r = await apiGet('/api/firewall/iptables/list-mangle');
showResult(r, 'ipt-rules');
}
async function iptCounters() {
const r = await apiGet('/api/firewall/iptables/counters');
showResult(r, 'ipt-rules');
}
async function iptIp6() {
const r = await apiGet('/api/firewall/iptables/ip6');
showResult(r, 'ipt-rules');
}
async function iptAdd() {
const chain = document.getElementById('ipt-chain').value;
const rule = document.getElementById('ipt-rule').value;
const r = await apiPost('/api/firewall/iptables/add', {chain, rule});
showResult(r, 'ipt-rules');
}
async function iptInsert() {
const chain = document.getElementById('ipt-chain').value;
const rule = document.getElementById('ipt-rule').value;
const pos = parseInt(document.getElementById('ipt-pos').value);
const r = await apiPost('/api/firewall/iptables/insert', {chain, rule, position: pos});
showResult(r, 'ipt-rules');
}
async function iptDelete() {
const chain = document.getElementById('ipt-del-chain').value;
const rule_num = parseInt(document.getElementById('ipt-del-num').value);
if (!confirm('Delete rule ' + rule_num + ' from ' + chain + '?')) return;
const r = await apiPost('/api/firewall/iptables/delete', {chain, rule_num});
showResult(r, 'ipt-rules');
}
async function iptPolicy() {
const chain = document.getElementById('ipt-pol-chain').value;
const target = document.getElementById('ipt-pol-target').value;
if (!confirm('Set ' + chain + ' policy to ' + target + '?')) return;
const r = await apiPost('/api/firewall/iptables/policy', {chain, target});
showResult(r, 'ipt-rules');
}
async function iptBlockIP() {
const ip = document.getElementById('ipt-ip').value;
if (!ip) return;
const r = await apiPost('/api/firewall/iptables/block-ip', {ip});
showResult(r, 'ipt-rules');
}
async function iptUnblockIP() {
const ip = document.getElementById('ipt-ip').value;
if (!ip) return;
const r = await apiPost('/api/firewall/iptables/unblock-ip', {ip});
showResult(r, 'ipt-rules');
}
async function iptListBlocked() {
const r = await apiGet('/api/firewall/iptables/blocked');
showResult(r, 'ipt-rules');
}
async function iptSave() {
const r = await apiPost('/api/firewall/iptables/save');
showResult(r, 'ipt-persist');
}
async function iptRestore() {
const r = await apiPost('/api/firewall/iptables/restore');
showResult(r, 'ipt-persist');
}
async function iptFlush() {
if (!confirm('Flush ALL iptables rules? This may lock you out if policy is DROP!')) return;
const r = await apiPost('/api/firewall/iptables/flush');
showResult(r, 'ipt-flush-out');
}
async function iptZero() {
const r = await apiPost('/api/firewall/iptables/zero');
showResult(r, 'ipt-flush-out');
}
async function iptLog() {
const r = await apiGet('/api/firewall/iptables/log');
showResult(r, 'ipt-log');
}
async function iptInstall() {
const r = await apiPost('/api/firewall/iptables/install');
showResult(r, 'ipt-install-out');
}
// ── nftables ──
async function nftList() {
const r = await apiGet('/api/firewall/nftables/list');
showResult(r, 'nft-rules');
}
async function nftTables() {
const r = await apiGet('/api/firewall/nftables/tables');
showResult(r, 'nft-rules');
}
async function nftCounters() {
const r = await apiGet('/api/firewall/nftables/counters');
showResult(r, 'nft-rules');
}
async function nftChains() {
const table = document.getElementById('nft-table').value;
const r = await apiPost('/api/firewall/nftables/chains', {table});
showResult(r, 'nft-chains');
}
async function nftAddRule() {
const table = document.getElementById('nft-add-table').value;
const chain = document.getElementById('nft-add-chain').value;
const rule = document.getElementById('nft-add-rule').value;
const r = await apiPost('/api/firewall/nftables/add-rule', {table, chain, rule});
showResult(r, 'nft-rules');
}
async function nftDelRule() {
const table = document.getElementById('nft-del-table').value;
const chain = document.getElementById('nft-del-chain').value;
const handle = parseInt(document.getElementById('nft-del-handle').value);
if (!confirm('Delete rule handle ' + handle + '?')) return;
const r = await apiPost('/api/firewall/nftables/delete-rule', {table, chain, handle});
showResult(r, 'nft-rules');
}
async function nftCreateTable() {
const family = document.getElementById('nft-family').value;
const name = document.getElementById('nft-new-table').value;
const r = await apiPost('/api/firewall/nftables/create-table', {family, name});
showResult(r, 'nft-rules');
}
async function nftCreateChain() {
const table = document.getElementById('nft-family').value + ' ' + document.getElementById('nft-new-table').value;
const chain = document.getElementById('nft-new-chain').value;
const hook = document.getElementById('nft-hook').value;
const r = await apiPost('/api/firewall/nftables/create-chain', {table, chain, hook});
showResult(r, 'nft-rules');
}
async function nftSave() {
const r = await apiPost('/api/firewall/nftables/save');
showResult(r, 'nft-persist');
}
async function nftRestore() {
const r = await apiPost('/api/firewall/nftables/restore');
showResult(r, 'nft-persist');
}
async function nftConfig() {
const r = await apiGet('/api/firewall/nftables/config');
showResult(r, 'nft-persist');
}
async function nftFlush() {
if (!confirm('Flush ALL nftables rules?')) return;
const r = await apiPost('/api/firewall/nftables/flush');
showResult(r, 'nft-flush-out');
}
async function nftInstall() {
document.getElementById('nft-install-out').innerHTML = '<span class="info">Installing nftables...</span>';
const r = await apiPost('/api/firewall/nftables/install');
showResult(r, 'nft-install-out');
}
// ── firewalld ──
async function fwdStatus() {
const r = await apiGet('/api/firewall/firewalld/status');
showResult(r, 'fwd-status');
}
async function fwdReload() {
const r = await apiPost('/api/firewall/firewalld/reload');
showResult(r, 'fwd-status');
}
async function fwdPanicOn() {
if (!confirm('Enable panic mode? ALL network traffic will be blocked!')) return;
const r = await apiPost('/api/firewall/firewalld/panic-on');
showResult(r, 'fwd-status');
}
async function fwdPanicOff() {
const r = await apiPost('/api/firewall/firewalld/panic-off');
showResult(r, 'fwd-status');
}
async function fwdZones() {
const r = await apiGet('/api/firewall/firewalld/zones');
showResult(r, 'fwd-zones');
}
async function fwdZoneInfo() {
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/zone-info', {zone});
showResult(r, 'fwd-zones');
}
async function fwdSetDefault() {
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/default-zone', {zone});
showResult(r, 'fwd-zones');
}
async function fwdServicesList() {
const r = await apiGet('/api/firewall/firewalld/services-list');
showResult(r, 'fwd-services');
}
async function fwdAddService() {
const svc = document.getElementById('fwd-service').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/add-service', {service: svc, zone});
showResult(r, 'fwd-services');
}
async function fwdRemoveService() {
const svc = document.getElementById('fwd-service').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/remove-service', {service: svc, zone});
showResult(r, 'fwd-services');
}
async function fwdAddPort() {
const port = document.getElementById('fwd-port').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/add-port', {port, zone});
showResult(r, 'fwd-ports');
}
async function fwdRemovePort() {
const port = document.getElementById('fwd-port').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/remove-port', {port, zone});
showResult(r, 'fwd-ports');
}
async function fwdAddRich() {
const rule = document.getElementById('fwd-rich-rule').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/add-rich-rule', {rule, zone});
showResult(r, 'fwd-rich');
}
async function fwdRemoveRich() {
const rule = document.getElementById('fwd-rich-rule').value;
const zone = document.getElementById('fwd-zone').value;
const r = await apiPost('/api/firewall/firewalld/remove-rich-rule', {rule, zone});
showResult(r, 'fwd-rich');
}
async function fwdBlockIP() {
const ip = document.getElementById('fwd-ip').value;
const r = await apiPost('/api/firewall/firewalld/block-ip', {ip});
showResult(r, 'fwd-block');
}
async function fwdUnblockIP() {
const ip = document.getElementById('fwd-ip').value;
const r = await apiPost('/api/firewall/firewalld/unblock-ip', {ip});
showResult(r, 'fwd-block');
}
async function fwdLog() {
const r = await apiGet('/api/firewall/firewalld/log');
showResult(r, 'fwd-log');
}
async function fwdInstall() {
document.getElementById('fwd-install-out').innerHTML = '<span class="info">Installing firewalld...</span>';
const r = await apiPost('/api/firewall/firewalld/install');
showResult(r, 'fwd-install-out');
}
// ── CSF ──
async function csfStatus() {
const r = await apiGet('/api/firewall/csf/status');
showResult(r, 'csf-status');
}
async function csfStart() {
const r = await apiPost('/api/firewall/csf/start');
showResult(r, 'csf-status');
}
async function csfStop() {
if (!confirm('Stop CSF? This will flush all rules.')) return;
const r = await apiPost('/api/firewall/csf/stop');
showResult(r, 'csf-status');
}
async function csfRestart() {
const r = await apiPost('/api/firewall/csf/restart');
showResult(r, 'csf-status');
}
async function csfTest() {
const r = await apiGet('/api/firewall/csf/test');
showResult(r, 'csf-test');
}
async function csfList() {
const r = await apiGet('/api/firewall/csf/list');
showResult(r, 'csf-rules');
}
async function csfAllow() {
const ip = document.getElementById('csf-ip').value;
const comment = document.getElementById('csf-comment').value;
const r = await apiPost('/api/firewall/csf/allow', {ip, comment});
showResult(r, 'csf-ip-out');
}
async function csfDeny() {
const ip = document.getElementById('csf-ip').value;
const comment = document.getElementById('csf-comment').value;
const r = await apiPost('/api/firewall/csf/deny', {ip, comment});
showResult(r, 'csf-ip-out');
}
async function csfRemove() {
const ip = document.getElementById('csf-ip').value;
const r = await apiPost('/api/firewall/csf/remove', {ip});
showResult(r, 'csf-ip-out');
}
async function csfGrep() {
const ip = document.getElementById('csf-ip').value;
const r = await apiPost('/api/firewall/csf/grep', {ip});
showResult(r, 'csf-ip-out');
}
async function csfTempAllow() {
const ip = document.getElementById('csf-ip').value;
const ttl = parseInt(document.getElementById('csf-ttl').value);
const r = await apiPost('/api/firewall/csf/temp-allow', {ip, ttl});
showResult(r, 'csf-temp');
}
async function csfTempDeny() {
const ip = document.getElementById('csf-ip').value;
const ttl = parseInt(document.getElementById('csf-ttl').value);
const r = await apiPost('/api/firewall/csf/temp-deny', {ip, ttl});
showResult(r, 'csf-temp');
}
async function csfTempList() {
const r = await apiGet('/api/firewall/csf/temp-list');
showResult(r, 'csf-temp');
}
async function csfConfig() {
const r = await apiGet('/api/firewall/csf/config');
showResult(r, 'csf-config');
}
async function csfLog() {
const r = await apiGet('/api/firewall/csf/log');
showResult(r, 'csf-log');
}
async function csfInstall() {
document.getElementById('csf-install-out').innerHTML = '<span class="info">Installing CSF...</span>';
const r = await apiPost('/api/firewall/csf/install');
showResult(r, 'csf-install-out');
}
// ── Migration: UFW → iptables ──
async function previewUfw2Ip() {
const r = await apiGet('/api/security/firewall/status');
showResult(r, 'm-ufw2ip-out');
}
async function runUfw2Ip() {
if (!confirm('Migrate from UFW to raw iptables? UFW will be disabled. Make sure you have console access as backup!')) return;
document.getElementById('m-ufw2ip-out').innerHTML = '<span class="info">Migrating UFW → iptables...</span>';
const r = await apiPost('/api/firewall/migrate/ufw-to-iptables');
showResult(r, 'm-ufw2ip-out');
}
// ── Migration: iptables → UFW ──
async function previewIp2Ufw() {
const r = await apiGet('/api/firewall/iptables/list');
showResult(r, 'm-ip2ufw-out');
}
async function runIp2Ufw() {
if (!confirm('Migrate from iptables to UFW? Current rules will be converted. Make sure you have console access as backup!')) return;
document.getElementById('m-ip2ufw-out').innerHTML = '<span class="info">Migrating iptables → UFW...</span>';
const r = await apiPost('/api/firewall/migrate/iptables-to-ufw');
showResult(r, 'm-ip2ufw-out');
}
// Auto-load dashboard on page load
fwDetect();
</script>
{% endblock %}