* 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
This commit is contained in:
parent
1d09ad240a
commit
3bc3dc3940
@ -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, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
@ -8,6 +28,15 @@ let
|
|||||||
|
|
||||||
cfg = config.networking.firewall;
|
cfg = config.networking.firewall;
|
||||||
|
|
||||||
|
helpers =
|
||||||
|
''
|
||||||
|
# Helper command to manipulate both the IPv4 and IPv6 tables.
|
||||||
|
ip46tables() {
|
||||||
|
iptables "$@"
|
||||||
|
ip6tables "$@"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -36,7 +65,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.logRefusedPackets = mkOption {
|
networking.firewall.logRefusedPackets = mkOption {
|
||||||
default = false;
|
default = true;
|
||||||
description =
|
description =
|
||||||
''
|
''
|
||||||
Whether to log all rejected or dropped incoming packets.
|
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 {
|
networking.firewall.rejectPackets = mkOption {
|
||||||
default = false;
|
default = false;
|
||||||
description =
|
description =
|
||||||
@ -124,50 +164,72 @@ in
|
|||||||
|
|
||||||
preStart =
|
preStart =
|
||||||
''
|
''
|
||||||
# Helper command to manipulate both the IPv4 and IPv6 tables.
|
${helpers}
|
||||||
ip46tables() {
|
set -x
|
||||||
iptables "$@"
|
|
||||||
ip6tables "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
ip46tables -F INPUT
|
# Flush the old firewall rules. !!! Ideally, updating the
|
||||||
ip46tables -F FW_REFUSE || true
|
# firewall would be atomic. Apparently that's possible
|
||||||
ip46tables -X # flush unused chains
|
# with iptables-restore.
|
||||||
ip46tables -P INPUT ACCEPT
|
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
|
# The "nixos-fw-accept" chain just accepts packets.
|
||||||
# rejecting/dropping of packets.
|
ip46tables -N nixos-fw-accept
|
||||||
ip46tables -N FW_REFUSE
|
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: "
|
# The "nixos-fw-refuse" chain rejects or drops packets.
|
||||||
''}
|
ip46tables -N nixos-fw-refuse
|
||||||
${optionalString cfg.logRefusedPackets ''
|
|
||||||
ip46tables -A FW_REFUSE -j LOG --log-level info --log-prefix "rejected packet: "
|
|
||||||
''}
|
|
||||||
|
|
||||||
${if cfg.rejectPackets then ''
|
${if cfg.rejectPackets then ''
|
||||||
# Send a reset for existing TCP connections that we've
|
# Send a reset for existing TCP connections that we've
|
||||||
# somehow forgotten about. Send ICMP "port unreachable"
|
# somehow forgotten about. Send ICMP "port unreachable"
|
||||||
# for everything else.
|
# for everything else.
|
||||||
ip46tables -A FW_REFUSE -p tcp ! --syn -j REJECT --reject-with tcp-reset
|
ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset
|
||||||
ip46tables -A FW_REFUSE -j REJECT
|
ip46tables -A nixos-fw-refuse -j REJECT
|
||||||
'' else ''
|
'' 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.
|
# 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.
|
# 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.
|
# Accept connections to the allowed TCP ports.
|
||||||
${concatMapStrings (port:
|
${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
|
) cfg.allowedTCPPorts
|
||||||
}
|
}
|
||||||
@ -175,39 +237,42 @@ in
|
|||||||
# Accept packets on the allowed UDP ports.
|
# Accept packets on the allowed UDP ports.
|
||||||
${concatMapStrings (port:
|
${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
|
) cfg.allowedUDPPorts
|
||||||
}
|
}
|
||||||
|
|
||||||
# Accept IPv4 multicast. Not a big security risk since
|
# Accept IPv4 multicast. Not a big security risk since
|
||||||
# probably nobody is listening anyway.
|
# 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.
|
# Optionally respond to ICMPv4 pings.
|
||||||
${optionalString cfg.allowPing ''
|
${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
|
# Accept all ICMPv6 messages except redirects and node
|
||||||
# information queries (type 139). See RFC 4890, section
|
# information queries (type 139). See RFC 4890, section
|
||||||
# 4.4.
|
# 4.4.
|
||||||
ip6tables -A INPUT -p icmpv6 --icmpv6-type redirect -j DROP
|
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP
|
||||||
ip6tables -A INPUT -p icmpv6 --icmpv6-type 139 -j DROP
|
ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP
|
||||||
ip6tables -A INPUT -p icmpv6 -j ACCEPT
|
ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept
|
||||||
|
|
||||||
${cfg.extraCommands}
|
${cfg.extraCommands}
|
||||||
|
|
||||||
# Reject/drop everything else.
|
# 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 =
|
postStop =
|
||||||
''
|
''
|
||||||
iptables -F INPUT
|
${helpers}
|
||||||
iptables -P INPUT ACCEPT
|
ip46tables -D INPUT -j nixos-fw || true
|
||||||
ip6tables -F INPUT
|
#ip46tables -P INPUT ACCEPT
|
||||||
ip6tables -P INPUT ACCEPT
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user