at 23.05-pre 5.3 kB view raw
1let 2 aliceIp6 = "202:b70:9b0b:cf34:f93c:8f18:bbfd:7034"; 3 aliceKeys = { 4 PublicKey = "3e91ec9e861960d86e1ce88051f97c435bdf2859640ab681dfa906eb45ad5182"; 5 PrivateKey = "a867f9e078e4ce58d310cf5acd4622d759e2a21df07e1d6fc380a2a26489480d3e91ec9e861960d86e1ce88051f97c435bdf2859640ab681dfa906eb45ad5182"; 6 }; 7 bobIp6 = "202:a483:73a4:9f2d:a559:4a19:bc9:8458"; 8 bobPrefix = "302:a483:73a4:9f2d"; 9 bobConfig = { 10 InterfacePeers = { 11 eth1 = [ "tcp://192.168.1.200:12345" ]; 12 }; 13 MulticastInterfaces = [ "eth1" ]; 14 LinkLocalTCPPort = 54321; 15 PublicKey = "2b6f918b6c1a4b54d6bcde86cf74e074fb32ead4ee439b7930df2aa60c825186"; 16 PrivateKey = "0c4a24acd3402722ce9277ed179f4a04b895b49586493c25fbaed60653d857d62b6f918b6c1a4b54d6bcde86cf74e074fb32ead4ee439b7930df2aa60c825186"; 17 }; 18 danIp6 = bobPrefix + "::2"; 19 20in import ./make-test-python.nix ({ pkgs, ...} : { 21 name = "yggdrasil"; 22 meta = with pkgs.lib.maintainers; { 23 maintainers = [ gazally ]; 24 }; 25 26 nodes = rec { 27 # Alice is listening for peerings on a specified port, 28 # but has multicast peering disabled. Alice has part of her 29 # yggdrasil config in Nix and part of it in a file. 30 alice = 31 { ... }: 32 { 33 networking = { 34 interfaces.eth1.ipv4.addresses = [{ 35 address = "192.168.1.200"; 36 prefixLength = 24; 37 }]; 38 firewall.allowedTCPPorts = [ 80 12345 ]; 39 }; 40 services.httpd.enable = true; 41 services.httpd.adminAddr = "foo@example.org"; 42 43 services.yggdrasil = { 44 enable = true; 45 settings = { 46 Listen = ["tcp://0.0.0.0:12345"]; 47 MulticastInterfaces = [ ]; 48 }; 49 configFile = toString (pkgs.writeTextFile { 50 name = "yggdrasil-alice-conf"; 51 text = builtins.toJSON aliceKeys; 52 }); 53 }; 54 }; 55 56 # Bob is set up to peer with Alice, and also to do local multicast 57 # peering. Bob's yggdrasil config is in a file. 58 bob = 59 { ... }: 60 { 61 networking.firewall.allowedTCPPorts = [ 54321 ]; 62 services.yggdrasil = { 63 enable = true; 64 openMulticastPort = true; 65 configFile = toString (pkgs.writeTextFile { 66 name = "yggdrasil-bob-conf"; 67 text = builtins.toJSON bobConfig; 68 }); 69 }; 70 71 boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; 72 73 networking = { 74 bridges.br0.interfaces = [ ]; 75 interfaces.br0 = { 76 ipv6.addresses = [{ 77 address = bobPrefix + "::1"; 78 prefixLength = 64; 79 }]; 80 }; 81 }; 82 83 # dan is a node inside a container running on bob's host. 84 containers.dan = { 85 autoStart = true; 86 privateNetwork = true; 87 hostBridge = "br0"; 88 config = { config, pkgs, ... }: { 89 networking.interfaces.eth0.ipv6 = { 90 addresses = [{ 91 address = bobPrefix + "::2"; 92 prefixLength = 64; 93 }]; 94 routes = [{ 95 address = "200::"; 96 prefixLength = 7; 97 via = bobPrefix + "::1"; 98 }]; 99 }; 100 services.httpd.enable = true; 101 services.httpd.adminAddr = "foo@example.org"; 102 networking.firewall.allowedTCPPorts = [ 80 ]; 103 }; 104 }; 105 }; 106 107 # Carol only does local peering. Carol's yggdrasil config is all Nix. 108 carol = 109 { ... }: 110 { 111 networking.firewall.allowedTCPPorts = [ 43210 ]; 112 services.yggdrasil = { 113 enable = true; 114 denyDhcpcdInterfaces = [ "ygg0" ]; 115 settings = { 116 IfTAPMode = true; 117 IfName = "ygg0"; 118 MulticastInterfaces = [ "eth1" ]; 119 LinkLocalTCPPort = 43210; 120 }; 121 persistentKeys = true; 122 }; 123 }; 124 }; 125 126 testScript = 127 '' 128 import re 129 130 # Give Alice a head start so she is ready when Bob calls. 131 alice.start() 132 alice.wait_for_unit("yggdrasil.service") 133 134 bob.start() 135 carol.start() 136 bob.wait_for_unit("default.target") 137 carol.wait_for_unit("yggdrasil.service") 138 139 ip_addr_show = "ip -o -6 addr show dev ygg0 scope global" 140 carol.wait_until_succeeds(f"[ `{ip_addr_show} | grep -v tentative | wc -l` -ge 1 ]") 141 carol_ip6 = re.split(" +|/", carol.succeed(ip_addr_show))[3] 142 143 # If Alice can talk to Carol, then Bob's outbound peering and Carol's 144 # local peering have succeeded and everybody is connected. 145 alice.wait_until_succeeds(f"ping -c 1 {carol_ip6}") 146 alice.succeed("ping -c 1 ${bobIp6}") 147 148 bob.succeed("ping -c 1 ${aliceIp6}") 149 bob.succeed(f"ping -c 1 {carol_ip6}") 150 151 carol.succeed("ping -c 1 ${aliceIp6}") 152 carol.succeed("ping -c 1 ${bobIp6}") 153 carol.succeed("ping -c 1 ${bobPrefix}::1") 154 carol.succeed("ping -c 8 ${danIp6}") 155 156 carol.fail("journalctl -u dhcpcd | grep ygg0") 157 158 alice.wait_for_unit("httpd.service") 159 carol.succeed("curl --fail -g http://[${aliceIp6}]") 160 carol.succeed("curl --fail -g http://[${danIp6}]") 161 ''; 162})