7 networking.useDHCP = false;
8 networking.interfaces.eth1.ipv4.addresses = lib.mkVMOverride [ ];
12 networking.useDHCP = false;
13 networking.interfaces.eth1.ipv6.addresses = lib.mkVMOverride [ ];
16 webserver = ip: msg: {
17 systemd.services.webserver = {
18 description = "Mock webserver";
19 wants = [ "network-online.target" ];
20 wantedBy = [ "multi-user.target" ];
24 printf 'HTTP/1.0 200 OK\n'
25 printf 'Content-Length: ${toString (1 + builtins.stringLength msg)}\n'
27 } | ${pkgs.libressl.nc}/bin/nc -${toString ip}nvl 80
31 networking.firewall.allowedTCPPorts = [ 80 ];
38 # This test simulates the setup described in [1] with two IPv6 and
39 # IPv4-only devices on different subnets communicating through a border
40 # relay running Jool in SIIT mode.
41 # [1]: https://nicmx.github.io/Jool/en/run-vanilla.html
43 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
47 virtualisation.vlans = [ 1 2 ];
49 # Enable packet routing
50 boot.kernel.sysctl = {
51 "net.ipv6.conf.all.forwarding" = 1;
52 "net.ipv4.conf.all.forwarding" = 1;
55 networking.useDHCP = false;
56 networking.interfaces = lib.mkVMOverride {
57 eth1.ipv6.addresses = [ { address = "fd::198.51.100.1"; prefixLength = 120; } ];
58 eth2.ipv4.addresses = [ { address = "192.0.2.1"; prefixLength = 24; } ];
61 networking.jool.enable = true;
62 networking.jool.siit.default.global.pool6 = "fd::/96";
67 imports = [ ipv6Only (webserver 6 "Hello, Bob!") ];
69 virtualisation.vlans = [ 1 ];
70 networking.interfaces.eth1.ipv6 = {
71 addresses = [ { address = "fd::198.51.100.8"; prefixLength = 120; } ];
72 routes = [ { address = "fd::192.0.2.0"; prefixLength = 120;
73 via = "fd::198.51.100.1"; } ];
79 imports = [ ipv4Only (webserver 4 "Hello, Alice!") ];
81 virtualisation.vlans = [ 2 ];
82 networking.interfaces.eth1.ipv4 = {
83 addresses = [ { address = "192.0.2.16"; prefixLength = 24; } ];
84 routes = [ { address = "198.51.100.0"; prefixLength = 24;
85 via = "192.0.2.1"; } ];
92 relay.wait_for_unit("jool-siit-default.service")
93 alice.wait_for_unit("network-addresses-eth1.service")
94 bob.wait_for_unit("network-addresses-eth1.service")
96 with subtest("Alice and Bob can't ping each other"):
97 relay.systemctl("stop jool-siit-default.service")
98 alice.fail("ping -c1 fd::192.0.2.16")
99 bob.fail("ping -c1 198.51.100.8")
101 with subtest("Alice and Bob can ping using the relay"):
102 relay.systemctl("start jool-siit-default.service")
103 alice.wait_until_succeeds("ping -c1 fd::192.0.2.16")
104 bob.wait_until_succeeds("ping -c1 198.51.100.8")
106 with subtest("Alice can connect to Bob's webserver"):
107 bob.wait_for_open_port(80)
108 alice.succeed("curl -vvv http://[fd::192.0.2.16] >&2")
109 alice.succeed("curl --fail -s http://[fd::192.0.2.16] | grep -q Alice")
111 with subtest("Bob can connect to Alices's webserver"):
112 alice.wait_for_open_port(80)
113 bob.succeed("curl --fail -s http://198.51.100.8 | grep -q Bob")
118 # This test simulates the setup described in [1] with two IPv6-only nodes
119 # (a client and a homeserver) on the LAN subnet and an IPv4 node on the WAN.
120 # The router runs Jool in stateful NAT64 mode, masquarading the LAN and
121 # forwarding ports using static BIB entries.
122 # [1]: https://nicmx.github.io/Jool/en/run-nat64.html
124 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
128 virtualisation.vlans = [ 1 2 ];
130 # Enable packet routing
131 boot.kernel.sysctl = {
132 "net.ipv6.conf.all.forwarding" = 1;
133 "net.ipv4.conf.all.forwarding" = 1;
136 networking.useDHCP = false;
137 networking.interfaces = lib.mkVMOverride {
138 eth1.ipv6.addresses = [ { address = "2001:db8::1"; prefixLength = 96; } ];
139 eth2.ipv4.addresses = [ { address = "203.0.113.1"; prefixLength = 24; } ];
142 networking.jool.enable = true;
143 networking.jool.nat64.default = {
145 { # forward HTTP 203.0.113.1 (router) → 2001:db8::9 (homeserver)
147 "ipv4 address" = "203.0.113.1#80";
148 "ipv6 address" = "2001:db8::9#80";
152 # Ports for dynamic translation
153 { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
154 { protocol = "UDP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
155 { protocol = "ICMP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
156 # Ports for static BIB entries
157 { protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "80"; }
162 # LAN client (IPv6 only)
164 imports = [ ipv6Only ];
165 virtualisation.vlans = [ 1 ];
167 networking.interfaces.eth1.ipv6 = {
168 addresses = [ { address = "2001:db8::8"; prefixLength = 96; } ];
169 routes = [ { address = "64:ff9b::"; prefixLength = 96;
170 via = "2001:db8::1"; } ];
174 # LAN server (IPv6 only)
176 imports = [ ipv6Only (webserver 6 "Hello from IPv6!") ];
178 virtualisation.vlans = [ 1 ];
179 networking.interfaces.eth1.ipv6 = {
180 addresses = [ { address = "2001:db8::9"; prefixLength = 96; } ];
181 routes = [ { address = "64:ff9b::"; prefixLength = 96;
182 via = "2001:db8::1"; } ];
186 # WAN server (IPv4 only)
188 imports = [ ipv4Only (webserver 4 "Hello from IPv4!") ];
190 virtualisation.vlans = [ 2 ];
191 networking.interfaces.eth1.ipv4.addresses =
192 [ { address = "203.0.113.16"; prefixLength = 24; } ];
198 for node in [client, homeserver, server]:
199 node.wait_for_unit("network-addresses-eth1.service")
201 with subtest("Client can ping the WAN server"):
202 router.wait_for_unit("jool-nat64-default.service")
203 client.succeed("ping -c1 64:ff9b::203.0.113.16")
205 with subtest("Client can connect to the WAN webserver"):
206 server.wait_for_open_port(80)
207 client.succeed("curl --fail -s http://[64:ff9b::203.0.113.16] | grep -q IPv4!")
209 with subtest("Router BIB entries are correctly populated"):
210 router.succeed("jool bib display | grep -q 'Dynamic TCP.*2001:db8::8'")
211 router.succeed("jool bib display | grep -q 'Static TCP.*2001:db8::9'")
213 with subtest("WAN server can reach the LAN server"):
214 homeserver.wait_for_open_port(80)
215 server.succeed("curl --fail -s http://203.0.113.1 | grep -q IPv6!")