Initial commit: SSL proxy / firewall appliance
Flask WebUI behind nginx reverse proxy with zone-based firewall, DHCP, WireGuard, and ACME certificate management.
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}DHCP & DNS - Vacuum Wall{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>DHCP & DNS</h1>
|
||||
<div class="subtitle">Dnsmasq configuration and lease management</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DHCP Ranges -->
|
||||
<div class="section-title">DHCP Ranges</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<form hx-post="/api/dhcp/ranges" hx-swap="none" class="htmx-on-success" data-success="DHCP range added" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<div class="inline-form">
|
||||
<div class="form-group">
|
||||
<label for="range-interface">Interface</label>
|
||||
<select id="range-interface" name="interface">
|
||||
<option value="">— Global —</option>
|
||||
{% for iface in (interfaces or []) %}
|
||||
<option value="{{ iface.get('name', '') }}">{{ iface.get('name', '') }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="range-start">Start IP</label>
|
||||
<input type="text" id="range-start" name="start" placeholder="192.168.1.100" required style="width:160px;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="range-end">End IP</label>
|
||||
<input type="text" id="range-end" name="end" placeholder="192.168.1.200" required style="width:160px;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="range-lease">Lease Time</label>
|
||||
<input type="text" id="range-lease" name="lease_time" placeholder="1h" value="{{ (config or {}).get('dhcp_lease_time', '1h') }}" style="width:80px;">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Range</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-4">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Interface</th>
|
||||
<th>Start</th>
|
||||
<th>End</th>
|
||||
<th>Lease Time</th>
|
||||
<th style="width:80px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rng in ((config or {}).get('dhcp_ranges', []) or []) %}
|
||||
<tr>
|
||||
<td>{{ rng.get('interface', '(global)') }}</td>
|
||||
<td>{{ rng.get('start', '') }}</td>
|
||||
<td>{{ rng.get('end', '') }}</td>
|
||||
<td>{{ rng.get('lease_time', '1h') }}</td>
|
||||
<td>
|
||||
<form hx-delete="/api/dhcp/ranges/{{ rng.get('start', '') }}/{{ rng.get('end', '') }}" hx-swap="none" class="htmx-on-success" data-success="Range removed" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Remove this range?')">Remove</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not ((config or {}).get('dhcp_ranges', []) or []) %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-muted text-sm">No DHCP ranges configured</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Static Leases -->
|
||||
<div class="section-title">Static Leases</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<form hx-post="/api/dhcp/leases/static" hx-swap="none" class="htmx-on-success" data-success="Static lease added" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<div class="inline-form">
|
||||
<div class="form-group">
|
||||
<label for="lease-mac">MAC Address</label>
|
||||
<input type="text" id="lease-mac" name="mac" placeholder="aa:bb:cc:dd:ee:ff" required style="width:180px;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lease-ip">IP Address</label>
|
||||
<input type="text" id="lease-ip" name="ip" placeholder="192.168.1.50" required style="width:160px;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="lease-host">Hostname</label>
|
||||
<input type="text" id="lease-host" name="hostname" placeholder="myhost" style="width:140px;">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Lease</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-4">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>MAC</th>
|
||||
<th>IP</th>
|
||||
<th>Hostname</th>
|
||||
<th style="width:80px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for lease in ((config or {}).get('static_leases', []) or []) %}
|
||||
<tr>
|
||||
<td>{{ lease.get('mac', '') }}</td>
|
||||
<td>{{ lease.get('ip', '') }}</td>
|
||||
<td>{{ lease.get('hostname', '-') }}</td>
|
||||
<td>
|
||||
<form hx-delete="/api/dhcp/leases/static/{{ lease.get('mac', '') }}" hx-swap="none" class="htmx-on-success" data-success="Lease removed" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Remove this lease?')">Remove</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not ((config or {}).get('static_leases', []) or []) %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-muted text-sm">No static leases configured</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom DNS Records -->
|
||||
<div class="section-title">Custom DNS Records</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<form hx-post="/api/dhcp/dns/records" hx-swap="none" class="htmx-on-success" data-success="DNS record added" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<div class="inline-form">
|
||||
<div class="form-group">
|
||||
<label for="dns-ip">IP Address</label>
|
||||
<input type="text" id="dns-ip" name="ip" placeholder="192.168.1.10" required style="width:160px;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="dns-hostname">Hostname / Domain</label>
|
||||
<input type="text" id="dns-hostname" name="hostname" placeholder="host.local" required style="width:200px;">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Record</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-4">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th>Hostname</th>
|
||||
<th style="width:80px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rec in ((config or {}).get('dns_records', []) or []) %}
|
||||
<tr>
|
||||
<td>{{ rec.get('ip', '') }}</td>
|
||||
<td>{{ rec.get('hostname', '') }}</td>
|
||||
<td>
|
||||
<form hx-delete="/api/dhcp/dns/records/{{ rec.get('ip', '') }}/{{ rec.get('hostname', '') }}" hx-swap="none" class="htmx-on-success" data-success="Record removed" onsuccess="setTimeout(function(){ location.reload(); }, 300);">
|
||||
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Remove this record?')">Remove</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not ((config or {}).get('dns_records', []) or []) %}
|
||||
<tr>
|
||||
<td colspan="3" class="text-muted text-sm">No custom DNS records</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current DHCP Leases -->
|
||||
<div class="section-title">Current DHCP Leases</div>
|
||||
|
||||
<div class="card">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Expires</th>
|
||||
<th>MAC</th>
|
||||
<th>IP</th>
|
||||
<th>Hostname</th>
|
||||
<th>Client ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for lease in (leases or []) %}
|
||||
<tr>
|
||||
<td>{{ lease.get('expires', 'N/A') }}</td>
|
||||
<td>{{ lease.get('mac', 'N/A') }}</td>
|
||||
<td>{{ lease.get('ip', 'N/A') }}</td>
|
||||
<td>{{ lease.get('hostname', '*') or '*' }}</td>
|
||||
<td class="text-muted text-sm">{{ lease.get('client_id', 'N/A') }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if not (leases or []) %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-muted text-sm">No active DHCP leases</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="mt-2 text-right">
|
||||
<button class="btn btn-sm btn-outline" hx-post="/api/dhcp/reload" hx-swap="none" class="htmx-on-success" data-success="Dnsmasq configuration reloaded">Apply & Restart Dnsmasq</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user