From e6795d6d2edb04b4e468e237ee443501b173b951 Mon Sep 17 00:00:00 2001
From: root <root@fudo.org>
Date: Thu, 19 Nov 2020 16:21:18 -0600
Subject: [PATCH] Modifications to DNS config

---
 config/fudo/backplane/dns.nix | 16 +++++--
 config/fudo/client/dns.nix    | 14 ++++++
 config/fudo/dns.nix           | 24 ++++++++---
 fudo/users.nix                |  3 +-
 hosts/france.nix              | 18 ++++++--
 hosts/france/backplane.nix    | 12 ++++--
 hosts/france/jabber.nix       | 80 ++++++++++++++++++++++++++---------
 packages/backplane-dns.nix    |  4 +-
 static/backplane-auth.scm     |  4 +-
 9 files changed, 133 insertions(+), 42 deletions(-)

diff --git a/config/fudo/backplane/dns.nix b/config/fudo/backplane/dns.nix
index e6dee50..068cc2f 100644
--- a/config/fudo/backplane/dns.nix
+++ b/config/fudo/backplane/dns.nix
@@ -82,12 +82,21 @@ in {
       default = 53;
     };
 
-    listen-addresses = mkOption {
+    listen-v4-addresses = mkOption {
       type = with types; listOf str;
-      description = "IP addresses on which to listen for dns requests.";
+      description = "IPv4 addresses on which to listen for dns requests.";
       default = [ "0.0.0.0" ];
     };
 
+    listen-v6-addresses = mkOption {
+      type = with types; listOf str;
+      description = "IPv6 addresses on which to listen for dns requests.";
+      example = [
+        "[abcd::1]"
+      ];
+      default = [];
+    };
+
     required-services = mkOption {
       type = with types; listOf str;
       description = "A list of services required before the DNS server can start.";
@@ -152,7 +161,8 @@ in {
 
         backplane-powerdns = let
           configDir = pkgs.writeTextDir "pdns.conf" ''
-            local-address=${lib.concatStringsSep ", " cfg.listen-addresses}
+            local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
+            local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
             local-port=${toString cfg.port}
             launch=
             include-dir=${powerdns-conf-dir}/
diff --git a/config/fudo/client/dns.nix b/config/fudo/client/dns.nix
index 7a9d348..a1db07e 100644
--- a/config/fudo/client/dns.nix
+++ b/config/fudo/client/dns.nix
@@ -86,6 +86,19 @@ in {
         };
       };
 
+      services.backplane-dns-client-pw-file = {
+        enable = true;
+        requiredBy = [ "backplane-dns-client.services" ];
+        reloadIfChanged = true;
+        serviceConfig = {
+          Type = "oneshot";
+        };
+        script = ''
+          chmod 600 ${cfg.password-file}
+          chown ${cfg.user} ${cfg.password-file}
+        '';
+      };
+
       services.backplane-dns-client = {
         enable = true;
         serviceConfig = {
@@ -94,6 +107,7 @@ in {
           User = cfg.user;
         };
         path = [ pkgs.openssh ];
+        reloadIfChanged = true;
         script = ''
           ${pkgs.backplane-dns-client}/bin/backplane-dns-client ${optionalString cfg.ipv4 "-4"} ${optionalString cfg.ipv6 "-6"} ${optionalString cfg.sshfp "-f"} ${optionalString (cfg.external-interface != null) "--interface=${cfg.external-interface}"} --domain=${cfg.domain} --server=${cfg.server} --password-file=${cfg.password-file}
         '';
diff --git a/config/fudo/dns.nix b/config/fudo/dns.nix
index 9de4805..4d04546 100644
--- a/config/fudo/dns.nix
+++ b/config/fudo/dns.nix
@@ -33,6 +33,18 @@ let
           A list of DNS SSHFP records for this host.
         '';
       };
+
+      description = mkOption {
+        type = with types; nullOr str;
+        description = "Description of this host for a TXT record.";
+        default = null;
+      };
+
+      rp = mkOption {
+        type = with types; nullOr str;
+        description = "Responsible person.";
+        default = null;
+      };
     };
   };
 
@@ -125,9 +137,12 @@ let
     };
   };
 
-  hostARecords = host: data:
+  hostRecords = host: data:
     join-lines ((map (ip: "${host} IN A ${ip}") data.ip-addresses) ++
-                (map (ip: "${host} IN AAAA ${ip}") data.ipv6-addresses));
+                (map (ip: "${host} IN AAAA ${ip}") data.ipv6-addresses) ++
+                (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints) ++
+                (optional (data.rp != null) "${host} IN RP ${data.rp}") ++
+                (optional (data.description != null) "${host} IN TXT ${data.description}"));
 
   makeSrvRecords = protocol: type: records:
     join-lines (map (record: "_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${toString record.host}.")
@@ -137,8 +152,6 @@ let
 
   cnameRecord = alias: host: "${alias} IN CNAME ${host}";
 
-  hostSshFpRecords = host: data: join-lines (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints);
-
   mxRecords = mxs:
     concatStringsSep "\n"
       (map (mx: "@ IN MX 10 ${mx}.") mxs);
@@ -207,8 +220,7 @@ in {
             ${dmarcRecord dom-cfg.dmarc-report-address}
 
             ${join-lines (mapAttrsToList makeSrvProtocolRecords dom-cfg.srv-records)}
-            ${join-lines (mapAttrsToList hostARecords dom-cfg.hosts)}
-            ${join-lines (mapAttrsToList hostSshFpRecords dom-cfg.hosts)}
+            ${join-lines (mapAttrsToList hostRecords dom-cfg.hosts)}
             ${join-lines (mapAttrsToList cnameRecord dom-cfg.aliases)}
             ${join-lines dom-cfg.extra-dns-records}
           '';
diff --git a/fudo/users.nix b/fudo/users.nix
index b7c943e..07e7c63 100644
--- a/fudo/users.nix
+++ b/fudo/users.nix
@@ -75,7 +75,8 @@
     uid = 10035;
     group = "selby";
     common-name = "Ken Selby";
-    hashed-password = "{SSHA}X8DxUcwH2Fzel5UKbGVNhC5B2vg0Prsc";
+    hashed-password = "{SSHA}wUGV/9dr8inz/HyqSF/OWKxy0DCy5AI3";
+    # hashed-password = "{SSHA}X8DxUcwH2Fzel5UKbGVNhC5B2vg0Prsc";
   };
 
   reaper = {
diff --git a/hosts/france.nix b/hosts/france.nix
index 73c6e46..911f0d1 100644
--- a/hosts/france.nix
+++ b/hosts/france.nix
@@ -7,7 +7,7 @@ let
   mail-hostname = "mail.${domain}";
   host_ipv4 = "208.81.3.117";
   # Use a special IP for git.fudo.org, since it needs to be SSH-able
-  git_ipv4 = "208.81.3.126";
+  link_ipv4 = "208.81.3.126";
   all-hostnames = [];
 
   acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
@@ -40,6 +40,7 @@ in {
     lxd
     multipath-tools
     nix-prefetch-docker
+    powerdns
     tshark
   ];
 
@@ -259,9 +260,18 @@ in {
   # TODO: not used yet
   fudo.acme.hostnames = all-hostnames;
 
+  fudo.client.dns = {
+    enable = true;
+    ipv4 = true;
+    ipv6 = true;
+    user = "fudo-client";
+    external-interface = "extif0";
+    password-file = "/srv/client/secure/client.passwd";
+  };
+
   fudo.mail-server = import ../fudo/email.nix { inherit config; } // {
     enableContainer = true;
-    debug = true;
+    # debug = true;
     monitoring = true;
 
     hostname = mail-hostname;
@@ -392,7 +402,7 @@ in {
     repository-dir = /srv/git/repo;
     state-dir = /srv/git/state;
     ssh = {
-      listen-ip = git_ipv4;
+      listen-ip = link_ipv4;
       listen-port = 2222;
     };
   };
@@ -438,7 +448,7 @@ in {
         macAddress = "02:6d:e2:e1:ad:ca";
         ipv4.addresses = [
           {
-            address = git_ipv4;
+            address = link_ipv4;
             prefixLength = 28;
           }
         ];
diff --git a/hosts/france/backplane.nix b/hosts/france/backplane.nix
index 8ce0ca8..0d98b60 100644
--- a/hosts/france/backplane.nix
+++ b/hosts/france/backplane.nix
@@ -58,8 +58,12 @@ in {
             databases = {
               backplane_dns = {
                 access = "CONNECT";
+                # entity-access = {
+                #   "ALL TABLES IN SCHEMA public" = "SELECT";
+                # };
                 entity-access = {
-                  "ALL TABLES IN SCHEMA public" = "SELECT";
+                  "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
+                  "ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
                 };
               };
             };
@@ -70,7 +74,7 @@ in {
               backplane_dns = {
                 access = "CONNECT";
                 entity-access = {
-                  "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE";
+                  "ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
                   "ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
                 };
               };
@@ -87,8 +91,8 @@ in {
 
       backplane.dns = {
         enable = true;
-        port = 353;
-        listen-addresses = [ "208.81.3.117" ];
+        listen-v4-addresses = [ "208.81.3.126" ];
+        listen-v6-addresses = [ "[2605:e200:d200:1:6d:e2ff:fee1:adca]" ];
         required-services = [ "fudo-passwords.target" ];
         user = "backplane-dns";
         group = "backplane-dns";
diff --git a/hosts/france/jabber.nix b/hosts/france/jabber.nix
index df4c16b..b900bad 100644
--- a/hosts/france/jabber.nix
+++ b/hosts/france/jabber.nix
@@ -4,6 +4,9 @@ with lib;
 let
   backplane-auth = "/etc/nixos/static/backplane-auth.scm";
 
+  host-passwd-file = "/srv/jabber/secret/hosts-passwd.scm";
+  service-passwd-file = "/srv/jabber/secret/services-passwd.scm";
+
   cert-basedir = "/var/lib/ejabberd/certs";
 
   target-certs = ["key" "cert" "chain" "fullchain"];
@@ -50,30 +53,67 @@ in {
     security.acme.certs."fudo.im".email = "admin@fudo.org";
     security.acme.certs."backplane.fudo.org".email = "admin@fudo.org";
 
-    systemd.services = {
-      ejabberd-generate-certs = {
-        enable = true;
-        description = "Generate required SSL certs for ejabberd.";
-        wantedBy = [ "ejabberd.service" ];
-        after = [
-          "acme-backplane.fudo.org.service"
-          "acme-fudo.im.service"
-        ];
+    systemd = {
+      services = {
+        ejabberd-generate-certs = {
+          enable = true;
+          description = "Generate required SSL certs for ejabberd.";
+          wantedBy = [ "ejabberd.service" ];
+          after = [
+            "acme-backplane.fudo.org.service"
+            "acme-fudo.im.service"
+          ];
+          serviceConfig = {
+            Type = "oneshot";
+            ExecStart = "${move-server-certs ["fudo.im" "backplane.fudo.org"]}";
+            RemainAfterExit = true;
+            ExecStop = remove-server-certs;
+            StandardOutput = "journal";
+          };
+        };
 
-        serviceConfig = {
-          Type = "oneshot";
-          ExecStart = "${move-server-certs ["fudo.im" "backplane.fudo.org"]}";
-          RemainAfterExit = true;
-          ExecStop = remove-server-certs;
-          StandardOutput = "journal";
+        ejabberd = {
+          requires = [ "ejabberd-generate-certs.service" ];
+          environment = {
+            FUDO_HOST_PASSWD_FILE = host-passwd-file;
+            FUDO_SERVICE_PASSWD_FILE = service-passwd-file;
+          };
+        };
+
+        ejabberd-hostfile-watcher = {
+          description = "Watch the ejabberd host file and restart if changes occur.";
+          serviceConfig.Type = "oneshot";
+          after = [ "ejabberd.service" ];
+          script = ''
+            SYSCTL=${pkgs.systemd}/bin/systemctl
+            if $SYSCTL is-active --quiet ejabberd.service; then
+              echo "restarting ejabberd.service because hostfile has changed."
+              $SYSCTL restart ejabberd.service
+            fi
+          '';
+        };
+
+        ejabberd-servicefile-watcher = {
+          description = "Watch the ejabberd service file and restart if changes occur.";
+          serviceConfig.Type = "oneshot";
+          after = [ "ejabberd.service" ];
+          script = ''
+            SYSCTL=${pkgs.systemd}/bin/systemctl
+            if $SYSCTL is-active --quiet ejabberd.service; then
+              echo "restarting ejabberd.service because servicefile has changed."
+              $SYSCTL restart ejabberd.service
+            fi
+          '';
         };
       };
 
-      ejabberd = {
-        requires = [ "ejabberd-generate-certs.service" ];
-        environment = {
-          FUDO_HOST_PASSWD_FILE = "/srv/jabber/secret/hosts-passwd.scm";
-          FUDO_SERVICE_PASSWD_FILE = "/srv/jabber/secret/services-passwd.scm";
+      paths = {
+        ejabberd-hostfile-watcher = {
+          pathConfig.PathChanged = host-passwd-file;
+        };
+
+        ejabberd-servicefile-watcher = {
+          pathConfig.PathChanged = service-passwd-file;
         };
       };
     };
diff --git a/packages/backplane-dns.nix b/packages/backplane-dns.nix
index 85287bb..10d08c2 100644
--- a/packages/backplane-dns.nix
+++ b/packages/backplane-dns.nix
@@ -9,8 +9,8 @@ in stdenv.mkDerivation {
 
   src = fetchgit {
     url = url;
-    rev = "543df72f3962cf91b0e0508d15cdc083a3cd7ed4";
-    sha256 = "0hda1wjf9wd4rvxchdlxw0af3i2cvl5plg37ric3ckma6gfzkmm0";
+    rev = "c552394e55816541a9426974c5f8e6f1f83bf195";
+    sha256 = "0r61bwj5a2dvzl41cwdf2pdnhdsmp3kzfyxa5x5hsg67al6s7vi8";
     fetchSubmodules = false;
   };
 
diff --git a/static/backplane-auth.scm b/static/backplane-auth.scm
index e017da5..f23ee80 100644
--- a/static/backplane-auth.scm
+++ b/static/backplane-auth.scm
@@ -16,8 +16,8 @@
   (format (current-error-port "FUDO_SERVICE_PASSWD_FILE not set~%"))
   (exit 1))
 
-(define host-regex "^host-([a-zA-Z][a-zA-Z0-9_-]+)")
-(define service-regex "^service-([a-zA-Z][a-zA-Z0-9_-]+)")
+(define host-regex "^host-([a-zA-Z][a-zA-Z0-9_-]+)$")
+(define service-regex "^service-([a-zA-Z][a-zA-Z0-9_-]+)$")
 
 (define (make-verifier passwd-file)
   (let ((passwds (load passwd-file)))