Add DNS enforcement, ACL templates, local hostnames, ctrld format fix
Features added: - Port 53 conflict resolution: auto-detect/fix systemd-resolved stub listener on Linux; instructions for OPNsense Unbound (ctrld auto-terminates it) - DNS enforcement ACLs: generate ERS 5952 ACL commands that permit DNS only to ctrld IP and block all other port 53/853 traffic per VLAN - Inter-VLAN routing ACL templates: Staff, IoT, Guest, Camera profiles with live preview and parameter inputs (ctrld IP, NVR IP, subnet) - Local hostname resolution: dnsmasq Docker service for .lan split-horizon DNS; manage hostname→IP mappings via UI; generates dnsmasq.conf and ctrld.toml upstream.local block - Fix ctrld.toml format: correct [listener.0], [network.N], [upstream.N] table notation (was using wrong [[array]] notation); matches official docs format - Backend docstrings: added docstrings to all previously undocumented functions - README: new sections for port 53 conflict resolution, DNS enforcement ACLs, ACL templates, and local hostname resolution (dnsmasq) - Fix Python 3.11 f-string syntax errors in Avaya_5952_setup.py (backslash in f-string expressions, same-type quote in dict access); embed now succeeds https://claude.ai/code/session_01JR2EMK7rwrZJowpstcaxQ6
This commit is contained in:
@@ -112,6 +112,8 @@ Create, rename, and delete VLANs. Shows port count and subnet per VLAN. VLAN 1 c
|
||||
|
||||
Build Access Control Lists visually. Each rule specifies action (permit/deny), protocol (ip/tcp/udp/icmp), source, destination, and optional port. The ACL is assigned to a VLAN interface with a direction. The tool generates all CLI syntax — you never write it yourself.
|
||||
|
||||
**Templates:** Click "Use Template" to pre-fill rules for common patterns: Staff (full internet, no management), IoT (internet only, no RFC1918), Guest (internet + ctrld DNS enforcement), Camera (NVR only). All rules are editable after applying the template.
|
||||
|
||||
### Review & Push
|
||||
|
||||
Every change across all tabs is translated into the exact CLI commands the ERS 5952 understands. This tab shows those commands before anything is sent.
|
||||
@@ -170,6 +172,10 @@ Generates the `ctrld.toml` config and install command. You install wherever you
|
||||
|
||||
**Per-VLAN Resolver IDs:** Each VLAN gets its own Control D profile. Enter the Resolver ID from the Control D dashboard (controld.com → Add Device → Router → Resolver ID). VLANs without a Resolver ID use the first configured profile as fallback.
|
||||
|
||||
**DNS Enforcement:** After installing ctrld, use the "Enforce DNS on Switch" button to generate ACLs that block devices from bypassing ctrld by using 8.8.8.8 directly. See [DNS Enforcement ACLs](#dns-enforcement-acls) below.
|
||||
|
||||
**Local Hostnames:** Optionally run a dnsmasq container so `.lan` names resolve for all devices. See [Local Hostname Resolution](#local-hostname-resolution-dnsmasq) below.
|
||||
|
||||
**References:**
|
||||
- Control D documentation: https://docs.controld.com/docs/ctrld
|
||||
- Router setup guide: https://docs.controld.com/docs/routers-platform
|
||||
@@ -354,6 +360,8 @@ The switch is never being polled when nobody is looking at the dashboard.
|
||||
| `wg_server_public` | `/etc/switch-manager/` | WireGuard server public key |
|
||||
| `clients/` | `/etc/switch-manager/` | WireGuard client .conf files |
|
||||
| `switch-manager.service` | `/etc/systemd/system/` | Systemd service (native mode) |
|
||||
| `local-hostnames.json` | `/etc/switch-manager/` | User-defined hostname→IP mappings (optional) |
|
||||
| `dnsmasq.conf` | `/etc/switch-manager/` | Generated dnsmasq config (optional) |
|
||||
|
||||
**Back up `/etc/switch-manager/totp_secret`** — if the management computer fails and you have not backed this up you will need to regenerate the TOTP secret and re-scan it into your authenticator app.
|
||||
|
||||
@@ -411,3 +419,107 @@ This switch has no REST API. Everything this tool does is via SSH sessions that
|
||||
There is an inherent limit to how reliably the tool can detect every possible error condition. The danger blocking system catches the known lethal patterns but cannot anticipate every possible misconfiguration. Use the CLI review step. Read what is about to be sent.
|
||||
|
||||
The console cable is always your fallback. Keep it accessible.
|
||||
|
||||
---
|
||||
|
||||
## DNS Filtering — Port 53 Conflict Resolution
|
||||
|
||||
When installing ctrld (Option A — local install), ctrld needs to bind port 53. On Ubuntu and Debian, `systemd-resolved` holds port 53 via its stub listener.
|
||||
|
||||
**The tool fixes this automatically** during installation. It adds `DNSStubListener=no` to `/etc/systemd/resolved.conf` and restarts `systemd-resolved`. The service itself keeps running — it still manages `/etc/resolv.conf` and local hostname caching. Only the stub listener is disabled.
|
||||
|
||||
If the automatic fix fails (permission issue, non-standard config), fix it manually:
|
||||
|
||||
```bash
|
||||
echo "[Resolve]" | sudo tee -a /etc/systemd/resolved.conf
|
||||
echo "DNSStubListener=no" | sudo tee -a /etc/systemd/resolved.conf
|
||||
sudo systemctl restart systemd-resolved
|
||||
```
|
||||
|
||||
**On OPNsense (Option B):** OPNsense runs Unbound DNS on port 53. The correct approach is not to uninstall Unbound — it handles `.lan` hostnames and local DNS. Instead:
|
||||
|
||||
1. In OPNsense UI: Services → Unbound DNS → General → set Listen Port to `5353`, Listen Interface to `Loopback (lo0)`. Save + Apply.
|
||||
2. Configure ctrld to forward `*.lan` and `*.local` to `127.0.0.1:5353` (the split-horizon block shown in the DNS tab result panel).
|
||||
3. ctrld handles all other queries via DoH3 to Control D.
|
||||
|
||||
This keeps local names working while all external DNS is filtered per-VLAN through Control D.
|
||||
|
||||
---
|
||||
|
||||
## DNS Enforcement ACLs
|
||||
|
||||
Without enforcement, a device can ignore DHCP-assigned DNS and use `8.8.8.8` directly, bypassing all ctrld filtering.
|
||||
|
||||
The DNS tab has an **"Enforce DNS on Switch"** button that generates ACLs blocking this. For each VLAN:
|
||||
|
||||
```
|
||||
ip access-list extended DNS-ENFORCE-VLAN10
|
||||
1 permit udp 192.168.10.0 0.0.0.255 host [ctrld-ip] eq 53
|
||||
2 permit tcp 192.168.10.0 0.0.0.255 host [ctrld-ip] eq 53
|
||||
3 deny udp 192.168.10.0 0.0.0.255 any eq 53
|
||||
4 deny tcp 192.168.10.0 0.0.0.255 any eq 53
|
||||
5 deny tcp 192.168.10.0 0.0.0.255 any eq 853
|
||||
6 permit ip any any
|
||||
interface vlan 10
|
||||
ip access-group DNS-ENFORCE-VLAN10 in
|
||||
```
|
||||
|
||||
Rules 1–2 permit DNS only to ctrld. Rules 3–4 block DNS anywhere else (8.8.8.8, Cloudflare, etc.). Rule 5 blocks DNS-over-TLS (port 853) as another bypass path. Rule 6 permits all other traffic so internet still works.
|
||||
|
||||
VLAN 99 (management) is automatically excluded — a broken ACL on the management VLAN would lock you out.
|
||||
|
||||
The generated commands are shown for review and pushed through the normal TOTP-gated push mechanism. Nothing is sent to the switch automatically.
|
||||
|
||||
---
|
||||
|
||||
## Inter-VLAN Routing ACL Templates
|
||||
|
||||
The **ACL Builder** tab has a **"Use Template"** button that pre-fills common policies:
|
||||
|
||||
**Staff VLAN — full internet, no management access**
|
||||
Permits everything except access to VLAN 99 (192.168.99.0/24). Use on a staff or office VLAN where users need full internet but must not reach the management interface.
|
||||
|
||||
**IoT VLAN — internet only, no RFC1918**
|
||||
Blocks all RFC1918 private address ranges (192.168.x.x, 10.x.x.x, 172.16-31.x.x). IoT devices get internet but cannot reach any other VLAN, internal servers, or management. Permits internet.
|
||||
|
||||
**Guest VLAN — internet only, DNS must work first**
|
||||
Like IoT but explicitly permits DNS to ctrld first (before the deny rules), ensuring DNS filtering continues to work even after RFC1918 is blocked.
|
||||
|
||||
**Camera VLAN — NVR only**
|
||||
Cameras may only send traffic to one NVR/DVR IP. All other traffic is dropped. Prevents cameras from phoning home, scanning the network, or accessing the internet directly.
|
||||
|
||||
All templates are fully editable after applying. The template fills the rule table — you adjust IPs, add rules, or delete rules before pushing.
|
||||
|
||||
---
|
||||
|
||||
## Local Hostname Resolution (dnsmasq)
|
||||
|
||||
The DNS tab has a **"Local Hostnames"** section. It manages an optional `dnsmasq` container that resolves `.lan` hostnames for all devices on the network.
|
||||
|
||||
**How it works:**
|
||||
1. dnsmasq runs in Docker, listening on port 5353 on the management computer.
|
||||
2. ctrld is configured to forward `*.lan` and `*.local` queries to `127.0.0.1:5353` (split-horizon rule).
|
||||
3. All other queries go through Control D as normal.
|
||||
4. `switch.mgmt.lan` and `management.lan` always resolve to the management computer's IP.
|
||||
|
||||
**Setup:**
|
||||
|
||||
Add hostname→IP mappings in the DNS tab → Local Hostnames section. Click **Save & Generate dnsmasq.conf**. The tab shows:
|
||||
- The generated `dnsmasq.conf` content and path
|
||||
- A docker-compose snippet to add the dnsmasq service
|
||||
- A ctrld.toml block to enable split-horizon forwarding
|
||||
|
||||
Add the docker-compose snippet to `docker-compose.yml`, add the toml block to `ctrld.toml`, then:
|
||||
```bash
|
||||
docker compose up -d dnsmasq
|
||||
ctrld restart
|
||||
```
|
||||
|
||||
The `dnsmasq.conf` is written to `/etc/switch-manager/dnsmasq.conf` and mounted read-only into the container.
|
||||
|
||||
**Files added:**
|
||||
|
||||
| File | Location | Purpose |
|
||||
|---|---|---|
|
||||
| `local-hostnames.json` | `/etc/switch-manager/` | User-defined hostname→IP mappings |
|
||||
| `dnsmasq.conf` | `/etc/switch-manager/` | Generated dnsmasq config |
|
||||
|
||||
Reference in New Issue
Block a user