summary refs log tree commit diff
path: root/modules/services/networking/firewall.nix
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2011-07-05 12:51:46 +0000
committerEelco Dolstra <eelco.dolstra@logicblox.com>2011-07-05 12:51:46 +0000
commit3bc3dc3940ba7079ca76341ade31c6c6a7580a9f (patch)
treead7e23d518842b4524a95da9178fdb1ed900563f /modules/services/networking/firewall.nix
parent1d09ad240a5a0641fd2f6574b8211ccd5361ae3d (diff)
downloadnixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar.gz
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar.bz2
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar.lz
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar.xz
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.tar.zst
nixpkgs-3bc3dc3940ba7079ca76341ade31c6c6a7580a9f.zip
* Put the NixOS firewall ruleset in its own chain (‘nixos-fw’). This
  should make it easier to compose with packages that set their own
  firewall rules, such as Nova or Libvirt.
* Provide a chain for accepted packets (‘nixos-fw-accept’), requested
  by Nicolas Pierron.

svn path=/nixos/trunk/; revision=27607
Diffstat (limited to 'modules/services/networking/firewall.nix')
-rw-r--r--modules/services/networking/firewall.nix139
1 files changed, 102 insertions, 37 deletions
diff --git a/modules/services/networking/firewall.nix b/modules/services/networking/firewall.nix
index 50790ba3135..83cb1ad0817 100644
--- a/modules/services/networking/firewall.nix
+++ b/modules/services/networking/firewall.nix
@@ -1,4 +1,24 @@
-# This module enables a simple firewall.
+/* This module enables a simple firewall.
+
+   The firewall can be customised in arbitrary ways by setting
+   ‘networking.firewall.extraCommands’.  For modularity, the firewall
+   uses several chains:
+
+   - ‘nixos-fw-input’ is the main chain for input packet processing.
+   
+   - ‘nixos-fw-log-refuse’ and ‘nixos-fw-refuse’ are called for
+     refused packets.  (The former jumps to the latter after logging
+     the packet.)  If you want additional logging, or want to accept
+     certain packets anyway, you can insert rules at the start of
+     these chain.
+
+   - ‘nixos-fw-accept’ is called for accepted packets.  If you want
+     additional logging, or want to reject certain packets anyway, you
+     can insert rules at the start of this chain.
+
+*/
+  
+
 
 { config, pkgs, ... }:
 
@@ -8,6 +28,15 @@ let
 
   cfg = config.networking.firewall;
 
+  helpers =
+    ''
+      # Helper command to manipulate both the IPv4 and IPv6 tables.
+      ip46tables() {
+        iptables "$@"
+        ip6tables "$@"
+      }
+    '';
+
 in
 
 {
@@ -36,7 +65,7 @@ in
     };
   
     networking.firewall.logRefusedPackets = mkOption {
-      default = false;
+      default = true;
       description =
         ''
           Whether to log all rejected or dropped incoming packets.
@@ -45,6 +74,17 @@ in
         '';
     };
 
+    networking.firewall.logRefusedUnicastsOnly = mkOption {
+      default = true;
+      description =
+        ''
+          If <option>networking.firewall.logRefusedPackets</option>
+          and this option are enabled, then only log packets
+          specifically directed at this machine, i.e., not broadcasts
+          or multicasts.
+        '';
+    };
+
     networking.firewall.rejectPackets = mkOption {
       default = false;
       description =
@@ -124,50 +164,72 @@ in
 
         preStart =
           ''
-            # Helper command to manipulate both the IPv4 and IPv6 tables.
-            ip46tables() {
-              iptables "$@"
-              ip6tables "$@"
-            }
+            ${helpers}
+            set -x
 
-            ip46tables -F INPUT
-            ip46tables -F FW_REFUSE || true
-            ip46tables -X # flush unused chains
-            ip46tables -P INPUT ACCEPT
+            # Flush the old firewall rules.  !!! Ideally, updating the
+            # firewall would be atomic.  Apparently that's possible
+            # with iptables-restore.
+            ip46tables -D INPUT -j nixos-fw || true
+            for chain in nixos-fw nixos-fw-accept nixos-fw-log-refuse nixos-fw-refuse FW_REFUSE; do
+              ip46tables -F "$chain" || true
+              ip46tables -X "$chain" || true
+            done
 
 
-            # The "FW_REFUSE" chain performs logging and
-            # rejecting/dropping of packets.
-            ip46tables -N FW_REFUSE
+            # The "nixos-fw-accept" chain just accepts packets.
+            ip46tables -N nixos-fw-accept
+            ip46tables -A nixos-fw-accept -j ACCEPT
 
-            ${optionalString cfg.logRefusedConnections ''
-              ip46tables -A FW_REFUSE -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: "
-            ''}
-            ${optionalString cfg.logRefusedPackets ''
-              ip46tables -A FW_REFUSE -j LOG --log-level info --log-prefix "rejected packet: "
-            ''}
 
+            # The "nixos-fw-refuse" chain rejects or drops packets.
+            ip46tables -N nixos-fw-refuse
+            
             ${if cfg.rejectPackets then ''
               # Send a reset for existing TCP connections that we've
               # somehow forgotten about.  Send ICMP "port unreachable"
               # for everything else.
-              ip46tables -A FW_REFUSE -p tcp ! --syn -j REJECT --reject-with tcp-reset
-              ip46tables -A FW_REFUSE -j REJECT
+              ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset
+              ip46tables -A nixos-fw-refuse -j REJECT
             '' else ''
-              ip46tables -A FW_REFUSE -j DROP
+              ip46tables -A nixos-fw-refuse -j DROP
             ''}
 
 
+            # The "nixos-fw-log-refuse" chain performs logging, then
+            # jumps to the "nixos-fw-refuse" chain.
+            ip46tables -N nixos-fw-log-refuse
+
+            ${optionalString cfg.logRefusedConnections ''
+              ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: "
+            ''}
+            ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) ''
+              ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \
+                -j LOG --log-level info --log-prefix "rejected broadcast: "
+              ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \
+                -j LOG --log-level info --log-prefix "rejected multicast: "
+            ''}
+            ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse
+            ${optionalString cfg.logRefusedPackets ''
+              ip46tables -A nixos-fw-log-refuse \
+                -j LOG --log-level info --log-prefix "rejected packet: "
+            ''}
+            ip46tables -A nixos-fw-log-refuse -j nixos-fw-refuse
+
+
+            # The "nixos-fw" chain does the actual work.
+            ip46tables -N nixos-fw
+            
             # Accept all traffic on the loopback interface.
-            ip46tables -A INPUT -i lo -j ACCEPT
+            ip46tables -A nixos-fw -i lo -j nixos-fw-accept
 
             # Accept packets from established or related connections.
-            ip46tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
+            ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
 
             # Accept connections to the allowed TCP ports.
             ${concatMapStrings (port:
                 ''
-                  ip46tables -A INPUT -p tcp --dport ${toString port} -j ACCEPT
+                  ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
                 ''
               ) cfg.allowedTCPPorts
             }
@@ -175,39 +237,42 @@ in
             # Accept packets on the allowed UDP ports.
             ${concatMapStrings (port:
                 ''
-                  ip46tables -A INPUT -p udp --dport ${toString port} -j ACCEPT
+                  ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
                 ''
               ) cfg.allowedUDPPorts
             }
 
             # Accept IPv4 multicast.  Not a big security risk since
             # probably nobody is listening anyway.
-            iptables -A INPUT -d 224.0.0.0/4 -j ACCEPT
+            #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept
 
             # Optionally respond to ICMPv4 pings.
             ${optionalString cfg.allowPing ''
-              iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
+              iptables -A nixos-fw -p icmp --icmp-type echo-request -j nixos-fw-accept
             ''}
 
             # Accept all ICMPv6 messages except redirects and node
             # information queries (type 139).  See RFC 4890, section
             # 4.4.
-            ip6tables -A INPUT -p icmpv6 --icmpv6-type redirect -j DROP
-            ip6tables -A INPUT -p icmpv6 --icmpv6-type 139 -j DROP
-            ip6tables -A INPUT -p icmpv6 -j ACCEPT
+            ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
+            ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
+            ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
 
             ${cfg.extraCommands}
 
             # Reject/drop everything else.
-            ip46tables -A INPUT -j FW_REFUSE
+            ip46tables -A nixos-fw -j nixos-fw-log-refuse
+
+
+            # Enable the firewall.
+            ip46tables -A INPUT -j nixos-fw
           '';
 
         postStop =
           ''
-            iptables -F INPUT
-            iptables -P INPUT ACCEPT
-            ip6tables -F INPUT
-            ip6tables -P INPUT ACCEPT
+            ${helpers}
+            ip46tables -D INPUT -j nixos-fw || true
+            #ip46tables -P INPUT ACCEPT
           '';
       };