From 7fb1a3e775439d61e054e872dad79f9b6b1ae227 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 7 Apr 2016 20:48:07 +0200
Subject: [PATCH 01/40] krebs.nginx: don't abuse extraConfig

---
 krebs/3modules/nginx.nix | 40 ++++++++++++++++++----------------------
 1 file changed, 18 insertions(+), 22 deletions(-)

diff --git a/krebs/3modules/nginx.nix b/krebs/3modules/nginx.nix
index 816c2ff69..6af93a570 100644
--- a/krebs/3modules/nginx.nix
+++ b/krebs/3modules/nginx.nix
@@ -117,28 +117,24 @@ let
     }
   '';
 
-  to-server = { server-names, listen, locations, extraConfig, ssl, ... }:
-    let
-      _extraConfig = if ssl.enable then
-        extraConfig + ''
-          ssl_certificate ${ssl.certificate};
-          ssl_certificate_key ${ssl.certificate_key};
-          ${optionalString ssl.prefer_server_ciphers "ssl_prefer_server_ciphers On;"}
-          ssl_ciphers ${ssl.ciphers};
-          ssl_protocols ${toString ssl.protocols};
-        ''
-      else
-        extraConfig
-      ;
-
-    in ''
-      server {
-        ${concatMapStringsSep "\n" (x: "listen ${x};") (listen ++ optional ssl.enable "443 ssl")}
-        server_name ${toString server-names};
-        ${indent _extraConfig}
-        ${indent (concatMapStrings to-location locations)}
-      }
-    '';
+  to-server = { server-names, listen, locations, extraConfig, ssl, ... }: ''
+    server {
+      server_name ${toString server-names};
+      ${concatMapStringsSep "\n" (x: indent "listen ${x};") listen}
+      ${optionalString ssl.enable (indent ''
+        listen 443 ssl;
+        ssl_certificate ${ssl.certificate};
+        ssl_certificate_key ${ssl.certificate_key};
+        ${optionalString ssl.prefer_server_ciphers ''
+          ssl_prefer_server_ciphers On;
+        ''}
+        ssl_ciphers ${ssl.ciphers};
+        ssl_protocols ${toString ssl.protocols};
+      '')}
+      ${indent extraConfig}
+      ${indent (concatMapStrings to-location locations)}
+    }
+  '';
 
 in
 out

From 827f1790803bda906ed71c56138cfdbf108ee730 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 7 Apr 2016 21:40:56 +0200
Subject: [PATCH 02/40] doppelbock: init

---
 krebs/3modules/tv/default.nix | 35 +++++++++++++++++++++++++++++++++++
 tv/1systems/doppelbock.nix    | 23 +++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 tv/1systems/doppelbock.nix

diff --git a/krebs/3modules/tv/default.nix b/krebs/3modules/tv/default.nix
index 13d3163c0..f0f0c5e79 100644
--- a/krebs/3modules/tv/default.nix
+++ b/krebs/3modules/tv/default.nix
@@ -62,6 +62,41 @@ with config.krebs.lib;
       ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOd/HqZIO9Trn3eycl23GZAz21HQCISaVNfNyaLSQvJ6";
     };
+    doppelbock = rec {
+      cores = 2;
+      nets = rec {
+        internet = {
+          addrs4 = ["45.62.237.203"];
+          aliases = [
+            "doppelbock.i"
+            "doppelbock.internet"
+          ];
+        };
+        retiolum = {
+          via = internet;
+          addrs4 = ["10.243.113.224"];
+          addrs6 = ["42:4522:25f8:36bb:8ccb:0150:231a:2af5"];
+          aliases = [
+            "doppelbock.r"
+            "doppelbock.retiolum"
+            "cgit.doppelbock.r"
+            "cgit.doppelbock.retiolum"
+          ];
+          tinc.pubkey = ''
+            -----BEGIN RSA PUBLIC KEY-----
+            MIIBCgKCAQEAq/luvzH4CQX5qRuucUqR3aLwXtzsRmBOdd2hvrPG1z8ML2kKV+IG
+            0aBfyJmQ8csfeGhOj0y0LEBv4bkEjEtYObs+LJfdWZC5e39eAVUE0z8QbSPOx4di
+            /7Bo+9sFRELP1kYb47eLR8quiIkslMWQMbTLM5RHoXJ5jE8fQSitfp4WUZYiSPDF
+            d5F7RU/ZQfTZuh8gv7RmSn/6N6bXAQWrueK6ZqMuImIjBrmYyXUWxgsDnpeHxR5j
+            j/0F2Bda5lyp+Qzv24PREdPT8FazUfmIQwZTTArXHxiqLq+SEVT21E4WEf2sJRan
+            dti9yVUW3eiqpu8b9BRpvxOB3YdkyqlrGwIDAQAB
+            -----END RSA PUBLIC KEY-----
+          '';
+        };
+      };
+      ssh.privkey.path = <secrets/ssh.id_rsa>;
+      ssh.pubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLhrVTEmbtuTsgRTHHxsLrq7ai1Yt7+oKFevr1gzktCQqHuyucXzxn60F00kuNDkNiKIF5fHmWy6ajU+6PKD3TfiFMagT9ah0x0RSB0+0tevxnlOp6VdHhrdM5YrBduWMiELmOiI1lvYhRqKd/ZE7b2mra6KYe5VtTi9UX3wQp8qN+bI01KCxv0p6ciUgEO8fnwLKDBUuFJ2UfE7Ais9XrXFIBFXB+MKcpLnIXvrV6dSXdUEiaswg8wo0Q0Y3tMaQ0dNJdH2yp3FVn1aiX3E/vVnffmDKMWYWqn78klujdEdmLm8/8NkXnc/jpgu8ZlSpQHECO2ZUJzd35yRnVKALv";
+    };
     mkdir = rec {
       cores = 1;
       nets = rec {
diff --git a/tv/1systems/doppelbock.nix b/tv/1systems/doppelbock.nix
new file mode 100644
index 000000000..9a8d5b05d
--- /dev/null
+++ b/tv/1systems/doppelbock.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+with config.krebs.lib;
+{
+  krebs.build.host = config.krebs.hosts.doppelbock;
+
+  imports = [
+    ../.
+    ../2configs/hw/CAC-Developer-2.nix
+    ../2configs/fs/CAC-CentOS-7-64bit.nix
+    ../2configs/retiolum.nix
+  ];
+
+  networking = {
+    interfaces.enp2s1.ip4 = singleton {
+      address = let
+        addr4 = "45.62.237.203";
+      in assert config.krebs.build.host.nets.internet.addrs4 == [addr4]; addr4;
+      prefixLength = 24;
+    };
+    defaultGateway = "45.62.237.1";
+    nameservers = ["8.8.8.8"];
+  };
+}

From 46e818ebbc5446b4215ad9524089d9b2dc91cbd3 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 03:53:34 +0200
Subject: [PATCH 03/40] retiolum: don't hardcode routing prefixes

---
 krebs/3modules/lass/default.nix               |  46 +++----
 krebs/3modules/makefu/default.nix             | 126 +++++++++---------
 krebs/3modules/miefda/default.nix             |   4 +-
 krebs/3modules/mv/default.nix                 |   4 +-
 krebs/3modules/retiolum.nix                   |  83 ++++--------
 krebs/3modules/shared/default.nix             |  10 +-
 krebs/3modules/tv/default.nix                 |  74 +++++-----
 krebs/4lib/types.nix                          |  48 +++++--
 lass/1systems/cloudkrebs.nix                  |   3 +-
 lass/1systems/echelon.nix                     |   3 +-
 lass/1systems/prism.nix                       |   4 +-
 lass/2configs/privoxy-retiolum.nix            |   3 +-
 lass/3modules/static_nginx.nix                |   2 +-
 makefu/1systems/gum.nix                       |   4 +-
 makefu/1systems/wry.nix                       |   4 +-
 .../deployment/mycube.connector.one.nix       |   2 +-
 makefu/2configs/iodined.nix                   |   2 +-
 makefu/2configs/nginx/euer.blog.nix           |   4 +-
 makefu/2configs/nginx/euer.test.nix           |   4 +-
 makefu/2configs/nginx/euer.wiki.nix           |   4 +-
 .../2configs/nginx/update.connector.one.nix   |   2 +-
 makefu/2configs/omo-share.nix                 |   2 +-
 shared/1systems/wolf.nix                      |   4 +-
 tv/1systems/doppelbock.nix                    |   4 +-
 tv/1systems/mkdir.nix                         |  11 +-
 tv/1systems/rmdir.nix                         |   7 +-
 tv/2configs/exim-smarthost.nix                |   2 +-
 tv/3modules/charybdis/config.nix              |   9 +-
 28 files changed, 228 insertions(+), 247 deletions(-)

diff --git a/krebs/3modules/lass/default.nix b/krebs/3modules/lass/default.nix
index 3d54900e4..b4686894e 100644
--- a/krebs/3modules/lass/default.nix
+++ b/krebs/3modules/lass/default.nix
@@ -8,15 +8,15 @@ with config.krebs.lib;
       cores = 4;
       nets = rec {
         internet = {
-          addrs4 = ["144.76.172.188"];
+          ip4.addr = "144.76.172.188";
           aliases = [
             "dishfire.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.133.99"];
-          addrs6 = ["42:0000:0000:0000:0000:0000:d15f:1233"];
+          ip4.addr = "10.243.133.99";
+          ip6.addr = "42:0000:0000:0000:0000:0000:d15f:1233";
           aliases = [
             "dishfire.retiolum"
             "dishfire.r"
@@ -40,15 +40,15 @@ with config.krebs.lib;
       cores = 2;
       nets = rec {
         internet = {
-          addrs4 = ["162.252.241.33"];
+          ip4.addr = "162.252.241.33";
           aliases = [
             "echelon.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.206.103"];
-          addrs6 = ["42:941e:2816:35f4:5c5e:206b:3f0b:f763"];
+          ip4.addr = "10.243.206.103";
+          ip6.addr = "42:941e:2816:35f4:5c5e:206b:3f0b:f763";
           aliases = [
             "echelon.retiolum"
             "echelon.r"
@@ -75,15 +75,15 @@ with config.krebs.lib;
       cores = 4;
       nets = rec {
         internet = {
-          addrs4 = ["213.239.205.240"];
+          ip4.addr = "213.239.205.240";
           aliases = [
             "prism.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.0.103"];
-          addrs6 = ["42:0000:0000:0000:0000:0000:0000:15ab"];
+          ip4.addr = "10.243.0.103";
+          ip6.addr = "42:0000:0000:0000:0000:0000:0000:15ab";
           aliases = [
             "prism.retiolum"
             "prism.r"
@@ -107,15 +107,15 @@ with config.krebs.lib;
     fastpoke = {
       nets = rec {
         internet = {
-          addrs4 = ["193.22.164.36"];
+          ip4.addr = "193.22.164.36";
           aliases = [
             "fastpoke.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.253.152"];
-          addrs6 = ["42:422a:194f:ff3b:e196:2f82:5cf5:bc00"];
+          ip4.addr = "10.243.253.152";
+          ip6.addr = "42:422a:194f:ff3b:e196:2f82:5cf5:bc00";
           aliases = [
             "fastpoke.retiolum"
             "fastpoke.r"
@@ -139,15 +139,15 @@ with config.krebs.lib;
       cores = 1;
       nets = rec {
         internet = {
-          addrs4 = ["104.167.113.104"];
+          ip4.addr = "104.167.113.104";
           aliases = [
             "cloudkrebs.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.206.102"];
-          addrs6 = ["42:941e:2816:35f4:5c5e:206b:3f0b:f762"];
+          ip4.addr = "10.243.206.102";
+          ip6.addr = "42:941e:2816:35f4:5c5e:206b:3f0b:f762";
           aliases = [
             "cloudkrebs.retiolum"
             "cloudkrebs.r"
@@ -172,12 +172,12 @@ with config.krebs.lib;
       cores = 1;
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.12"];
+          ip4.addr = "10.23.1.12";
           aliases = ["uriel.gg23"];
         };
         retiolum = {
-          addrs4 = ["10.243.81.176"];
-          addrs6 = ["42:dc25:60cf:94ef:759b:d2b6:98a9:2e56"];
+          ip4.addr = "10.243.81.176";
+          ip6.addr = "42:dc25:60cf:94ef:759b:d2b6:98a9:2e56";
           aliases = [
             "uriel.retiolum"
             "uriel.r"
@@ -203,12 +203,12 @@ with config.krebs.lib;
       cores = 2;
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.11"];
+          ip4.addr = "10.23.1.11";
           aliases = ["mors.gg23"];
         };
         retiolum = {
-          addrs4 = ["10.243.0.2"];
-          addrs6 = ["42:0:0:0:0:0:0:dea7"];
+          ip4.addr = "10.243.0.2";
+          ip6.addr = "42:0:0:0:0:0:0:dea7";
           aliases = [
             "mors.retiolum"
             "mors.r"
@@ -234,8 +234,8 @@ with config.krebs.lib;
       cores = 2;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.3"];
-          addrs6 = ["42:0:0:0:0:0:0:7105"];
+          ip4.addr = "10.243.0.3";
+          ip6.addr = "42:0:0:0:0:0:0:7105";
           aliases = [
             "helios.retiolum"
             "helios.r"
diff --git a/krebs/3modules/makefu/default.nix b/krebs/3modules/makefu/default.nix
index bd7c0db48..b93b34d24 100644
--- a/krebs/3modules/makefu/default.nix
+++ b/krebs/3modules/makefu/default.nix
@@ -8,8 +8,8 @@ with config.krebs.lib;
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.210"];
-          addrs6 = ["42:f9f1:0000:0000:0000:0000:0000:0001"];
+          ip4.addr = "10.243.0.210";
+          ip6.addr = "42:f9f1:0000:0000:0000:0000:0000:0001";
           aliases = [
             "pnp.retiolum"
             "cgit.pnp.retiolum"
@@ -31,8 +31,8 @@ with config.krebs.lib;
       cores = 4;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.84"];
-          addrs6 = ["42:ff6b:5f0b:460d:2cee:4d05:73f7:5566"];
+          ip4.addr = "10.243.0.84";
+          ip6.addr = "42:ff6b:5f0b:460d:2cee:4d05:73f7:5566";
           aliases = [
             "darth.retiolum"
             "darth.r"
@@ -54,8 +54,8 @@ with config.krebs.lib;
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.212"];
-          addrs6 = ["42:f9f1:0000:0000:0000:0000:0000:0002"];
+          ip4.addr = "10.243.0.212";
+          ip6.addr = "42:f9f1:0000:0000:0000:0000:0000:0002";
           aliases = [
             "tsp.retiolum"
           ];
@@ -81,8 +81,8 @@ with config.krebs.lib;
       cores = 2;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.91"];
-          addrs6 = ["42:0b2c:d90e:e717:03dc:9ac1:7c30:a4db"];
+          ip4.addr = "10.243.0.91";
+          ip6.addr = "42:0b2c:d90e:e717:03dc:9ac1:7c30:a4db";
           aliases = [
             "pornocauster.retiolum"
             "pornocauster.r"
@@ -108,8 +108,8 @@ with config.krebs.lib;
       cores = 2;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.1.91"];
-          addrs6 = ["42:0b2c:d90e:e717:03dd:9ac1:0000:a400"];
+          ip4.addr = "10.243.1.91";
+          ip6.addr = "42:0b2c:d90e:e717:03dd:9ac1:0000:a400";
           aliases = [
             "vbob.retiolum"
           ];
@@ -135,22 +135,22 @@ with config.krebs.lib;
       extraZones = {
         "krebsco.de" = ''
           euer              IN MX 1   aspmx.l.google.com.
-          pigstarter        IN A      ${head nets.internet.addrs4}
-          gold              IN A      ${head nets.internet.addrs4}
-          boot              IN A      ${head nets.internet.addrs4}
+          pigstarter        IN A      ${nets.internet.ip4.addr}
+          gold              IN A      ${nets.internet.ip4.addr}
+          boot              IN A      ${nets.internet.ip4.addr}
         '';
       };
       nets = {
         internet = {
-          addrs4 = ["192.40.56.122"];
-          addrs6 = ["2604:2880::841f:72c"];
+          ip4.addr = "192.40.56.122";
+          ip6.addr = "2604:2880::841f:72c";
           aliases = [
             "pigstarter.internet"
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.0.153"];
-          addrs6 = ["42:9143:b4c0:f981:6030:7aa2:8bc5:4110"];
+          ip4.addr = "10.243.0.153";
+          ip6.addr = "42:9143:b4c0:f981:6030:7aa2:8bc5:4110";
           aliases = [
             "pigstarter.retiolum"
           ];
@@ -171,18 +171,18 @@ with config.krebs.lib;
       cores = 1;
       extraZones = {
         "krebsco.de" = ''
-          euer           IN A  ${head nets.internet.addrs4}
-          wiki.euer      IN A  ${head nets.internet.addrs4}
-          wry            IN A  ${head nets.internet.addrs4}
+          euer           IN A  ${nets.internet.ip4.addr}
+          wiki.euer      IN A  ${nets.internet.ip4.addr}
+          wry            IN A  ${nets.internet.ip4.addr}
           io             IN NS wry.krebsco.de.
-          graphs         IN A  ${head nets.internet.addrs4}
-          paste       60 IN A  ${head nets.internet.addrs4}
-          tinc           IN A  ${head nets.internet.addrs4}
+          graphs         IN A  ${nets.internet.ip4.addr}
+          paste       60 IN A  ${nets.internet.ip4.addr}
+          tinc           IN A  ${nets.internet.ip4.addr}
         '';
       };
       nets = rec {
         internet = {
-          addrs4 = ["104.233.87.86"];
+          ip4.addr = "104.233.87.86";
           aliases = [
             "wry.internet"
             "paste.internet"
@@ -190,8 +190,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.29.169"];
-          addrs6 = ["42:6e1e:cc8a:7cef:827:f938:8c64:baad"];
+          ip4.addr = "10.243.29.169";
+          ip6.addr = "42:6e1e:cc8a:7cef:827:f938:8c64:baad";
           aliases = [
             "graphs.wry.retiolum"
             "graphs.retiolum"
@@ -228,8 +228,8 @@ with config.krebs.lib;
 
       nets = {
         retiolum = {
-          addrs4 = ["10.243.153.102"];
-          addrs6 = ["42:4b0b:d990:55ba:8da8:630f:dc0e:aae0"];
+          ip4.addr = "10.243.153.102";
+          ip6.addr = "42:4b0b:d990:55ba:8da8:630f:dc0e:aae0";
           aliases = [
             "filepimp.retiolum"
           ];
@@ -252,8 +252,8 @@ with config.krebs.lib;
 
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.89"];
-          addrs6 = ["42:f9f0::10"];
+          ip4.addr = "10.243.0.89";
+          ip6.addr = "42:f9f0::10";
           aliases = [
             "omo.retiolum"
             "omo.r"
@@ -277,8 +277,8 @@ with config.krebs.lib;
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.214.15"];
-          addrs6 = ["42:5a02:2c30:c1b1:3f2e:7c19:2496:a732"];
+          ip4.addr = "10.243.214.15";
+          ip6.addr = "42:5a02:2c30:c1b1:3f2e:7c19:2496:a732";
           aliases = [
               "wbob.retiolum"
           ];
@@ -301,24 +301,24 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
 
       extraZones = {
         "krebsco.de" = ''
-          share.euer        IN A      ${head nets.internet.addrs4}
-          mattermost.euer   IN A      ${head nets.internet.addrs4}
-          git.euer          IN A      ${head nets.internet.addrs4}
-          gum               IN A      ${head nets.internet.addrs4}
-          cgit.euer         IN A      ${head nets.internet.addrs4}
+          share.euer        IN A      ${nets.internet.ip4.addr}
+          mattermost.euer   IN A      ${nets.internet.ip4.addr}
+          git.euer          IN A      ${nets.internet.ip4.addr}
+          gum               IN A      ${nets.internet.ip4.addr}
+          cgit.euer         IN A      ${nets.internet.ip4.addr}
         '';
       };
       nets = rec {
         internet = {
-          addrs4 = ["195.154.108.70"];
+          ip4.addr = "195.154.108.70";
           aliases = [
             "gum.internet"
           ];
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.0.211"];
-          addrs6 = ["42:f9f0:0000:0000:0000:0000:0000:70d2"];
+          ip4.addr = "10.243.0.211";
+          ip6.addr = "42:f9f0:0000:0000:0000:0000:0000:70d2";
           aliases = [
             "gum.r"
             "gum.retiolum"
@@ -346,20 +346,20 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       extraZones = {
         "krebsco.de" = ''
-          mediengewitter    IN A      ${head nets.internet.addrs4}
-          flap              IN A      ${head nets.internet.addrs4}
+          mediengewitter    IN A      ${nets.internet.ip4.addr}
+          flap              IN A      ${nets.internet.ip4.addr}
         '';
       };
       nets = {
         internet = {
-          addrs4 = ["162.248.11.162"];
+          ip4.addr = "162.248.11.162";
           aliases = [
             "flap.internet"
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.211.172"];
-          addrs6 = ["42:472a:3d01:bbe4:4425:567e:592b:065d"];
+          ip4.addr = "10.243.211.172";
+          ip6.addr = "42:472a:3d01:bbe4:4425:567e:592b:065d";
           aliases = [
             "flap.retiolum"
             "flap.r"
@@ -382,8 +382,8 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.231.219"];
-          addrs6 = ["42:f7bf:178d:4b68:1c1b:42e8:6b27:6a72"];
+          ip4.addr = "10.243.231.219";
+          ip6.addr = "42:f7bf:178d:4b68:1c1b:42e8:6b27:6a72";
           aliases = [
             "nukular.r"
           ];
@@ -405,8 +405,8 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.124.21"];
-          addrs6 = ["42:9898:a8be:ce56:0ee3:b99c:42c5:109e"];
+          ip4.addr = "10.243.124.21";
+          ip6.addr = "42:9898:a8be:ce56:0ee3:b99c:42c5:109e";
           aliases = [
             "heidi.r"
           ];
@@ -428,7 +428,7 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.69.184"];
+          ip4.addr = "10.243.69.184";
           aliases = [
             "soundflower.r"
           ];
@@ -450,7 +450,7 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.120.19"];
+          ip4.addr = "10.243.120.19";
           aliases = [
             "falk.r"
           ];
@@ -472,8 +472,8 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 4;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.189.130"];
-          addrs6 = ["42:c64e:011f:9755:31e1:c3e6:73c0:af2d"];
+          ip4.addr = "10.243.189.130";
+          ip6.addr = "42:c64e:011f:9755:31e1:c3e6:73c0:af2d";
           aliases = [
             "filebitch.r"
           ];
@@ -495,8 +495,8 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.26.29"];
-          addrs6 = ["42:927a:3d59:1cb3:29d6:1a08:78d3:812e"];
+          ip4.addr = "10.243.26.29";
+          ip6.addr = "42:927a:3d59:1cb3:29d6:1a08:78d3:812e";
           aliases = [
             "excobridge.r"
           ];
@@ -518,14 +518,14 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         internet = {
-          addrs4 = ["148.251.47.69"];
+          ip4.addr = "148.251.47.69";
           aliases = [
             "wooki.internet"
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.57.85"];
-          addrs6 = ["42:2f06:b899:a3b5:1dcf:51a4:a02b:8731"];
+          ip4.addr = "10.243.57.85";
+          ip6.addr = "42:2f06:b899:a3b5:1dcf:51a4:a02b:8731";
           aliases = [
             "wooki.r"
           ];
@@ -547,8 +547,8 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 2;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.0.163"];
-          addrs6 = ["42:b67b:5752:a730:5f28:d80d:6b37:5bda/128"];
+          ip4.addr = "10.243.0.163";
+          ip6.addr = "42:b67b:5752:a730:5f28:d80d:6b37:5bda/128";
           aliases = [
             "senderechner.r"
           ];
@@ -570,14 +570,14 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       cores = 1;
       nets = {
         internet = {
-          addrs4 = ["217.160.206.154"];
+          ip4.addr = "217.160.206.154";
           aliases = [
             "muhbaasu.internet"
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.139.184"];
-          addrs6 = ["42:d568:6106:ba30:753b:0f2a:8225:b1fb"];
+          ip4.addr = "10.243.139.184";
+          ip6.addr = "42:d568:6106:ba30:753b:0f2a:8225:b1fb";
           aliases = [
             "muhbaasu.r"
           ];
diff --git a/krebs/3modules/miefda/default.nix b/krebs/3modules/miefda/default.nix
index 9a5866294..a03f7ff4d 100644
--- a/krebs/3modules/miefda/default.nix
+++ b/krebs/3modules/miefda/default.nix
@@ -8,8 +8,8 @@ with config.krebs.lib;
       cores = 4;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.111.112"];
-          addrs6 = ["42:0:0:0:0:0:111:112"];
+          ip4.addr = "10.243.111.112";
+          ip6.addr = "42:0:0:0:0:0:111:112";
           aliases = [
             "bobby.retiolum"
             "cgit.bobby.retiolum"
diff --git a/krebs/3modules/mv/default.nix b/krebs/3modules/mv/default.nix
index 3b4001e7a..20118c61f 100644
--- a/krebs/3modules/mv/default.nix
+++ b/krebs/3modules/mv/default.nix
@@ -8,8 +8,8 @@ with config.krebs.lib;
       cores = 4;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.111.111"];
-          addrs6 = ["42:0:0:0:0:0:111:111"];
+          ip4.addr = "10.243.111.111";
+          ip6.addr = "42:0:0:0:0:0:111:111";
           aliases = [
             "stro.retiolum"
             "cgit.stro.retiolum"
diff --git a/krebs/3modules/retiolum.nix b/krebs/3modules/retiolum.nix
index 61b4473e1..fe4dbd50c 100644
--- a/krebs/3modules/retiolum.nix
+++ b/krebs/3modules/retiolum.nix
@@ -11,26 +11,13 @@ let
   api = {
     enable = mkEnableOption "krebs.retiolum";
 
-    name = mkOption {
-      type = types.str;
-      default = config.networking.hostName;
-      # Description stolen from tinc.conf(5).
-      description = ''
-        This is the name which identifies this tinc daemon.  It must
-        be unique for the virtual private network this daemon will
-        connect to.  The Name may only consist of alphanumeric and
-        underscore characters.  If Name starts with a $, then the
-        contents of the environment variable that follows will be
-        used.  In that case, invalid characters will be converted to
-        underscores.  If Name is $HOST, but no such environment
-        variable exist, the hostname will be read using the
-        gethostnname() system call This is the name which identifies
-        the this tinc daemon.
-      '';
+    host = mkOption {
+      type = types.host;
+      default = config.krebs.build.host;
     };
 
     netname = mkOption {
-      type = types.str;
+      type = types.hostname;
       default = "retiolum";
       description = ''
         The tinc network name.
@@ -157,46 +144,34 @@ let
     uid = genid name;
   };
 
+  net = cfg.host.nets.${cfg.netname};
+
   tinc = cfg.tincPackage;
 
   iproute = cfg.iproutePackage;
 
-  confDir = pkgs.runCommand "retiolum" {
-    # TODO text
-    executable = true;
-    preferLocalBuild = true;
-  } ''
-    set -euf
-
-    mkdir -p $out
-
-    ln -s ${cfg.hostsPackage} $out/hosts
-
-    cat > $out/tinc.conf <<EOF
-    Name = ${cfg.name}
-    Device = /dev/net/tun
-    Interface = ${cfg.netname}
-    ${concatStrings (map (c : "ConnectTo = " + c + "\n") cfg.connectTo)}
-    PrivateKeyFile = /tmp/retiolum-rsa_key.priv
-    ${cfg.extraConfig}
-    EOF
-
-    # source: krebscode/painload/retiolum/scripts/tinc_setup/tinc-up
-    cat > $out/tinc-up <<EOF
-    host=$out/hosts/${cfg.name}
-    ${iproute}/sbin/ip link set \$INTERFACE up
-
-    addr4=\$(sed -n 's|^ *Subnet *= *\(10[.][^ ]*\) *$|\1|p' \$host)
-    if [ -n "\$addr4" ];then
-        ${iproute}/sbin/ip -4 addr add \$addr4 dev \$INTERFACE
-        ${iproute}/sbin/ip -4 route add 10.243.0.0/16 dev \$INTERFACE
-    fi
-    addr6=\$(sed -n 's|^ *Subnet *= *\(42[:][^ ]*\) *$|\1|p' \$host)
-    ${iproute}/sbin/ip -6 addr add \$addr6 dev \$INTERFACE
-    ${iproute}/sbin/ip -6 route add 42::/16 dev \$INTERFACE
-    EOF
-
-    chmod +x $out/tinc-up
-  '';
+  confDir = let
+    namePathPair = name: path: { inherit name path; };
+  in pkgs.linkFarm "${cfg.netname}-etc-tinc" (mapAttrsToList namePathPair {
+    "hosts" = cfg.hostsPackage;
+    "tinc.conf" = pkgs.writeText "${cfg.netname}-tinc.conf" ''
+      Name = ${cfg.host.name}
+      Interface = ${cfg.netname}
+      ${concatStrings (map (c: "ConnectTo = ${c}\n") cfg.connectTo)}
+      PrivateKeyFile = /tmp/retiolum-rsa_key.priv
+      ${cfg.extraConfig}
+    '';
+    "tinc-up" = pkgs.writeScript "${cfg.netname}-tinc-up" ''
+      ${iproute}/sbin/ip link set ${cfg.netname} up
+      ${optionalString (net.ip4 != null) ''
+        ${iproute}/sbin/ip -4 addr add ${net.ip4.addr} dev ${cfg.netname}
+        ${iproute}/sbin/ip -4 route add ${net.ip4.prefix} dev ${cfg.netname}
+      ''}
+      ${optionalString (net.ip6 != null) ''
+        ${iproute}/sbin/ip -6 addr add ${net.ip6.addr} dev ${cfg.netname}
+        ${iproute}/sbin/ip -6 route add ${net.ip6.prefix} dev ${cfg.netname}
+      ''}
+    '';
+  });
 
 in out
diff --git a/krebs/3modules/shared/default.nix b/krebs/3modules/shared/default.nix
index ccd15b569..47767d370 100644
--- a/krebs/3modules/shared/default.nix
+++ b/krebs/3modules/shared/default.nix
@@ -12,8 +12,8 @@ let
     cores = 1;
     nets = {
       retiolum = {
-        addrs4 = ["10.243.111.111"];
-        addrs6 = ["42:0:0:0:0:0:0:7357"];
+        ip4.addr = "10.243.111.111";
+        ip6.addr = "42:0:0:0:0:0:0:7357";
         aliases = [
           "test.r"
           "test.retiolum"
@@ -36,7 +36,7 @@ in {
     wolf = {
       nets = {
         shack = {
-          addrs4 = [ "10.42.2.150" ];
+          ip4.addr =  "10.42.2.150" ;
           aliases = [
             "wolf.shack"
             "graphite.shack"
@@ -45,8 +45,8 @@ in {
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.77.1"];
-          addrs6 = ["42:0:0:0:0:0:77:1"];
+          ip4.addr = "10.243.77.1";
+          ip6.addr = "42:0:0:0:0:0:77:1";
           aliases = [
             "wolf.retiolum"
             "cgit.wolf.retiolum"
diff --git a/krebs/3modules/tv/default.nix b/krebs/3modules/tv/default.nix
index f0f0c5e79..b0f0ce547 100644
--- a/krebs/3modules/tv/default.nix
+++ b/krebs/3modules/tv/default.nix
@@ -13,15 +13,15 @@ with config.krebs.lib;
         # TODO generate krebsco.de zone from nets and don't use extraZones at all
         "krebsco.de" = ''
           krebsco.de. 60 IN MX 5 mx23
-          mx23        60 IN A ${elemAt nets.internet.addrs4 0}
-          cd          60 IN A ${elemAt nets.internet.addrs4 0}
-          cgit        60 IN A ${elemAt nets.internet.addrs4 0}
-          cgit.cd     60 IN A ${elemAt nets.internet.addrs4 0}
+          mx23        60 IN A ${nets.internet.ip4.addr}
+          cd          60 IN A ${nets.internet.ip4.addr}
+          cgit        60 IN A ${nets.internet.ip4.addr}
+          cgit.cd     60 IN A ${nets.internet.ip4.addr}
         '';
       };
       nets = rec {
         internet = {
-          addrs4 = ["162.219.7.216"];
+          ip4.addr = "162.219.7.216";
           aliases = [
             "cd.i"
             "cd.internet"
@@ -34,8 +34,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.113.222"];
-          addrs6 = ["42:4522:25f8:36bb:8ccb:0150:231a:2af3"];
+          ip4.addr = "10.243.113.222";
+          ip6.addr = "42:4522:25f8:36bb:8ccb:0150:231a:2af3";
           aliases = [
             "cd.r"
             "cd.retiolum"
@@ -66,7 +66,7 @@ with config.krebs.lib;
       cores = 2;
       nets = rec {
         internet = {
-          addrs4 = ["45.62.237.203"];
+          ip4.addr = "45.62.237.203";
           aliases = [
             "doppelbock.i"
             "doppelbock.internet"
@@ -74,8 +74,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.113.224"];
-          addrs6 = ["42:4522:25f8:36bb:8ccb:0150:231a:2af5"];
+          ip4.addr = "10.243.113.224";
+          ip6.addr = "42:4522:25f8:36bb:8ccb:0150:231a:2af5";
           aliases = [
             "doppelbock.r"
             "doppelbock.retiolum"
@@ -101,7 +101,7 @@ with config.krebs.lib;
       cores = 1;
       nets = rec {
         internet = {
-          addrs4 = ["104.167.114.142"];
+          ip4.addr = "104.167.114.142";
           aliases = [
             "mkdir.i"
             "mkdir.internet"
@@ -109,8 +109,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.113.223"];
-          addrs6 = ["42:4522:25f8:36bb:8ccb:0150:231a:2af4"];
+          ip4.addr = "10.243.113.223";
+          ip6.addr = "42:4522:25f8:36bb:8ccb:0150:231a:2af4";
           aliases = [
             "mkdir.r"
             "mkdir.retiolum"
@@ -136,12 +136,12 @@ with config.krebs.lib;
       extraZones = {
         # TODO generate krebsco.de zone from nets and don't use extraZones at all
         "krebsco.de" = ''
-          ire 60 IN A ${elemAt nets.internet.addrs4 0}
+          ire 60 IN A ${nets.internet.ip4.addr}
         '';
       };
       nets = rec {
         internet = {
-          addrs4 = ["198.147.22.115"];
+          ip4.addr = "198.147.22.115";
           aliases = [
             "ire.i"
             "ire.internet"
@@ -151,8 +151,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.231.66"];
-          addrs6 = ["42:b912:0f42:a82d:0d27:8610:e89b:490c"];
+          ip4.addr = "10.243.231.66";
+          ip6.addr = "42:b912:0f42:a82d:0d27:8610:e89b:490c";
           aliases = [
             "ire.r"
             "ire.retiolum"
@@ -175,7 +175,7 @@ with config.krebs.lib;
     kaepsele = {
       nets = {
         internet = {
-          addrs4 = ["92.222.10.169"];
+          ip4.addr = "92.222.10.169";
           aliases = [
             "kaepsele.i"
             "kaepsele.internet"
@@ -183,8 +183,8 @@ with config.krebs.lib;
           ];
         };
         retiolum = {
-          addrs4 = ["10.243.166.2"];
-          addrs6 = ["42:0b9d:6660:d07c:2bb7:4e91:1a01:2e7d"];
+          ip4.addr = "10.243.166.2";
+          ip6.addr = "42:0b9d:6660:d07c:2bb7:4e91:1a01:2e7d";
           aliases = [
             "kaepsele.r"
             "kaepsele.retiolum"
@@ -207,8 +207,8 @@ with config.krebs.lib;
       cores = 2;
       nets = {
         retiolum = {
-          addrs4 = ["10.243.20.1"];
-          addrs6 = ["42:0:0:0:0:0:0:2001"];
+          ip4.addr = "10.243.20.1";
+          ip6.addr = "42:0:0:0:0:0:0:2001";
           aliases = [
             "mu.r"
             "mu.retiolum"
@@ -232,13 +232,13 @@ with config.krebs.lib;
       cores = 2;
       nets = rec {
         gg23 = {
-          addrs4 = ["10.23.1.110"];
+          ip4.addr = "10.23.1.110";
           aliases = ["nomic.gg23"];
           ssh.port = 11423;
         };
         retiolum = {
-          addrs4 = ["10.243.0.110"];
-          addrs6 = ["42:02d5:733f:d6da:c0f5:2bb7:2b18:09ec"];
+          ip4.addr = "10.243.0.110";
+          ip6.addr = "42:02d5:733f:d6da:c0f5:2bb7:2b18:09ec";
           aliases = [
             "nomic.r"
             "nomic.retiolum"
@@ -264,7 +264,7 @@ with config.krebs.lib;
     ok = {
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.1"];
+          ip4.addr = "10.23.1.1";
           aliases = ["ok.gg23"];
         };
       };
@@ -273,7 +273,7 @@ with config.krebs.lib;
       cores = 1;
       nets = rec {
         internet = {
-          addrs4 = ["167.88.34.182"];
+          ip4.addr = "167.88.34.182";
           aliases = [
             "rmdir.i"
             "rmdir.internet"
@@ -281,8 +281,8 @@ with config.krebs.lib;
         };
         retiolum = {
           via = internet;
-          addrs4 = ["10.243.113.224"];
-          addrs6 = ["42:4522:25f8:36bb:8ccb:0150:231a:2af5"];
+          ip4.addr = "10.243.113.224";
+          ip6.addr = "42:4522:25f8:36bb:8ccb:0150:231a:2af5";
           aliases = [
             "rmdir.r"
             "rmdir.retiolum"
@@ -307,7 +307,7 @@ with config.krebs.lib;
     schnabeldrucker = {
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.21"];
+          ip4.addr = "10.23.1.21";
           aliases = ["schnabeldrucker.gg23"];
         };
       };
@@ -315,7 +315,7 @@ with config.krebs.lib;
     schnabelscanner = {
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.22"];
+          ip4.addr = "10.23.1.22";
           aliases = ["schnabelscanner.gg23"];
         };
       };
@@ -324,7 +324,7 @@ with config.krebs.lib;
       cores = 4;
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.37"];
+          ip4.addr = "10.23.1.37";
           aliases = [
             "wu.gg23"
             "cache.wu.gg23"
@@ -332,8 +332,8 @@ with config.krebs.lib;
           ssh.port = 11423;
         };
         retiolum = {
-          addrs4 = ["10.243.13.37"];
-          addrs6 = ["42:0:0:0:0:0:0:1337"];
+          ip4.addr = "10.243.13.37";
+          ip6.addr = "42:0:0:0:0:0:0:1337";
           aliases = [
             "wu.r"
             "wu.retiolum"
@@ -360,13 +360,13 @@ with config.krebs.lib;
       cores = 4;
       nets = {
         gg23 = {
-          addrs4 = ["10.23.1.38"];
+          ip4.addr = "10.23.1.38";
           aliases = ["xu.gg23"];
           ssh.port = 11423;
         };
         retiolum = {
-          addrs4 = ["10.243.13.38"];
-          addrs6 = ["42:0:0:0:0:0:0:1338"];
+          ip4.addr = "10.243.13.38";
+          ip6.addr = "42:0:0:0:0:0:0:1338";
           aliases = [
             "xu.r"
             "xu.retiolum"
diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index 7255dc3e1..24b4e14b1 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -63,28 +63,56 @@ types // rec {
 
   net = submodule ({ config, ... }: {
     options = {
+      name = mkOption {
+        type = label;
+        default = config._module.args.name;
+      };
       via = mkOption {
         type = nullOr net;
         default = null;
       };
       addrs = mkOption {
         type = listOf addr;
-        default = config.addrs4 ++ config.addrs6;
-        # TODO only default addrs make sense
-      };
-      addrs4 = mkOption {
-        type = listOf addr4;
-        default = [];
-      };
-      addrs6 = mkOption {
-        type = listOf addr6;
-        default = [];
+        default =
+          optional (config.ip4 != null) config.ip4.addr ++
+          optional (config.ip6 != null) config.ip6.addr;
+        readOnly = true;
       };
       aliases = mkOption {
         # TODO nonEmptyListOf hostname
         type = listOf hostname;
         default = [];
       };
+      ip4 = mkOption {
+        type = nullOr (submodule {
+          options = {
+            addr = mkOption {
+              type = addr4;
+            };
+            prefix = mkOption ({
+              type = str; # TODO routing prefix (CIDR)
+            } // optionalAttrs (config.name == "retiolum") {
+              default = "10.243.0.0/16";
+            });
+          };
+        });
+        default = null;
+      };
+      ip6 = mkOption {
+        type = nullOr (submodule {
+          options = {
+            addr = mkOption {
+              type = addr6;
+            };
+            prefix = mkOption ({
+              type = str; # TODO routing prefix (CIDR)
+            } // optionalAttrs (config.name == "retiolum") {
+              default = "42::/16";
+            });
+          };
+        });
+        default = null;
+      };
       ssh = mkOption {
         type = submodule {
           options = {
diff --git a/lass/1systems/cloudkrebs.nix b/lass/1systems/cloudkrebs.nix
index 98f509050..6cfba567a 100644
--- a/lass/1systems/cloudkrebs.nix
+++ b/lass/1systems/cloudkrebs.nix
@@ -2,9 +2,8 @@
 
 let
   inherit (import ../4lib { inherit pkgs lib; }) getDefaultGateway;
-  inherit (lib) head;
 
-  ip = (head config.krebs.build.host.nets.internet.addrs4);
+  ip = config.krebs.build.host.nets.internet.ip4.addr;
 in {
   imports = [
     ../.
diff --git a/lass/1systems/echelon.nix b/lass/1systems/echelon.nix
index 2ff6dba70..80611ee80 100644
--- a/lass/1systems/echelon.nix
+++ b/lass/1systems/echelon.nix
@@ -2,9 +2,8 @@
 
 let
   inherit (import ../4lib { inherit pkgs lib; }) getDefaultGateway;
-  inherit (lib) head;
 
-  ip = (head config.krebs.build.host.nets.internet.addrs4);
+  ip = config.krebs.build.host.nets.internet.ip4.addr;
 in {
   imports = [
     ../.
diff --git a/lass/1systems/prism.nix b/lass/1systems/prism.nix
index 4d40c8d59..20c919b9b 100644
--- a/lass/1systems/prism.nix
+++ b/lass/1systems/prism.nix
@@ -1,9 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) head;
-
-  ip = (head config.krebs.build.host.nets.internet.addrs4);
+  ip = config.krebs.build.host.nets.internet.ip4.addr;
 in {
   imports = [
     ../.
diff --git a/lass/2configs/privoxy-retiolum.nix b/lass/2configs/privoxy-retiolum.nix
index 3a3641ad8..9059bbac8 100644
--- a/lass/2configs/privoxy-retiolum.nix
+++ b/lass/2configs/privoxy-retiolum.nix
@@ -1,8 +1,7 @@
 { config, lib, ... }:
 
 let
-  r_ip = (head config.krebs.build.host.nets.retiolum.addrs4);
-  inherit (lib) head;
+  r_ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 
 in {
   imports = [
diff --git a/lass/3modules/static_nginx.nix b/lass/3modules/static_nginx.nix
index 6e87e9853..6b5d19615 100644
--- a/lass/3modules/static_nginx.nix
+++ b/lass/3modules/static_nginx.nix
@@ -54,7 +54,7 @@ let
   user = config.services.nginx.user;
   group = config.services.nginx.group;
 
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
 
   imp = {
     krebs.nginx.servers = flip mapAttrs cfg ( name: { domain, folder, ssl, ... }: {
diff --git a/makefu/1systems/gum.nix b/makefu/1systems/gum.nix
index 710421659..7bac4398c 100644
--- a/makefu/1systems/gum.nix
+++ b/makefu/1systems/gum.nix
@@ -2,8 +2,8 @@
 
 with config.krebs.lib;
 let
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
-  internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in {
   imports = [
       ../.
diff --git a/makefu/1systems/wry.nix b/makefu/1systems/wry.nix
index edaf1b803..d9f8ded83 100644
--- a/makefu/1systems/wry.nix
+++ b/makefu/1systems/wry.nix
@@ -3,8 +3,8 @@
 with config.krebs.lib;
 let
 
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
-  internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in {
   imports = [
       ../.
diff --git a/makefu/2configs/deployment/mycube.connector.one.nix b/makefu/2configs/deployment/mycube.connector.one.nix
index 125b3dfff..8f51c91dd 100644
--- a/makefu/2configs/deployment/mycube.connector.one.nix
+++ b/makefu/2configs/deployment/mycube.connector.one.nix
@@ -3,7 +3,7 @@
 with config.krebs.lib;
 let
   hostname = config.krebs.build.host.name;
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
   wsgi-sock = "${config.services.uwsgi.runDir}/uwsgi.sock";
 in {
   services.redis.enable = true;
diff --git a/makefu/2configs/iodined.nix b/makefu/2configs/iodined.nix
index 2e69d167c..d57c91ce8 100644
--- a/makefu/2configs/iodined.nix
+++ b/makefu/2configs/iodined.nix
@@ -10,7 +10,7 @@ in {
     enable = true;
     domain = domain;
     ip = "172.16.10.1/24";
-    extraConfig = "-P ${pw} -l ${pkgs.lib.head config.krebs.build.host.nets.internet.addrs4}";
+    extraConfig = "-P ${pw} -l ${config.krebs.build.host.nets.internet.ip4.addr}";
   };
 
 }
diff --git a/makefu/2configs/nginx/euer.blog.nix b/makefu/2configs/nginx/euer.blog.nix
index 9d08f4b9a..137c0b0e3 100644
--- a/makefu/2configs/nginx/euer.blog.nix
+++ b/makefu/2configs/nginx/euer.blog.nix
@@ -8,8 +8,8 @@ let
   hostname = config.krebs.build.host.name;
   user = config.services.nginx.user;
   group = config.services.nginx.group;
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
-  internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
   base-dir = "/var/www/blog.euer";
 in {
   # Prepare Blog directory
diff --git a/makefu/2configs/nginx/euer.test.nix b/makefu/2configs/nginx/euer.test.nix
index f7214e613..84b9bacda 100644
--- a/makefu/2configs/nginx/euer.test.nix
+++ b/makefu/2configs/nginx/euer.test.nix
@@ -5,8 +5,8 @@ let
   hostname = config.krebs.build.host.name;
   user = config.services.nginx.user;
   group = config.services.nginx.group;
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
-  internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in {
   krebs.nginx = {
     enable = mkDefault true;
diff --git a/makefu/2configs/nginx/euer.wiki.nix b/makefu/2configs/nginx/euer.wiki.nix
index a5572a519..10985c833 100644
--- a/makefu/2configs/nginx/euer.wiki.nix
+++ b/makefu/2configs/nginx/euer.wiki.nix
@@ -18,8 +18,8 @@ let
   #  user1 = pass1
   #  userN = passN
   tw-pass-file = "${sec}/tw-pass.ini";
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
-  internal-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in {
   services.phpfpm = {
     # phpfpm does not have an enable option
diff --git a/makefu/2configs/nginx/update.connector.one.nix b/makefu/2configs/nginx/update.connector.one.nix
index ac5e6b17b..dde3e3a64 100644
--- a/makefu/2configs/nginx/update.connector.one.nix
+++ b/makefu/2configs/nginx/update.connector.one.nix
@@ -3,7 +3,7 @@
 with config.krebs.lib;
 let
   hostname = config.krebs.build.host.name;
-  external-ip = head config.krebs.build.host.nets.internet.addrs4;
+  external-ip = config.krebs.build.host.nets.internet.ip4.addr;
 in {
   krebs.nginx = {
     enable = mkDefault true;
diff --git a/makefu/2configs/omo-share.nix b/makefu/2configs/omo-share.nix
index 3a4dd456f..c943e3d9a 100644
--- a/makefu/2configs/omo-share.nix
+++ b/makefu/2configs/omo-share.nix
@@ -5,7 +5,7 @@ let
   hostname = config.krebs.build.host.name;
   # TODO local-ip from the nets config
   local-ip = "192.168.1.11";
-  # local-ip = head config.krebs.build.host.nets.retiolum.addrs4;
+  # local-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in {
   krebs.nginx = {
     enable = mkDefault true;
diff --git a/shared/1systems/wolf.nix b/shared/1systems/wolf.nix
index f0323dc2f..53334d6f1 100644
--- a/shared/1systems/wolf.nix
+++ b/shared/1systems/wolf.nix
@@ -1,8 +1,8 @@
 { config, lib, pkgs, ... }:
 
 let
-  shack-ip = lib.head config.krebs.build.host.nets.shack.addrs4;
-  internal-ip = lib.head config.krebs.build.host.nets.retiolum.addrs4;
+  shack-ip = config.krebs.build.host.nets.shack.ip4.addr;
+  internal-ip = config.krebs.build.host.nets.retiolum.ip4.addr;
 in
 {
   imports = [
diff --git a/tv/1systems/doppelbock.nix b/tv/1systems/doppelbock.nix
index 9a8d5b05d..ec85a7772 100644
--- a/tv/1systems/doppelbock.nix
+++ b/tv/1systems/doppelbock.nix
@@ -13,8 +13,8 @@ with config.krebs.lib;
   networking = {
     interfaces.enp2s1.ip4 = singleton {
       address = let
-        addr4 = "45.62.237.203";
-      in assert config.krebs.build.host.nets.internet.addrs4 == [addr4]; addr4;
+        addr = "45.62.237.203";
+      in assert config.krebs.build.host.nets.internet.ip4.addr == addr; addr;
       prefixLength = 24;
     };
     defaultGateway = "45.62.237.1";
diff --git a/tv/1systems/mkdir.nix b/tv/1systems/mkdir.nix
index 58a8fdcb2..f46ed9547 100644
--- a/tv/1systems/mkdir.nix
+++ b/tv/1systems/mkdir.nix
@@ -7,12 +7,7 @@ let
   getDefaultGateway = ip:
     concatStringsSep "." (take 3 (splitString "." ip) ++ ["1"]);
 
-
-  primary-addr4 =
-    builtins.elemAt config.krebs.build.host.nets.internet.addrs4 0;
-
-  #secondary-addr4 =
-  #  builtins.elemAt config.krebs.build.host.nets.internet.addrs4 1;
+  primary-addr4 = config.krebs.build.host.nets.internet.ip4.addr;
 in
 
 {
@@ -55,10 +50,6 @@ in
       address = primary-addr4;
       prefixLength = 24;
     }
-    #{
-    #  address = secondary-addr4;
-    #  prefixLength = 24;
-    #}
   ];
 
   # TODO define gateway in krebs/3modules/default.nix
diff --git a/tv/1systems/rmdir.nix b/tv/1systems/rmdir.nix
index c54caa649..25fae2c36 100644
--- a/tv/1systems/rmdir.nix
+++ b/tv/1systems/rmdir.nix
@@ -7,12 +7,7 @@ let
   getDefaultGateway = ip:
     concatStringsSep "." (take 3 (splitString "." ip) ++ ["1"]);
 
-
-  primary-addr4 =
-    builtins.elemAt config.krebs.build.host.nets.internet.addrs4 0;
-
-  #secondary-addr4 =
-  #  builtins.elemAt config.krebs.build.host.nets.internet.addrs4 1;
+  primary-addr4 = config.krebs.build.host.nets.internet.ip4.addr;
 in
 
 {
diff --git a/tv/2configs/exim-smarthost.nix b/tv/2configs/exim-smarthost.nix
index 280d8572b..8a90639b6 100644
--- a/tv/2configs/exim-smarthost.nix
+++ b/tv/2configs/exim-smarthost.nix
@@ -13,7 +13,7 @@ with config.krebs.lib;
       "shackspace.de"
       "viljetic.de"
     ];
-    relay_from_hosts = concatMap (host: host.nets.retiolum.addrs4) [
+    relay_from_hosts = concatMap (host: host.nets.retiolum.ip4.addr) [
       config.krebs.hosts.nomic
       config.krebs.hosts.wu
       config.krebs.hosts.xu
diff --git a/tv/3modules/charybdis/config.nix b/tv/3modules/charybdis/config.nix
index e4d754ff3..1b160926c 100644
--- a/tv/3modules/charybdis/config.nix
+++ b/tv/3modules/charybdis/config.nix
@@ -56,9 +56,9 @@ in toFile "charybdis.conf" ''
     /* On multi-homed hosts you may need the following. These define
      * the addresses we connect from to other servers. */
     /* for IPv4 */
-    vhost = ${concatMapStringsSep ", " toJSON config.krebs.build.host.nets.retiolum.addrs4};
+    vhost = ${toJSON config.krebs.build.host.nets.retiolum.ip4.addr};
     /* for IPv6 */
-    vhost6 = ${concatMapStringsSep ", " toJSON config.krebs.build.host.nets.retiolum.addrs6};
+    vhost6 = ${toJSON config.krebs.build.host.nets.retiolum.ip6.addr};
 
     /* ssl_private_key: our ssl private key */
     ssl_private_key = ${toJSON cfg.ssl_private_key.path};
@@ -160,10 +160,7 @@ in toFile "charybdis.conf" ''
     /* If you want to listen on a specific IP only, specify host.
      * host definitions apply only to the following port line.
      */
-    # XXX This is stupid because only one host is allowed[?]
-    #host = ''${concatMapStringsSep ", " toJSON (
-    #  config.krebs.build.host.nets.retiolum.addrs
-    #)};
+    #host = ${toJSON config.krebs.build.host.nets.retiolum.ip4.addr};
     port = ${toString cfg.port};
     sslport = ${toString cfg.sslport};
   };

From 7b7e8b11b56fe92ff9a62895d329fcc24c9d7489 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 03:59:26 +0200
Subject: [PATCH 04/40] retiolum netname: hostname -> enum

---
 krebs/3modules/retiolum.nix | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/krebs/3modules/retiolum.nix b/krebs/3modules/retiolum.nix
index fe4dbd50c..8217cbcfd 100644
--- a/krebs/3modules/retiolum.nix
+++ b/krebs/3modules/retiolum.nix
@@ -17,7 +17,7 @@ let
     };
 
     netname = mkOption {
-      type = types.hostname;
+      type = types.enum (attrNames cfg.host.nets);
       default = "retiolum";
       description = ''
         The tinc network name.
@@ -114,7 +114,7 @@ let
   imp = {
     environment.systemPackages = [ tinc iproute ];
 
-    systemd.services.retiolum = {
+    systemd.services.${cfg.netname} = {
       description = "Tinc daemon for Retiolum";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
@@ -125,12 +125,12 @@ let
         Restart = "always";
         # TODO we cannot chroot (-R) b/c we use symlinks to hosts
         #      and the private key.
-        ExecStartPre = pkgs.writeScript "retiolum-init" ''
+        ExecStartPre = pkgs.writeScript "${cfg.netname}-prestart" ''
           #! /bin/sh
           install -o ${user.name} -m 0400 ${cfg.privateKeyFile} /tmp/retiolum-rsa_key.priv
         '';
         ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${user.name} -D --pidfile=/var/run/tinc.${SyslogIdentifier}.pid";
-        SyslogIdentifier = "retiolum";
+        SyslogIdentifier = cfg.netname;
       };
     };
 
@@ -140,7 +140,7 @@ let
   };
 
   user = rec {
-    name = "retiolum";
+    name = cfg.netname;
     uid = genid name;
   };
 

From 0dc2a751a902e11b4e3d2805fe2f97b09479ec85 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 04:11:00 +0200
Subject: [PATCH 05/40] krebs.retiolum: use krebs.secret

---
 krebs/3modules/retiolum.nix | 50 ++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 28 deletions(-)

diff --git a/krebs/3modules/retiolum.nix b/krebs/3modules/retiolum.nix
index 8217cbcfd..5aaeb5a30 100644
--- a/krebs/3modules/retiolum.nix
+++ b/krebs/3modules/retiolum.nix
@@ -86,17 +86,13 @@ let
       description = "Iproute2 package to use.";
     };
 
-
-    privateKeyFile = mkOption {
-      # TODO if it's types.path then it gets copied to /nix/store with
-      #      bad unsafe permissions...
-      type = types.str;
-      default = toString <secrets/retiolum.rsa_key.priv>;
-      description = ''
-          Generate file with <literal>tincd -K</literal>.
-          This file must exist on the local system. The default points to 
-          <secrets/retiolum.rsa_key.priv>.
-        '';
+    privkey = mkOption {
+      type = types.secret-file;
+      default = {
+        path = "${cfg.user.home}/tinc.rsa_key.priv";
+        owner = cfg.user;
+        source-path = toString <secrets> + "/${cfg.netname}.rsa_key.priv";
+      };
     };
 
     connectTo = mkOption {
@@ -109,41 +105,39 @@ let
       '';
     };
 
+    user = mkOption {
+      type = types.user;
+      default = {
+        name = cfg.netname;
+        home = "/var/lib/${cfg.user.name}";
+      };
+    };
   };
 
   imp = {
+    krebs.secret.files."${cfg.netname}.rsa_key.priv" = cfg.privkey;
+
     environment.systemPackages = [ tinc iproute ];
 
     systemd.services.${cfg.netname} = {
       description = "Tinc daemon for Retiolum";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
+      requires = [ "secret.service" ];
       path = [ tinc iproute ];
       serviceConfig = rec {
-        PermissionsStartOnly = "true";
-        PrivateTmp = "true";
         Restart = "always";
-        # TODO we cannot chroot (-R) b/c we use symlinks to hosts
-        #      and the private key.
-        ExecStartPre = pkgs.writeScript "${cfg.netname}-prestart" ''
-          #! /bin/sh
-          install -o ${user.name} -m 0400 ${cfg.privateKeyFile} /tmp/retiolum-rsa_key.priv
-        '';
-        ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${user.name} -D --pidfile=/var/run/tinc.${SyslogIdentifier}.pid";
+        ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${cfg.user.name} -D --pidfile=/var/run/tinc.${SyslogIdentifier}.pid";
         SyslogIdentifier = cfg.netname;
       };
     };
 
-    users.extraUsers = singleton {
-      inherit (user) name uid;
+    users.users.${cfg.user.name} = {
+      inherit (cfg.user) home name uid;
+      createHome = true;
     };
   };
 
-  user = rec {
-    name = cfg.netname;
-    uid = genid name;
-  };
-
   net = cfg.host.nets.${cfg.netname};
 
   tinc = cfg.tincPackage;
@@ -158,7 +152,7 @@ let
       Name = ${cfg.host.name}
       Interface = ${cfg.netname}
       ${concatStrings (map (c: "ConnectTo = ${c}\n") cfg.connectTo)}
-      PrivateKeyFile = /tmp/retiolum-rsa_key.priv
+      PrivateKeyFile = ${cfg.privkey.path}
       ${cfg.extraConfig}
     '';
     "tinc-up" = pkgs.writeScript "${cfg.netname}-tinc-up" ''

From 4e99bb9d12405cf1910af3205d8668604e516f50 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 04:38:10 +0200
Subject: [PATCH 06/40] krebs types.addr4: check type harder

---
 krebs/4lib/types.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index 24b4e14b1..6396927dd 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -220,7 +220,7 @@ types // rec {
     check = let
       IPv4address = let d = "([1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"; in
         concatMapStringsSep "." (const d) (range 1 4);
-    in x: match IPv4address != null;
+    in x: match IPv4address x != null;
     merge = mergeOneOption;
   };
   addr6 = str; # TODO

From e74f4ddf8182067ca4f44d8d4ed91a8c5fc65147 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 04:41:30 +0200
Subject: [PATCH 07/40] krebs types.addr6: str -> IPv6 address*

---
 krebs/3modules/makefu/default.nix | 2 +-
 krebs/4lib/types.nix              | 9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/makefu/default.nix b/krebs/3modules/makefu/default.nix
index b93b34d24..814e6929b 100644
--- a/krebs/3modules/makefu/default.nix
+++ b/krebs/3modules/makefu/default.nix
@@ -548,7 +548,7 @@ TNs2RYfwDy/r6H/hDeB/BSngPouedEVcPwIDAQAB
       nets = {
         retiolum = {
           ip4.addr = "10.243.0.163";
-          ip6.addr = "42:b67b:5752:a730:5f28:d80d:6b37:5bda/128";
+          ip6.addr = "42:b67b:5752:a730:5f28:d80d:6b37:5bda";
           aliases = [
             "senderechner.r"
           ];
diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index 6396927dd..f46491801 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -223,7 +223,14 @@ types // rec {
     in x: match IPv4address x != null;
     merge = mergeOneOption;
   };
-  addr6 = str; # TODO
+  addr6 = mkOptionType {
+    name = "IPv6 address";
+    check = let
+      # TODO check IPv6 address harder
+      IPv6address = "[0-9a-f.:]+";
+    in x: match IPv6address x != null;
+    merge = mergeOneOption;
+  };
 
   pgp-pubkey = str;
 

From 345efd36833fc0ada2805b46fd71bcc9642f4374 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 8 Apr 2016 05:06:22 +0200
Subject: [PATCH 08/40] tv.exim-smarthost: duh

---
 tv/2configs/exim-smarthost.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tv/2configs/exim-smarthost.nix b/tv/2configs/exim-smarthost.nix
index 8a90639b6..2b9ad77d7 100644
--- a/tv/2configs/exim-smarthost.nix
+++ b/tv/2configs/exim-smarthost.nix
@@ -13,7 +13,7 @@ with config.krebs.lib;
       "shackspace.de"
       "viljetic.de"
     ];
-    relay_from_hosts = concatMap (host: host.nets.retiolum.ip4.addr) [
+    relay_from_hosts = map (host: host.nets.retiolum.ip4.addr) [
       config.krebs.hosts.nomic
       config.krebs.hosts.wu
       config.krebs.hosts.xu

From a0d08d4793e9aa66837519d5171f4aefa7ea59fb Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 12 Apr 2016 14:26:37 +0200
Subject: [PATCH 09/40] exim-smarthost: don't tls_advertise_hosts

---
 krebs/3modules/exim-smarthost.nix | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/krebs/3modules/exim-smarthost.nix b/krebs/3modules/exim-smarthost.nix
index cee10ce7d..a01ab543b 100644
--- a/krebs/3modules/exim-smarthost.nix
+++ b/krebs/3modules/exim-smarthost.nix
@@ -136,6 +136,8 @@ let
         syslog_timestamp = false
         syslog_duplication = false
 
+        tls_advertise_hosts =
+
         begin acl
 
         acl_check_rcpt:

From 2b0c6616b66570d5648c5ebe3fdad6642510ede9 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 12 Apr 2016 17:13:29 +0200
Subject: [PATCH 10/40] doppelbock -> cd

---
 krebs/3modules/tv/default.nix | 37 +----------------------------------
 tv/1systems/cd.nix            | 18 ++++++++---------
 tv/1systems/doppelbock.nix    | 23 ----------------------
 3 files changed, 10 insertions(+), 68 deletions(-)
 delete mode 100644 tv/1systems/doppelbock.nix

diff --git a/krebs/3modules/tv/default.nix b/krebs/3modules/tv/default.nix
index b0f0ce547..a44aa552f 100644
--- a/krebs/3modules/tv/default.nix
+++ b/krebs/3modules/tv/default.nix
@@ -21,7 +21,7 @@ with config.krebs.lib;
       };
       nets = rec {
         internet = {
-          ip4.addr = "162.219.7.216";
+          ip4.addr = "45.62.237.203";
           aliases = [
             "cd.i"
             "cd.internet"
@@ -62,41 +62,6 @@ with config.krebs.lib;
       ssh.privkey.path = <secrets/ssh.id_ed25519>;
       ssh.pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOd/HqZIO9Trn3eycl23GZAz21HQCISaVNfNyaLSQvJ6";
     };
-    doppelbock = rec {
-      cores = 2;
-      nets = rec {
-        internet = {
-          ip4.addr = "45.62.237.203";
-          aliases = [
-            "doppelbock.i"
-            "doppelbock.internet"
-          ];
-        };
-        retiolum = {
-          via = internet;
-          ip4.addr = "10.243.113.224";
-          ip6.addr = "42:4522:25f8:36bb:8ccb:0150:231a:2af5";
-          aliases = [
-            "doppelbock.r"
-            "doppelbock.retiolum"
-            "cgit.doppelbock.r"
-            "cgit.doppelbock.retiolum"
-          ];
-          tinc.pubkey = ''
-            -----BEGIN RSA PUBLIC KEY-----
-            MIIBCgKCAQEAq/luvzH4CQX5qRuucUqR3aLwXtzsRmBOdd2hvrPG1z8ML2kKV+IG
-            0aBfyJmQ8csfeGhOj0y0LEBv4bkEjEtYObs+LJfdWZC5e39eAVUE0z8QbSPOx4di
-            /7Bo+9sFRELP1kYb47eLR8quiIkslMWQMbTLM5RHoXJ5jE8fQSitfp4WUZYiSPDF
-            d5F7RU/ZQfTZuh8gv7RmSn/6N6bXAQWrueK6ZqMuImIjBrmYyXUWxgsDnpeHxR5j
-            j/0F2Bda5lyp+Qzv24PREdPT8FazUfmIQwZTTArXHxiqLq+SEVT21E4WEf2sJRan
-            dti9yVUW3eiqpu8b9BRpvxOB3YdkyqlrGwIDAQAB
-            -----END RSA PUBLIC KEY-----
-          '';
-        };
-      };
-      ssh.privkey.path = <secrets/ssh.id_rsa>;
-      ssh.pubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLhrVTEmbtuTsgRTHHxsLrq7ai1Yt7+oKFevr1gzktCQqHuyucXzxn60F00kuNDkNiKIF5fHmWy6ajU+6PKD3TfiFMagT9ah0x0RSB0+0tevxnlOp6VdHhrdM5YrBduWMiELmOiI1lvYhRqKd/ZE7b2mra6KYe5VtTi9UX3wQp8qN+bI01KCxv0p6ciUgEO8fnwLKDBUuFJ2UfE7Ais9XrXFIBFXB+MKcpLnIXvrV6dSXdUEiaswg8wo0Q0Y3tMaQ0dNJdH2yp3FVn1aiX3E/vVnffmDKMWYWqn78klujdEdmLm8/8NkXnc/jpgu8ZlSpQHECO2ZUJzd35yRnVKALv";
-    };
     mkdir = rec {
       cores = 1;
       nets = rec {
diff --git a/tv/1systems/cd.nix b/tv/1systems/cd.nix
index 687f17951..32d956b8a 100644
--- a/tv/1systems/cd.nix
+++ b/tv/1systems/cd.nix
@@ -61,16 +61,16 @@ with config.krebs.lib;
     }
   ];
 
-  networking.interfaces.enp2s1.ip4 = [
-    {
-      address = "162.219.7.216";
+  networking = {
+    interfaces.enp2s1.ip4 = singleton {
+      address = let
+        addr = "45.62.237.203";
+      in assert config.krebs.build.host.nets.internet.ip4.addr == addr; addr;
       prefixLength = 24;
-    }
-  ];
-  networking.defaultGateway = "162.219.7.1";
-  networking.nameservers = [
-    "8.8.8.8"
-  ];
+    };
+    defaultGateway = "45.62.237.1";
+    nameservers = ["8.8.8.8"];
+  };
 
   environment.systemPackages = with pkgs; [
     htop
diff --git a/tv/1systems/doppelbock.nix b/tv/1systems/doppelbock.nix
deleted file mode 100644
index ec85a7772..000000000
--- a/tv/1systems/doppelbock.nix
+++ /dev/null
@@ -1,23 +0,0 @@
-{ config, lib, pkgs, ... }:
-with config.krebs.lib;
-{
-  krebs.build.host = config.krebs.hosts.doppelbock;
-
-  imports = [
-    ../.
-    ../2configs/hw/CAC-Developer-2.nix
-    ../2configs/fs/CAC-CentOS-7-64bit.nix
-    ../2configs/retiolum.nix
-  ];
-
-  networking = {
-    interfaces.enp2s1.ip4 = singleton {
-      address = let
-        addr = "45.62.237.203";
-      in assert config.krebs.build.host.nets.internet.ip4.addr == addr; addr;
-      prefixLength = 24;
-    };
-    defaultGateway = "45.62.237.1";
-    nameservers = ["8.8.8.8"];
-  };
-}

From e4422212d4e40189ee23ede2b404006039035bc8 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 02:04:52 +0200
Subject: [PATCH 11/40] krebs.on-failure: send journal since start of failed
 plan

---
 krebs/3modules/on-failure.nix | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/krebs/3modules/on-failure.nix b/krebs/3modules/on-failure.nix
index 13d561b8d..a471a4bc2 100644
--- a/krebs/3modules/on-failure.nix
+++ b/krebs/3modules/on-failure.nix
@@ -84,6 +84,14 @@
       ${pkgs.systemd}/bin/journalctl \
           --lines=${toString plan.journalctl.lines} \
           --output=${plan.journalctl.output} \
+          --since="$(
+            ${pkgs.coreutils}/bin/date +'%F %T UTC' -ud "$(
+              ${pkgs.systemd}/bin/systemctl show \
+                  -p ExecMainStartTimestamp \
+                  ${shell.escape plan.name} \
+                | ${pkgs.coreutils}/bin/cut -d= -f2-
+            )"
+          )" \
           --unit=${shell.escape plan.name}.service
     } | ${shell.escape cfg.sendmail} -t
   '';

From 904d037bd704d9690b8a9a8e8338950931e3ccd1 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 03:50:49 +0200
Subject: [PATCH 12/40] krebs.backup: allow injecting variables into dst shell

---
 krebs/3modules/backup.nix | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index d22dd3810..1cd851a4e 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -103,7 +103,8 @@ let
     plan.method == method &&
     config.krebs.build.host.name == plan.${side}.host.name;
 
-  start = plan: pkgs.writeDash "backup.${plan.name}" ''
+  start = plan: pkgs.writeScript "backup.${plan.name}" ''
+    #! ${pkgs.bash}/bin/bash
     set -efu
     ${getAttr plan.method {
       push = ''
@@ -116,12 +117,12 @@ let
         dst_path=${shell.escape plan.dst.path}
         dst=$dst_user@$dst_host:$dst_path
         echo "update snapshot: current; $src -> $dst" >&2
-        dst_shell() {
+        dst_exec() {
           exec ssh -F /dev/null \
               -i "$identity" \
               ''${dst_port:+-p $dst_port} \
               "$dst_user@$dst_host" \
-              -T "$with_dst_path_lock_script"
+              -T "exec$(printf ' %q' "$@")"
         }
         rsh="ssh -F /dev/null -i $identity ''${dst_port:+-p $dst_port}"
         local_rsync() {
@@ -142,8 +143,8 @@ let
         dst_path=${shell.escape plan.dst.path}
         dst=$dst_path
         echo "update snapshot: current; $dst <- $src" >&2
-        dst_shell() {
-          eval "$with_dst_path_lock_script"
+        dst_exec() {
+          exec "$@"
         }
         rsh="ssh -F /dev/null -i $identity ''${src_port:+-p $src_port}"
         local_rsync() {
@@ -153,13 +154,7 @@ let
         remote_rsync=rsync
       '';
     }}
-    # Note that this only works because we trust date +%s to produce output
-    # that doesn't need quoting when used to generate a command string.
-    # TODO relax this requirement by selectively allowing to inject variables
-    #   e.g.: ''${shell.quote "exec env NOW=''${shell.unquote "$NOW"} ..."}
-    with_dst_path_lock_script="exec env start_date=$(date +%s) "${shell.escape
-      "flock -n ${shell.escape plan.dst.path} /bin/sh"
-    }
+    start_date=$(date +%s)
     local_rsync >&2 \
         -aAXF --delete \
         --rsh="$rsh" \
@@ -167,7 +162,10 @@ let
         --link-dest="$dst_path/current" \
         "$src/" \
         "$dst/.partial"
-    dst_shell < ${toFile "backup.${plan.name}.take-snapshots" ''
+    dst_exec env \
+        start_date="$start_date" \
+        flock -n "$dst_path" \
+        /bin/sh < ${toFile "backup.${plan.name}.take-snapshots" ''
       set -efu
       : $start_date
 

From 453384b60b628f97074c74940e88570aa8eab811 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 03:51:55 +0200
Subject: [PATCH 13/40] krebs.backup: inject dst_path into dst shell

---
 krebs/3modules/backup.nix | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index 1cd851a4e..1e926429a 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -163,41 +163,40 @@ let
         "$src/" \
         "$dst/.partial"
     dst_exec env \
+        dst_path="$dst_path" \
         start_date="$start_date" \
         flock -n "$dst_path" \
         /bin/sh < ${toFile "backup.${plan.name}.take-snapshots" ''
       set -efu
-      : $start_date
+      : $dst_path $start_date
 
-      dst=${shell.escape plan.dst.path}
-
-      mv "$dst/current" "$dst/.previous"
-      mv "$dst/.partial" "$dst/current"
-      rm -fR "$dst/.previous"
+      mv "$dst_path/current" "$dst_path/.previous"
+      mv "$dst_path/.partial" "$dst_path/current"
+      rm -fR "$dst_path/.previous"
       echo >&2
 
       snapshot() {(
         : $ns $format $retain
         name=$(date --date="@$start_date" +"$format")
-        if ! test -e "$dst/$ns/$name"; then
+        if ! test -e "$dst_path/$ns/$name"; then
           echo >&2 "create snapshot: $ns/$name"
-          mkdir -m 0700 -p "$dst/$ns"
+          mkdir -m 0700 -p "$dst_path/$ns"
           rsync >&2 \
               -aAXF --delete \
-              --link-dest="$dst/current" \
-              "$dst/current/" \
-              "$dst/$ns/.partial.$name"
-          mv "$dst/$ns/.partial.$name" "$dst/$ns/$name"
+              --link-dest="$dst_path/current" \
+              "$dst_path/current/" \
+              "$dst_path/$ns/.partial.$name"
+          mv "$dst_path/$ns/.partial.$name" "$dst_path/$ns/$name"
           echo >&2
         fi
         case $retain in
           ([0-9]*)
             delete_from=$(($retain + 1))
-            ls -r "$dst/$ns" \
+            ls -r "$dst_path/$ns" \
               | sed -n "$delete_from,\$p" \
               | while read old_name; do
                   echo >&2 "delete snapshot: $ns/$old_name"
-                  rm -fR "$dst/$ns/$old_name"
+                  rm -fR "$dst_path/$ns/$old_name"
                 done
             ;;
           (ALL)

From affb69250d13f64d2be14327c1b47d23cadcb987 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 04:13:32 +0200
Subject: [PATCH 14/40] krebs.backup network-ssh-port: fail if cannot find port

---
 krebs/3modules/backup.nix  | 9 ++++++---
 krebs/3modules/default.nix | 2 +-
 krebs/4lib/types.nix       | 4 ++--
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index 1e926429a..e85a3dfa8 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -120,11 +120,11 @@ let
         dst_exec() {
           exec ssh -F /dev/null \
               -i "$identity" \
-              ''${dst_port:+-p $dst_port} \
+              -p $dst_port \
               "$dst_user@$dst_host" \
               -T "exec$(printf ' %q' "$@")"
         }
-        rsh="ssh -F /dev/null -i $identity ''${dst_port:+-p $dst_port}"
+        rsh="ssh -F /dev/null -i $identity -p $dst_port"
         local_rsync() {
           rsync "$@"
         }
@@ -146,7 +146,7 @@ let
         dst_exec() {
           exec "$@"
         }
-        rsh="ssh -F /dev/null -i $identity ''${src_port:+-p $src_port}"
+        rsh="ssh -F /dev/null -i $identity -p $src_port"
         local_rsync() {
           mkdir -m 0700 -p ${shell.escape plan.dst.path}/current
           flock -n ${shell.escape plan.dst.path} rsync "$@"
@@ -231,6 +231,9 @@ let
     ${concatStringsSep ";;\n" (mapAttrsToList
       (_: net: "(${head net.aliases}) echo ${toString net.ssh.port}")
       host.nets)};;
+    (*)
+      echo network-ssh-port: unhandled case: ${word} >&2
+      exit 1
     esac
   '';
 
diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index be530d46f..10c61b63a 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -218,7 +218,7 @@ let
                             (filter (hasSuffix ".${cfg.search-domain}")
                                     longs);
                       add-port = a:
-                        if net.ssh.port != null
+                        if net.ssh.port != 22
                           then "[${a}]:${toString net.ssh.port}"
                           else a;
                     in
diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index f46491801..405a91e45 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -117,8 +117,8 @@ types // rec {
         type = submodule {
           options = {
             port = mkOption {
-              type = nullOr int;
-              default = null;
+              type = int;
+              default = 22;
             };
           };
         };

From 6ec3d922a48ad6a583315a4433a7170e6850c676 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 05:24:33 +0200
Subject: [PATCH 15/40] krebs.backup network-ssh-port -> pkgs.get-ssh-port

---
 krebs/3modules/backup.nix            | 17 ++--------------
 krebs/5pkgs/default.nix              | 21 ++++++++++----------
 krebs/5pkgs/get-ssh-port/default.nix | 29 ++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+), 25 deletions(-)
 create mode 100644 krebs/5pkgs/get-ssh-port/default.nix

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index e85a3dfa8..f90081501 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -113,7 +113,7 @@ let
         src=$src_path
         dst_user=root
         dst_host=$(${fastest-address plan.dst.host})
-        dst_port=$(${network-ssh-port plan.dst.host "$dst_host"})
+        dst_port=$(${pkgs.get-ssh-port}/bin/get-ssh-port "$dst_host")
         dst_path=${shell.escape plan.dst.path}
         dst=$dst_user@$dst_host:$dst_path
         echo "update snapshot: current; $src -> $dst" >&2
@@ -137,7 +137,7 @@ let
         identity=${shell.escape plan.dst.host.ssh.privkey.path}
         src_user=root
         src_host=$(${fastest-address plan.src.host})
-        src_port=$(${network-ssh-port plan.src.host "$src_host"})
+        src_port=$(${pkgs.get-ssh-port}/bin/get-ssh-port "$src_host")
         src_path=${shell.escape plan.src.path}
         src=$src_user@$src_host:$src_path
         dst_path=${shell.escape plan.dst.path}
@@ -224,19 +224,6 @@ let
       | ${pkgs.coreutils}/bin/head -1; }
   '';
 
-  # Note that we don't escape word on purpose, so we can deref shell vars.
-  # TODO type word
-  network-ssh-port = host: word: ''
-    case ${word} in
-    ${concatStringsSep ";;\n" (mapAttrsToList
-      (_: net: "(${head net.aliases}) echo ${toString net.ssh.port}")
-      host.nets)};;
-    (*)
-      echo network-ssh-port: unhandled case: ${word} >&2
-      exit 1
-    esac
-  '';
-
 in out
 # TODO ionice
 # TODO mail on failed push, pull
diff --git a/krebs/5pkgs/default.nix b/krebs/5pkgs/default.nix
index 0c39324a7..5ec0d54e9 100644
--- a/krebs/5pkgs/default.nix
+++ b/krebs/5pkgs/default.nix
@@ -14,7 +14,16 @@ with config.krebs.lib;
       then trace "Upstream `${upstream.name}' gets overridden by `${override.name}'." override
       else override;
 
-  in {
+  in {}
+  // import ./builders.nix args
+  // mapAttrs (_: flip callPackage {})
+              (filterAttrs (_: dir.has-default-nix)
+                           (subdirsOf ./.))
+  // {
+    get-ssh-port = callPackage ./get-ssh-port {
+      inherit config;
+    };
+
     haskellPackages = pkgs.haskellPackages.override {
       overrides = self: super:
         mapAttrs (name: path: self.callPackage path {})
@@ -29,18 +38,10 @@ with config.krebs.lib;
             (builtins.readDir ./haskell-overrides));
     };
 
-    push = callPackage ./push {
-      inherit (subdirs) get;
-    };
-
     ReaktorPlugins = callPackage ./Reaktor/plugins.nix {};
 
     test = {
       infest-cac-centos7 = callPackage ./test/infest-cac-centos7 {};
     };
-  }
-  // import ./builders.nix args
-  // mapAttrs (_: flip callPackage {})
-              (filterAttrs (_: dir.has-default-nix)
-                           (subdirsOf ./.));
+  };
 }
diff --git a/krebs/5pkgs/get-ssh-port/default.nix b/krebs/5pkgs/get-ssh-port/default.nix
new file mode 100644
index 000000000..2d106b2b6
--- /dev/null
+++ b/krebs/5pkgs/get-ssh-port/default.nix
@@ -0,0 +1,29 @@
+{ config, pkgs, ... }: with config.krebs.lib;
+
+pkgs.writeScriptBin "get-ssh-port" ''
+  #! ${pkgs.dash}/bin/dash
+  set -efu
+  if test $# != 1 || test $1 = -h || test $1 = --help; then
+    echo "usage: get-ssh-port HOSTNAME" >&2
+    exit 23
+  fi
+  case $1 in
+  ${concatMapStringsSep ";;\n"
+    (host: toString [
+      "(${shell.escape host.name})"
+      "echo ${toString host.nets.${config.krebs.search-domain}.ssh.port}"
+    ])
+    (filter (host: hasAttr config.krebs.search-domain host.nets)
+            (attrValues config.krebs.hosts))
+  };;
+  ${concatMapStringsSep ";;\n"
+    (net: toString [
+      "(${concatMapStringsSep "|" shell.escape net.aliases})"
+      "echo ${toString net.ssh.port}"
+    ])
+    (concatMap (host: attrValues host.nets) (attrValues config.krebs.hosts))
+  };;
+  (*) echo "get-ssh-port: don't know ssh port of $1" >&2
+      exit 1
+  esac
+''

From 70c27e21b1a31aac678a0a19127d86395e2b115e Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 05:26:02 +0200
Subject: [PATCH 16/40] krebs.backup: rm stale TODO

Done in 13df24f8f09469c32077ded463d99033042e25ee
---
 krebs/3modules/backup.nix | 1 -
 1 file changed, 1 deletion(-)

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index f90081501..22c860b87 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -226,7 +226,6 @@ let
 
 in out
 # TODO ionice
-# TODO mail on failed push, pull
 # TODO mail on missing push
 # TODO don't cancel plans on activation
 #   also, don't hang while deploying at:

From 377b0dff1ca075a9b57660d8e2ec3596fd3e08e7 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 06:00:48 +0200
Subject: [PATCH 17/40] krebs.backup: don't create plan.dst.path implicitly

---
 krebs/3modules/backup.nix | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index 22c860b87..4172c9800 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -129,6 +129,7 @@ let
           rsync "$@"
         }
         remote_rsync=${shell.escape (concatStringsSep " && " [
+          "stat ${shell.escape plan.dst.path} >/dev/null"
           "mkdir -m 0700 -p ${shell.escape plan.dst.path}/current"
           "exec flock -n ${shell.escape plan.dst.path} rsync"
         ])}
@@ -148,6 +149,7 @@ let
         }
         rsh="ssh -F /dev/null -i $identity -p $src_port"
         local_rsync() {
+          stat ${shell.escape plan.dst.path} >/dev/null
           mkdir -m 0700 -p ${shell.escape plan.dst.path}/current
           flock -n ${shell.escape plan.dst.path} rsync "$@"
         }
@@ -230,7 +232,6 @@ in out
 # TODO don't cancel plans on activation
 #   also, don't hang while deploying at:
 #   starting the following units: backup.wu-home-xu.push.service, backup.wu-home-xu.push.timer
-# TODO make sure /bku is properly mounted
 # TODO make sure that secure hosts cannot backup to insecure ones
 # TODO optionally only backup when src and dst are near enough :)
 # TODO try using btrfs for snapshots (configurable)

From f5f7abce0d343c20a35bb12c49d03c5bf544d8a9 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 10:23:01 +0200
Subject: [PATCH 18/40] krebs: programs.ssh.extraConfig += Host ... Port ...

---
 krebs/3modules/default.nix | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 10c61b63a..9dac50d55 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -228,8 +228,25 @@ let
             publicKey = host.ssh.pubkey;
           })
           (filterAttrs (_: host: host.ssh.pubkey != null) cfg.hosts);
+
+      programs.ssh.extraConfig = concatMapStrings
+        (net: ''
+          Host ${toString (net.aliases ++ net.addrs)}
+            Port ${toString net.ssh.port}
+        '')
+        (filter
+          (net: net.ssh.port != 22)
+          (concatMap (host: attrValues host.nets)
+            (mapAttrsToList
+              (_: host: recursiveUpdate host
+                (optionalAttrs (hasAttr config.krebs.search-domain host.nets) {
+                  nets."" = host.nets.${config.krebs.search-domain} // {
+                    aliases = [host.name];
+                    addrs = [];
+                  };
+                }))
+              config.krebs.hosts)));
     }
   ];
 
-in
-out
+in out

From 41ff57c6d6a7ed4d8562169c0d3fd9d6adb949e6 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 10:25:59 +0200
Subject: [PATCH 19/40] krebs.backup: use globally configured ssh ports

---
 krebs/3modules/backup.nix            | 99 +++++++++++++---------------
 krebs/5pkgs/default.nix              |  4 --
 krebs/5pkgs/get-ssh-port/default.nix | 29 --------
 3 files changed, 44 insertions(+), 88 deletions(-)
 delete mode 100644 krebs/5pkgs/get-ssh-port/default.nix

diff --git a/krebs/3modules/backup.nix b/krebs/3modules/backup.nix
index 4172c9800..71b22d8cb 100644
--- a/krebs/3modules/backup.nix
+++ b/krebs/3modules/backup.nix
@@ -103,74 +103,63 @@ let
     plan.method == method &&
     config.krebs.build.host.name == plan.${side}.host.name;
 
-  start = plan: pkgs.writeScript "backup.${plan.name}" ''
+  start = plan: let
+    login-name = "root";
+    identity = local.host.ssh.privkey.path;
+    ssh = "ssh -i ${shell.escape identity}";
+    local = getAttr plan.method {
+      push = plan.src // { rsync = src-rsync; };
+      pull = plan.dst // { rsync = dst-rsync; };
+    };
+    remote = getAttr plan.method {
+      push = plan.dst // { rsync = dst-rsync; };
+      pull = plan.src // { rsync = src-rsync; };
+    };
+    src-rsync = "rsync";
+    dst-rsync = concatStringsSep " && " [
+      "stat ${shell.escape plan.dst.path} >/dev/null"
+      "mkdir -m 0700 -p ${shell.escape plan.dst.path}/current"
+      "flock -n ${shell.escape plan.dst.path} rsync"
+    ];
+  in pkgs.writeScript "backup.${plan.name}" ''
     #! ${pkgs.bash}/bin/bash
     set -efu
+    start_date=$(date +%s)
+    ssh_target=${shell.escape login-name}@$(${fastest-address remote.host})
     ${getAttr plan.method {
       push = ''
-        identity=${shell.escape plan.src.host.ssh.privkey.path}
-        src_path=${shell.escape plan.src.path}
-        src=$src_path
-        dst_user=root
-        dst_host=$(${fastest-address plan.dst.host})
-        dst_port=$(${pkgs.get-ssh-port}/bin/get-ssh-port "$dst_host")
-        dst_path=${shell.escape plan.dst.path}
-        dst=$dst_user@$dst_host:$dst_path
-        echo "update snapshot: current; $src -> $dst" >&2
-        dst_exec() {
-          exec ssh -F /dev/null \
-              -i "$identity" \
-              -p $dst_port \
-              "$dst_user@$dst_host" \
-              -T "exec$(printf ' %q' "$@")"
-        }
-        rsh="ssh -F /dev/null -i $identity -p $dst_port"
-        local_rsync() {
-          rsync "$@"
-        }
-        remote_rsync=${shell.escape (concatStringsSep " && " [
-          "stat ${shell.escape plan.dst.path} >/dev/null"
-          "mkdir -m 0700 -p ${shell.escape plan.dst.path}/current"
-          "exec flock -n ${shell.escape plan.dst.path} rsync"
-        ])}
+        rsync_src=${shell.escape plan.src.path}
+        rsync_dst=$ssh_target:${shell.escape plan.dst.path}
+        echo >&2 "update snapshot current; $rsync_src -> $rsync_dst"
       '';
       pull = ''
-        identity=${shell.escape plan.dst.host.ssh.privkey.path}
-        src_user=root
-        src_host=$(${fastest-address plan.src.host})
-        src_port=$(${pkgs.get-ssh-port}/bin/get-ssh-port "$src_host")
-        src_path=${shell.escape plan.src.path}
-        src=$src_user@$src_host:$src_path
-        dst_path=${shell.escape plan.dst.path}
-        dst=$dst_path
-        echo "update snapshot: current; $dst <- $src" >&2
-        dst_exec() {
-          exec "$@"
-        }
-        rsh="ssh -F /dev/null -i $identity -p $src_port"
-        local_rsync() {
-          stat ${shell.escape plan.dst.path} >/dev/null
-          mkdir -m 0700 -p ${shell.escape plan.dst.path}/current
-          flock -n ${shell.escape plan.dst.path} rsync "$@"
-        }
-        remote_rsync=rsync
+        rsync_src=$ssh_target:${shell.escape plan.src.path}
+        rsync_dst=${shell.escape plan.dst.path}
+        echo >&2 "update snapshot current; $rsync_dst <- $rsync_src"
       '';
     }}
-    start_date=$(date +%s)
-    local_rsync >&2 \
+    ${local.rsync} >&2 \
         -aAXF --delete \
-        --rsh="$rsh" \
-        --rsync-path="$remote_rsync" \
-        --link-dest="$dst_path/current" \
-        "$src/" \
-        "$dst/.partial"
+        --rsh=${shell.escape ssh} \
+        --rsync-path=${shell.escape remote.rsync} \
+        --link-dest=${shell.escape plan.dst.path}/current \
+        "$rsync_src/" \
+        "$rsync_dst/.partial"
+
+    dst_exec() {
+      ${getAttr plan.method {
+        push = ''exec ${ssh} "$ssh_target" -T "exec$(printf ' %q' "$@")"'';
+        pull = ''exec "$@"'';
+      }}
+    }
     dst_exec env \
-        dst_path="$dst_path" \
         start_date="$start_date" \
-        flock -n "$dst_path" \
+        flock -n ${shell.escape plan.dst.path} \
         /bin/sh < ${toFile "backup.${plan.name}.take-snapshots" ''
       set -efu
-      : $dst_path $start_date
+      : $start_date
+
+      dst_path=${shell.escape plan.dst.path}
 
       mv "$dst_path/current" "$dst_path/.previous"
       mv "$dst_path/.partial" "$dst_path/current"
diff --git a/krebs/5pkgs/default.nix b/krebs/5pkgs/default.nix
index 5ec0d54e9..bcc894b2c 100644
--- a/krebs/5pkgs/default.nix
+++ b/krebs/5pkgs/default.nix
@@ -20,10 +20,6 @@ with config.krebs.lib;
               (filterAttrs (_: dir.has-default-nix)
                            (subdirsOf ./.))
   // {
-    get-ssh-port = callPackage ./get-ssh-port {
-      inherit config;
-    };
-
     haskellPackages = pkgs.haskellPackages.override {
       overrides = self: super:
         mapAttrs (name: path: self.callPackage path {})
diff --git a/krebs/5pkgs/get-ssh-port/default.nix b/krebs/5pkgs/get-ssh-port/default.nix
deleted file mode 100644
index 2d106b2b6..000000000
--- a/krebs/5pkgs/get-ssh-port/default.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-{ config, pkgs, ... }: with config.krebs.lib;
-
-pkgs.writeScriptBin "get-ssh-port" ''
-  #! ${pkgs.dash}/bin/dash
-  set -efu
-  if test $# != 1 || test $1 = -h || test $1 = --help; then
-    echo "usage: get-ssh-port HOSTNAME" >&2
-    exit 23
-  fi
-  case $1 in
-  ${concatMapStringsSep ";;\n"
-    (host: toString [
-      "(${shell.escape host.name})"
-      "echo ${toString host.nets.${config.krebs.search-domain}.ssh.port}"
-    ])
-    (filter (host: hasAttr config.krebs.search-domain host.nets)
-            (attrValues config.krebs.hosts))
-  };;
-  ${concatMapStringsSep ";;\n"
-    (net: toString [
-      "(${concatMapStringsSep "|" shell.escape net.aliases})"
-      "echo ${toString net.ssh.port}"
-    ])
-    (concatMap (host: attrValues host.nets) (attrValues config.krebs.hosts))
-  };;
-  (*) echo "get-ssh-port: don't know ssh port of $1" >&2
-      exit 1
-  esac
-''

From 066381dff01f51dd24a829d6cf9de9f6465534f3 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sun, 17 Apr 2016 11:48:54 +0200
Subject: [PATCH 20/40] tv.git: irc-announce only at cd

---
 tv/2configs/git.nix | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tv/2configs/git.nix b/tv/2configs/git.nix
index 4c1fba59a..2e5fc301b 100644
--- a/tv/2configs/git.nix
+++ b/tv/2configs/git.nix
@@ -71,13 +71,13 @@ let
   make-public-repo = name: { desc ? null, section ? null, ... }: {
     inherit name desc section;
     public = true;
-    hooks = {
+    hooks = optionalAttrs (config.krebs.build.host.name == "cd") {
       post-receive = pkgs.git-hooks.irc-announce {
         # TODO make nick = config.krebs.build.host.name the default
         nick = config.krebs.build.host.name;
         channel = "#retiolum";
         server = "cd.retiolum";
-        verbose = config.krebs.build.host.name == "cd";
+        verbose = true;
       };
     };
   };

From 54947849ffbe27e4d0123f649b79264c6da47763 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 20 Apr 2016 16:03:02 +0200
Subject: [PATCH 21/40] tv: "fix" PGP key

---
 krebs/3modules/tv/default.nix | 1 +
 1 file changed, 1 insertion(+)

diff --git a/krebs/3modules/tv/default.nix b/krebs/3modules/tv/default.nix
index a44aa552f..711121a40 100644
--- a/krebs/3modules/tv/default.nix
+++ b/krebs/3modules/tv/default.nix
@@ -362,6 +362,7 @@ with config.krebs.lib;
       mail = "tv@nomic.retiolum";
       pgp.pubkeys.default = ''
         -----BEGIN PGP PUBLIC KEY BLOCK-----
+
         mQINBFbJ/B0BEADZx8l5gRurzhEHcc3PbBepdZqDJQZ2cGHixi8VEk9iN25qJO5y
         HB0q5sQRsh7oNCbzKp6qRhaG9kXmEda+Uu+qbHWxE32QcT76+W8npH73qthaFwC/
         5RA8KcSE8/XFxVBnVb14PNVHyAVxPHawawbhsOeaiZcHrq5IF6sVzcsc2KN87sIE

From 6121befdb64cccf9ff9a562b42217289c43c67f4 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 26 Apr 2016 23:58:36 +0200
Subject: [PATCH 22/40] wu: disable tor

---
 tv/1systems/wu.nix | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tv/1systems/wu.nix b/tv/1systems/wu.nix
index 27dd12520..cebd7c9e4 100644
--- a/tv/1systems/wu.nix
+++ b/tv/1systems/wu.nix
@@ -183,7 +183,5 @@ with config.krebs.lib;
     KERNEL=="hpet", GROUP="audio"
   '';
 
-  services.tor.client.enable = true;
-  services.tor.enable = true;
   services.virtualboxHost.enable = true;
 }

From 87dabec64d9dbe35f1fcc35b7b4c8ab00a02cf84 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 01:33:39 +0200
Subject: [PATCH 23/40] krebs types.group: init

---
 krebs/4lib/types.nix | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/krebs/4lib/types.nix b/krebs/4lib/types.nix
index 405a91e45..56d1d55c3 100644
--- a/krebs/4lib/types.nix
+++ b/krebs/4lib/types.nix
@@ -213,6 +213,18 @@ types // rec {
       };
     };
   });
+  group = submodule ({ config, ... }: {
+    options = {
+      name = mkOption {
+        type = username;
+        default = config._module.args.name;
+      };
+      gid = mkOption {
+        type = int;
+        default = genid config.name;
+      };
+    };
+  });
 
   addr = either addr4 addr6;
   addr4 = mkOptionType {

From f9d42f3a814a316b3dc0a517b76d6dadcfa8b6a8 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 01:03:47 +0200
Subject: [PATCH 24/40] import NixOS' services.exim

---
 krebs/3modules/exim.nix | 111 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 krebs/3modules/exim.nix

diff --git a/krebs/3modules/exim.nix b/krebs/3modules/exim.nix
new file mode 100644
index 000000000..e0890d96a
--- /dev/null
+++ b/krebs/3modules/exim.nix
@@ -0,0 +1,111 @@
+{ config, lib, pkgs, ... }:
+
+let
+  inherit (lib) mkIf mkOption singleton types;
+  inherit (pkgs) coreutils exim;
+  cfg = config.services.exim;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.exim = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Exim mail transfer agent.";
+      };
+
+      config = mkOption {
+        type = types.string;
+        default = "";
+        description = ''
+          Verbatim Exim configuration.  This should not contain exim_user,
+          exim_group, exim_path, or spool_directory.
+        '';
+      };
+
+      user = mkOption {
+        type = types.string;
+        default = "exim";
+        description = ''
+          User to use when no root privileges are required.
+          In particular, this applies when receiving messages and when doing
+          remote deliveries.  (Local deliveries run as various non-root users,
+          typically as the owner of a local mailbox.) Specifying this value
+          as root is not supported.
+        '';
+      };
+
+      group = mkOption {
+        type = types.string;
+        default = "exim";
+        description = ''
+          Group to use when no root privileges are required.
+        '';
+      };
+
+      spoolDir = mkOption {
+        type = types.string;
+        default = "/var/spool/exim";
+        description = ''
+          Location of the spool directory of exim.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment = {
+      etc."exim.conf".text = ''
+        exim_user = ${cfg.user}
+        exim_group = ${cfg.group}
+        exim_path = /var/setuid-wrappers/exim
+        spool_directory = ${cfg.spoolDir}
+        ${cfg.config}
+      '';
+      systemPackages = [ exim ];
+    };
+
+    users.extraUsers = singleton {
+      name = cfg.user;
+      description = "Exim mail transfer agent user";
+      uid = config.ids.uids.exim;
+      group = cfg.group;
+    };
+
+    users.extraGroups = singleton {
+      name = cfg.group;
+      gid = config.ids.gids.exim;
+    };
+
+    security.setuidPrograms = [ "exim" ];
+
+    systemd.services.exim = {
+      description = "Exim Mail Daemon";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart   = "${exim}/bin/exim -bdf -q30m";
+        ExecReload  = "${coreutils}/bin/kill -HUP $MAINPID";
+      };
+      preStart = ''
+        if ! test -d ${cfg.spoolDir}; then
+          ${coreutils}/bin/mkdir -p ${cfg.spoolDir}
+          ${coreutils}/bin/chown ${cfg.user}:${cfg.group} ${cfg.spoolDir}
+        fi
+      '';
+    };
+
+  };
+
+}

From 96301634b906182be0d8a5d669481da309f4a17a Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 01:10:25 +0200
Subject: [PATCH 25/40] services.exim -> krebs.exim

---
 krebs/3modules/default.nix |   1 +
 krebs/3modules/exim.nix    | 167 +++++++++++++++----------------------
 2 files changed, 69 insertions(+), 99 deletions(-)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 9dac50d55..e87b33600 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -13,6 +13,7 @@ let
       ./buildbot/slave.nix
       ./build.nix
       ./current.nix
+      ./exim.nix
       ./exim-retiolum.nix
       ./exim-smarthost.nix
       ./fetchWallpaper.nix
diff --git a/krebs/3modules/exim.nix b/krebs/3modules/exim.nix
index e0890d96a..16a2a37b6 100644
--- a/krebs/3modules/exim.nix
+++ b/krebs/3modules/exim.nix
@@ -1,111 +1,80 @@
-{ config, lib, pkgs, ... }:
-
-let
-  inherit (lib) mkIf mkOption singleton types;
-  inherit (pkgs) coreutils exim;
-  cfg = config.services.exim;
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.exim = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable the Exim mail transfer agent.";
-      };
-
-      config = mkOption {
-        type = types.string;
-        default = "";
-        description = ''
-          Verbatim Exim configuration.  This should not contain exim_user,
-          exim_group, exim_path, or spool_directory.
-        '';
-      };
-
-      user = mkOption {
-        type = types.string;
-        default = "exim";
-        description = ''
-          User to use when no root privileges are required.
-          In particular, this applies when receiving messages and when doing
-          remote deliveries.  (Local deliveries run as various non-root users,
-          typically as the owner of a local mailbox.) Specifying this value
-          as root is not supported.
-        '';
-      };
-
-      group = mkOption {
-        type = types.string;
-        default = "exim";
-        description = ''
-          Group to use when no root privileges are required.
-        '';
-      };
-
-      spoolDir = mkOption {
-        type = types.string;
-        default = "/var/spool/exim";
-        description = ''
-          Location of the spool directory of exim.
-        '';
-      };
-
+{ config, lib, pkgs, ... }: with config.krebs.lib; let
+  cfg = config.krebs.exim;
+in {
+  options.krebs.exim = {
+    enable = mkEnableOption "krebs.exim";
+    config = mkOption {
+      type = types.str;
+      default = "";
+      description = ''
+        Verbatim Exim configuration.  This should not contain exim_user,
+        exim_group, exim_path, or spool_directory.
+      '';
+    };
+    user = mkOption {
+      type = types.user;
+      default = {
+        name = "exim";
+        home = "/var/spool/exim";
+      };
+      description = ''
+        User to use when no root privileges are required.
+        In particular, this applies when receiving messages and when doing
+        remote deliveries.  (Local deliveries run as various non-root users,
+        typically as the owner of a local mailbox.) Specifying this value
+        as root is not supported.
+      '';
+    };
+    group = mkOption {
+      type = types.group;
+      default = {
+        name = "exim";
+      };
+      description = ''
+        Group to use when no root privileges are required.
+      '';
     };
-
   };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
+  config = lib.mkIf cfg.enable {
     environment = {
       etc."exim.conf".text = ''
-        exim_user = ${cfg.user}
-        exim_group = ${cfg.group}
+        exim_user = ${cfg.user.name}
+        exim_group = ${cfg.group.name}
         exim_path = /var/setuid-wrappers/exim
-        spool_directory = ${cfg.spoolDir}
+        spool_directory = ${cfg.user.home}
         ${cfg.config}
       '';
-      systemPackages = [ exim ];
+      systemPackages = [ pkgs.exim ];
     };
-
-    users.extraUsers = singleton {
-      name = cfg.user;
-      description = "Exim mail transfer agent user";
-      uid = config.ids.uids.exim;
-      group = cfg.group;
-    };
-
-    users.extraGroups = singleton {
-      name = cfg.group;
-      gid = config.ids.gids.exim;
-    };
-
-    security.setuidPrograms = [ "exim" ];
-
-    systemd.services.exim = {
-      description = "Exim Mail Daemon";
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig = {
-        ExecStart   = "${exim}/bin/exim -bdf -q30m";
-        ExecReload  = "${coreutils}/bin/kill -HUP $MAINPID";
+    krebs.setuid = {
+      exim = {
+        filename = "${pkgs.exim}/bin/exim";
+        mode = "4111";
+      };
+      sendmail = {
+        filename = "${pkgs.exim}/bin/exim";
+        mode = "4111";
+      };
+    };
+    systemd.services.exim = {
+      restartTriggers = [
+        config.environment.etc."exim.conf".source
+      ];
+      serviceConfig = {
+        ExecStart = "${pkgs.exim}/bin/exim -bdf -q30m";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+      wantedBy = [ "multi-user.target" ];
+    };
+    users = {
+      groups.${cfg.group.name} = {
+        inherit (cfg.group) name gid;
+      };
+      users.${cfg.user.name} = {
+        inherit (cfg.user) home name uid;
+        createHome = true;
+        group = cfg.group.name;
       };
-      preStart = ''
-        if ! test -d ${cfg.spoolDir}; then
-          ${coreutils}/bin/mkdir -p ${cfg.spoolDir}
-          ${coreutils}/bin/chown ${cfg.user}:${cfg.group} ${cfg.spoolDir}
-        fi
-      '';
     };
-
   };
-
 }

From 4abd59f59d8541a93ccbf1e76d1f9b95c44a9bf2 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 01:54:58 +0200
Subject: [PATCH 26/40] krebs.exim-{retiolum,smarthost}: use krebs.exim

---
 krebs/3modules/exim-retiolum.nix  | 2 +-
 krebs/3modules/exim-smarthost.nix | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/exim-retiolum.nix b/krebs/3modules/exim-retiolum.nix
index 696c48baf..8b6ac4a4e 100644
--- a/krebs/3modules/exim-retiolum.nix
+++ b/krebs/3modules/exim-retiolum.nix
@@ -32,7 +32,7 @@ let
   };
 
   imp = {
-    services.exim = {
+    krebs.exim = {
       enable = true;
       config =
         # This configuration makes only sense for retiolum-enabled hosts.
diff --git a/krebs/3modules/exim-smarthost.nix b/krebs/3modules/exim-smarthost.nix
index a01ab543b..8d9227039 100644
--- a/krebs/3modules/exim-smarthost.nix
+++ b/krebs/3modules/exim-smarthost.nix
@@ -105,7 +105,7 @@ let
         requires = [ "secret.service" ];
       };
     };
-    services.exim = {
+    krebs.exim = {
       enable = true;
       config = ''
         keep_environment =

From 92605d46b2d770b4724809fcb2267c1618ae0b59 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 02:00:26 +0200
Subject: [PATCH 27/40] tv exim: drop krebs.setuid.sendmail

---
 tv/2configs/exim-retiolum.nix  | 4 ----
 tv/2configs/exim-smarthost.nix | 4 ----
 2 files changed, 8 deletions(-)

diff --git a/tv/2configs/exim-retiolum.nix b/tv/2configs/exim-retiolum.nix
index dbe83dcf1..9197a3c30 100644
--- a/tv/2configs/exim-retiolum.nix
+++ b/tv/2configs/exim-retiolum.nix
@@ -4,9 +4,5 @@ with config.krebs.lib;
 
 {
   krebs.exim-retiolum.enable = true;
-  krebs.setuid.sendmail = {
-    filename = "${pkgs.exim}/bin/exim";
-    mode = "4111";
-  };
   tv.iptables.input-retiolum-accept-new-tcp = singleton "smtp";
 }
diff --git a/tv/2configs/exim-smarthost.nix b/tv/2configs/exim-smarthost.nix
index 2b9ad77d7..3616a8f52 100644
--- a/tv/2configs/exim-smarthost.nix
+++ b/tv/2configs/exim-smarthost.nix
@@ -43,9 +43,5 @@ with config.krebs.lib;
       { from = "mirko"; to = "mv"; }
     ];
   };
-  krebs.setuid.sendmail = {
-    filename = "${pkgs.exim}/bin/exim";
-    mode = "4111";
-  };
   tv.iptables.input-internet-accept-new-tcp = singleton "smtp";
 }

From 1241c61b8867b46a572605a69dd9b1fead65aa2b Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Wed, 27 Apr 2016 02:24:20 +0200
Subject: [PATCH 28/40] test-all-krebs-modules: disable exim-retiolum

---
 shared/1systems/test-all-krebs-modules.nix | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/shared/1systems/test-all-krebs-modules.nix b/shared/1systems/test-all-krebs-modules.nix
index 5c3ba9421..0084a7837 100644
--- a/shared/1systems/test-all-krebs-modules.nix
+++ b/shared/1systems/test-all-krebs-modules.nix
@@ -19,10 +19,11 @@ in {
       username = "lol";
       password = "wut";
     };
-    exim-retiolum = {
-      enable = true;
-      primary_hostname = "test.r";
-    };
+    # XXX exim-retiolum and exim-smarthost are mutually exclusive
+    #exim-retiolum = {
+    #  enable = true;
+    #  primary_hostname = "test.r";
+    #};
     exim-smarthost = {
       enable = true;
       primary_hostname = "test.r";

From 9b0edc2ee8c7158ba0c78d73950f22b8b186de75 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 28 Apr 2016 22:24:44 +0200
Subject: [PATCH 29/40] krebs.build.populate: set SSL_CERT_FILE

---
 krebs/3modules/build.nix | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/krebs/3modules/build.nix b/krebs/3modules/build.nix
index d4c6b08df..9cd095622 100644
--- a/krebs/3modules/build.nix
+++ b/krebs/3modules/build.nix
@@ -88,6 +88,8 @@ let
           #! /bin/sh
           set -efu
 
+          export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
+
           verbose() {
             printf '%s%s\n' "$PS5$(printf ' %q' "$@")" >&2
             "$@"

From 289231f1974c6ce4b6794060bc6b80d236b3e4fc Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 19 May 2016 15:05:16 +0200
Subject: [PATCH 30/40] exim-smarthost: add eloop2016 ML

---
 krebs/3modules/default.nix | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index e87b33600..cbd6975a4 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -158,7 +158,10 @@ let
           makefu
           tv
         ];
+        ciko.mail = "ciko@shackspace.de";
+        Mic92.mail = "joerg@higgsboson.tk";
       in {
+        "eloop2016@krebsco.de" = spam-ml ++ [ ciko Mic92 ];
         "postmaster@krebsco.de" = spam-ml; # RFC 822
         "lass@krebsco.de" = lass;
         "makefu@krebsco.de" = makefu;

From c40ff531b4b63ff76b37be19c11d754277dfb6ed Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 19 May 2016 15:18:26 +0200
Subject: [PATCH 31/40] exim-smarthost: cfp@eloop.org -> eloop2016 ML

---
 krebs/3modules/default.nix | 1 +
 1 file changed, 1 insertion(+)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index cbd6975a4..1c56bfbfe 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -161,6 +161,7 @@ let
         ciko.mail = "ciko@shackspace.de";
         Mic92.mail = "joerg@higgsboson.tk";
       in {
+        "cfp@eloop.org" = [{ mail = "eloop2016@krebsco.de"; }];
         "eloop2016@krebsco.de" = spam-ml ++ [ ciko Mic92 ];
         "postmaster@krebsco.de" = spam-ml; # RFC 822
         "lass@krebsco.de" = lass;

From ee0c30cbe5a5614e7f5f2e6edc13fb0c7c434ad4 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Thu, 19 May 2016 15:43:06 +0200
Subject: [PATCH 32/40] exim-smarthost: update ciko's mail

---
 krebs/3modules/default.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 1c56bfbfe..2f3c20906 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -158,7 +158,7 @@ let
           makefu
           tv
         ];
-        ciko.mail = "ciko@shackspace.de";
+        ciko.mail = "wieczorek.stefan@gmail.com";
         Mic92.mail = "joerg@higgsboson.tk";
       in {
         "cfp@eloop.org" = [{ mail = "eloop2016@krebsco.de"; }];

From 28d623cf98b5d5b0f23b1b7761c884b8631b8f78 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 20 May 2016 02:52:23 +0200
Subject: [PATCH 33/40] Makefile: disable default goal

---
 Makefile | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Makefile b/Makefile
index 7252ca70e..58a46c643 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,10 @@ execute = \
 	script=$$(echo "$$result" | jq -r .) && \
 	echo "$$script" | PS5=% sh
 
+ifeq ($(MAKECMDGOALS),)
+$(error No goals specified)
+endif
+
 # usage: make deploy system=foo [target_host=bar]
 deploy: ssh ?= ssh
 deploy:

From 47a9308fc9eb41f7fe1f5d160a45e6a23e9f12d1 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 20 May 2016 03:02:35 +0200
Subject: [PATCH 34/40] Makefile evaluate: provide access to all of stockholm

---
 Makefile | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile
index 58a46c643..d3823077e 100644
--- a/Makefile
+++ b/Makefile
@@ -54,9 +54,7 @@ evaluate = \
 		--show-trace \
 		-I nixos-config=$(nixos-config) \
 		-I stockholm=$(stockholm) \
-		-E '{ eval, f }: f eval' \
-		--arg eval 'import ./.' \
-		--arg f "eval@{ config, ... }: $(1)"
+		-E "let eval = import <stockholm>; in with eval; $(1)"
 
 execute = \
 	result=$$($(call evaluate,config.krebs.build.$(1))) && \
@@ -77,7 +75,7 @@ deploy:
 
 # usage: make LOGNAME=shared system=wolf eval.config.krebs.build.host.name
 eval eval.:;@$(call evaluate,$${expr-eval})
-eval.%:;@$(call evaluate,$*)
+eval.%:;@$(call evaluate,$@)
 
 # usage: make install system=foo [target_host=bar]
 install: ssh ?= ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null

From 8014be4f2e0a5d9091150d2e4944706c31e4a62d Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Fri, 20 May 2016 03:21:56 +0200
Subject: [PATCH 35/40] Makefile system: add default value

---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index d3823077e..a74e3a877 100644
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,7 @@ export STOCKHOLM_VERSION ?= $(shell \
 	printf '%s' "$$date.$$version"; \
 )
 
+system ?= $(HOSTNAME)
 $(if $(system),,$(error unbound variable: system))
 
 nixos-config ?= $(stockholm)/$(LOGNAME)/1systems/$(system).nix

From ca48a77050933cab8114d9047e2e9c72a5496f0b Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sat, 21 May 2016 09:27:55 +0200
Subject: [PATCH 36/40] exim-smarthost: allow per-domain defaults in
 internet-aliases

---
 krebs/3modules/exim-smarthost.nix | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/exim-smarthost.nix b/krebs/3modules/exim-smarthost.nix
index 8d9227039..aba6ee0b5 100644
--- a/krebs/3modules/exim-smarthost.nix
+++ b/krebs/3modules/exim-smarthost.nix
@@ -164,7 +164,7 @@ let
                   control       = dkim_disable_verify
 
           accept message = relay not permitted 2
-                  recipients = lsearch;${lsearch.internet-aliases}
+                  recipients = lsearch*@;${lsearch.internet-aliases}
 
           require message = relay not permitted
                   domains = +local_domains : +relay_to_domains
@@ -198,7 +198,7 @@ let
         internet_aliases:
           debug_print = "R: internet_aliases for $local_part@$domain"
           driver = redirect
-          data = ''${lookup{$local_part@$domain}lsearch{${lsearch.internet-aliases}}}
+          data = ''${lookup{$local_part@$domain}lsearch*@{${lsearch.internet-aliases}}}
 
         dnslookup:
           debug_print = "R: dnslookup for $local_part@$domain"

From 1e9199f93920d794789c8585b7cb196372f4864e Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sat, 21 May 2016 09:28:50 +0200
Subject: [PATCH 37/40] krebs internet-aliases: *@eloop.org ->
 eloop2016@krebsco.de

---
 krebs/3modules/default.nix | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/krebs/3modules/default.nix b/krebs/3modules/default.nix
index 2f3c20906..c114b74df 100644
--- a/krebs/3modules/default.nix
+++ b/krebs/3modules/default.nix
@@ -161,7 +161,7 @@ let
         ciko.mail = "wieczorek.stefan@gmail.com";
         Mic92.mail = "joerg@higgsboson.tk";
       in {
-        "cfp@eloop.org" = [{ mail = "eloop2016@krebsco.de"; }];
+        "*@eloop.org" = [{ mail = "eloop2016@krebsco.de"; }];
         "eloop2016@krebsco.de" = spam-ml ++ [ ciko Mic92 ];
         "postmaster@krebsco.de" = spam-ml; # RFC 822
         "lass@krebsco.de" = lass;

From ace70674aa9fc4580816225223934b6d7edd9204 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sat, 21 May 2016 09:52:25 +0200
Subject: [PATCH 38/40] {mv,tv}.mail: retiolum -> r

---
 krebs/3modules/tv/default.nix | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/krebs/3modules/tv/default.nix b/krebs/3modules/tv/default.nix
index 711121a40..12aa91ba8 100644
--- a/krebs/3modules/tv/default.nix
+++ b/krebs/3modules/tv/default.nix
@@ -355,11 +355,11 @@ with config.krebs.lib;
   };
   users = rec {
     mv = {
-      mail = "mv@cd.retiolum";
+      mail = "mv@cd.r";
       pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGer9e2+Lew7vnisgBbsFNECEIkpNJgEaqQqgb9inWkQ mv@vod";
     };
     tv = {
-      mail = "tv@nomic.retiolum";
+      mail = "tv@nomic.r";
       pgp.pubkeys.default = ''
         -----BEGIN PGP PUBLIC KEY BLOCK-----
 

From 97c2e4bbd99f6034d550a83804e508c278045b67 Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Sat, 21 May 2016 11:18:24 +0200
Subject: [PATCH 39/40] krebs.exim: validate config file syntax

---
 krebs/3modules/exim.nix  | 2 +-
 krebs/5pkgs/builders.nix | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/krebs/3modules/exim.nix b/krebs/3modules/exim.nix
index 16a2a37b6..7b18c72c1 100644
--- a/krebs/3modules/exim.nix
+++ b/krebs/3modules/exim.nix
@@ -37,7 +37,7 @@ in {
   };
   config = lib.mkIf cfg.enable {
     environment = {
-      etc."exim.conf".text = ''
+      etc."exim.conf".source = pkgs.writeEximConfig "exim.conf" ''
         exim_user = ${cfg.user.name}
         exim_group = ${cfg.group.name}
         exim_path = /var/setuid-wrappers/exim
diff --git a/krebs/5pkgs/builders.nix b/krebs/5pkgs/builders.nix
index 146e6f9e1..70d65cfc3 100644
--- a/krebs/5pkgs/builders.nix
+++ b/krebs/5pkgs/builders.nix
@@ -56,6 +56,14 @@ rec {
     '';
   };
 
+  writeEximConfig = name: text: pkgs.runCommand name {
+    inherit text;
+    passAsFile = [ "text" ];
+  } ''
+    ${pkgs.exim}/bin/exim -C "$textPath" -bV >/dev/null
+    mv "$textPath" $out
+  '';
+
   writeNixFromCabal = name: path: pkgs.runCommand name {} ''
     ${pkgs.cabal2nix}/bin/cabal2nix ${path} > $out
   '';

From c44e649455f3c162b66fb9d2d678a7a0eeff598b Mon Sep 17 00:00:00 2001
From: tv <tv@krebsco.de>
Date: Tue, 24 May 2016 20:58:19 +0200
Subject: [PATCH 40/40] krebs.exim-retiolum: disable TLS

---
 krebs/3modules/exim-retiolum.nix | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/krebs/3modules/exim-retiolum.nix b/krebs/3modules/exim-retiolum.nix
index 8b6ac4a4e..d6b7ab753 100644
--- a/krebs/3modules/exim-retiolum.nix
+++ b/krebs/3modules/exim-retiolum.nix
@@ -57,6 +57,8 @@ let
           syslog_timestamp = false
           syslog_duplication = false
 
+          tls_advertise_hosts =
+
           begin acl
 
           acl_check_rcpt: