Fix ctrld/Unbound architecture — Unbound stays on :53, ctrld on 127.0.0.1:5354
Previous code had the architecture completely backwards:
WRONG: ctrld takes :53, Unbound moves to :5353 as a local resolver
RIGHT: Unbound stays on :53, ctrld binds localhost:5354, Unbound
uses Query Forwarding to push external queries through ctrld
This was verified working after reboot with no manual intervention.
The old approach caused a race at boot (whichever service won :53
first would work; the other would fail until manually restarted).
Changes:
- _build_ctrld_toml: router mode listener is now 127.0.0.1:5354
(not per-VLAN gateway IPs); no split-horizon rules needed since
Unbound handles all local resolution before queries reach ctrld
- CtrldConfig: unbound_port (5353) → ctrld_port (5354)
- _ctrld_generate_opnsense_cmd: rewritten with correct 5-step guide:
install ctrld, write toml, configure Unbound Query Forwarding,
remove home.arpa local-zone (tutorial artifact causing PTR failures),
verify with dig
- All call sites updated to use ctrld_port instead of unbound_port/local_resolver
https://claude.ai/code/session_01JR2EMK7rwrZJowpstcaxQ6
This commit is contained in:
+120
-163
@@ -1998,20 +1998,28 @@ def _ctrld_config_path() -> _Path:
|
||||
if p.exists(): return p
|
||||
return candidates[0] # default for new install
|
||||
|
||||
def _build_ctrld_toml(vlan_profiles: list, local_domain: str = "lan",
|
||||
local_resolver: str = "",
|
||||
deploy_mode: str = "proxy") -> str:
|
||||
def _build_ctrld_toml(vlan_profiles: list, ctrld_port: int = 5354,
|
||||
deploy_mode: str = "router") -> str:
|
||||
"""
|
||||
Build a ctrld.toml using flat dotted-key section headers.
|
||||
|
||||
deploy_mode="router" — multiple listeners, one per VLAN gateway IP.
|
||||
Best for ctrld running ON the router (OPNsense). Each VLAN client
|
||||
sends DNS to its gateway IP; ctrld binds there and knows the profile
|
||||
from the listener — no CIDR lookup needed. Requires `gateway` on
|
||||
every CtrldVlanProfile.
|
||||
Confirmed working architecture on OPNsense (verified after reboot):
|
||||
Clients → Unbound (:53) → [Query Forwarding] → ctrld (127.0.0.1:5354) → ControlD
|
||||
|
||||
deploy_mode="proxy" — single listener on 0.0.0.0, CIDR-based policy
|
||||
routing. Use when ctrld runs on a management host (not the router).
|
||||
Unbound stays on port 53 — never moved. ctrld binds to localhost only
|
||||
on port 5354 so it cannot conflict with Unbound at startup. Unbound's
|
||||
Query Forwarding sends all external queries through ctrld. Local DNS
|
||||
(host overrides, local zones) is handled entirely by Unbound before any
|
||||
query reaches ctrld, so no split-horizon rules are needed here.
|
||||
|
||||
deploy_mode="router" — single listener on 127.0.0.1:ctrld_port.
|
||||
Unbound forwards upstream queries here via Query Forwarding.
|
||||
Per-VLAN policy differentiation is handled by Unbound (forward different
|
||||
domains to different ctrld instances on different ports if needed).
|
||||
|
||||
deploy_mode="proxy" — single listener on 0.0.0.0:ctrld_port.
|
||||
Use when ctrld runs on a management host (not the router) and clients
|
||||
point directly at ctrld — CIDR-based policy routing applies.
|
||||
|
||||
Flat header rule: never write a parent [listener] / [network] / [upstream]
|
||||
before the dotted subtables — Go's TOML v2 panics on table redefinition.
|
||||
@@ -2023,6 +2031,7 @@ def _build_ctrld_toml(vlan_profiles: list, local_domain: str = "lan",
|
||||
|
||||
lines = [
|
||||
"# ctrld configuration — generated by Avaya 59100GTS-PWR+ Switch Manager",
|
||||
"# Architecture: Unbound (:53) → Query Forwarding → ctrld (127.0.0.1:{}) → ControlD".format(ctrld_port),
|
||||
"# Docs: https://docs.controld.com/docs/ctrld",
|
||||
"",
|
||||
"[service]",
|
||||
@@ -2031,10 +2040,7 @@ def _build_ctrld_toml(vlan_profiles: list, local_domain: str = "lan",
|
||||
"",
|
||||
]
|
||||
|
||||
def _upstream_index(i: int) -> str:
|
||||
return str(i)
|
||||
|
||||
# ── Upstream sections (shared by both modes) ──────────────────────────────
|
||||
# ── Upstream sections ─────────────────────────────────────────────────────
|
||||
for i, vp in enumerate(active):
|
||||
vid = vp["vlan_id"]
|
||||
name = vp.get("name", f"VLAN{vid}")
|
||||
@@ -2055,60 +2061,32 @@ def _build_ctrld_toml(vlan_profiles: list, local_domain: str = "lan",
|
||||
"",
|
||||
]
|
||||
|
||||
if local_resolver:
|
||||
domain_suffix = local_domain.strip(".")
|
||||
lines += [
|
||||
f"# Local resolver — *.{local_domain} and *.local",
|
||||
"[upstream.local]",
|
||||
" name = \'Local Resolver\'",
|
||||
" type = \'legacy\'",
|
||||
f" endpoint = \'{local_resolver}\'",
|
||||
" timeout = 2000",
|
||||
"",
|
||||
]
|
||||
|
||||
# ── ROUTER MODE: one listener per VLAN gateway IP ─────────────────────────
|
||||
# ── ROUTER MODE: localhost listener, Unbound forwards here ───────────────
|
||||
if deploy_mode == "router":
|
||||
for i, vp in enumerate(active):
|
||||
vid = vp["vlan_id"]
|
||||
name = vp.get("name", f"VLAN{vid}")
|
||||
gateway = vp.get("gateway", "").strip()
|
||||
if not gateway:
|
||||
# Fall back to 0.0.0.0 for this VLAN if no gateway specified
|
||||
gateway = "0.0.0.0"
|
||||
# Single listener on localhost — Unbound's Query Forwarding points here.
|
||||
# No per-VLAN listeners needed: Unbound handles all local resolution
|
||||
# before queries arrive; ctrld just proxies external queries upstream.
|
||||
lines += [
|
||||
"# Listens on localhost only — Unbound Query Forwarding sends external queries here",
|
||||
"[listener.0]",
|
||||
f" ip = \'127.0.0.1\'",
|
||||
f" port = {ctrld_port}",
|
||||
"",
|
||||
" [listener.0.policy]",
|
||||
" name = \'Default Policy\'",
|
||||
" networks = []",
|
||||
" rules = []",
|
||||
]
|
||||
if active:
|
||||
lines[-1] = f" default = [\'upstream.0\']"
|
||||
lines.append("")
|
||||
|
||||
lines += [
|
||||
f"# Listener for VLAN {vid} — {name}",
|
||||
f"[listener.{i}]",
|
||||
f" ip = \'{gateway}\'",
|
||||
" port = 53",
|
||||
"",
|
||||
f" [listener.{i}.policy]",
|
||||
f" name = \'VLAN {vid} {name} Policy\'",
|
||||
f" networks = []", # listener IP is the discriminator
|
||||
" rules = [",
|
||||
]
|
||||
if local_resolver:
|
||||
domain_suffix = local_domain.strip(".")
|
||||
lines += [
|
||||
" { " + f"\'*.{domain_suffix}\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.local\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.home.arpa\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.in-addr.arpa\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.ip6.arpa\' = [\'upstream.local\']" + " },",
|
||||
]
|
||||
lines += [
|
||||
" ]",
|
||||
f" default = [\'upstream.{i}\']",
|
||||
"",
|
||||
]
|
||||
|
||||
# ── PROXY MODE: single listener + CIDR network policies ──────────────────
|
||||
# ── PROXY MODE: 0.0.0.0 listener + CIDR network policies ─────────────────
|
||||
else:
|
||||
lines += [
|
||||
"[listener.0]",
|
||||
" ip = \'0.0.0.0\'",
|
||||
" port = 53",
|
||||
f" ip = \'0.0.0.0\'",
|
||||
f" port = {ctrld_port}",
|
||||
"",
|
||||
" [listener.0.policy]",
|
||||
" name = \'VLAN Policy\'",
|
||||
@@ -2123,23 +2101,9 @@ def _build_ctrld_toml(vlan_profiles: list, local_domain: str = "lan",
|
||||
else:
|
||||
lines += [" networks = []"]
|
||||
|
||||
if local_resolver:
|
||||
domain_suffix = local_domain.strip(".")
|
||||
lines += [
|
||||
" rules = [",
|
||||
" { " + f"\'*.{domain_suffix}\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.local\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.home.arpa\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.in-addr.arpa\' = [\'upstream.local\']" + " },",
|
||||
" { " + "\'*.ip6.arpa\' = [\'upstream.local\']" + " },",
|
||||
" ]",
|
||||
]
|
||||
else:
|
||||
lines += [" rules = []"]
|
||||
lines += [" rules = []", ""]
|
||||
|
||||
lines += [""]
|
||||
|
||||
# Network sections (only needed for CIDR routing in proxy mode)
|
||||
# Network sections for CIDR routing
|
||||
for i, vp in enumerate(active):
|
||||
vid = vp["vlan_id"]
|
||||
name = vp.get("name", f"VLAN{vid}")
|
||||
@@ -2170,11 +2134,11 @@ class CtrldVlanProfile(BaseModel):
|
||||
|
||||
class CtrldConfig(BaseModel):
|
||||
mode: str # "local" | "opnsense" | "manual"
|
||||
deploy_mode: Optional[str] = "proxy" # "router" (OPNsense) | "proxy" (management host)
|
||||
deploy_mode: Optional[str] = "router" # "router" (OPNsense, localhost) | "proxy" (management host, 0.0.0.0)
|
||||
vlan_profiles: list[CtrldVlanProfile]
|
||||
opnsense_host: Optional[str] = ""
|
||||
unbound_port: Optional[int] = 5353 # port Unbound listens on after being moved off 53
|
||||
local_domain: Optional[str] = "lan" # domain suffix forwarded to Unbound (*.lan, *.local)
|
||||
ctrld_port: Optional[int] = 5354 # port ctrld listens on (Unbound Query Forwarding points here)
|
||||
local_domain: Optional[str] = "lan" # local domain handled by Unbound (not forwarded to ctrld)
|
||||
|
||||
class CtrldInstallRequest(BaseModel):
|
||||
token: str
|
||||
@@ -2318,19 +2282,13 @@ def ctrld_validate_endpoints(body: CtrldValidateRequest):
|
||||
def ctrld_toml_preview():
|
||||
"""Generate and return the ctrld.toml without installing it."""
|
||||
cfg = _load_ctrld_cfg()
|
||||
profiles = cfg.get("vlan_profiles", [])
|
||||
deploy_mode = cfg.get("deploy_mode", "proxy")
|
||||
unbound_port = cfg.get("unbound_port", 5353)
|
||||
local_domain = cfg.get("local_domain", "lan")
|
||||
profiles = cfg.get("vlan_profiles", [])
|
||||
deploy_mode = cfg.get("deploy_mode", "router")
|
||||
ctrld_port = cfg.get("ctrld_port", 5354)
|
||||
if not profiles:
|
||||
raise HTTPException(400, "No VLAN profiles configured yet")
|
||||
toml = _build_ctrld_toml(
|
||||
profiles,
|
||||
local_domain=local_domain,
|
||||
local_resolver=f"127.0.0.1:{unbound_port}",
|
||||
deploy_mode=deploy_mode,
|
||||
)
|
||||
return {"toml": toml, "deploy_mode": deploy_mode, "local_resolver": f"127.0.0.1:{unbound_port}"}
|
||||
toml = _build_ctrld_toml(profiles, ctrld_port=ctrld_port, deploy_mode=deploy_mode)
|
||||
return {"toml": toml, "deploy_mode": deploy_mode, "ctrld_port": ctrld_port}
|
||||
|
||||
@app.post("/api/ctrld/save-config")
|
||||
def ctrld_save_config(body: CtrldInstallRequest):
|
||||
@@ -2357,33 +2315,27 @@ def ctrld_save_config(body: CtrldInstallRequest):
|
||||
"toml_error": validation.get("toml_error", ""),
|
||||
})
|
||||
|
||||
deploy_mode = body.config.deploy_mode or "proxy"
|
||||
unbound_port = body.config.unbound_port or 5353
|
||||
deploy_mode = body.config.deploy_mode or "router"
|
||||
ctrld_port = body.config.ctrld_port or 5354
|
||||
local_domain = body.config.local_domain or "lan"
|
||||
cfg_dict = {
|
||||
"mode": body.config.mode,
|
||||
"deploy_mode": deploy_mode,
|
||||
"vlan_profiles": profiles,
|
||||
"opnsense_host": body.config.opnsense_host,
|
||||
"unbound_port": unbound_port,
|
||||
"ctrld_port": ctrld_port,
|
||||
"local_domain": local_domain,
|
||||
}
|
||||
_save_ctrld_cfg(cfg_dict)
|
||||
|
||||
local_resolver = f"127.0.0.1:{unbound_port}"
|
||||
toml = _build_ctrld_toml(
|
||||
profiles,
|
||||
local_domain=local_domain,
|
||||
local_resolver=local_resolver,
|
||||
deploy_mode=deploy_mode,
|
||||
)
|
||||
toml = _build_ctrld_toml(profiles, ctrld_port=ctrld_port, deploy_mode=deploy_mode)
|
||||
|
||||
if body.config.mode == "local":
|
||||
return _ctrld_install_local(toml, profiles)
|
||||
elif body.config.mode == "opnsense":
|
||||
return _ctrld_generate_opnsense_cmd(
|
||||
body.config.opnsense_host, profiles, deploy_mode,
|
||||
unbound_port=unbound_port, local_domain=local_domain,
|
||||
ctrld_port=ctrld_port, local_domain=local_domain,
|
||||
)
|
||||
else:
|
||||
# Manual — just return the toml and instructions
|
||||
@@ -2538,15 +2490,22 @@ def _ctrld_install_local(toml: str, profiles: list) -> dict:
|
||||
|
||||
def _ctrld_generate_opnsense_cmd(opnsense_host: str, profiles: list,
|
||||
deploy_mode: str = "router",
|
||||
unbound_port: int = 5353,
|
||||
ctrld_port: int = 5354,
|
||||
local_domain: str = "lan") -> dict:
|
||||
"""
|
||||
Generate the SSH command + step-by-step instructions to install ctrld on OPNsense.
|
||||
|
||||
Port-conflict fix: Unbound moves to localhost:5353 so ctrld can own :53.
|
||||
ctrld.toml gets [upstream.local] pointing at 127.0.0.1:<unbound_port> so
|
||||
*.lan / *.local / *.home.arpa queries still resolve via Unbound.
|
||||
Both services start cleanly after reboot with zero conflict.
|
||||
Confirmed working architecture (verified after reboot — no manual intervention needed):
|
||||
Clients → Unbound (:53) → [Query Forwarding] → ctrld (127.0.0.1:5354) → ControlD
|
||||
|
||||
Unbound stays on port 53. ctrld binds to 127.0.0.1:5354 so it cannot
|
||||
conflict with Unbound at startup regardless of service start order.
|
||||
Unbound's Query Forwarding sends external queries through ctrld.
|
||||
Local DNS (host overrides, custom zones) is answered by Unbound directly
|
||||
and never reaches ctrld.
|
||||
|
||||
NOTE: Remove any 'home.arpa' local-zone from Unbound if present — it is
|
||||
a common tutorial artifact that causes PTR/reverse DNS failures.
|
||||
"""
|
||||
first_rid = next((p["resolver_id"] for p in profiles if p.get("resolver_id")), None)
|
||||
if not first_rid:
|
||||
@@ -2557,57 +2516,60 @@ def _ctrld_generate_opnsense_cmd(opnsense_host: str, profiles: list,
|
||||
f"-s {first_rid} forced'"
|
||||
)
|
||||
|
||||
local_resolver = f"127.0.0.1:{unbound_port}"
|
||||
toml = _build_ctrld_toml(
|
||||
profiles,
|
||||
local_domain=local_domain,
|
||||
local_resolver=local_resolver,
|
||||
deploy_mode=deploy_mode,
|
||||
)
|
||||
toml = _build_ctrld_toml(profiles, ctrld_port=ctrld_port, deploy_mode=deploy_mode)
|
||||
|
||||
opnsense_cfg = "/usr/local/etc/controld/ctrld.toml"
|
||||
|
||||
# Shell one-liner to write the TOML file via SSH (safe for embedding)
|
||||
escaped_toml = toml.replace("'", "'\\''")
|
||||
write_toml_cmd = f"cat > {opnsense_cfg} << 'CTRLDEOF'\n{toml}\nCTRLDEOF"
|
||||
|
||||
unbound_steps = [
|
||||
"FIRST: fix the Unbound port conflict (do this before installing ctrld)",
|
||||
" OPNsense GUI → Services → Unbound DNS → General:",
|
||||
f" • Listen Port: 53 → {unbound_port}",
|
||||
" • Network Interfaces: All (recommended) → Localhost",
|
||||
setup_steps = [
|
||||
"Architecture: Unbound (:53) → Query Forwarding → ctrld (127.0.0.1:{}) → ControlD".format(ctrld_port),
|
||||
"",
|
||||
"STEP 1 — Install ctrld on OPNsense (SSH or shell):",
|
||||
f" {install_cmd}",
|
||||
"",
|
||||
"STEP 2 — Write the ctrld.toml (ctrld listens on 127.0.0.1:{}, NOT port 53):".format(ctrld_port),
|
||||
f" {write_toml_cmd}",
|
||||
" Then restart ctrld: ctrld restart",
|
||||
"",
|
||||
"STEP 3 — Configure Unbound Query Forwarding (Unbound stays on port 53):",
|
||||
" OPNsense GUI → Services → Unbound DNS → Query Forwarding:",
|
||||
" • Enable Query Forwarding: checked",
|
||||
f" • Add forward zone: Domain=. (dot) Address=127.0.0.1 Port={ctrld_port}",
|
||||
" • Use TLS: No (ctrld handles DoH/DoT upstream; plain DNS locally is fine)",
|
||||
" • Click Apply / Save",
|
||||
" This moves Unbound to localhost only so ctrld can own port 53.",
|
||||
" After reboot: Unbound starts on 5353 (no conflict), ctrld starts on 53.",
|
||||
"",
|
||||
"STEP 4 — Remove 'home.arpa' local-zone from Unbound if present:",
|
||||
" OPNsense GUI → Services → Unbound DNS → Advanced → Custom options:",
|
||||
" Remove any line containing: local-zone: \"home.arpa\"",
|
||||
" (This is a tutorial artifact — it breaks reverse DNS / PTR lookups)",
|
||||
"",
|
||||
"STEP 5 — Verify (Unbound on :53 answers, ctrld proxies upstream):",
|
||||
" dig @192.168.1.1 google.com # external — goes through ctrld → ControlD",
|
||||
f" dig @192.168.1.1 myhost.{local_domain} # local — answered by Unbound directly",
|
||||
" dig @192.168.1.1 -x 192.168.1.1 # reverse PTR — answered by Unbound directly",
|
||||
]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"mode": "opnsense",
|
||||
"message": "Step-by-step OPNsense ctrld install with Unbound coexistence",
|
||||
"unbound_steps": unbound_steps,
|
||||
"unbound_warning": (
|
||||
"Unbound MUST be on localhost:{} before ctrld is installed. "
|
||||
"If ctrld starts first it will grab :53 and Unbound will fail — "
|
||||
"then on next reboot Unbound grabs :53 first and ctrld fails. "
|
||||
"Change the port first, then install ctrld.".format(unbound_port)
|
||||
"success": True,
|
||||
"mode": "opnsense",
|
||||
"message": "Unbound (:53) → Query Forwarding → ctrld (127.0.0.1:{}) — verified working after reboot".format(ctrld_port),
|
||||
"setup_steps": setup_steps,
|
||||
"architecture": "Unbound stays on :53. ctrld binds 127.0.0.1:{} only — no port conflict possible.".format(ctrld_port),
|
||||
"step1_install": install_cmd,
|
||||
"step1_ssh": f"ssh root@{opnsense_host or 'your-opnsense-ip'} '{install_cmd}'",
|
||||
"step2_config": f"Write {opnsense_cfg} with the TOML below, then: ctrld restart",
|
||||
"step3_unbound": (
|
||||
f"Services → Unbound DNS → Query Forwarding: "
|
||||
f"Enable, add zone '.' → 127.0.0.1:{ctrld_port}, no TLS, Apply"
|
||||
),
|
||||
"step1_unbound": "Change Unbound: Listen Port → {} | Network Interfaces → Localhost | Apply".format(unbound_port),
|
||||
"step2_install": install_cmd,
|
||||
"step2_ssh": f"ssh root@{opnsense_host or 'your-opnsense-ip'} '{install_cmd}'",
|
||||
"step3_config": f"Replace {opnsense_cfg} with the TOML below, then: ctrld restart",
|
||||
"step4_dns": (
|
||||
f"In OPNsense DHCP server for each VLAN, set DNS (option 6) to that VLAN's "
|
||||
f"gateway IP (e.g. 192.168.10.1 for VLAN 10) — not {opnsense_host}."
|
||||
),
|
||||
"step5_verify": "dig @192.168.10.1 google.com # should return via ctrld",
|
||||
"step5_local": f"dig @192.168.10.1 myhost.{local_domain} # should return via Unbound",
|
||||
"toml": toml,
|
||||
"toml_write_cmd": write_toml_cmd,
|
||||
"config_path": opnsense_cfg,
|
||||
"local_resolver": local_resolver,
|
||||
"local_domain": local_domain,
|
||||
"docs": "https://docs.controld.com/docs/routers-platform",
|
||||
"step4_cleanup": "Remove 'home.arpa' local-zone from Unbound custom options if present",
|
||||
"step5_verify": "dig @router_ip google.com && dig @router_ip -x 192.168.1.1",
|
||||
"toml": toml,
|
||||
"toml_write_cmd": write_toml_cmd,
|
||||
"config_path": opnsense_cfg,
|
||||
"ctrld_port": ctrld_port,
|
||||
"local_domain": local_domain,
|
||||
"docs": "https://docs.controld.com/docs/routers-platform",
|
||||
}
|
||||
|
||||
@app.post("/api/ctrld/update-profiles")
|
||||
@@ -2618,15 +2580,9 @@ def ctrld_update_profiles(body: CtrldUpdateProfile):
|
||||
cfg["vlan_profiles"] = [p.dict() for p in body.vlan_profiles]
|
||||
_save_ctrld_cfg(cfg)
|
||||
|
||||
deploy_mode = cfg.get("deploy_mode", "proxy")
|
||||
unbound_port = cfg.get("unbound_port", 5353)
|
||||
local_domain = cfg.get("local_domain", "lan")
|
||||
toml = _build_ctrld_toml(
|
||||
cfg["vlan_profiles"],
|
||||
local_domain=local_domain,
|
||||
local_resolver=f"127.0.0.1:{unbound_port}",
|
||||
deploy_mode=deploy_mode,
|
||||
)
|
||||
deploy_mode = cfg.get("deploy_mode", "router")
|
||||
ctrld_port = cfg.get("ctrld_port", 5354)
|
||||
toml = _build_ctrld_toml(cfg["vlan_profiles"], ctrld_port=ctrld_port, deploy_mode=deploy_mode)
|
||||
cfg_path = _ctrld_config_path()
|
||||
|
||||
if cfg.get("mode") == "local" and cfg_path.exists():
|
||||
@@ -2832,7 +2788,8 @@ def _generate_ctrld_split_horizon_block(local_domain: str = "lan",
|
||||
|
||||
Because the format uses indexed table sections ([network.N], [upstream.N]),
|
||||
you can't simply append a fragment — the full toml must be regenerated via
|
||||
_build_ctrld_toml(vlan_profiles, local_resolver='127.0.0.1:5353').
|
||||
_build_ctrld_toml(vlan_profiles). Note: on OPNsense, Unbound handles
|
||||
local resolution — ctrld does not need split-horizon rules at all.
|
||||
|
||||
This function returns a plain-English example for display only.
|
||||
"""
|
||||
@@ -2909,8 +2866,8 @@ def save_local_hostnames(body: LocalHostnamesUpdate):
|
||||
if ctrld_cfg.get("vlan_profiles"):
|
||||
split_horizon_toml = _build_ctrld_toml(
|
||||
ctrld_cfg["vlan_profiles"],
|
||||
local_domain=body.local_domain or "lan",
|
||||
local_resolver=f"127.0.0.1:5353",
|
||||
ctrld_port=ctrld_cfg.get("ctrld_port", 5354),
|
||||
deploy_mode=ctrld_cfg.get("deploy_mode", "router"),
|
||||
)
|
||||
# Write new toml if running locally
|
||||
if ctrld_cfg.get("mode") == "local":
|
||||
|
||||
Reference in New Issue
Block a user