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