vuls: init at 0.27.0 (#348530)
[NixPkgs.git] / nixos / tests / clatd.nix
blobd0d504851ce4e5c4efef4c16cd65231d3bb3e0f1
1 # This test verifies that we can ping an IPv4-only server from an IPv6-only
2 # client via a NAT64 router using CLAT on the client. The hosts and networks
3 # are configured as follows:
5 #        +------
6 # Client | clat    Address: 192.0.0.1/32  (configured via clatd)
7 #        |         Route:   default
8 #        |
9 #        | eth1    Address: Assigned via SLAAC within 2001:db8::/64
10 #        |  |      Route:   default via IPv6LL address
11 #        +--|---
12 #           | VLAN 3
13 #        +--|---
14 #        | eth2    Address: 2001:db8::1/64
15 # Router |
16 #        | nat64   Address: 64:ff9b::1/128
17 #        |         Route:   64:ff9b::/96
18 #        |         Address: 192.0.2.0/32
19 #        |         Route:   192.0.2.0/24
20 #        |
21 #        | eth1    Address: 100.64.0.1/24
22 #        +--|---
23 #           | VLAN 2
24 #        +--|---
25 # Server | eth1    Address: 100.64.0.2/24
26 #        |         Route:   192.0.2.0/24 via 100.64.0.1
27 #        +------
29 import ./make-test-python.nix ({ pkgs, lib, ... }:
32   name = "clatd";
33   meta = with pkgs.lib.maintainers; {
34     maintainers = [ hax404 jmbaur ];
35   };
37   nodes = {
38     # The server is configured with static IPv4 addresses. RFC 6052 Section 3.1
39     # disallows the mapping of non-global IPv4 addresses like RFC 1918 into the
40     # Well-Known Prefix 64:ff9b::/96. TAYGA also does not allow the mapping of
41     # documentation space (RFC 5737). To circumvent this, 100.64.0.2/24 from
42     # RFC 6589 (Carrier Grade NAT) is used here.
43     # To reach the IPv4 address pool of the NAT64 gateway, there is a static
44     # route configured. In normal cases, where the router would also source NAT
45     # the pool addresses to one IPv4 addresses, this would not be needed.
46     server = {
47       virtualisation.vlans = [
48         2 # towards router
49       ];
50       networking = {
51         useDHCP = false;
52         interfaces.eth1 = lib.mkForce {};
53       };
54       systemd.network = {
55         enable = true;
56         networks."vlan1" = {
57           matchConfig.Name = "eth1";
58           address = [
59             "100.64.0.2/24"
60           ];
61           routes = [
62             { Destination = "192.0.2.0/24"; Gateway = "100.64.0.1"; }
63           ];
64         };
65       };
66     };
68     # The router is configured with static IPv4 addresses towards the server
69     # and IPv6 addresses towards the client. DNS64 is exposed towards the
70     # client so clatd is able to auto-discover the PLAT prefix. For NAT64, the
71     # Well-Known prefix 64:ff9b::/96 is used. NAT64 is done with TAYGA which
72     # provides the tun-interface nat64 and does the translation over it. The
73     # IPv6 packets are sent to this interfaces and received as IPv4 packets and
74     # vice versa. As TAYGA only translates IPv6 addresses to dedicated IPv4
75     # addresses, it needs a pool of IPv4 addresses which must be at least as
76     # big as the expected amount of clients. In this test, the packets from the
77     # pool are directly routed towards the client. In normal cases, there would
78     # be a second source NAT44 to map all clients behind one IPv4 address.
79     router = {
80       boot.kernel.sysctl = {
81         "net.ipv4.conf.all.forwarding" = 1;
82         "net.ipv6.conf.all.forwarding" = 1;
83       };
85       virtualisation.vlans = [
86         2 # towards server
87         3 # towards client
88       ];
90       networking = {
91         useDHCP = false;
92         useNetworkd = true;
93         firewall.enable = false;
94         interfaces.eth1 = lib.mkForce {
95           ipv4 = {
96             addresses = [ { address = "100.64.0.1"; prefixLength = 24; } ];
97           };
98         };
99         interfaces.eth2 = lib.mkForce {
100           ipv6 = {
101             addresses = [ { address = "2001:db8::1"; prefixLength = 64; } ];
102           };
103         };
104       };
106       systemd.network.networks."40-eth2" = {
107         networkConfig.IPv6SendRA = true;
108         ipv6Prefixes = [ { Prefix = "2001:db8::/64"; } ];
109         ipv6PREF64Prefixes = [ { Prefix = "64:ff9b::/96"; } ];
110         ipv6SendRAConfig = {
111           EmitDNS = true;
112           DNS = "_link_local";
113         };
114       };
116       services.resolved.extraConfig = ''
117         DNSStubListener=no
118       '';
120       networking.extraHosts = ''
121         192.0.0.171 ipv4only.arpa
122         192.0.0.170 ipv4only.arpa
123       '';
125       services.coredns = {
126         enable = true;
127         config = ''
128           .:53 {
129             bind ::
130             hosts /etc/hosts
131             dns64 64:ff9b::/96
132           }
133         '';
134       };
136       services.tayga = {
137         enable = true;
138         ipv4 = {
139           address = "192.0.2.0";
140           router = {
141             address = "192.0.2.1";
142           };
143           pool = {
144             address = "192.0.2.0";
145             prefixLength = 24;
146           };
147         };
148         ipv6 = {
149           address = "2001:db8::1";
150           router = {
151             address = "64:ff9b::1";
152           };
153           pool = {
154             address = "64:ff9b::";
155             prefixLength = 96;
156           };
157         };
158       };
159     };
161     # The client uses SLAAC to assign IPv6 addresses. To reach the IPv4-only
162     # server, the client starts the clat daemon which starts and configures the
163     # local IPv4 -> IPv6 translation via Tayga after discovering the PLAT
164     # prefix via DNS64.
165     client = {
166       virtualisation.vlans = [
167         3 # towards router
168       ];
170       networking = {
171         useDHCP = false;
172         interfaces.eth1 = lib.mkForce {};
173       };
175       systemd.network = {
176         enable = true;
177         networks."vlan1" = {
178           matchConfig.Name = "eth1";
180           # NOTE: clatd does not actually use the PREF64 prefix discovered by
181           # systemd-networkd (nor does systemd-networkd do anything with it,
182           # yet), but we set this to confirm it works. See the test script
183           # below.
184           ipv6AcceptRAConfig.UsePREF64 = true;
185         };
186       };
188       services.clatd = {
189         enable = true;
190         # NOTE: Perl's Net::DNS resolver does not seem to work well querying
191         # for AAAA records to systemd-resolved's default IPv4 bind address
192         # (127.0.0.53), so we add an IPv6 listener address to systemd-resolved
193         # and tell clatd to use that instead.
194         settings.dns64-servers = "::1";
195       };
197       # Allow clatd to find dns server. See comment above.
198       services.resolved.extraConfig = ''
199         DNSStubListenerExtra=::1
200       '';
202       environment.systemPackages = [ pkgs.mtr ];
203     };
204   };
206   testScript = ''
207     import json
209     start_all()
211     # wait for all machines to start up
212     for machine in client, router, server:
213       machine.wait_for_unit("network-online.target")
215     with subtest("Wait for tayga and clatd"):
216       router.wait_for_unit("tayga.service")
217       client.wait_for_unit("clatd.service")
218       # clatd checks if this system has IPv4 connectivity for 10 seconds
219       client.wait_until_succeeds(
220         'journalctl -u clatd -e | grep -q "Starting up TAYGA, using config file"'
221       )
223     with subtest("networkd exports PREF64 prefix"):
224       assert json.loads(client.succeed("networkctl status eth1 --json=short"))[
225           "NDisc"
226       ]["PREF64"][0]["Prefix"] == [0x0, 0x64, 0xFF, 0x9B] + ([0] * 12)
228     with subtest("Test ICMP"):
229       client.wait_until_succeeds("ping -c 3 100.64.0.2 >&2")
231     with subtest("Test ICMP and show a traceroute"):
232       client.wait_until_succeeds("mtr --show-ips --report-wide 100.64.0.2 >&2")
234     client.log(client.execute("systemd-analyze security clatd.service")[1])
235   '';