mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-30 10:53:11 +00:00
3fd324f823
Eelco has made several early contributions to NixOS including writing the samba module among other things, but is more or less inactive these days. By my brief inspection, he has not committed to the nixos/ tree since releasing Nix 2.13 in early 2023 and merging a PR to networking tests slightly before that. A lot of these tests/modules are actually unmaintained in practice, so we should update the code to reflect the practical reality so someone can consider picking them up.
131 lines
4.9 KiB
Nix
131 lines
4.9 KiB
Nix
# Test of IPv6 functionality in NixOS, including whether router
|
|
# solicication/advertisement using radvd works.
|
|
|
|
import ./make-test-python.nix ({ pkgs, lib, ...} : {
|
|
name = "ipv6";
|
|
meta = with pkgs.lib.maintainers; {
|
|
maintainers = [ ];
|
|
};
|
|
|
|
nodes =
|
|
{
|
|
# We use lib.mkForce here to remove the interface configuration
|
|
# provided by makeTest, so that the interfaces are all configured
|
|
# implicitly.
|
|
|
|
# This client should use privacy extensions fully, having a
|
|
# completely-default network configuration.
|
|
client_defaults.networking.interfaces = lib.mkForce {};
|
|
|
|
# Both of these clients should obtain temporary addresses, but
|
|
# not use them as the default source IP. We thus run the same
|
|
# checks against them — but the configuration resulting in this
|
|
# behaviour is different.
|
|
|
|
# Here, by using an altered default value for the global setting...
|
|
client_global_setting = {
|
|
networking.interfaces = lib.mkForce {};
|
|
networking.tempAddresses = "enabled";
|
|
};
|
|
# and here, by setting this on the interface explicitly.
|
|
client_interface_setting = {
|
|
networking.tempAddresses = "disabled";
|
|
networking.interfaces = lib.mkForce {
|
|
eth1.tempAddress = "enabled";
|
|
};
|
|
};
|
|
|
|
server =
|
|
{ services.httpd.enable = true;
|
|
services.httpd.adminAddr = "foo@example.org";
|
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
|
};
|
|
|
|
router =
|
|
{ ... }:
|
|
{ services.radvd.enable = true;
|
|
services.radvd.config =
|
|
''
|
|
interface eth1 {
|
|
AdvSendAdvert on;
|
|
# ULA prefix (RFC 4193).
|
|
prefix fd60:cc69:b537:1::/64 { };
|
|
};
|
|
'';
|
|
};
|
|
};
|
|
|
|
testScript =
|
|
''
|
|
import re
|
|
|
|
# Start the router first so that it respond to router solicitations.
|
|
router.wait_for_unit("radvd")
|
|
|
|
clients = [client_defaults, client_global_setting, client_interface_setting]
|
|
|
|
start_all()
|
|
|
|
for client in clients:
|
|
client.wait_for_unit("network.target")
|
|
server.wait_for_unit("network.target")
|
|
server.wait_for_unit("httpd.service")
|
|
|
|
# Wait until the given interface has a non-tentative address of
|
|
# the desired scope (i.e. has completed Duplicate Address
|
|
# Detection).
|
|
def wait_for_address(machine, iface, scope, temporary=False):
|
|
temporary_flag = "temporary" if temporary else "-temporary"
|
|
cmd = f"ip -o -6 addr show dev {iface} scope {scope} -tentative {temporary_flag}"
|
|
|
|
machine.wait_until_succeeds(f"[ `{cmd} | wc -l` -eq 1 ]")
|
|
output = machine.succeed(cmd)
|
|
ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1)
|
|
|
|
if temporary:
|
|
scope = scope + " temporary"
|
|
machine.log(f"{scope} address on {iface} is {ip}")
|
|
return ip
|
|
|
|
|
|
with subtest("Loopback address can be pinged"):
|
|
client_defaults.succeed("ping -c 1 ::1 >&2")
|
|
client_defaults.fail("ping -c 1 2001:db8:: >&2")
|
|
|
|
with subtest("Local link addresses can be obtained and pinged"):
|
|
for client in clients:
|
|
client_ip = wait_for_address(client, "eth1", "link")
|
|
server_ip = wait_for_address(server, "eth1", "link")
|
|
client.succeed(f"ping -c 1 {client_ip}%eth1 >&2")
|
|
client.succeed(f"ping -c 1 {server_ip}%eth1 >&2")
|
|
|
|
with subtest("Global addresses can be obtained, pinged, and reached via http"):
|
|
for client in clients:
|
|
client_ip = wait_for_address(client, "eth1", "global")
|
|
server_ip = wait_for_address(server, "eth1", "global")
|
|
client.succeed(f"ping -c 1 {client_ip} >&2")
|
|
client.succeed(f"ping -c 1 {server_ip} >&2")
|
|
client.succeed(f"curl --fail -g http://[{server_ip}]")
|
|
client.fail(f"curl --fail -g http://[{client_ip}]")
|
|
|
|
with subtest(
|
|
"Privacy extensions: Global temporary address is used as default source address"
|
|
):
|
|
ip = wait_for_address(client_defaults, "eth1", "global", temporary=True)
|
|
# Default route should have "src <temporary address>" in it
|
|
client_defaults.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
|
|
|
|
for client, setting_desc in (
|
|
(client_global_setting, "global"),
|
|
(client_interface_setting, "interface"),
|
|
):
|
|
with subtest(f'Privacy extensions: "enabled" through {setting_desc} setting)'):
|
|
# We should be obtaining both a temporary address and an EUI-64 address...
|
|
ip = wait_for_address(client, "eth1", "global")
|
|
assert "ff:fe" in ip
|
|
ip_temp = wait_for_address(client, "eth1", "global", temporary=True)
|
|
# But using the EUI-64 one.
|
|
client.succeed(f"ip route get 2001:db8:: | grep 'src {ip}'")
|
|
'';
|
|
})
|