2011-07-05 13:51:46 +01:00
|
|
|
|
/* 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.
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
- ‘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.
|
|
|
|
|
|
|
|
|
|
*/
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
|
2011-03-10 09:39:17 +00:00
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
{ config, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
with pkgs.lib;
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
cfg = config.networking.firewall;
|
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
helpers =
|
|
|
|
|
''
|
|
|
|
|
# Helper command to manipulate both the IPv4 and IPv6 tables.
|
|
|
|
|
ip46tables() {
|
|
|
|
|
iptables "$@"
|
2012-09-18 22:20:46 +01:00
|
|
|
|
${optionalString config.networking.enableIPv6 ''
|
|
|
|
|
ip6tables "$@"
|
|
|
|
|
''}
|
2011-07-05 13:51:46 +01:00
|
|
|
|
}
|
|
|
|
|
'';
|
|
|
|
|
|
2012-10-12 12:09:19 +01:00
|
|
|
|
kernelPackages = config.boot.kernelPackages;
|
|
|
|
|
kernelHasRPFilter = kernelPackages.kernel ? features
|
|
|
|
|
&& kernelPackages.kernel.features ? netfilterRPFilter
|
|
|
|
|
&& kernelPackages.kernel.features.netfilterRPFilter;
|
|
|
|
|
|
2012-10-12 12:16:33 +01:00
|
|
|
|
kernelCanDisableHelpers = kernelPackages.kernel ? features
|
|
|
|
|
&& kernelPackages.kernel.features ? canDisableNetfilterConntrackHelpers
|
|
|
|
|
&& kernelPackages.kernel.features.canDisableNetfilterConntrackHelpers;
|
|
|
|
|
|
2009-07-25 00:12:52 +01:00
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
|
|
options = {
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
networking.firewall.enable = mkOption {
|
2009-07-26 22:27:35 +01:00
|
|
|
|
default = false;
|
|
|
|
|
description =
|
|
|
|
|
''
|
2011-03-10 09:39:17 +00:00
|
|
|
|
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.
|
2009-07-26 22:27:35 +01:00
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
networking.firewall.logRefusedConnections = mkOption {
|
|
|
|
|
default = true;
|
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
Whether to log rejected or dropped incoming connections.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
networking.firewall.logRefusedPackets = mkOption {
|
2011-07-05 13:54:50 +01:00
|
|
|
|
default = false;
|
2009-09-29 15:21:56 +01:00
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
networking.firewall.rejectPackets = mkOption {
|
|
|
|
|
default = false;
|
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
If set, forbidden packets are rejected rather than dropped
|
|
|
|
|
(ignored). This means that a ICMP "port unreachable" error
|
|
|
|
|
message is sent back to the client. Rejecting packets makes
|
|
|
|
|
port scanning somewhat easier.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2012-09-20 22:51:44 +01:00
|
|
|
|
networking.firewall.trustedInterfaces = mkOption {
|
|
|
|
|
type = types.list types.string;
|
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
Traffic coming in from these interfaces will be accepted
|
|
|
|
|
unconditionally.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2009-09-29 15:21:56 +01:00
|
|
|
|
networking.firewall.allowedTCPPorts = mkOption {
|
2009-07-25 00:12:52 +01:00
|
|
|
|
default = [];
|
2011-03-09 16:37:16 +00:00
|
|
|
|
example = [ 22 80 ];
|
2009-09-29 15:21:56 +01:00
|
|
|
|
type = types.list types.int;
|
2009-07-25 00:12:52 +01:00
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
List of TCP ports on which incoming connections are
|
|
|
|
|
accepted.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2011-03-09 16:37:16 +00:00
|
|
|
|
networking.firewall.allowedUDPPorts = mkOption {
|
|
|
|
|
default = [];
|
|
|
|
|
example = [ 53 ];
|
|
|
|
|
type = types.list types.int;
|
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
List of open UDP ports.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2011-03-09 15:28:47 +00:00
|
|
|
|
networking.firewall.allowPing = mkOption {
|
|
|
|
|
default = false;
|
|
|
|
|
type = types.bool;
|
|
|
|
|
description =
|
|
|
|
|
''
|
2011-03-11 11:08:16 +00:00
|
|
|
|
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.
|
2011-03-09 15:28:47 +00:00
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2012-10-12 12:09:19 +01:00
|
|
|
|
networking.firewall.checkReversePath = mkOption {
|
|
|
|
|
default = kernelHasRPFilter;
|
|
|
|
|
type = types.bool;
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
If using asymmetric routing or other complicated routing,
|
|
|
|
|
disable this setting and setup your own counter-measures.
|
|
|
|
|
|
|
|
|
|
(needs kernel 3.3+)
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2012-10-12 12:16:33 +01:00
|
|
|
|
networking.firewall.connectionTrackingModules = mkOption {
|
|
|
|
|
default = [ "ftp" ];
|
|
|
|
|
example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
|
|
|
|
|
type = types.list types.string;
|
|
|
|
|
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 adviced to
|
|
|
|
|
set this to an empty list and disable the setting
|
|
|
|
|
networking.firewall.autoLoadConntrackHelpers
|
|
|
|
|
|
|
|
|
|
Loading of helpers is recommended to be done through the new
|
|
|
|
|
CT target. More info:
|
|
|
|
|
https://home.regit.org/netfilter-en/secure-use-of-helpers/
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
networking.firewall.autoLoadConntrackHelpers = mkOption {
|
|
|
|
|
default = true;
|
|
|
|
|
type = types.bool;
|
|
|
|
|
description =
|
|
|
|
|
''
|
|
|
|
|
Whether to auto-load connection-tracking helpers.
|
|
|
|
|
See the description at networking.firewall.connectionTrackingModules
|
|
|
|
|
|
|
|
|
|
(needs kernel 3.5+)
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
2011-03-11 13:04:17 +00:00
|
|
|
|
networking.firewall.extraCommands = mkOption {
|
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2009-07-25 00:12:52 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
2009-07-26 22:27:35 +01:00
|
|
|
|
|
|
|
|
|
# !!! Maybe if `enable' is false, the firewall should still be built
|
|
|
|
|
# but not started by default. However, currently nixos-rebuild
|
|
|
|
|
# doesn't deal with such Upstart jobs properly (it starts them if
|
|
|
|
|
# they are changed, regardless of whether the start condition
|
|
|
|
|
# holds).
|
2011-03-10 09:39:17 +00:00
|
|
|
|
config = mkIf cfg.enable {
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
2012-09-20 22:51:44 +01:00
|
|
|
|
networking.firewall.trustedInterfaces = [ "lo" ];
|
|
|
|
|
|
2011-03-09 12:28:44 +00:00
|
|
|
|
environment.systemPackages = [ pkgs.iptables ];
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
2012-10-12 12:16:33 +01:00
|
|
|
|
boot.kernelModules = map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules;
|
|
|
|
|
boot.extraModprobeConfig = optionalString (!cfg.autoLoadConntrackHelpers) ''
|
|
|
|
|
options nf_conntrack nf_conntrack_helper=0
|
|
|
|
|
'';
|
2011-03-11 13:34:17 +00:00
|
|
|
|
|
2012-10-12 12:09:19 +01:00
|
|
|
|
assertions = [ { assertion = ! cfg.checkReversePath || kernelHasRPFilter;
|
2012-10-12 12:16:33 +01:00
|
|
|
|
message = "This kernel does not support rpfilter"; }
|
|
|
|
|
{ assertion = cfg.autoLoadConntrackHelpers || kernelCanDisableHelpers;
|
|
|
|
|
message = "This kernel does not support disabling conntrack helpers"; }
|
|
|
|
|
];
|
2011-03-11 13:34:17 +00:00
|
|
|
|
|
2009-10-12 19:09:34 +01:00
|
|
|
|
jobs.firewall =
|
2013-01-10 12:59:41 +00:00
|
|
|
|
{ description = "Firewall";
|
|
|
|
|
|
|
|
|
|
startOn = "started network-interfaces";
|
2009-07-26 22:27:35 +01:00
|
|
|
|
|
2011-03-09 12:28:44 +00:00
|
|
|
|
path = [ pkgs.iptables ];
|
|
|
|
|
|
2009-07-25 00:12:52 +01:00
|
|
|
|
preStart =
|
|
|
|
|
''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
${helpers}
|
2011-03-09 14:41:48 +00:00
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
# 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
|
2011-03-09 15:11:01 +00:00
|
|
|
|
|
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
# The "nixos-fw-accept" chain just accepts packets.
|
|
|
|
|
ip46tables -N nixos-fw-accept
|
|
|
|
|
ip46tables -A nixos-fw-accept -j ACCEPT
|
2011-03-09 15:11:01 +00:00
|
|
|
|
|
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
# The "nixos-fw-refuse" chain rejects or drops packets.
|
|
|
|
|
ip46tables -N nixos-fw-refuse
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2011-04-12 12:25:57 +01:00
|
|
|
|
${if cfg.rejectPackets then ''
|
|
|
|
|
# Send a reset for existing TCP connections that we've
|
|
|
|
|
# somehow forgotten about. Send ICMP "port unreachable"
|
|
|
|
|
# for everything else.
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset
|
|
|
|
|
ip46tables -A nixos-fw-refuse -j REJECT
|
2011-04-12 12:25:57 +01:00
|
|
|
|
'' else ''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw-refuse -j DROP
|
2011-04-12 12:25:57 +01:00
|
|
|
|
''}
|
2011-03-09 15:11:01 +00:00
|
|
|
|
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
2011-07-05 13:51:46 +01:00
|
|
|
|
# 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
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2012-10-12 12:09:19 +01:00
|
|
|
|
# Perform a reverse-path test to refuse spoofers
|
|
|
|
|
# For now, we just drop, as the raw table doesn't have a log-refuse yet
|
|
|
|
|
${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
|
|
|
|
|
ip46tables -A PREROUTING -t raw -m rpfilter --invert -j DROP
|
|
|
|
|
''}
|
|
|
|
|
|
2012-09-20 22:51:44 +01:00
|
|
|
|
# Accept all traffic on the trusted interfaces.
|
|
|
|
|
${flip concatMapStrings cfg.trustedInterfaces (iface: ''
|
|
|
|
|
ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept
|
|
|
|
|
'')}
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
|
|
|
|
# Accept packets from established or related connections.
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
|
2009-07-25 00:12:52 +01:00
|
|
|
|
|
2011-03-09 14:41:48 +00:00
|
|
|
|
# Accept connections to the allowed TCP ports.
|
2009-09-29 15:21:56 +01:00
|
|
|
|
${concatMapStrings (port:
|
2009-07-25 00:12:52 +01:00
|
|
|
|
''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
|
2009-07-25 00:12:52 +01:00
|
|
|
|
''
|
2011-03-10 09:39:17 +00:00
|
|
|
|
) cfg.allowedTCPPorts
|
2009-07-25 00:12:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-09 16:37:16 +00:00
|
|
|
|
# Accept packets on the allowed UDP ports.
|
|
|
|
|
${concatMapStrings (port:
|
|
|
|
|
''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
|
2011-03-09 16:37:16 +00:00
|
|
|
|
''
|
2011-03-10 09:39:17 +00:00
|
|
|
|
) cfg.allowedUDPPorts
|
2011-03-09 16:37:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-09 14:41:48 +00:00
|
|
|
|
# Accept IPv4 multicast. Not a big security risk since
|
2009-08-10 19:25:09 +01:00
|
|
|
|
# probably nobody is listening anyway.
|
2011-07-05 13:51:46 +01:00
|
|
|
|
#iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept
|
2009-08-10 19:25:09 +01:00
|
|
|
|
|
2011-03-11 11:08:16 +00:00
|
|
|
|
# Optionally respond to ICMPv4 pings.
|
2011-03-09 15:28:47 +00:00
|
|
|
|
${optionalString cfg.allowPing ''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
iptables -A nixos-fw -p icmp --icmp-type echo-request -j nixos-fw-accept
|
2011-03-09 15:28:47 +00:00
|
|
|
|
''}
|
|
|
|
|
|
2011-03-11 11:08:16 +00:00
|
|
|
|
# Accept all ICMPv6 messages except redirects and node
|
|
|
|
|
# information queries (type 139). See RFC 4890, section
|
|
|
|
|
# 4.4.
|
2012-10-19 20:21:06 +01:00
|
|
|
|
${optionalString config.networking.enableIPv6 ''
|
|
|
|
|
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
|
|
|
|
|
''}
|
2011-03-11 11:08:16 +00:00
|
|
|
|
|
2011-03-11 13:04:17 +00:00
|
|
|
|
${cfg.extraCommands}
|
|
|
|
|
|
2011-03-09 15:11:01 +00:00
|
|
|
|
# Reject/drop everything else.
|
2011-07-05 13:51:46 +01:00
|
|
|
|
ip46tables -A nixos-fw -j nixos-fw-log-refuse
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Enable the firewall.
|
|
|
|
|
ip46tables -A INPUT -j nixos-fw
|
2009-07-25 00:12:52 +01:00
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
postStop =
|
|
|
|
|
''
|
2011-07-05 13:51:46 +01:00
|
|
|
|
${helpers}
|
|
|
|
|
ip46tables -D INPUT -j nixos-fw || true
|
|
|
|
|
#ip46tables -P INPUT ACCEPT
|
2011-03-09 12:28:44 +00:00
|
|
|
|
'';
|
2009-07-25 00:12:52 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|