1{ system ? builtins.currentSystem 2, config ? {} 3, pkgs ? import ../.. { inherit system config; } 4, systemdStage1 ? false 5}: 6 7import ../make-test-python.nix ({ lib, ...}: 8 9{ 10 name = "initrd-network-openvpn"; 11 12 nodes = 13 let 14 15 # Inlining of the shared secret for the 16 # OpenVPN server and client 17 secretblock = '' 18 secret [inline] 19 <secret> 20 ${lib.readFile ./shared.key} 21 </secret> 22 ''; 23 24 in 25 { 26 27 # Minimal test case to check a successful boot, even with invalid config 28 minimalboot = 29 { ... }: 30 { 31 boot.initrd.systemd.enable = systemdStage1; 32 boot.initrd.network = { 33 enable = true; 34 openvpn = { 35 enable = true; 36 configuration = builtins.toFile "initrd.ovpn" ""; 37 }; 38 }; 39 }; 40 41 # initrd VPN client 42 ovpnclient = 43 { ... }: 44 { 45 virtualisation.useBootLoader = true; 46 virtualisation.vlans = [ 1 ]; 47 48 boot.initrd = { 49 systemd.enable = systemdStage1; 50 systemd.extraBin.nc = "${pkgs.busybox}/bin/nc"; 51 systemd.services.nc = { 52 requiredBy = ["initrd.target"]; 53 after = ["network.target"]; 54 serviceConfig = { 55 ExecStart = "/bin/nc -p 1234 -lke /bin/echo TESTVALUE"; 56 Type = "oneshot"; 57 }; 58 }; 59 60 # This command does not fork to keep the VM in the state where 61 # only the initramfs is loaded 62 preLVMCommands = 63 '' 64 /bin/nc -p 1234 -lke /bin/echo TESTVALUE 65 ''; 66 67 network = { 68 enable = true; 69 70 # Work around udhcpc only getting a lease on eth0 71 postCommands = '' 72 /bin/ip addr add 192.168.1.2/24 dev eth1 73 ''; 74 75 # Example configuration for OpenVPN 76 # This is the main reason for this test 77 openvpn = { 78 enable = true; 79 configuration = "${./initrd.ovpn}"; 80 }; 81 }; 82 }; 83 }; 84 85 # VPN server and gateway for ovpnclient between vlan 1 and 2 86 ovpnserver = 87 { ... }: 88 { 89 virtualisation.vlans = [ 1 2 ]; 90 91 # Enable NAT and forward port 12345 to port 1234 92 networking.nat = { 93 enable = true; 94 internalInterfaces = [ "tun0" ]; 95 externalInterface = "eth2"; 96 forwardPorts = [ { destination = "10.8.0.2:1234"; 97 sourcePort = 12345; } ]; 98 }; 99 100 # Trust tun0 and allow the VPN Server to be reached 101 networking.firewall = { 102 trustedInterfaces = [ "tun0" ]; 103 allowedUDPPorts = [ 1194 ]; 104 }; 105 106 # Minimal OpenVPN server configuration 107 services.openvpn.servers.testserver = 108 { 109 config = '' 110 dev tun0 111 ifconfig 10.8.0.1 10.8.0.2 112 cipher AES-256-CBC 113 ${secretblock} 114 ''; 115 }; 116 }; 117 118 # Client that resides in the "external" VLAN 119 testclient = 120 { ... }: 121 { 122 virtualisation.vlans = [ 2 ]; 123 }; 124 }; 125 126 127 testScript = 128 '' 129 # Minimal test case, checks whether enabling (with invalid config) harms 130 # the boot process 131 with subtest("Check for successful boot with broken openvpn config"): 132 minimalboot.start() 133 # If we get to multi-user.target, we booted successfully 134 minimalboot.wait_for_unit("multi-user.target") 135 minimalboot.shutdown() 136 137 # Elaborated test case where the ovpnclient (where this module is used) 138 # can be reached by testclient only over ovpnserver. 139 # This is an indirect test for success. 140 with subtest("Check for connection from initrd VPN client, config as file"): 141 ovpnserver.start() 142 testclient.start() 143 ovpnclient.start() 144 145 # Wait until the OpenVPN Server is available 146 ovpnserver.wait_for_unit("openvpn-testserver.service") 147 ovpnserver.succeed("ping -c 1 10.8.0.1") 148 149 # Wait for the client to connect 150 ovpnserver.wait_until_succeeds("ping -c 1 10.8.0.2") 151 152 # Wait until the testclient has network 153 testclient.wait_for_unit("network.target") 154 155 # Check that ovpnclient is reachable over vlan 1 156 ovpnserver.succeed("nc -w 2 192.168.1.2 1234 | grep -q TESTVALUE") 157 158 # Check that ovpnclient is reachable over tun0 159 ovpnserver.succeed("nc -w 2 10.8.0.2 1234 | grep -q TESTVALUE") 160 161 # Check that ovpnclient is reachable from testclient over the gateway 162 testclient.succeed("nc -w 2 192.168.2.3 12345 | grep -q TESTVALUE") 163 ''; 164})