| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  | # Test of IPv6 functionality in NixOS, including whether router | 
					
						
							|  |  |  | # solicication/advertisement using radvd works. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  | import ./make-test-python.nix ({ pkgs, lib, ...} : { | 
					
						
							| 
									
										
										
										
											2014-06-28 16:04:49 +02:00
										 |  |  |   name = "ipv6"; | 
					
						
							| 
									
										
										
										
											2021-01-10 20:08:30 +01:00
										 |  |  |   meta = with pkgs.lib.maintainers; { | 
					
						
							| 
									
										
										
										
											2019-02-22 16:14:13 +01:00
										 |  |  |     maintainers = [ eelco ]; | 
					
						
							| 
									
										
										
										
											2015-07-12 12:09:40 +02:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   nodes = | 
					
						
							| 
									
										
										
										
											2019-04-11 19:41:47 +02:00
										 |  |  |     # Remove the interface configuration provided by makeTest so that the | 
					
						
							|  |  |  |     # interfaces are all configured implicitly | 
					
						
							|  |  |  |     { client = { ... }: { networking.interfaces = lib.mkForce {}; }; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  |       server = | 
					
						
							| 
									
										
										
										
											2018-07-20 20:56:59 +00:00
										 |  |  |         { ... }: | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  |         { services.httpd.enable = true; | 
					
						
							|  |  |  |           services.httpd.adminAddr = "foo@example.org"; | 
					
						
							| 
									
										
										
										
											2014-04-11 17:15:56 +02:00
										 |  |  |           networking.firewall.allowedTCPPorts = [ 80 ]; | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  |       router = | 
					
						
							| 
									
										
										
										
											2018-07-20 20:56:59 +00:00
										 |  |  |         { ... }: | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  |         { services.radvd.enable = true; | 
					
						
							|  |  |  |           services.radvd.config = | 
					
						
							|  |  |  |             ''
 | 
					
						
							|  |  |  |               interface eth1 { | 
					
						
							|  |  |  |                 AdvSendAdvert on; | 
					
						
							|  |  |  |                 # ULA prefix (RFC 4193). | 
					
						
							|  |  |  |                 prefix fd60:cc69:b537:1::/64 { }; | 
					
						
							|  |  |  |               }; | 
					
						
							|  |  |  |             '';
 | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   testScript = | 
					
						
							|  |  |  |     ''
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       import re | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  |       # Start the router first so that it respond to router solicitations. | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       router.wait_for_unit("radvd") | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       start_all() | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       client.wait_for_unit("network.target") | 
					
						
							|  |  |  |       server.wait_for_unit("network.target") | 
					
						
							|  |  |  |       server.wait_for_unit("httpd.service") | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # Wait until the given interface has a non-tentative address of | 
					
						
							|  |  |  |       # the desired scope (i.e. has completed Duplicate Address | 
					
						
							|  |  |  |       # Detection). | 
					
						
							| 
									
										
										
										
											2019-12-08 19:47:15 +01:00
										 |  |  |       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) | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |           ip = re.search(r"inet6 ([0-9a-f:]{2,})/", output).group(1) | 
					
						
							| 
									
										
										
										
											2019-12-08 19:47:15 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |           if temporary: | 
					
						
							|  |  |  |               scope = scope + " temporary" | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |           machine.log(f"{scope} address on {iface} is {ip}") | 
					
						
							|  |  |  |           return ip | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       with subtest("Loopback address can be pinged"): | 
					
						
							|  |  |  |           client.succeed("ping -c 1 ::1 >&2") | 
					
						
							|  |  |  |           client.fail("ping -c 1 ::2 >&2") | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       with subtest("Local link addresses can be obtained and pinged"): | 
					
						
							|  |  |  |           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") | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       with subtest("Global addresses can be obtained, pinged, and reached via http"): | 
					
						
							|  |  |  |           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}]") | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |       with subtest("Privacy extensions: Global temporary address can be obtained and pinged"): | 
					
						
							| 
									
										
										
										
											2019-12-08 19:47:15 +01:00
										 |  |  |           ip = wait_for_address(client, "eth1", "global", temporary=True) | 
					
						
							| 
									
										
										
										
											2019-04-11 19:41:47 +02:00
										 |  |  |           # Default route should have "src <temporary address>" in it | 
					
						
							| 
									
										
										
										
											2019-12-01 01:08:44 +01:00
										 |  |  |           client.succeed(f"ip r g ::2 | grep {ip}") | 
					
						
							| 
									
										
										
										
											2011-02-19 19:21:19 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # TODO: test reachability of a machine on another network. | 
					
						
							|  |  |  |     '';
 | 
					
						
							| 
									
										
										
										
											2015-07-12 12:09:40 +02:00
										 |  |  | }) |