at master 8.3 kB view raw
1{ pkgs, runTest }: 2 3let 4 inherit (pkgs) lib; 5 6 ipv6Only = { 7 networking.useDHCP = false; 8 networking.interfaces.eth1.ipv4.addresses = lib.mkVMOverride [ ]; 9 }; 10 11 ipv4Only = { 12 networking.useDHCP = false; 13 networking.interfaces.eth1.ipv6.addresses = lib.mkVMOverride [ ]; 14 }; 15 16 webserver = ip: msg: { 17 systemd.services.webserver = { 18 description = "Mock webserver"; 19 wants = [ "network-online.target" ]; 20 wantedBy = [ "multi-user.target" ]; 21 script = '' 22 while true; do 23 { 24 printf 'HTTP/1.0 200 OK\n' 25 printf 'Content-Length: ${toString (1 + builtins.stringLength msg)}\n' 26 printf '\n${msg}\n\n' 27 } | ${pkgs.libressl.nc}/bin/nc -${toString ip}nvl 80 28 done 29 ''; 30 }; 31 networking.firewall.allowedTCPPorts = [ 80 ]; 32 }; 33 34in 35 36{ 37 siit = runTest { 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 42 name = "jool-siit"; 43 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 44 45 # Border relay 46 nodes.relay = { 47 virtualisation.vlans = [ 48 1 49 2 50 ]; 51 52 # Enable packet routing 53 boot.kernel.sysctl = { 54 "net.ipv6.conf.all.forwarding" = 1; 55 "net.ipv4.conf.all.forwarding" = 1; 56 }; 57 58 networking.useDHCP = false; 59 networking.interfaces = lib.mkVMOverride { 60 eth1.ipv6.addresses = [ 61 { 62 address = "fd::198.51.100.1"; 63 prefixLength = 120; 64 } 65 ]; 66 eth2.ipv4.addresses = [ 67 { 68 address = "192.0.2.1"; 69 prefixLength = 24; 70 } 71 ]; 72 }; 73 74 networking.jool.enable = true; 75 networking.jool.siit.default.global.pool6 = "fd::/96"; 76 }; 77 78 # IPv6 only node 79 nodes.alice = { 80 imports = [ 81 ipv6Only 82 (webserver 6 "Hello, Bob!") 83 ]; 84 85 virtualisation.vlans = [ 1 ]; 86 networking.interfaces.eth1.ipv6 = { 87 addresses = [ 88 { 89 address = "fd::198.51.100.8"; 90 prefixLength = 120; 91 } 92 ]; 93 routes = [ 94 { 95 address = "fd::192.0.2.0"; 96 prefixLength = 120; 97 via = "fd::198.51.100.1"; 98 } 99 ]; 100 }; 101 }; 102 103 # IPv4 only node 104 nodes.bob = { 105 imports = [ 106 ipv4Only 107 (webserver 4 "Hello, Alice!") 108 ]; 109 110 virtualisation.vlans = [ 2 ]; 111 networking.interfaces.eth1.ipv4 = { 112 addresses = [ 113 { 114 address = "192.0.2.16"; 115 prefixLength = 24; 116 } 117 ]; 118 routes = [ 119 { 120 address = "198.51.100.0"; 121 prefixLength = 24; 122 via = "192.0.2.1"; 123 } 124 ]; 125 }; 126 }; 127 128 testScript = '' 129 start_all() 130 131 relay.wait_for_unit("jool-siit-default.service") 132 alice.wait_for_unit("network-addresses-eth1.service") 133 bob.wait_for_unit("network-addresses-eth1.service") 134 135 with subtest("Alice and Bob can't ping each other"): 136 relay.systemctl("stop jool-siit-default.service") 137 alice.fail("ping -c1 fd::192.0.2.16") 138 bob.fail("ping -c1 198.51.100.8") 139 140 with subtest("Alice and Bob can ping using the relay"): 141 relay.systemctl("start jool-siit-default.service") 142 alice.wait_until_succeeds("ping -c1 fd::192.0.2.16") 143 bob.wait_until_succeeds("ping -c1 198.51.100.8") 144 145 with subtest("Alice can connect to Bob's webserver"): 146 bob.wait_for_open_port(80) 147 alice.succeed("curl -vvv http://[fd::192.0.2.16] >&2") 148 alice.succeed("curl --fail -s http://[fd::192.0.2.16] | grep -q Alice") 149 150 with subtest("Bob can connect to Alices's webserver"): 151 alice.wait_for_open_port(80) 152 bob.succeed("curl --fail -s http://198.51.100.8 | grep -q Bob") 153 ''; 154 }; 155 156 nat64 = runTest { 157 # This test simulates the setup described in [1] with two IPv6-only nodes 158 # (a client and a homeserver) on the LAN subnet and an IPv4 node on the WAN. 159 # The router runs Jool in stateful NAT64 mode, masquarading the LAN and 160 # forwarding ports using static BIB entries. 161 # [1]: https://nicmx.github.io/Jool/en/run-nat64.html 162 name = "jool-nat64"; 163 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 164 165 # Router 166 nodes.router = { 167 virtualisation.vlans = [ 168 1 169 2 170 ]; 171 172 # Enable packet routing 173 boot.kernel.sysctl = { 174 "net.ipv6.conf.all.forwarding" = 1; 175 "net.ipv4.conf.all.forwarding" = 1; 176 }; 177 178 networking.useDHCP = false; 179 networking.interfaces = lib.mkVMOverride { 180 eth1.ipv6.addresses = [ 181 { 182 address = "2001:db8::1"; 183 prefixLength = 96; 184 } 185 ]; 186 eth2.ipv4.addresses = [ 187 { 188 address = "203.0.113.1"; 189 prefixLength = 24; 190 } 191 ]; 192 }; 193 194 networking.jool.enable = true; 195 networking.jool.nat64.default = { 196 bib = [ 197 { 198 # forward HTTP 203.0.113.1 (router) → 2001:db8::9 (homeserver) 199 "protocol" = "TCP"; 200 "ipv4 address" = "203.0.113.1#80"; 201 "ipv6 address" = "2001:db8::9#80"; 202 } 203 ]; 204 pool4 = [ 205 # Ports for dynamic translation 206 { 207 protocol = "TCP"; 208 prefix = "203.0.113.1/32"; 209 "port range" = "40001-65535"; 210 } 211 { 212 protocol = "UDP"; 213 prefix = "203.0.113.1/32"; 214 "port range" = "40001-65535"; 215 } 216 { 217 protocol = "ICMP"; 218 prefix = "203.0.113.1/32"; 219 "port range" = "40001-65535"; 220 } 221 # Ports for static BIB entries 222 { 223 protocol = "TCP"; 224 prefix = "203.0.113.1/32"; 225 "port range" = "80"; 226 } 227 ]; 228 }; 229 }; 230 231 # LAN client (IPv6 only) 232 nodes.client = { 233 imports = [ ipv6Only ]; 234 virtualisation.vlans = [ 1 ]; 235 236 networking.interfaces.eth1.ipv6 = { 237 addresses = lib.mkForce [ 238 { 239 address = "2001:db8::8"; 240 prefixLength = 96; 241 } 242 ]; 243 routes = lib.mkForce [ 244 { 245 address = "64:ff9b::"; 246 prefixLength = 96; 247 via = "2001:db8::1"; 248 } 249 ]; 250 }; 251 }; 252 253 # LAN server (IPv6 only) 254 nodes.homeserver = { 255 imports = [ 256 ipv6Only 257 (webserver 6 "Hello from IPv6!") 258 ]; 259 260 virtualisation.vlans = [ 1 ]; 261 networking.interfaces.eth1.ipv6 = { 262 addresses = lib.mkForce [ 263 { 264 address = "2001:db8::9"; 265 prefixLength = 96; 266 } 267 ]; 268 routes = lib.mkForce [ 269 { 270 address = "64:ff9b::"; 271 prefixLength = 96; 272 via = "2001:db8::1"; 273 } 274 ]; 275 }; 276 }; 277 278 # WAN server (IPv4 only) 279 nodes.server = { 280 imports = [ 281 ipv4Only 282 (webserver 4 "Hello from IPv4!") 283 ]; 284 285 virtualisation.vlans = [ 2 ]; 286 networking.interfaces.eth1.ipv4.addresses = [ 287 { 288 address = "203.0.113.16"; 289 prefixLength = 24; 290 } 291 ]; 292 }; 293 294 testScript = '' 295 start_all() 296 297 for node in [client, homeserver, server]: 298 node.wait_for_unit("network-addresses-eth1.service") 299 300 with subtest("Client can ping the WAN server"): 301 router.wait_for_unit("jool-nat64-default.service") 302 client.succeed("ping -c1 64:ff9b::203.0.113.16") 303 304 with subtest("Client can connect to the WAN webserver"): 305 server.wait_for_open_port(80) 306 client.succeed("curl --fail -s http://[64:ff9b::203.0.113.16] | grep -q IPv4!") 307 308 with subtest("Router BIB entries are correctly populated"): 309 router.succeed("jool bib display | grep -q 'Dynamic TCP.*2001:db8::8'") 310 router.succeed("jool bib display | grep -q 'Static TCP.*2001:db8::9'") 311 312 with subtest("WAN server can reach the LAN server"): 313 homeserver.wait_for_open_port(80) 314 server.succeed("curl --fail -s http://203.0.113.1 | grep -q IPv6!") 315 ''; 316 317 }; 318 319}