Development

This commit is contained in:
Matthew Grotke 2026-05-25 02:22:21 -04:00
parent 27eaea3d73
commit c6d2ded525
8 changed files with 188 additions and 171 deletions

View file

@ -1,8 +1,7 @@
{
"network_interfaces": {
"wan_interface": "eno2",
"lan_interface": "enp6s0",
"dnsmasq_log_queries": false
"lan_interface": "enp6s0"
},
"upstream_dns": {
"strict_order": false,
@ -264,10 +263,11 @@
],
"vlans": [
{
"vlan_id": 1,
"name": "trusted",
"subnet": "192.168.1.0",
"subnet_mask": 24,
"is_vpn": false,
"dnsmasq_log_queries": false,
"radius_default": false,
"mdns_reflection": false,
"use_blocklists": [
@ -364,14 +364,14 @@
"dest_port": 123,
"redirect_to": "192.168.1.1"
}
],
"is_vpn": false
]
},
{
"vlan_id": 10,
"name": "iot",
"subnet": "192.168.10.0",
"subnet_mask": 24,
"is_vpn": false,
"dnsmasq_log_queries": false,
"radius_default": false,
"mdns_reflection": true,
"use_blocklists": [
@ -468,14 +468,14 @@
"dest_port": 123,
"redirect_to": "192.168.10.1"
}
],
"is_vpn": false
]
},
{
"vlan_id": 20,
"name": "guest",
"subnet": "192.168.20.0",
"subnet_mask": 24,
"is_vpn": false,
"dnsmasq_log_queries": false,
"radius_default": true,
"mdns_reflection": true,
"use_blocklists": [
@ -530,14 +530,14 @@
"dest_port": 123,
"redirect_to": "192.168.20.1"
}
],
"is_vpn": false
]
},
{
"vlan_id": 30,
"name": "kids",
"subnet": "192.168.30.0",
"subnet_mask": 24,
"is_vpn": false,
"dnsmasq_log_queries": false,
"radius_default": false,
"mdns_reflection": true,
"use_blocklists": [
@ -607,14 +607,14 @@
"dest_port": 123,
"redirect_to": "192.168.30.1"
}
],
"is_vpn": false
]
},
{
"vlan_id": 40,
"name": "vpn",
"subnet": "192.168.40.0",
"subnet_mask": 24,
"is_vpn": true,
"dnsmasq_log_queries": false,
"radius_default": false,
"mdns_reflection": false,
"use_blocklists": [
@ -653,8 +653,7 @@
"dest_port": 123,
"redirect_to": "192.168.40.1"
}
],
"is_vpn": true
]
}
],
"ddns": {

View file

@ -87,7 +87,6 @@ Usage:
import hashlib
import ipaddress
import json
import logging
import os
import re
import subprocess
@ -108,7 +107,6 @@ PRODUCT_NAME = "routlin"
SCRIPT_DIR = Path(__file__).parent
CONFIG_FILE = SCRIPT_DIR / "core.json"
BLOCKLIST_DIR = SCRIPT_DIR / "blocklists"
LOG_FILE = SCRIPT_DIR / "core.log"
METRICS_FILE = SCRIPT_DIR / ".dns-metrics"
DNSMASQ_CONF_DIR = Path(f"/etc/dnsmasq-{PRODUCT_NAME}")
LEASES_DIR = Path("/var/lib/misc")
@ -140,48 +138,6 @@ NAT_SERVICE_FILE = SYSTEMD_DIR / f"{NAT_SERVICE_NAME}.service"
WG_DIR = Path("/etc/wireguard")
WG_KEEPALIVE = 25
log = None
# ===================================================================
# Logging
# ===================================================================
def chown_to_script_dir_owner(path):
"""Chown a file to the owner of the script directory.
This works correctly whether invoked via sudo, directly as root (e.g. systemd timer),
or as a normal user - the script directory owner is always the right target.
"""
try:
stat = SCRIPT_DIR.stat()
os.chown(path, stat.st_uid, stat.st_gid)
except OSError:
pass # non-fatal
def setup_logging(max_kb, errors_only):
global log
try:
if LOG_FILE.exists() and LOG_FILE.stat().st_size > max_kb * 1024:
LOG_FILE.write_text("")
if not LOG_FILE.exists():
LOG_FILE.touch()
chown_to_script_dir_owner(LOG_FILE)
file_handler = logging.FileHandler(LOG_FILE)
except PermissionError:
print(f"WARNING: Cannot write to {LOG_FILE} (permission denied). "
f"Run with sudo or fix ownership: sudo chown $USER {LOG_FILE}")
file_handler = None
level = logging.ERROR if errors_only else logging.INFO
handlers = [logging.StreamHandler(sys.stdout)]
if file_handler:
handlers.insert(0, file_handler)
logging.basicConfig(
level=level,
format="%(asctime)s %(levelname)-8s %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=handlers,
)
log = logging.getLogger("dns-dhcp")
# ===================================================================
# Helpers
# ===================================================================
@ -592,7 +548,7 @@ def build_vlan_dnsmasq_conf(vlan, data, iface):
continue # skip IPv6 upstream -- WAN has no IPv6 address
line(f"server={srv}")
line(f"cache-size={dns_cfg.get('cache_size', 1000)}")
if general.get("dnsmasq_log_queries", False):
if vlan.get("dnsmasq_log_queries", False):
line("log-queries")
line()
@ -3132,11 +3088,6 @@ def main():
print(f" - {e}", file=sys.stderr)
sys.exit(1)
general = data.get("dns_blocking", {}).get("general", {})
setup_logging(
general.get("log_max_kb", 1024),
general.get("log_errors_only", False)
)
if args.status:
show_status(data)