vuls: init at 0.27.0
[NixPkgs.git] / nixos / tests / ipv6.nix
blob8fa7eec8ffb2a82b9d700fc95446dbca2ace0ada
1 # Test of IPv6 functionality in NixOS, including whether router
2 # solicication/advertisement using radvd works.
4 import ./make-test-python.nix ({ pkgs, lib, ...} : {
5   name = "ipv6";
6   meta = with pkgs.lib.maintainers; {
7     maintainers = [ ];
8   };
10   nodes =
11     {
12       # We use lib.mkForce here to remove the interface configuration
13       # provided by makeTest, so that the interfaces are all configured
14       # implicitly.
16       # This client should use privacy extensions fully, having a
17       # completely-default network configuration.
18       client_defaults.networking.interfaces = lib.mkForce {};
20       # Both of these clients should obtain temporary addresses, but
21       # not use them as the default source IP. We thus run the same
22       # checks against them — but the configuration resulting in this
23       # behaviour is different.
25       # Here, by using an altered default value for the global setting...
26       client_global_setting = {
27         networking.interfaces = lib.mkForce {};
28         networking.tempAddresses = "enabled";
29       };
30       # and here, by setting this on the interface explicitly.
31       client_interface_setting = {
32         networking.tempAddresses = "disabled";
33         networking.interfaces = lib.mkForce {
34           eth1.tempAddress = "enabled";
35         };
36       };
38       server =
39         { services.httpd.enable = true;
40           services.httpd.adminAddr = "foo@example.org";
41           networking.firewall.allowedTCPPorts = [ 80 ];
42           # disable testing driver's default IPv6 address.
43           networking.interfaces.eth1.ipv6.addresses = lib.mkForce [ ];
44         };
46       router =
47         { ... }:
48         { services.radvd.enable = true;
49           services.radvd.config =
50             ''
51               interface eth1 {
52                 AdvSendAdvert on;
53                 # ULA prefix (RFC 4193).
54                 prefix fd60:cc69:b537:1::/64 { };
55               };
56             '';
57         };
58     };
60   testScript =
61     ''
62       import re
64       # Start the router first so that it respond to router solicitations.
65       router.wait_for_unit("radvd")
67       clients = [client_defaults, client_global_setting, client_interface_setting]
69       start_all()
71       for client in clients:
72           client.wait_for_unit("network.target")
73       server.wait_for_unit("network.target")
74       server.wait_for_unit("httpd.service")
76       # Wait until the given interface has a non-tentative address of
77       # the desired scope (i.e. has completed Duplicate Address
78       # Detection).
79       def wait_for_address(machine, iface, scope, temporary=False):
80           temporary_flag = "temporary" if temporary else "-temporary"
81           cmd = f"ip -o -6 addr show dev {iface} scope {scope} -tentative {temporary_flag}"
83           machine.wait_until_succeeds(f"[ `{cmd} | wc -l` -eq 1 ]")
84           output = machine.succeed(cmd)
85           ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1)
87           if temporary:
88               scope = scope + " temporary"
89           machine.log(f"{scope} address on {iface} is {ip}")
90           return ip
93       with subtest("Loopback address can be pinged"):
94           client_defaults.succeed("ping -c 1 ::1 >&2")
95           client_defaults.fail("ping -c 1 2001:db8:: >&2")
97       with subtest("Local link addresses can be obtained and pinged"):
98           for client in clients:
99               client_ip = wait_for_address(client, "eth1", "link")
100               server_ip = wait_for_address(server, "eth1", "link")
101               client.succeed(f"ping -c 1 {client_ip}%eth1 >&2")
102               client.succeed(f"ping -c 1 {server_ip}%eth1 >&2")
104       with subtest("Global addresses can be obtained, pinged, and reached via http"):
105           for client in clients:
106               client_ip = wait_for_address(client, "eth1", "global")
107               server_ip = wait_for_address(server, "eth1", "global")
108               client.succeed(f"ping -c 1 {client_ip} >&2")
109               client.succeed(f"ping -c 1 {server_ip} >&2")
110               client.succeed(f"curl --fail -g http://[{server_ip}]")
111               client.fail(f"curl --fail -g http://[{client_ip}]")
113       with subtest(
114           "Privacy extensions: Global temporary address is used as default source address"
115       ):
116           ip = wait_for_address(client_defaults, "eth1", "global", temporary=True)
117           # Default route should have "src <temporary address>" in it
118           client_defaults.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
120       for client, setting_desc in (
121           (client_global_setting, "global"),
122           (client_interface_setting, "interface"),
123       ):
124           with subtest(f'Privacy extensions: "enabled" through {setting_desc} setting)'):
125               # We should be obtaining both a temporary address and an EUI-64 address...
126               ip = wait_for_address(client, "eth1", "global")
127               assert "ff:fe" in ip
128               ip_temp = wait_for_address(client, "eth1", "global", temporary=True)
129               # But using the EUI-64 one.
130               client.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
131     '';