1# Test the firewall module.
2
3import ./make-test-python.nix (
4 { pkgs, nftables, ... }:
5 {
6 name = "firewall" + pkgs.lib.optionalString nftables "-nftables";
7 meta = with pkgs.lib.maintainers; {
8 maintainers = [
9 rvfg
10 garyguo
11 ];
12 };
13
14 nodes = {
15 walled =
16 { ... }:
17 {
18 networking.firewall = {
19 enable = true;
20 logRefusedPackets = true;
21 # Syntax smoke test, not actually verified otherwise
22 allowedTCPPorts = [
23 25
24 993
25 8005
26 ];
27 allowedTCPPortRanges = [
28 {
29 from = 980;
30 to = 1000;
31 }
32 {
33 from = 990;
34 to = 1010;
35 }
36 {
37 from = 8000;
38 to = 8010;
39 }
40 ];
41 interfaces.eth0 = {
42 allowedTCPPorts = [ 10003 ];
43 allowedTCPPortRanges = [
44 {
45 from = 10000;
46 to = 10005;
47 }
48 ];
49 };
50 interfaces.eth3 = {
51 allowedUDPPorts = [ 10003 ];
52 allowedUDPPortRanges = [
53 {
54 from = 10000;
55 to = 10005;
56 }
57 ];
58 };
59 };
60 networking.nftables.enable = nftables;
61 services.httpd.enable = true;
62 services.httpd.adminAddr = "foo@example.org";
63
64 specialisation.different-config.configuration = {
65 networking.firewall.rejectPackets = true;
66 };
67 };
68
69 attacker =
70 { ... }:
71 {
72 services.httpd.enable = true;
73 services.httpd.adminAddr = "foo@example.org";
74 networking.firewall.enable = false;
75 };
76 };
77
78 testScript =
79 { nodes, ... }:
80 let
81 unit = if nftables then "nftables" else "firewall";
82 in
83 ''
84 start_all()
85
86 walled.wait_for_unit("${unit}")
87 walled.wait_for_unit("httpd")
88 attacker.wait_for_unit("network.target")
89
90 # Local connections should still work.
91 walled.succeed("curl -v http://localhost/ >&2")
92
93 # Connections to the firewalled machine should fail, but ping should succeed.
94 attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
95 attacker.succeed("ping -c 1 walled >&2")
96
97 # Outgoing connections/pings should still work.
98 walled.succeed("curl -v http://attacker/ >&2")
99 walled.succeed("ping -c 1 attacker >&2")
100
101 # Open tcp port 80 at runtime
102 walled.succeed("nixos-firewall-tool open tcp 80")
103 attacker.succeed("curl -v http://walled/ >&2")
104
105 # Reset the firewall
106 walled.succeed("nixos-firewall-tool reset")
107 attacker.fail("curl --fail --connect-timeout 2 http://walled/ >&2")
108
109 # If we stop the firewall, then connections should succeed.
110 walled.stop_job("${unit}")
111 attacker.succeed("curl -v http://walled/ >&2")
112
113 # Check whether activation of a new configuration reloads the firewall.
114 walled.succeed(
115 "/run/booted-system/specialisation/different-config/bin/switch-to-configuration test 2>&1 | grep -qF ${unit}.service"
116 )
117 '';
118 }
119)