1let 2 carolKey = "2d2a338b46f8e4a8c462f0c385b481292a05f678e19a2b82755258cf0f0af7e2"; 3 carolPubKey = "n932l3pjvmhtxxcdrqq2qpw5zc58f01vvjx01h4dtd1bb0nnu2h0.k"; 4 carolPassword = "678287829ce4c67bc8b227e56d94422ee1b85fa11618157b2f591de6c6322b52"; 5 carolIp4 = "192.168.0.9"; 6 7 basicConfig = 8 { config, pkgs, ... }: 9 { services.cjdns.enable = true; 10 11 # Turning off DHCP isn't very realistic but makes 12 # the sequence of address assignment less stochastic. 13 networking.useDHCP = false; 14 15 networking.interfaces.eth1.prefixLength = 24; 16 # CJDNS output is incompatible with the XML log. 17 systemd.services.cjdns.serviceConfig.StandardOutput = "null"; 18 #networking.firewall.enable = true; 19 networking.firewall.allowPing = true; 20 #networking.firewall.rejectPackets = true; 21 }; 22 23in 24 25import ./make-test.nix ({ pkgs, ...} : { 26 name = "cjdns"; 27 meta = with pkgs.stdenv.lib.maintainers; { 28 maintainers = [ ehmry ]; 29 }; 30 31 nodes = rec 32 { # Alice finds peers over over ETHInterface. 33 alice = 34 { config, ... }: 35 { imports = [ basicConfig ]; 36 37 services.cjdns.ETHInterface.bind = "eth1"; 38 39 services.httpd.enable = true; 40 services.httpd.adminAddr = "foo@example.org"; 41 networking.firewall.allowedTCPPorts = [ 80 ]; 42 }; 43 44 # Bob explicitly connects to Carol over UDPInterface. 45 bob = 46 { config, lib, nodes, ... }: 47 48 let carolIp4 = lib.mkForce nodes.carol.config.networking.interfaces.eth1; in 49 50 { imports = [ basicConfig ]; 51 52 networking.interfaces.eth1.ipAddress = "192.168.0.2"; 53 54 services.cjdns = 55 { UDPInterface = 56 { bind = "0.0.0.0:1024"; 57 connectTo."192.168.0.1:1024}" = 58 { password = carolPassword; 59 publicKey = carolPubKey; 60 }; 61 }; 62 }; 63 }; 64 65 # Carol listens on ETHInterface and UDPInterface, 66 # but knows neither Alice or Bob. 67 carol = 68 { config, lib, nodes, ... }: 69 let 70 carolIp4 = (lib.mkForce nodes.carol.config.networking.interfaces.eth1); 71 in 72 { imports = [ basicConfig ]; 73 74 environment.etc."cjdns.keys".text = '' 75 CJDNS_PRIVATE_KEY=${carolKey} 76 CJDNS_ADMIN_PASSWORD=FOOBAR 77 ''; 78 79 networking.interfaces.eth1.ipAddress = "192.168.0.1"; 80 81 services.cjdns = 82 { authorizedPasswords = [ carolPassword ]; 83 ETHInterface.bind = "eth1"; 84 UDPInterface.bind = "192.168.0.1:1024"; 85 }; 86 networking.firewall.allowedUDPPorts = [ 1024 ]; 87 }; 88 89 }; 90 91 testScript = 92 '' 93 startAll; 94 95 $alice->waitForUnit("cjdns.service"); 96 $bob->waitForUnit("cjdns.service"); 97 $carol->waitForUnit("cjdns.service"); 98 99 sub cjdnsIp { 100 my ($machine) = @_; 101 my $ip = (split /[ \/]+/, $machine->succeed("ip -o -6 addr show dev tun0"))[3]; 102 $machine->log("has ip $ip"); 103 return $ip; 104 } 105 106 my $aliceIp6 = cjdnsIp $alice; 107 my $bobIp6 = cjdnsIp $bob; 108 my $carolIp6 = cjdnsIp $carol; 109 110 # ping a few times each to let the routing table establish itself 111 112 $alice->succeed("ping6 -c 4 $carolIp6"); 113 $bob->succeed("ping6 -c 4 $carolIp6"); 114 115 $carol->succeed("ping6 -c 4 $aliceIp6"); 116 $carol->succeed("ping6 -c 4 $bobIp6"); 117 118 $alice->succeed("ping6 -c 4 $bobIp6"); 119 $bob->succeed("ping6 -c 4 $aliceIp6"); 120 121 $alice->waitForUnit("httpd.service"); 122 123 $bob->succeed("curl --fail -g http://[$aliceIp6]"); 124 ''; 125})