python310Packages.pydeconz: 104 -> 105
[NixPkgs.git] / nixos / tests / yggdrasil.nix
blobb60a0e6b06cc4f52c062ca645674303002663656
1 let
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";
20 in import ./make-test-python.nix ({ pkgs, ...} : {
21   name = "yggdrasil";
22   meta = with pkgs.lib.maintainers; {
23     maintainers = [ gazally ];
24   };
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";
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       };
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         };
71         boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1;
73         networking = {
74           bridges.br0.interfaces = [ ];
75           interfaces.br0 = {
76             ipv6.addresses = [{
77               address = bobPrefix + "::1";
78               prefixLength = 64;
79             }];
80           };
81         };
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       };
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     };
126   testScript =
127     ''
128       import re
130       # Give Alice a head start so she is ready when Bob calls.
131       alice.start()
132       alice.wait_for_unit("yggdrasil.service")
134       bob.start()
135       carol.start()
136       bob.wait_for_unit("default.target")
137       carol.wait_for_unit("yggdrasil.service")
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]
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}")
148       bob.succeed("ping -c 1 ${aliceIp6}")
149       bob.succeed(f"ping -c 1 {carol_ip6}")
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}")
156       carol.fail("journalctl -u dhcpcd | grep ygg0")
158       alice.wait_for_unit("httpd.service")
159       carol.succeed("curl --fail -g http://[${aliceIp6}]")
160       carol.succeed("curl --fail -g http://[${danIp6}]")
161     '';