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 = lib.mkForce [ { address = "2001:db8::8"; prefixLength = 96; } ];
169 routes = lib.mkForce [ {
170 address = "64:ff9b::";
177 # LAN server (IPv6 only)
179 imports = [ ipv6Only (webserver 6 "Hello from IPv6!") ];
181 virtualisation.vlans = [ 1 ];
182 networking.interfaces.eth1.ipv6 = {
183 addresses = lib.mkForce [ { address = "2001:db8::9"; prefixLength = 96; } ];
184 routes = lib.mkForce [ {
185 address = "64:ff9b::";
192 # WAN server (IPv4 only)
194 imports = [ ipv4Only (webserver 4 "Hello from IPv4!") ];
196 virtualisation.vlans = [ 2 ];
197 networking.interfaces.eth1.ipv4.addresses =
198 [ { address = "203.0.113.16"; prefixLength = 24; } ];
204 for node in [client, homeserver, server]:
205 node.wait_for_unit("network-addresses-eth1.service")
207 with subtest("Client can ping the WAN server"):
208 router.wait_for_unit("jool-nat64-default.service")
209 client.succeed("ping -c1 64:ff9b::203.0.113.16")
211 with subtest("Client can connect to the WAN webserver"):
212 server.wait_for_open_port(80)
213 client.succeed("curl --fail -s http://[64:ff9b::203.0.113.16] | grep -q IPv4!")
215 with subtest("Router BIB entries are correctly populated"):
216 router.succeed("jool bib display | grep -q 'Dynamic TCP.*2001:db8::8'")
217 router.succeed("jool bib display | grep -q 'Static TCP.*2001:db8::9'")
219 with subtest("WAN server can reach the LAN server"):
220 homeserver.wait_for_open_port(80)
221 server.succeed("curl --fail -s http://203.0.113.1 | grep -q IPv6!")