diff --git a/docker/routlin-dash/app/pages/networklayout/action.py b/docker/routlin-dash/app/pages/networklayout/action.py index 2f8267d..30c2aea 100644 --- a/docker/routlin-dash/app/pages/networklayout/action.py +++ b/docker/routlin-dash/app/pages/networklayout/action.py @@ -112,9 +112,9 @@ def addvlan_add(): inferred_gw = (min(identity_ips, key=lambda ip: int(ip.split('.')[-1])) if identity_ips else '') new_stored_gw = gateway_raw if (gateway_raw and gateway_raw != inferred_gw) else '' - dns_override = 'dns_server_override' in request.form + dns_override = 'dns_servers_override' in request.form dns_ips = [] - for _line in request.form.get('dns_server', '').splitlines(): + for _line in request.form.get('dns_servers', '').splitlines(): _line = _line.strip() if not _line: continue @@ -130,9 +130,9 @@ def addvlan_add(): return redirect(f'/{_PAGE}') new_stored_dns = dns_ips if dns_override else [] - ntp_override = 'ntp_server_override' in request.form + ntp_override = 'ntp_servers_override' in request.form ntp_ips = [] - for _line in request.form.get('ntp_server', '').splitlines(): + for _line in request.form.get('ntp_servers', '').splitlines(): _line = _line.strip() if not _line: continue @@ -207,9 +207,9 @@ def addvlan_add(): if new_stored_gw: dhcp_overrides['gateway'] = new_stored_gw if new_stored_dns: - dhcp_overrides['dns_server'] = new_stored_dns + dhcp_overrides['dns_servers'] = new_stored_dns if new_stored_ntp: - dhcp_overrides['ntp_server'] = new_stored_ntp + dhcp_overrides['ntp_servers'] = new_stored_ntp if dhcp_overrides: dhcp_info['explicit_overrides'] = dhcp_overrides @@ -361,9 +361,9 @@ def vlans_edit(): new_stored_gw = gateway_raw if (gateway_raw and gateway_raw != inferred_gw) else '' existing_gw = existing.get('dhcp_information', {}).get('explicit_overrides', {}).get('gateway', '') - dns_override = 'dns_server_override' in request.form + dns_override = 'dns_servers_override' in request.form dns_ips = [] - for _line in request.form.get('dns_server', '').splitlines(): + for _line in request.form.get('dns_servers', '').splitlines(): _line = _line.strip() if not _line: continue @@ -382,12 +382,12 @@ def vlans_edit(): flash(f"DNS server '{_ip}' is not in the VLAN subnet ({subnet}/{final_mask}).", 'error') return redirect(f'/{_PAGE}') new_stored_dns = dns_ips if dns_override else [] - _existing_dns = existing.get('dhcp_information', {}).get('explicit_overrides', {}).get('dns_server', []) + _existing_dns = existing.get('dhcp_information', {}).get('explicit_overrides', {}).get('dns_servers', []) existing_dns = _existing_dns if isinstance(_existing_dns, list) else ([_existing_dns] if _existing_dns else []) ntp_override = 'ntp_server_override' in request.form ntp_ips = [] - for _line in request.form.get('ntp_server', '').splitlines(): + for _line in request.form.get('ntp_servers', '').splitlines(): _line = _line.strip() if not _line: continue @@ -406,7 +406,7 @@ def vlans_edit(): flash(f"NTP server '{_ip}' is not in the VLAN subnet ({subnet}/{final_mask}).", 'error') return redirect(f'/{_PAGE}') new_stored_ntp = ntp_ips if ntp_override else [] - _existing_ntp = existing.get('dhcp_information', {}).get('explicit_overrides', {}).get('ntp_server', []) + _existing_ntp = existing.get('dhcp_information', {}).get('explicit_overrides', {}).get('ntp_servers', []) existing_ntp = _existing_ntp if isinstance(_existing_ntp, list) else ([_existing_ntp] if _existing_ntp else []) _ids_unchanged = ( @@ -452,13 +452,13 @@ def vlans_edit(): else: dhcp_overrides.pop('gateway', None) if new_stored_dns: - dhcp_overrides['dns_server'] = new_stored_dns + dhcp_overrides['dns_servers'] = new_stored_dns else: - dhcp_overrides.pop('dns_server', None) + dhcp_overrides.pop('dns_servers', None) if new_stored_ntp: - dhcp_overrides['ntp_server'] = new_stored_ntp + dhcp_overrides['ntp_servers'] = new_stored_ntp else: - dhcp_overrides.pop('ntp_server', None) + dhcp_overrides.pop('ntp_servers', None) if not dhcp_overrides: existing.get('dhcp_information', {}).pop('explicit_overrides', None) errors = validate.validate_config(cfg) diff --git a/docker/routlin-dash/app/pages/networklayout/content.json b/docker/routlin-dash/app/pages/networklayout/content.json index 55f0320..c2806be 100644 --- a/docker/routlin-dash/app/pages/networklayout/content.json +++ b/docker/routlin-dash/app/pages/networklayout/content.json @@ -221,16 +221,16 @@ { "type": "overridable_textarea", "label": "DNS Server(s)", - "name": "dns_server", - "override_name": "dns_server_override", + "name": "dns_servers", + "override_name": "dns_servers_override", "validate": "VALIDATION_ADDRESS", "hint": "DNS server(s) advertised to clients via DHCP." }, { "type": "overridable_textarea", "label": "NTP Server(s)", - "name": "ntp_server", - "override_name": "ntp_server_override", + "name": "ntp_servers", + "override_name": "ntp_servers_override", "validate": "VALIDATION_ADDRESS", "hint": "NTP server(s) advertised to clients via DHCP." }, diff --git a/docker/routlin-dash/app/pages/vpn/action.py b/docker/routlin-dash/app/pages/vpn/action.py index 67a69e8..10f56bd 100644 --- a/docker/routlin-dash/app/pages/vpn/action.py +++ b/docker/routlin-dash/app/pages/vpn/action.py @@ -88,7 +88,7 @@ def _build_client_conf(vlan, peer_name, peer_ip, private_key, server_pubkey): default = str(min((ipaddress.IPv4Address(ip) for ip in ident_ips), key=lambda x: x.packed[-1])) if ident_ips else str(next(network.hosts())) gateway = overrides.get('gateway') or default - dns = overrides.get('dns_server') or gateway + dns = overrides.get('dns_servers') or gateway prefix = network.prefixlen mtu = overrides.get('mtu', '') endpoint = info.get('server_endpoint', '') @@ -138,7 +138,7 @@ def wireguard_apply(): listen_port_raw = request.form.get('vpn_listen_port', '').strip() server_endpoint = validate.domainname(request.form.get('vpn_server_endpoint', '')) domain = validate.domainname(request.form.get('vpn_domain', '')) - dns_raw = request.form.get('vpn_dns_server', '').strip() + dns_raw = request.form.get('vpn_dns_servers', '').strip() mtu_raw = request.form.get('vpn_mtu', '').strip() if not listen_port_raw: @@ -185,9 +185,9 @@ def wireguard_apply(): overrides = info.setdefault('explicit_overrides', {}) if dns_server: - overrides['dns_server'] = dns_server + overrides['dns_servers'] = dns_server else: - overrides.pop('dns_server', None) + overrides.pop('dns_servers', None) if mtu is not None: overrides['mtu'] = mtu else: diff --git a/docker/routlin-dash/app/view_page.py b/docker/routlin-dash/app/view_page.py index c2bd59f..94bb647 100644 --- a/docker/routlin-dash/app/view_page.py +++ b/docker/routlin-dash/app/view_page.py @@ -302,10 +302,10 @@ def config_datasource(name): row['server_identity_gateway'] = ( v.get('dhcp_information', {}).get('explicit_overrides', {}).get('gateway', '') ) - _dns = v.get('dhcp_information', {}).get('explicit_overrides', {}).get('dns_server', []) - row['server_identity_dns_server'] = '\n'.join(_dns) if isinstance(_dns, list) else str(_dns or '') - _ntp = v.get('dhcp_information', {}).get('explicit_overrides', {}).get('ntp_server', []) - row['server_identity_ntp_server'] = '\n'.join(_ntp) if isinstance(_ntp, list) else str(_ntp or '') + _dns = v.get('dhcp_information', {}).get('explicit_overrides', {}).get('dns_servers', []) + row['server_identity_dns_servers'] = '\n'.join(_dns) if isinstance(_dns, list) else str(_dns or '') + _ntp = v.get('dhcp_information', {}).get('explicit_overrides', {}).get('ntp_servers', []) + row['server_identity_ntp_servers'] = '\n'.join(_ntp) if isinstance(_ntp, list) else str(_ntp or '') rows.append(row) return rows @@ -819,7 +819,7 @@ def collect_tokens(): tokens['VPN_LISTEN_PORT'] = str(vpn.get('listen_port', '')) tokens['VPN_SERVER_ENDPOINT'] = str(vpn.get('server_endpoint', '')) tokens['VPN_DOMAIN'] = str(vpn.get('domain', '')) - tokens['VPN_DNS_SERVER'] = str(overrides.get('dns_server', '')) + tokens['VPN_DNS_SERVER'] = str(overrides.get('dns_servers', '')) tokens['VPN_MTU'] = str(overrides.get('mtu', '')) # Compute gateway from server_identities (lowest last-octet), fallback to first subnet host diff --git a/routlin/USAGE.md b/routlin/USAGE.md index 979af5b..601f552 100644 --- a/routlin/USAGE.md +++ b/routlin/USAGE.md @@ -77,7 +77,7 @@ Edit the `vlans` array to match your network topology. For each VLAN: "listen_port": 51820, "server_endpoint": "vpn.example.com", "domain": "local", - "explicit_overrides": { "gateway": "", "dns_server": "", "mtu": "" } + "explicit_overrides": { "gateway": "", "dns_servers": "", "mtu": "" } }, "peers": [], "port_wrangling": [] diff --git a/routlin/config.json b/routlin/config.json index 847a364..a8962fe 100644 --- a/routlin/config.json +++ b/routlin/config.json @@ -298,8 +298,8 @@ "domain": "lan", "explicit_overrides": { "gateway": "", - "dns_server": "", - "ntp_server": "" + "dns_servers": "", + "ntp_servers": "" } }, "reservations": [ @@ -393,8 +393,8 @@ "domain": "lan", "explicit_overrides": { "gateway": "", - "dns_server": "", - "ntp_server": "" + "dns_servers": "", + "ntp_servers": "" } }, "reservations": [ @@ -498,8 +498,8 @@ "domain": "lan", "explicit_overrides": { "gateway": "", - "dns_server": "", - "ntp_server": "" + "dns_servers": "", + "ntp_servers": "" } }, "reservations": [ @@ -562,8 +562,8 @@ "domain": "lan", "explicit_overrides": { "gateway": "", - "dns_server": "", - "ntp_server": "" + "dns_servers": "", + "ntp_servers": "" } }, "reservations": [ @@ -638,7 +638,7 @@ "domain": "lan", "explicit_overrides": { "gateway": "", - "dns_server": "", + "dns_servers": "", "mtu": "" } }, diff --git a/routlin/core.py b/routlin/core.py index 76737f1..cd8544a 100644 --- a/routlin/core.py +++ b/routlin/core.py @@ -195,11 +195,11 @@ def resolve_vlan_options(vlan): overrides = vpi.get("explicit_overrides", {}) default = lowest_quartet_ip(vlan) or str(next(network_for(vlan).hosts())) gateway = overrides.get("gateway", "") or default - dns = overrides.get("dns_server", "") or gateway + dns = overrides.get("dns_servers", "") or gateway return { "gateway": gateway, - "dns_server": dns, - "ntp_server": None, + "dns_servers": dns, + "ntp_servers": None, } overrides = vlan.get("dhcp_information", {}).get("explicit_overrides", {}) default = lowest_quartet_ip(vlan) @@ -210,8 +210,8 @@ def resolve_vlan_options(vlan): return v or default return { "gateway": overrides.get("gateway", "") or default, - "dns_server": _resolve("dns_server"), - "ntp_server": _resolve("ntp_server"), + "dns_servers": _resolve("dns_servers"), + "ntp_servers": _resolve("ntp_servers"), } def is_physical(vlan): @@ -481,8 +481,8 @@ def build_vlan_dnsmasq_conf(vlan, data, iface): line(f"domain={d.get('domain', 'local')}") line() line(f"dhcp-option=tag:{name},option:router,{gateway}") - line(f"dhcp-option=tag:{name},option:dns-server,{opts['dns_server']}") - line(f"dhcp-option=tag:{name},option:ntp-server,{opts['ntp_server']}") + line(f"dhcp-option=tag:{name},option:dns-server,{opts['dns_servers']}") + line(f"dhcp-option=tag:{name},option:ntp-server,{opts['ntp_servers']}") line() identity_hosts = [s for s in vlan.get("server_identities", []) if s.get("hostname")] diff --git a/routlin/create_vpn_peer.py b/routlin/create_vpn_peer.py index 76a2f6a..da1aa9c 100644 --- a/routlin/create_vpn_peer.py +++ b/routlin/create_vpn_peer.py @@ -122,7 +122,7 @@ def build_client_conf(vlan, peer_ip, private_key, server_pub, split_tunnel): default = str(min((ipaddress.IPv4Address(ip) for ip in ident_ips), key=lambda x: x.packed[-1])) if ident_ips else str(next(network.hosts())) gateway = overrides.get("gateway") or default - dns = overrides.get("dns_server") or gateway + dns = overrides.get("dns_servers") or gateway prefix = network.prefixlen mtu = overrides.get("mtu", "") endpoint = info.get("server_endpoint", "") diff --git a/routlin/validation.py b/routlin/validation.py index 4ea742a..66d7515 100644 --- a/routlin/validation.py +++ b/routlin/validation.py @@ -460,7 +460,7 @@ def validate_config(data): f"any server_identity IP. Must be one of: " f"{[str(ip) for ip in identity_ips]}." ) - dns = eo.get("dns_server", "") + dns = eo.get("dns_servers", "") if dns and not ipv4(dns): errors.append(f"{label}: vpn_information.explicit_overrides.dns_server '{dns}' is not a valid IPv4 address.") mtu = eo.get("mtu", "") @@ -564,14 +564,14 @@ def validate_config(data): f"any server_identity IP. Must be one of: " f"{[str(ip) for ip in identity_ips]}." ) - dns = eo.get("dns_server", "") + dns = eo.get("dns_servers", "") if dns: for _ip in (dns if isinstance(dns, list) else [dns]): - check_ip("explicit_overrides.dns_server", _ip) - ntp = eo.get("ntp_server", "") + check_ip("explicit_overrides.dns_servers", _ip) + ntp = eo.get("ntp_servers", "") if ntp: for _ip in (ntp if isinstance(ntp, list) else [ntp]): - check_ip("explicit_overrides.ntp_server", _ip) + check_ip("explicit_overrides.ntp_servers", _ip) pool_start = check_ip("dynamic_pool_start", d["dynamic_pool_start"]) pool_end = check_ip("dynamic_pool_end", d["dynamic_pool_end"])