diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index c4bd0e7f9ee..36f1dd8d247 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -148,38 +148,42 @@ let
ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
# Accept connections to the allowed TCP ports.
- ${concatMapStrings (port:
+ ${concatStrings (mapAttrsToList (iface: cfg:
+ concatMapStrings (port:
''
- ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
+ ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
''
) cfg.allowedTCPPorts
- }
+ ) cfg.interfaces)}
# Accept connections to the allowed TCP port ranges.
- ${concatMapStrings (rangeAttr:
+ ${concatStrings (mapAttrsToList (iface: cfg:
+ concatMapStrings (rangeAttr:
let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
''
- ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept
+ ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
''
) cfg.allowedTCPPortRanges
- }
+ ) cfg.interfaces)}
# Accept packets on the allowed UDP ports.
- ${concatMapStrings (port:
+ ${concatStrings (mapAttrsToList (iface: cfg:
+ concatMapStrings (port:
''
- ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
+ ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
''
) cfg.allowedUDPPorts
- }
+ ) cfg.interfaces)}
# Accept packets on the allowed UDP port ranges.
- ${concatMapStrings (rangeAttr:
+ ${concatStrings (mapAttrsToList (iface: cfg:
+ concatMapStrings (rangeAttr:
let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
''
- ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept
+ ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
''
) cfg.allowedUDPPortRanges
- }
+ ) cfg.interfaces)}
# Accept IPv4 multicast. Not a big security risk since
# probably nobody is listening anyway.
@@ -254,106 +258,30 @@ let
fi
'';
-in
-
-{
-
- ###### interface
-
- options = {
-
- networking.firewall.enable = mkOption {
- type = types.bool;
- default = true;
- description =
- ''
- Whether to enable the firewall. This is a simple stateful
- firewall that blocks connection attempts to unauthorised TCP
- or UDP ports on this machine. It does not affect packet
- forwarding.
- '';
- };
-
- networking.firewall.logRefusedConnections = mkOption {
- type = types.bool;
- default = true;
- description =
- ''
- Whether to log rejected or dropped incoming connections.
- '';
- };
-
- networking.firewall.logRefusedPackets = mkOption {
- type = types.bool;
- default = false;
- description =
- ''
- Whether to log all rejected or dropped incoming packets.
- This tends to give a lot of log messages, so it's mostly
- useful for debugging.
- '';
- };
-
- networking.firewall.logRefusedUnicastsOnly = mkOption {
- type = types.bool;
- default = true;
- description =
- ''
- If
- and this option are enabled, then only log packets
- specifically directed at this machine, i.e., not broadcasts
- or multicasts.
- '';
- };
-
- networking.firewall.rejectPackets = mkOption {
- type = types.bool;
- default = false;
- description =
- ''
- If set, refused packets are rejected rather than dropped
- (ignored). This means that an ICMP "port unreachable" error
- message is sent back to the client (or a TCP RST packet in
- case of an existing connection). Rejecting packets makes
- port scanning somewhat easier.
- '';
- };
-
- networking.firewall.trustedInterfaces = mkOption {
- type = types.listOf types.str;
- default = [ ];
- example = [ "enp0s2" ];
- description =
- ''
- Traffic coming in from these interfaces will be accepted
- unconditionally. Traffic from the loopback (lo) interface
- will always be accepted.
- '';
- };
-
- networking.firewall.allowedTCPPorts = mkOption {
+ commonOptions = {
+ allowedTCPPorts = mkOption {
type = types.listOf types.int;
default = [ ];
example = [ 22 80 ];
description =
- ''
+ ''
List of TCP ports on which incoming connections are
accepted.
'';
};
- networking.firewall.allowedTCPPortRanges = mkOption {
+ allowedTCPPortRanges = mkOption {
type = types.listOf (types.attrsOf types.int);
default = [ ];
example = [ { from = 8999; to = 9003; } ];
description =
- ''
+ ''
A range of TCP ports on which incoming connections are
accepted.
'';
};
- networking.firewall.allowedUDPPorts = mkOption {
+ allowedUDPPorts = mkOption {
type = types.listOf types.int;
default = [ ];
example = [ 53 ];
@@ -363,7 +291,7 @@ in
'';
};
- networking.firewall.allowedUDPPortRanges = mkOption {
+ allowedUDPPortRanges = mkOption {
type = types.listOf (types.attrsOf types.int);
default = [ ];
example = [ { from = 60000; to = 61000; } ];
@@ -372,133 +300,226 @@ in
Range of open UDP ports.
'';
};
+ };
- networking.firewall.allowPing = mkOption {
- type = types.bool;
- default = true;
- description =
- ''
- Whether to respond to incoming ICMPv4 echo requests
- ("pings"). ICMPv6 pings are always allowed because the
- larger address space of IPv6 makes network scanning much
- less effective.
- '';
- };
+in
- networking.firewall.pingLimit = mkOption {
- type = types.nullOr (types.separatedString " ");
- default = null;
- example = "--limit 1/minute --limit-burst 5";
- description =
- ''
- If pings are allowed, this allows setting rate limits
- on them. If non-null, this option should be in the form of
- flags like "--limit 1/minute --limit-burst 5"
- '';
- };
+{
- networking.firewall.checkReversePath = mkOption {
- type = types.either types.bool (types.enum ["strict" "loose"]);
- default = kernelHasRPFilter;
- example = "loose";
- description =
- ''
- Performs a reverse path filter test on a packet. If a reply
- to the packet would not be sent via the same interface that
- the packet arrived on, it is refused.
+ ###### interface
- If using asymmetric routing or other complicated routing, set
- this option to loose mode or disable it and setup your own
- counter-measures.
+ options = {
- This option can be either true (or "strict"), "loose" (only
- drop the packet if the source address is not reachable via any
- interface) or false. Defaults to the value of
- kernelHasRPFilter.
+ networking.firewall = {
+ enable = mkOption {
+ type = types.bool;
+ default = true;
+ description =
+ ''
+ Whether to enable the firewall. This is a simple stateful
+ firewall that blocks connection attempts to unauthorised TCP
+ or UDP ports on this machine. It does not affect packet
+ forwarding.
+ '';
+ };
- (needs kernel 3.3+)
- '';
- };
+ logRefusedConnections = mkOption {
+ type = types.bool;
+ default = true;
+ description =
+ ''
+ Whether to log rejected or dropped incoming connections.
+ '';
+ };
- networking.firewall.logReversePathDrops = mkOption {
- type = types.bool;
- default = false;
- description =
- ''
- Logs dropped packets failing the reverse path filter test if
- the option networking.firewall.checkReversePath is enabled.
- '';
- };
+ logRefusedPackets = mkOption {
+ type = types.bool;
+ default = false;
+ description =
+ ''
+ Whether to log all rejected or dropped incoming packets.
+ This tends to give a lot of log messages, so it's mostly
+ useful for debugging.
+ '';
+ };
- networking.firewall.connectionTrackingModules = mkOption {
- type = types.listOf types.str;
- default = [ ];
- example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
- description =
- ''
- List of connection-tracking helpers that are auto-loaded.
- The complete list of possible values is given in the example.
+ logRefusedUnicastsOnly = mkOption {
+ type = types.bool;
+ default = true;
+ description =
+ ''
+ If
+ and this option are enabled, then only log packets
+ specifically directed at this machine, i.e., not broadcasts
+ or multicasts.
+ '';
+ };
- As helpers can pose as a security risk, it is advised to
- set this to an empty list and disable the setting
- networking.firewall.autoLoadConntrackHelpers unless you
- know what you are doing. Connection tracking is disabled
- by default.
+ rejectPackets = mkOption {
+ type = types.bool;
+ default = false;
+ description =
+ ''
+ If set, refused packets are rejected rather than dropped
+ (ignored). This means that an ICMP "port unreachable" error
+ message is sent back to the client (or a TCP RST packet in
+ case of an existing connection). Rejecting packets makes
+ port scanning somewhat easier.
+ '';
+ };
- Loading of helpers is recommended to be done through the
- CT target. More info:
- https://home.regit.org/netfilter-en/secure-use-of-helpers/
- '';
- };
+ trustedInterfaces = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "enp0s2" ];
+ description =
+ ''
+ Traffic coming in from these interfaces will be accepted
+ unconditionally. Traffic from the loopback (lo) interface
+ will always be accepted.
+ '';
+ };
- networking.firewall.autoLoadConntrackHelpers = mkOption {
- type = types.bool;
- default = false;
- description =
- ''
- Whether to auto-load connection-tracking helpers.
- See the description at networking.firewall.connectionTrackingModules
+ allowPing = mkOption {
+ type = types.bool;
+ default = true;
+ description =
+ ''
+ Whether to respond to incoming ICMPv4 echo requests
+ ("pings"). ICMPv6 pings are always allowed because the
+ larger address space of IPv6 makes network scanning much
+ less effective.
+ '';
+ };
- (needs kernel 3.5+)
- '';
- };
+ pingLimit = mkOption {
+ type = types.nullOr (types.separatedString " ");
+ default = null;
+ example = "--limit 1/minute --limit-burst 5";
+ description =
+ ''
+ If pings are allowed, this allows setting rate limits
+ on them. If non-null, this option should be in the form of
+ flags like "--limit 1/minute --limit-burst 5"
+ '';
+ };
- networking.firewall.extraCommands = mkOption {
- type = types.lines;
- default = "";
- example = "iptables -A INPUT -p icmp -j ACCEPT";
- description =
- ''
- Additional shell commands executed as part of the firewall
- initialisation script. These are executed just before the
- final "reject" firewall rule is added, so they can be used
- to allow packets that would otherwise be refused.
- '';
- };
+ checkReversePath = mkOption {
+ type = types.either types.bool (types.enum ["strict" "loose"]);
+ default = kernelHasRPFilter;
+ example = "loose";
+ description =
+ ''
+ Performs a reverse path filter test on a packet. If a reply
+ to the packet would not be sent via the same interface that
+ the packet arrived on, it is refused.
- networking.firewall.extraPackages = mkOption {
- type = types.listOf types.package;
- default = [ ];
- example = literalExample "[ pkgs.ipset ]";
- description =
- ''
- Additional packages to be included in the environment of the system
- as well as the path of networking.firewall.extraCommands.
- '';
- };
+ If using asymmetric routing or other complicated routing, set
+ this option to loose mode or disable it and setup your own
+ counter-measures.
- networking.firewall.extraStopCommands = mkOption {
- type = types.lines;
- default = "";
- example = "iptables -P INPUT ACCEPT";
- description =
- ''
- Additional shell commands executed as part of the firewall
- shutdown script. These are executed just after the removal
- of the NixOS input rule, or if the service enters a failed
- state.
- '';
- };
+ This option can be either true (or "strict"), "loose" (only
+ drop the packet if the source address is not reachable via any
+ interface) or false. Defaults to the value of
+ kernelHasRPFilter.
+
+ (needs kernel 3.3+)
+ '';
+ };
+
+ logReversePathDrops = mkOption {
+ type = types.bool;
+ default = false;
+ description =
+ ''
+ Logs dropped packets failing the reverse path filter test if
+ the option networking.firewall.checkReversePath is enabled.
+ '';
+ };
+
+ connectionTrackingModules = mkOption {
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
+ description =
+ ''
+ List of connection-tracking helpers that are auto-loaded.
+ The complete list of possible values is given in the example.
+
+ As helpers can pose as a security risk, it is advised to
+ set this to an empty list and disable the setting
+ networking.firewall.autoLoadConntrackHelpers unless you
+ know what you are doing. Connection tracking is disabled
+ by default.
+
+ Loading of helpers is recommended to be done through the
+ CT target. More info:
+ https://home.regit.org/netfilter-en/secure-use-of-helpers/
+ '';
+ };
+
+ autoLoadConntrackHelpers = mkOption {
+ type = types.bool;
+ default = false;
+ description =
+ ''
+ Whether to auto-load connection-tracking helpers.
+ See the description at networking.firewall.connectionTrackingModules
+
+ (needs kernel 3.5+)
+ '';
+ };
+
+ extraCommands = mkOption {
+ type = types.lines;
+ default = "";
+ example = "iptables -A INPUT -p icmp -j ACCEPT";
+ description =
+ ''
+ Additional shell commands executed as part of the firewall
+ initialisation script. These are executed just before the
+ final "reject" firewall rule is added, so they can be used
+ to allow packets that would otherwise be refused.
+ '';
+ };
+
+ extraPackages = mkOption {
+ type = types.listOf types.package;
+ default = [ ];
+ example = literalExample "[ pkgs.ipset ]";
+ description =
+ ''
+ Additional packages to be included in the environment of the system
+ as well as the path of networking.firewall.extraCommands.
+ '';
+ };
+
+ extraStopCommands = mkOption {
+ type = types.lines;
+ default = "";
+ example = "iptables -P INPUT ACCEPT";
+ description =
+ ''
+ Additional shell commands executed as part of the firewall
+ shutdown script. These are executed just after the removal
+ of the NixOS input rule, or if the service enters a failed
+ state.
+ '';
+ };
+
+ interfaces = mkOption {
+ default = {
+ default = mapAttrs (name: value: cfg."${name}") commonOptions;
+ };
+ type = with types; attrsOf (submodule [ { options = commonOptions; } ]);
+ description =
+ ''
+ Interface-specific open ports. Setting this value will override
+ all values of the networking.firewall.allowed*
+ options.
+ '';
+ };
+ } // commonOptions;
};