nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1# This test verifies that we can ping an IPv4-only server from an IPv6-only
2# client via a NAT64 router. The hosts and networks are configured as follows:
3#
4# +------
5# Client | eth1 Address: 2001:db8::2/64
6# | | Route: 64:ff9b::/96 via 2001:db8::1
7# +--|---
8# | VLAN 3
9# +--|---
10# | eth2 Address: 2001:db8::1/64
11# Router |
12# | nat64 Address: 64:ff9b::1/128
13# | Route: 64:ff9b::/96
14# | Address: 192.0.2.0/32
15# | Route: 192.0.2.0/24
16# |
17# | eth1 Address: 100.64.0.1/24
18# +--|---
19# | VLAN 2
20# +--|---
21# Server | eth1 Address: 100.64.0.2/24
22# | Route: 192.0.2.0/24 via 100.64.0.1
23# +------
24
25{ pkgs, lib, ... }:
26
27{
28 name = "tayga";
29 meta = with pkgs.lib.maintainers; {
30 maintainers = [ hax404 ];
31 };
32
33 nodes = {
34 # The server is configured with static IPv4 addresses. RFC 6052 Section 3.1
35 # disallows the mapping of non-global IPv4 addresses like RFC 1918 into the
36 # Well-Known Prefix 64:ff9b::/96. TAYGA also does not allow the mapping of
37 # documentation space (RFC 5737). To circumvent this, 100.64.0.2/24 from
38 # RFC 6589 (Carrier Grade NAT) is used here.
39 # To reach the IPv4 address pool of the NAT64 gateway, there is a static
40 # route configured. In normal cases, where the router would also source NAT
41 # the pool addresses to one IPv4 addresses, this would not be needed.
42 server = {
43 virtualisation.vlans = [
44 2 # towards router
45 ];
46 networking = {
47 useDHCP = false;
48 interfaces.eth1 = lib.mkForce { };
49 };
50 systemd.network = {
51 enable = true;
52 networks."vlan1" = {
53 matchConfig.Name = "eth1";
54 address = [
55 "100.64.0.2/24"
56 ];
57 routes = [
58 {
59 Destination = "192.0.2.0/24";
60 Gateway = "100.64.0.1";
61 }
62 ];
63 };
64 };
65 programs.mtr.enable = true;
66 };
67
68 # The router is configured with static IPv4 addresses towards the server
69 # and IPv6 addresses towards the client. For NAT64, the Well-Known prefix
70 # 64:ff9b::/96 is used. NAT64 is done with TAYGA which provides the
71 # tun-interface nat64 and does the translation over it. The IPv6 packets
72 # are sent to this interfaces and received as IPv4 packets and vice versa.
73 # As TAYGA only translates IPv6 addresses to dedicated IPv4 addresses, it
74 # needs a pool of IPv4 addresses which must be at least as big as the
75 # expected amount of clients. In this test, the packets from the pool are
76 # directly routed towards the client. In normal cases, there would be a
77 # second source NAT44 to map all clients behind one IPv4 address.
78 router_systemd = {
79 boot.kernel.sysctl = {
80 "net.ipv4.ip_forward" = 1;
81 "net.ipv6.conf.all.forwarding" = 1;
82 };
83
84 virtualisation.vlans = [
85 2 # towards server
86 3 # towards client
87 ];
88
89 networking = {
90 useDHCP = false;
91 useNetworkd = true;
92 firewall.enable = false;
93 interfaces.eth1 = lib.mkForce {
94 ipv4 = {
95 addresses = [
96 {
97 address = "100.64.0.1";
98 prefixLength = 24;
99 }
100 ];
101 };
102 };
103 interfaces.eth2 = lib.mkForce {
104 ipv6 = {
105 addresses = [
106 {
107 address = "2001:db8::1";
108 prefixLength = 64;
109 }
110 ];
111 };
112 };
113 };
114
115 services.tayga = {
116 enable = true;
117 ipv4 = {
118 address = "192.0.2.0";
119 router = {
120 address = "192.0.2.1";
121 };
122 pool = {
123 address = "192.0.2.0";
124 prefixLength = 24;
125 };
126 };
127 ipv6 = {
128 address = "2001:db8::1";
129 router = {
130 address = "64:ff9b::1";
131 };
132 pool = {
133 address = "64:ff9b::";
134 prefixLength = 96;
135 };
136 };
137 mappings = {
138 "192.0.2.42" = "2001:db8::2";
139 };
140 };
141 };
142
143 router_nixos = {
144 boot.kernel.sysctl = {
145 "net.ipv4.ip_forward" = 1;
146 "net.ipv6.conf.all.forwarding" = 1;
147 };
148
149 virtualisation.vlans = [
150 2 # towards server
151 3 # towards client
152 ];
153
154 networking = {
155 useDHCP = false;
156 firewall.enable = false;
157 interfaces.eth1 = lib.mkForce {
158 ipv4 = {
159 addresses = [
160 {
161 address = "100.64.0.1";
162 prefixLength = 24;
163 }
164 ];
165 };
166 };
167 interfaces.eth2 = lib.mkForce {
168 ipv6 = {
169 addresses = [
170 {
171 address = "2001:db8::1";
172 prefixLength = 64;
173 }
174 ];
175 };
176 };
177 };
178
179 services.tayga = {
180 enable = true;
181 ipv4 = {
182 address = "192.0.2.0";
183 router = {
184 address = "192.0.2.1";
185 };
186 pool = {
187 address = "192.0.2.0";
188 prefixLength = 24;
189 };
190 };
191 ipv6 = {
192 address = "2001:db8::1";
193 router = {
194 address = "64:ff9b::1";
195 };
196 pool = {
197 address = "64:ff9b::";
198 prefixLength = 96;
199 };
200 };
201 mappings = {
202 "192.0.2.42" = "2001:db8::2";
203 };
204 };
205 };
206
207 # The client is configured with static IPv6 addresses. It has also a static
208 # route for the NAT64 IP space where the IPv4 addresses are mapped in. In
209 # normal cases, there would be only a default route.
210 client = {
211 virtualisation.vlans = [
212 3 # towards router
213 ];
214
215 networking = {
216 useDHCP = false;
217 interfaces.eth1 = lib.mkForce { };
218 };
219
220 systemd.network = {
221 enable = true;
222 networks."vlan1" = {
223 matchConfig.Name = "eth1";
224 address = [
225 "2001:db8::2/64"
226 ];
227 routes = [
228 {
229 Destination = "64:ff9b::/96";
230 Gateway = "2001:db8::1";
231 }
232 ];
233 };
234 };
235 programs.mtr.enable = true;
236 };
237 };
238
239 testScript = ''
240 # start client and server
241 for machine in client, server:
242 machine.systemctl("start network-online.target")
243 machine.wait_for_unit("network-online.target")
244 machine.log(machine.execute("ip addr")[1])
245 machine.log(machine.execute("ip route")[1])
246 machine.log(machine.execute("ip -6 route")[1])
247
248 # test systemd-networkd and nixos-scripts based router
249 for router in router_systemd, router_nixos:
250 router.start()
251 router.systemctl("start network-online.target")
252 router.wait_for_unit("network-online.target")
253 router.wait_for_unit("tayga.service")
254 router.log(machine.execute("ip addr")[1])
255 router.log(machine.execute("ip route")[1])
256 router.log(machine.execute("ip -6 route")[1])
257
258 with subtest("Wait for tayga"):
259 router.wait_for_unit("tayga.service")
260
261 with subtest("Test ICMP server -> client"):
262 server.wait_until_succeeds("ping -c 3 192.0.2.42 >&2")
263
264 with subtest("Test ICMP and show a traceroute server -> client"):
265 server.wait_until_succeeds("mtr --show-ips --report-wide 192.0.2.42 >&2")
266
267 with subtest("Test ICMP client -> server"):
268 client.wait_until_succeeds("ping -c 3 64:ff9b::100.64.0.2 >&2")
269
270 with subtest("Test ICMP and show a traceroute client -> server"):
271 client.wait_until_succeeds("mtr --show-ips --report-wide 64:ff9b::100.64.0.2 >&2")
272
273 router.log(router.execute("systemd-analyze security tayga.service")[1])
274 router.shutdown()
275 '';
276}