summaryrefslogtreecommitdiff
path: root/hostnix/elmo/dyndns.nix
diff options
context:
space:
mode:
Diffstat (limited to 'hostnix/elmo/dyndns.nix')
-rw-r--r--hostnix/elmo/dyndns.nix78
1 files changed, 78 insertions, 0 deletions
diff --git a/hostnix/elmo/dyndns.nix b/hostnix/elmo/dyndns.nix
new file mode 100644
index 0000000..a59c665
--- /dev/null
+++ b/hostnix/elmo/dyndns.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, ... }:
+
+{
+ # Needs to be started manually, and the key added to nameservers.
+ # Based on https://nixos.org/manual/nixos/stable/index.html#module-security-acme-config-dns
+ systemd.services.sig0-keygen = {
+ unitConfig = {
+ ConditionPathExists = "!/var/lib/secrets/${config.networking.fqdn}.id";
+ };
+ serviceConfig = {
+ Type = "oneshot";
+ };
+ path = [ pkgs.bind ];
+ scriptArgs = config.networking.fqdn;
+ script = ''
+ mkdir -p /var/lib/secrets
+ chmod 755 /var/lib/secrets
+ cd /var/lib/secrets
+ dnssec-keygen -a RSASHA512 -b 2048 -n HOST -T KEY $1. > $1.id
+ '';
+ };
+
+ systemd.services.dyndns = {
+ requires = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+ unitConfig = {
+ AssertPathExists = "/var/lib/secrets/${config.networking.fqdn}.id";
+ # Defer errors for ~45min, throttle e-mails to ~hourly.
+ StartLimitIntervalSec = "1hr";
+ StartLimitBurst = "45";
+ };
+ serviceConfig = {
+ Type = "oneshot";
+ Restart = "on-failure";
+ RestartSec = "1min";
+ };
+ path = [ pkgs.dnsutils pkgs.gawk pkgs.iproute2 ];
+ scriptArgs = config.networking.fqdn;
+ script = ''
+ RR=''${1%%.*}.dynamic.''${1#*.}
+
+ IP4=`dig +short @1.1.1.1 ch txt whoami.cloudflare | tr -d \"`
+ if [ -z "$IP4" ]; then
+ echo "Missing IP: $IP4" >&2
+ exit 100
+ fi
+
+ # Follow some RFC 6724 default address guidance, excluding ULA.
+ # It might be more robust to bind a public source socket (RFC 5014).
+ IP6=`ip -6 address show scope global -deprecated | awk -F'[ /]+' '$2 == "inet6" && $3 !~ /^f[cd]/ { print $3; exit }'`
+
+ OLDIP4=`dig +short @popfresh.mou.fo $RR A 2> /dev/null`
+ OLDIP6=`dig +short @popfresh.mou.fo $RR AAAA 2> /dev/null`
+ # [ "x$IP" = "x$OLDIP4" ] && exit 0 # no update
+ if [ "x$IP4" = "x$OLDIP4" -a "x$IP6" = "x$OLDIP6" ]; then
+ exit 0
+ fi
+
+ nsupdate -v -k /var/lib/secrets/`< /var/lib/secrets/$1.id`.private <<.
+ update delete $RR. A
+ update add $RR. 300 A $IP4
+ update delete $RR. AAAA
+ ''${IP6:+update add $RR. 300 AAAA $IP6}
+ update delete $RR. TXT
+ update add $RR. 300 TXT "v=spf1 include:_spf.mou.fo ~all"
+ send
+ .
+ '';
+ };
+
+ systemd.timers.dyndns = {
+ wantedBy = [ "multi-user.target" ];
+ timerConfig = {
+ OnStartupSec = "10";
+ OnUnitActiveSec = "1min";
+ };
+ };
+}