diff --git a/switch_backend.py b/switch_backend.py index fce77d4..bfa7fa8 100644 --- a/switch_backend.py +++ b/switch_backend.py @@ -2857,22 +2857,33 @@ def _build_unbound_lan_zone_conf(entries: list, mgmt_ip: str = "192.168.99.50") """ Build the full local-lan-zone.conf for Unbound. + OPNsense includes /var/unbound/etc/*.conf at the TOP LEVEL of unbound.conf + (either via include: or include-toplevel:). This means server-level + directives (local-zone:, local-data:) must be wrapped in a server: block. + Without the wrapper they land outside any section and are silently ignored + or cause unbound-checkconf to error. forward-zone: is a top-level section + and needs no wrapper — that's why forward_to_ctrld.conf works without one. + Declares 'lan.' as a static zone (so .lan never leaks to ControlD) and adds local-data A records for every entry in local-hostnames.json plus - the two built-in management aliases. Without these local-data lines every - .lan name that isn't listed gets NXDOMAIN — including pbx.lan and any + the two built-in management aliases. Without local-data entries every + .lan name not explicitly listed gets NXDOMAIN — including pbx.lan and any other custom hostname the user defined. """ - lines = ['local-zone: "lan." static', ""] + lines = [ + "server:", + ' local-zone: "lan." static', + "", + ] # Management PC aliases — always present for alias in ("switch.mgmt.lan", "management.lan"): - lines.append(f'local-data: "{alias}. A {mgmt_ip}"') + lines.append(f' local-data: "{alias}. A {mgmt_ip}"') # User-defined entries from local-hostnames.json for e in entries: name = e.get("name", "").strip().rstrip(".") ip = e.get("ip", "").strip() if name and ip: - lines.append(f'local-data: "{name}. A {ip}"') + lines.append(f' local-data: "{name}. A {ip}"') return "\n".join(lines) + "\n"