dhcp: auto-populate gateway from interface IP for DHCP ranges

Add get_interface_ip() helper to resolve an interface's IPv4 address
via 'ip -o addr show'.  Use it to back-propagate gateway into DHCP
ranges so clients receive their default route.

- set_dhcp_range() resolves gateway: explicit > existing range > iface IP
- DnsToFirewallSync and FirewallToDhcpSync sync ensure gateways are set
- Remove automatic masquerade toggle from DnsToFirewallSync
- Fix dnsmasq lease file path to /var/lib/misc/dnsmasq.leases
- Rename lease state field expires_at -> expires (ISO string)
- Add 'ip -o addr show' to sudo whitelist
This commit is contained in:
2026-07-09 00:58:09 +00:00
parent 5135de0921
commit 803258cf18
7 changed files with 143 additions and 35 deletions
+22 -6
View File
@@ -30,6 +30,7 @@ from lib.common import (
config_hash,
deep_merge,
ensure_dirs,
get_interface_ip,
load_json,
run,
save_json,
@@ -44,7 +45,7 @@ DATA_DIR = PROJECT_DIR / "data" / "dnsmasq"
CONFIG_PATH = CONFIG_DIR / "config.json"
FRAGMENTS_DIR = DATA_DIR / "fragments"
DNSMASQ_CONF = "/etc/dnsmasq.d/vacuum-wall.conf"
LEASE_FILE = "/var/lib/dnsmasq/dnsmasq.leases"
LEASE_FILE = "/var/lib/misc/dnsmasq.leases"
ENV = Environment(
loader=FileSystemLoader(str(PROJECT_DIR / "system")),
@@ -225,15 +226,30 @@ def set_dhcp_range(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]
Endpoint: POST /dnsmasq/ranges/add
Add or update a DHCP pool range by interface. Raises ValueError on invalid input.
Auto-populates ``gateway`` from the interface's IPv4 address when not provided.
"""
if not body:
raise ValueError("Request body required")
iface = body.get("interface", "").strip() or ""
iface = (body.get("interface") or "").strip()
start = body.get("start", "").strip()
end = body.get("end", "").strip()
lease_time = body.get("lease_time", "12h")
if not start or not end:
raise ValueError("'start' and 'end' are required")
# Resolve gateway: explicit value > existing range value > interface IP
gateway = body.get("gateway")
if not gateway:
# Check existing range for same interface
cfg_tmp = _get_config()
for r in cfg_tmp["dhcp"]["ranges"]:
if r.get("interface") == iface:
gateway = r.get("gateway")
break
# Fall back to interface's own IP
if not gateway and iface:
gateway = get_interface_ip(iface)
cfg = _get_config()
ranges = cfg["dhcp"]["ranges"]
found = False
@@ -245,8 +261,8 @@ def set_dhcp_range(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]
"end": end,
"lease_time": lease_time,
}
if body.get("gateway"):
ranges[i]["gateway"] = body["gateway"]
if gateway:
ranges[i]["gateway"] = gateway
if body.get("dns"):
ranges[i]["dns"] = body["dns"]
found = True
@@ -258,8 +274,8 @@ def set_dhcp_range(_request: Any, body: dict[str, Any] | None) -> dict[str, Any]
"end": end,
"lease_time": lease_time,
}
if body.get("gateway"):
entry["gateway"] = body["gateway"]
if gateway:
entry["gateway"] = gateway
if body.get("dns"):
entry["dns"] = body["dns"]
ranges.append(entry)