Development

This commit is contained in:
Matthew Grotke 2026-05-25 21:49:47 -04:00
parent ac0aa4de22
commit 91d8b950b7
5 changed files with 38 additions and 35 deletions

View file

@ -331,11 +331,11 @@ def validate_config(data):
_vid = _derived_ids[i]
vlan_ifaces.append(_lan if _vid == 1 else f"{_lan}.{_vid}")
# -- upstream_dns block ----------------------------------------------------
# upstream_dns block ============================================
if not data.get("upstream_dns", {}).get("upstream_servers"):
errors.append("upstream_dns.upstream_servers is missing or empty.")
# -- WAN / LAN interfaces --------------------------------------------------
# WAN / LAN interfaces ==========================================
gen = data.get("network_interfaces", {})
wan = gen.get("wan_interface", "")
lan = gen.get("lan_interface", "")
@ -357,7 +357,7 @@ def validate_config(data):
if wan == lan:
errors.append(f"network_interfaces.wan_interface and network_interfaces.lan_interface must be different (both set to '{wan}').")
# -- Blocklist library -----------------------------------------------------
# Blocklist library =============================================
blocklists_by_name = {}
for idx, bl in enumerate(data.get("dns_blocking", {}).get("blocklists", [])):
name = bl.get("name", "")
@ -373,7 +373,7 @@ def validate_config(data):
else:
blocklists_by_name[name] = bl
# -- Per-VLAN validation ---------------------------------------------------
# Per-VLAN validation ===========================================
vlan_networks = {} # iface -> IPv4Network (used for NAT section)
for i, (vlan, iface) in enumerate(zip(_all_vlans, vlan_ifaces)):
@ -403,7 +403,7 @@ def validate_config(data):
errors.append(f"{label}: mdns_reflection must be false for WireGuard interfaces.")
if is_wg(vlan):
# -- vpn_information -----------------------------------------------
# vpn_information =======================================
vpi = vlan.get("vpn_information")
if not isinstance(vpi, dict):
errors.append(f"{label}: vpn_information must be a plain object.")
@ -418,7 +418,7 @@ def validate_config(data):
else:
seen_listen_ports[lp] = name
# -- subnet/subnet_mask --------------------------------------------
# subnet/subnet_mask ====================================
for field in ("subnet", "subnet_mask"):
if not vlan.get(field):
errors.append(f"{label}: missing required field '{field}'.")
@ -430,7 +430,7 @@ def validate_config(data):
except ValueError as e:
errors.append(f"{label}: invalid subnet/subnet_mask: {e}")
# -- server_identities ---------------------------------------------
# server_identities =====================================
if not vlan.get("server_identities"):
errors.append(f"{label}: server_identities is empty or missing.")
identity_ips = []
@ -449,7 +449,7 @@ def validate_config(data):
else:
identity_ips.append(ip_addr)
# -- vpn_information.explicit_overrides ----------------------------
# vpn_information.explicit_overrides ====================
eo = vpi.get("explicit_overrides", {}) if isinstance(vpi, dict) else {}
if not isinstance(eo, dict):
errors.append(f"{label}: vpn_information.explicit_overrides must be a plain object.")
@ -476,7 +476,7 @@ def validate_config(data):
if domain_val and not domainname(domain_val):
errors.append(f"{label}: vpn_information.domain '{domain_val}' is not a valid domain name.")
# -- peers ---------------------------------------------------------
# peers =================================================
seen_peer_names = {}
seen_peer_ips = {}
for pidx, peer in enumerate(vlan.get("peers", [])):
@ -556,7 +556,7 @@ def validate_config(data):
if ip:
identity_ips.append(ip)
# -- Validate explicit_overrides ---------------------------------------
# Validate explicit_overrides ===============================
eo = d.get("explicit_overrides", {})
if not isinstance(eo, dict):
errors.append(f"{label}: explicit_overrides must be a plain object.")
@ -642,7 +642,7 @@ def validate_config(data):
if bl_name not in blocklists_by_name:
errors.append(f"{label}: use_blocklists references unknown blocklist '{bl_name}'.")
# -- NAT / firewall validation ---------------------------------------------
# NAT / firewall validation =====================================
valid_protos = VALID_PROTOCOLS
known_interfaces = set(seen_interfaces.keys())
@ -675,7 +675,7 @@ def validate_config(data):
if net:
nat_check_ip_in_network(f"{label} redirect_to", r.get("redirect_to", ""), net)
# -- port_forwarding validation (top-level) --------------------------------
# port_forwarding validation (top-level) ========================
for idx, r in enumerate(data.get("port_forwarding", [])):
desc = r.get("description", "?")
label = f"port_forwarding[{idx}] '{desc}'"
@ -709,13 +709,13 @@ def validate_config(data):
if r.get("dst_port") is not None:
nat_check_port(f"{label} dst_port", r.get("dst_port"))
# -- radius_default uniqueness check ---------------------------------------
# radius_default uniqueness check ===============================
defaults = [v["name"] for v in data.get("vlans", []) if v.get("radius_default") is True]
if len(defaults) > 1:
errors.append(f"Multiple VLANs have radius_default: true ({', '.join(defaults)}). "
f"Only one VLAN may be the RADIUS default.")
# -- RADIUS requires multiple VLANs ----------------------------------------
# RADIUS requires multiple VLANs ================================
non_wg_vlans = [v for v in data.get("vlans", []) if not is_wg(v)]
has_radius_clients = any(
r.get("radius_client")
@ -728,7 +728,7 @@ def validate_config(data):
"Dynamic VLAN assignment requires at least two VLANs."
)
# -- host_overrides validation ---------------------------------------------
# host_overrides validation =====================================
all_vlan_nets = list(vlan_networks.values())
for idx, entry in enumerate(data.get("host_overrides", [])):
lbl = f"host_overrides[{idx}] '{entry.get('host', '?')}'"
@ -744,7 +744,7 @@ def validate_config(data):
if all_vlan_nets and not any(ip_addr in net for net in all_vlan_nets):
errors.append(f"{lbl}: '{ip_str}' does not fall within any configured VLAN subnet.")
# -- banned_ips validation -------------------------------------------------
# banned_ips validation =========================================
for idx, entry in enumerate(data.get("banned_ips", [])):
ip_val = entry.get("ip", "")
lbl = f"banned_ips[{idx}] '{entry.get('description', '')}'"