Compare commits

...

3 Commits

Author SHA1 Message Date
4e3ff0a466 nixos/home/routing-common: Add dynamic DNS update script
All checks were successful
CI / Check, build and cache Nix flake (push) Successful in 20m48s
2023-12-23 01:22:41 +00:00
b1af3dbf18 nixos/tower: Add wireshark and Tailscale shell abbrev 2023-12-23 00:49:24 +00:00
f58b71e8d3 nixos/britway: Use internal addresses for DNS 2023-12-23 00:49:02 +00:00
8 changed files with 105 additions and 12 deletions

View File

@ -49,15 +49,19 @@ in
noise.private_key_path = "/var/lib/headscale/noise_private.key"; noise.private_key_path = "/var/lib/headscale/noise_private.key";
ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ]; ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ];
dns_config = { dns_config = {
# Use IPs that will route inside the VPN to prevent interception
# (e.g. DNS rebinding filtering)
restricted_nameservers = { restricted_nameservers = {
"${domain}" = pubNameservers; "${domain}" = pubNameservers;
"${lib.my.c.colony.domain}" = with allAssignments.estuary.internal; [ "${lib.my.c.colony.domain}" = with allAssignments.estuary.base; [
ipv4.address ipv6.address ipv4.address ipv6.address
]; ];
"${lib.my.c.home.domain}" = lib.my.c.home.routersPubV4 ++ ([ "${lib.my.c.home.domain}" = with allAssignments; [
allAssignments.river.as211024.ipv6.address river.hi.ipv4.address
allAssignments.stream.as211024.ipv6.address river.hi.ipv6.address
]); stream.hi.ipv4.address
stream.hi.ipv6.address
];
}; };
magic_dns = true; magic_dns = true;
base_domain = "ts.${pubDomain}"; base_domain = "ts.${pubDomain}";

View File

@ -52,7 +52,7 @@ in
allowFrom = [ allowFrom = [
"127.0.0.0/8" "::1/128" "127.0.0.0/8" "::1/128"
prefixes.all.v4 prefixes.all.v6 prefixes.all.v4 prefixes.all.v6
]; ] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
}; };
settings = { settings = {

View File

@ -2,6 +2,7 @@ index: { lib, pkgs, config, assignments, allAssignments, ... }:
let let
inherit (builtins) attrNames elemAt; inherit (builtins) attrNames elemAt;
inherit (lib.my) net; inherit (lib.my) net;
inherit (lib.my.c) pubDomain;
inherit (lib.my.c.home) prefixes vips routers; inherit (lib.my.c.home) prefixes vips routers;
name = elemAt routers index; name = elemAt routers index;
@ -22,6 +23,7 @@ in
owner = "pdns-recursor"; owner = "pdns-recursor";
group = "pdns-recursor"; group = "pdns-recursor";
}; };
"home/ddclient-cloudflare.key" = {};
}; };
pdns.recursor = { pdns.recursor = {
@ -42,7 +44,7 @@ in
"127.0.0.0/8" "::1/128" "127.0.0.0/8" "::1/128"
prefixes.hi.v4 prefixes.hi.v6 prefixes.hi.v4 prefixes.hi.v6
prefixes.lo.v4 prefixes.lo.v6 prefixes.lo.v4 prefixes.lo.v6
]; ] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
}; };
settings = { settings = {
@ -63,9 +65,36 @@ in
}; };
}; };
systemd.services = { systemd = {
# Add AF_NETLINK to allow pulling IP from network interfaces services = {
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; # Add AF_NETLINK to allow pulling IP from network interfaces
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
ddns-update = {
description = "DNS update script";
after = [ "network.target" ];
path = [
(pkgs.python3.withPackages (ps: [ ps.cloudflare ]))
pkgs.ldns
];
serviceConfig = {
Type = "oneshot";
ExecStart =
''${./dns_update.py} -k ${config.age.secrets."home/ddclient-cloudflare.key".path} '' +
''${pubDomain} ns${toString (index + 1)}.${config.networking.domain}'';
};
wantedBy = [ "multi-user.target" ];
};
};
timers = {
ddns-update = {
description = "Periodically update DNS";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5min";
OnUnitInactiveSec = "5min";
};
};
};
}; };
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [

View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
import argparse
import subprocess
import CloudFlare
def main():
parser = argparse.ArgumentParser(description='Cloudflare DNS update script')
parser.add_argument('-k', '--api-token-file', help='Cloudflare API token file')
parser.add_argument('zone', help='Cloudflare Zone')
parser.add_argument('record', help='Cloudflare record name')
args = parser.parse_args()
address = subprocess.check_output(
['drill', '-Q', '-p5353', '@127.0.0.1', args.record, 'A'],
encoding='utf8').strip()
cf_token = None
if args.api_token_file:
with open(args.api_token_file) as f:
cf_token = f.readline().strip()
cf = CloudFlare.CloudFlare(token=cf_token)
zones = cf.zones.get(params={'name': args.zone})
assert zones, f'Zone {args.zone} not found'
records = cf.zones.dns_records.get(zones[0]['id'], params={'name': args.record})
assert records, f'Record {args.record} not found in zone {args.zone}'
print(f'Updating {args.record} -> {address}')
cf.zones.dns_records.patch(
zones[0]['id'], records[0]['id'],
data={'type': 'A', 'name': args.record, 'content': address})
if __name__ == '__main__':
main()

View File

@ -55,7 +55,7 @@ in
} }
{ {
name = "domain-search"; name = "domain-search";
data = "${domain}, dyn.${domain}"; data = "${domain}, dyn.${domain}, ${lib.my.c.colony.domain}, ${lib.my.c.britway.domain}";
always-send = true; always-send = true;
} }
]; ];

View File

@ -11,7 +11,7 @@ let
AdvLinkMTU ${toString prefixes."${name}".mtu}; AdvLinkMTU ${toString prefixes."${name}".mtu};
prefix ${prefixes."${name}".v6} {}; prefix ${prefixes."${name}".v6} {};
RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {}; RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {};
DNSSL ${domain} dyn.${domain} {}; DNSSL ${domain} dyn.${domain} ${lib.my.c.colony.domain} ${lib.my.c.britway.domain} {};
}; };
''; '';
in in

View File

@ -116,6 +116,10 @@
programs = { programs = {
steam.enable = true; steam.enable = true;
wireshark = {
enable = true;
package = pkgs.wireshark-qt;
};
}; };
networking = { networking = {
@ -171,6 +175,14 @@
packages = with pkgs; [ ]; packages = with pkgs; [ ];
}; };
programs = {
fish = {
shellAbbrs = {
tsup = "doas tailscale up --login-server=https://ts.nul.ie --accept-routes";
};
};
};
services = { services = {
blueman-applet.enable = true; blueman-applet.enable = true;
}; };

View File

@ -0,0 +1,13 @@
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpOcUlvZyBNalB5
RUZRNE1CTUJsbW1kSkxBSWVIcG1RUnBKd1gvcnRQVkZCUXFOQmhvClJUN2ltbnNk
T1grdVJSTzIyNTBTTGVEckVGQXdYNHdwOU5NbW1md3lGM0kKLT4gc3NoLWVkMjU1
MTkgcytxUmZnIHZ4bFZSS0huWFBDbUhNcTd2MFhvV0lOY1l3d3ZXNU4vT3dwMmlI
emhoV0kKcDF4M0FPK0JpclI5Q3Q5WGxpZWVYbHVWbkNWdTArclZsN09XK3VJSXc1
awotPiBYMjU1MTkgRjRCNVZmcXVnQnJ4KzZoM1ZkdWxYUkJTM1JuK3ZlRWJYdkFR
WXpFSmR4NApTbU5qR3ZuN0ZmbzIvMTFsMkdNSGJXSVlrVmZPdnZvcHFiZW45SW9I
endJCi0+IDEoIjlcJi1ncmVhc2UgJUE4IWl5ODkgfGVdLihEfT4gWCAreSduPS4K
bkI2Wm9LRGJXdW11aDl2VgotLS0gTENqYjZEUUZaWVZEcWQvWW5yTzJEdHRLeDJm
QUl5aytXdDE5QVMwVHZVSQo+aDbaGNOrz+hTSUQ4IAjDC9EfNwrlXDZtBqw8HkRv
1/Rr737scjrM7Bgt9zuKn6CB0zdeHTW5u685V2hCW/3aTy1eppWMWj3r
-----END AGE ENCRYPTED FILE-----