summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/services/networking/cjdns.nix48
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/cjdns.nix123
-rw-r--r--pkgs/tools/networking/cjdns/default.nix3
-rw-r--r--pkgs/tools/networking/cjdns/makekeys-sigpipe.patch29
5 files changed, 180 insertions, 24 deletions
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 9888419309c..be0acb27324 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -204,8 +204,29 @@ in
 
     systemd.services.cjdns = {
       description = "encrypted networking for everybody";
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      wantedBy = [ "network.target" ];
+      after = [ "networkSetup.service" "network-interfaces.target" ];
+
+      preStart = if cfg.confFile != "" then "" else ''
+        [ -e /etc/cjdns.keys ] && source /etc/cjdns.keys
+
+        if [ -z "$CJDNS_PRIVATE_KEY" ]; then
+            shopt -s lastpipe
+            ${pkg}/bin/makekeys | { read private ipv6 public; }
+
+            umask 0077
+            echo "CJDNS_PRIVATE_KEY=$private" >> /etc/cjdns.keys
+            echo -e "CJDNS_IPV6=$ipv6\nCJDNS_PUBLIC_KEY=$public" > /etc/cjdns.public
+
+            chmod 600 /etc/cjdns.keys
+            chmod 444 /etc/cjdns.public
+        fi
+
+        if [ -z "$CJDNS_ADMIN_PASSWORD" ]; then
+            echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
+                >> /etc/cjdns.keys
+        fi
+      '';
 
       script = (
         if cfg.confFile != "" then "${pkg}/bin/cjdroute < ${cfg.confFile}" else
@@ -224,27 +245,6 @@ in
       };
     };
 
-    system.activationScripts.cjdns = if (cfg.confFile == "") then "" else ''
-      cjdnsWriteKeys() {
-        private=$1
-        ipv6=$2
-        public=$3
-
-        echo "CJDNS_PRIVATE_KEY=$1" >> /etc/cjdns.keys
-        echo -e "CJDNS_IPV6=$2\nCJDNS_PUBLIC_KEY=$3" > /etc/cjdns.public
-
-        chmod 600 /etc/cjdns.keys
-        chmod 444 /etc/cjdns.public
-      }
-
-      grep -q "CJDNS_PRIVATE_KEY=" /etc/cjdns.keys || \
-          cjdnsWriteKeys $(${pkg}/bin/makekeys)
-
-      grep -q "CJDNS_ADMIN_PASSWORD=" /etc/cjdns.keys || \
-          echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
-          >> /etc/cjdns.keys
-    '';
-
     networking.extraHosts = "${cjdnsHosts}";
 
     assertions = [
@@ -258,4 +258,4 @@ in
 
   };
 
-}
\ No newline at end of file
+}
diff --git a/nixos/release.nix b/nixos/release.nix
index cb79dd3a226..5a89b38acc7 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -235,6 +235,7 @@ in rec {
   tests.avahi = callTest tests/avahi.nix {};
   tests.bittorrent = callTest tests/bittorrent.nix {};
   tests.blivet = callTest tests/blivet.nix {};
+  tests.cjdns = callTest tests/cjdns.nix {};
   tests.containers = callTest tests/containers.nix {};
   tests.firefox = callTest tests/firefox.nix {};
   tests.firewall = callTest tests/firewall.nix {};
diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix
new file mode 100644
index 00000000000..7bb3863c683
--- /dev/null
+++ b/nixos/tests/cjdns.nix
@@ -0,0 +1,123 @@
+let
+  carolKey = "2d2a338b46f8e4a8c462f0c385b481292a05f678e19a2b82755258cf0f0af7e2";
+  carolPubKey = "n932l3pjvmhtxxcdrqq2qpw5zc58f01vvjx01h4dtd1bb0nnu2h0.k";
+  carolPassword = "678287829ce4c67bc8b227e56d94422ee1b85fa11618157b2f591de6c6322b52";
+  carolIp4 = "192.168.0.9";
+  
+  basicConfig =
+    { config, pkgs, ... }:
+    { services.cjdns.enable = true;
+    
+      # Turning off DHCP isn't very realistic but makes
+      # the sequence of address assignment less stochastic.
+      networking.useDHCP = false;
+      
+      networking.interfaces.eth1.prefixLength = 24;
+      # CJDNS output is incompatible with the XML log.
+      systemd.services.cjdns.serviceConfig.StandardOutput = "null";
+      #networking.firewall.enable = true;
+      networking.firewall.allowPing = true;
+      #networking.firewall.rejectPackets = true;
+    };
+
+in
+
+import ./make-test.nix {
+  name = "cjdns";
+
+  nodes = rec
+    { # Alice finds peers over over ETHInterface.
+      alice =
+        { config, ... }:
+        { imports = [ basicConfig ];
+
+          services.cjdns.ETHInterface.bind = "eth1";
+
+          services.httpd.enable = true;
+          services.httpd.adminAddr = "foo@example.org";
+          networking.firewall.allowedTCPPorts = [ 80 ];
+        };
+
+      # Bob explicitly connects to Carol over UDPInterface.
+      bob =
+        { config, lib, nodes, ... }:
+        
+        let carolIp4 = lib.mkForce nodes.carol.config.networking.interfaces.eth1; in
+        
+          { imports = [ basicConfig ];
+          
+          networking.interfaces.eth1.ipAddress = "192.168.0.2";
+          
+          services.cjdns =
+            { UDPInterface =
+                { bind = "0.0.0.0:1024";
+                  connectTo."192.168.0.1:1024}" =
+                    { hostname = "carol.hype";
+                      password = carolPassword;
+                      publicKey = carolPubKey;
+                    };
+                };
+            };
+        };
+
+      # Carol listens on ETHInterface and UDPInterface,
+      # but knows neither Alice or Bob.
+      carol =
+        { config, lib, nodes, ... }:
+          let
+            carolIp4 = (lib.mkForce nodes.carol.config.networking.interfaces.eth1);
+          in
+          { imports = [ basicConfig ];
+
+          environment.etc."cjdns.keys".text = ''
+            CJDNS_PRIVATE_KEY=${carolKey}
+            CJDNS_ADMIN_PASSWORD=FOOBAR
+          '';
+
+          networking.interfaces.eth1.ipAddress = "192.168.0.1";
+                    
+          services.cjdns =
+            { authorizedPasswords = [ carolPassword ];
+              ETHInterface.bind = "eth1";
+              UDPInterface.bind = "192.168.0.1:1024";
+            };
+          networking.firewall.allowedUDPPorts = [ 1024 ];
+        };
+
+    };
+
+  testScript =
+    ''
+      startAll;
+
+      $alice->waitForUnit("cjdns.service");
+      $bob->waitForUnit("cjdns.service");
+      $carol->waitForUnit("cjdns.service");
+
+      sub cjdnsIp {
+          my ($machine) = @_;
+          my $ip = (split /[ \/]+/, $machine->succeed("ip -o -6 addr show dev tun0"))[3];
+          $machine->log("has ip $ip");
+          return $ip;
+      }
+
+      my $aliceIp6 = cjdnsIp $alice;
+      my $bobIp6   = cjdnsIp $bob;
+      my $carolIp6 = cjdnsIp $carol;
+
+      # ping a few times each to let the routing table establish itself
+      
+      $alice->succeed("ping6 -c 4 $carolIp6");
+      $bob->succeed("ping6 -c 4 carol.hype");
+
+      $carol->succeed("ping6 -c 4 $aliceIp6");
+      $carol->succeed("ping6 -c 4 $bobIp6");
+      
+      $alice->succeed("ping6 -c 4 $bobIp6");
+      $bob->succeed("ping6 -c 4 $aliceIp6");
+
+      $alice->waitForUnit("httpd.service");
+
+      $bob->succeed("curl --fail -g http://[$aliceIp6]");
+    '';
+}
diff --git a/pkgs/tools/networking/cjdns/default.nix b/pkgs/tools/networking/cjdns/default.nix
index c32bc224bdd..cbaca948b2b 100644
--- a/pkgs/tools/networking/cjdns/default.nix
+++ b/pkgs/tools/networking/cjdns/default.nix
@@ -14,6 +14,9 @@ stdenv.mkDerivation {
     sha256 = "11z8dk7byxh9pfv7mhfvnk465qln1g7z8c8f822623d59lwjpbs1";
   };
 
+  # Make the NixOS service work a little better.
+  patches = [ ./makekeys-sigpipe.patch ];
+
   buildInputs = [ which python27 nodejs ] ++
     # for flock
     stdenv.lib.optional stdenv.isLinux [ utillinux ];
diff --git a/pkgs/tools/networking/cjdns/makekeys-sigpipe.patch b/pkgs/tools/networking/cjdns/makekeys-sigpipe.patch
new file mode 100644
index 00000000000..2b21f56709d
--- /dev/null
+++ b/pkgs/tools/networking/cjdns/makekeys-sigpipe.patch
@@ -0,0 +1,29 @@
+diff --git a/contrib/c/makekeys.c b/contrib/c/makekeys.c
+index 29582f1..555cf85 100644
+--- a/contrib/c/makekeys.c
++++ b/contrib/c/makekeys.c
+@@ -21,6 +21,7 @@
+ 
+ #include "crypto_scalarmult_curve25519.h"
+ 
++#include <signal.h>
+ #include <stdio.h>
+ 
+ int main(int argc, char** argv)
+@@ -35,6 +36,8 @@ int main(int argc, char** argv)
+     uint8_t hexPrivateKey[65];
+     uint8_t printedIp[40];
+ 
++    signal(SIGPIPE,SIG_DFL);
++
+     for (;;) {
+         Random_bytes(rand, privateKey, 32);
+         crypto_scalarmult_curve25519_base(publicKey, privateKey);
+@@ -43,6 +46,7 @@ int main(int argc, char** argv)
+             Base32_encode(publicKeyBase32, 53, publicKey, 32);
+             AddrTools_printShortIp(printedIp, ip);
+             printf("%s %s %s.k\n", hexPrivateKey, printedIp, publicKeyBase32);
++            fflush(stdout);
+         }
+     }
+     return 0;