WIP: sane-vpn: fix "sane-vpn up none" to correctly delegate all DNS to the DHCP-provided servers when using BIND
previously this only worked when using hickory-dns as the local resolver
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
# debugging:
|
||||
# - `man named`
|
||||
# - `man named.conf`
|
||||
# - `systemctl stop bind`
|
||||
# - `sudo /nix/store/0zpdy93sd3fgbxgvf8dsxhn8fbbya8d2-bind-9.18.28/sbin/named -g -u named -4 -c /nix/store/f1mp0myzmfms71h9vinwxpn2i9362a9a-named.conf`
|
||||
# - `-g` = don't fork
|
||||
# - `-u named` = start as superuser (to claim port 53), then drop to user `named`
|
||||
{ config, lib, ... }:
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
hostCfg = config.sane.hosts.by-name."${config.networking.hostName}";
|
||||
bindCfg = config.services.bind;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (!config.sane.services.hickory-dns.asSystemResolver) {
|
||||
@@ -53,5 +56,52 @@ in
|
||||
networking.resolvconf.useLocalResolver = false; #< we manage resolvconf explicitly, above
|
||||
|
||||
# TODO: how to exempt `pool.ntp.org` from DNSSEC checks, as i did when using unbound?
|
||||
|
||||
# allow runtime insertion of zones or other config changes:
|
||||
# add your supplemental config as a toplevel file in /run/named/dhcp-configs/, then `systemctl restart bind`
|
||||
services.bind.extraConfig = ''
|
||||
include "/run/named/dhcp-configs.conf";
|
||||
'';
|
||||
services.bind.extraOptions = ''
|
||||
// we can't guarantee that all forwarders support DNSSEC,
|
||||
// and as of 2025-01-30 BIND9 gives no way to disable DNSSEC per-forwarder/zone,
|
||||
// so just disable it globally
|
||||
dnssec-validation no;
|
||||
'';
|
||||
# re-implement the nixos default bind config, but without `options { forwarders { }; };`,
|
||||
# as having an empty `forwarders` at the top-level prevents me from forwarding the `.` zone in a separate statement
|
||||
# (which i want to do to allow sane-vpn to forward all DNS).
|
||||
services.bind.configFile = pkgs.writeText "named.conf" ''
|
||||
include "/etc/bind/rndc.key";
|
||||
controls {
|
||||
inet 127.0.0.1 allow {localhost;} keys {"rndc-key";};
|
||||
};
|
||||
|
||||
acl cachenetworks { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.cacheNetworks} };
|
||||
acl badnetworks { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.blockedNetworks} };
|
||||
|
||||
options {
|
||||
listen-on { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.listenOn} };
|
||||
listen-on-v6 { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.listenOnIpv6} };
|
||||
allow-query-cache { cachenetworks; };
|
||||
blackhole { badnetworks; };
|
||||
//v disable top-level forwards, so that i can do forwarding more generically in `zone FOO { ... }` directives.
|
||||
// forward ${bindCfg.forward};
|
||||
// forwarders { ${lib.concatMapStrings (entry: " ${entry}; ") bindCfg.forwarders} };
|
||||
directory "${bindCfg.directory}";
|
||||
pid-file "/run/named/named.pid";
|
||||
${bindCfg.extraOptions}
|
||||
};
|
||||
|
||||
${bindCfg.extraConfig}
|
||||
'';
|
||||
|
||||
systemd.services.bind.serviceConfig.ExecStartPre = pkgs.writeShellScript "named-generate-config" ''
|
||||
mkdir -p /run/named/dhcp-configs
|
||||
echo "// FILE GENERATED BY bind.service's ExecStartPre: CHANGES TO THIS FILE WILL BE OVERWRITTEN" > /run/named/dhcp-configs.conf
|
||||
for c in $(ls /run/named/dhcp-configs/); do
|
||||
cat "/run/named/dhcp-configs/$c" >> /run/named/dhcp-configs.conf
|
||||
done
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@@ -279,7 +279,32 @@ def vpn_toggle(config: VpnConfig, dir_: ToggleDir) -> None:
|
||||
print("new IP address ...")
|
||||
subprocess.check_call(["sane-ip-check", "--no-upnp"])
|
||||
|
||||
def dns_toggle(dns: list[str], dir_: ToggleDir) -> None:
|
||||
def dns_toggle_bind(dns: list[str], dir_: ToggleDir) -> None:
|
||||
if dir_ == ToggleDir.Up:
|
||||
formatted_nameservers = "\n".join(f"{ns};" for ns in dns)
|
||||
text = f'''
|
||||
zone . {{
|
||||
//v XXX(2025-01-30): BIND9 doesn't allow dnssec-validation per-zone. put this in toplevel `options` instead.
|
||||
// dnssec-validation no; // compatibility: many network-specific DNS servers fail DNSSEC, by design
|
||||
type forward;
|
||||
forward first;
|
||||
forwarders {{
|
||||
{formatted_nameservers}
|
||||
}};
|
||||
}};
|
||||
'''
|
||||
elif dir == ToggleDir.Down:
|
||||
text = ""
|
||||
|
||||
if not os.path.isdir("/run/named/dhcp-configs"):
|
||||
logger.info("not restarting bind because it appears to not be in use")
|
||||
return
|
||||
|
||||
with open("/run/named/dhcp-configs/210-sane-vpn.conf", "w") as f:
|
||||
f.write(text)
|
||||
subprocess.check_call([ "systemctl", "restart", "bind" ])
|
||||
|
||||
def dns_toggle_hickory(dns: list[str], dir_: ToggleDir) -> None:
|
||||
if dir_ == ToggleDir.Up:
|
||||
formatted_nameservers = ",\n".join(
|
||||
'{ socket_addr = "{ns}:53", protocol = "udp", trust_nx_responses = false }'.replace("{ns}", ns)
|
||||
@@ -304,6 +329,10 @@ stores = {{ type = "forward", name_servers = [
|
||||
f.write(text)
|
||||
subprocess.check_call([ "systemctl", "restart", "hickory-dns-localhost" ])
|
||||
|
||||
def dns_toggle(dns: list[str], dir_: ToggleDir) -> None:
|
||||
dns_toggle_bind(dns, dir_)
|
||||
dns_toggle_hickory(dns, dir_)
|
||||
|
||||
def main():
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
Reference in New Issue
Block a user