parent
b508c1b792
commit
e2c95b46e5
@ -0,0 +1,174 @@ |
||||
{ config, pkgs, lib, ... }: |
||||
with lib; |
||||
let |
||||
cfg = config.networking.nftables; |
||||
in |
||||
{ |
||||
###### interface |
||||
|
||||
options = { |
||||
networking.nftables.enable = mkOption { |
||||
type = types.bool; |
||||
default = false; |
||||
description = |
||||
'' |
||||
Whether to enable nftables. nftables is a Linux-based packet |
||||
filtering framework intended to replace frameworks like iptables. |
||||
|
||||
This conflicts with the standard networking firewall, so make sure to |
||||
disable it before using nftables. |
||||
''; |
||||
}; |
||||
networking.nftables.ruleset = mkOption { |
||||
type = types.lines; |
||||
default = |
||||
'' |
||||
table inet filter { |
||||
# Block all IPv4/IPv6 input traffic except SSH. |
||||
chain input { |
||||
type filter hook input priority 0; |
||||
ct state invalid reject |
||||
ct state {established, related} accept |
||||
iifname lo accept |
||||
tcp dport 22 accept |
||||
reject |
||||
} |
||||
|
||||
# Allow anything in. |
||||
chain output { |
||||
type filter hook output priority 0; |
||||
ct state invalid reject |
||||
ct state {established, related} accept |
||||
oifname lo accept |
||||
accept |
||||
} |
||||
|
||||
chain forward { |
||||
type filter hook forward priority 0; |
||||
accept |
||||
} |
||||
} |
||||
''; |
||||
example = |
||||
'' |
||||
# Check out http://wiki.nftables.org/ for better documentation. |
||||
|
||||
define LAN = 192.168.0.1/24 |
||||
|
||||
# Handle IPv4 traffic. |
||||
table ip filter { |
||||
chain input { |
||||
type filter hook input priority 0; |
||||
# Handle existing connections. |
||||
ct state invalid reject |
||||
ct state {established, related} accept |
||||
# Allow loopback for applications. |
||||
iifname lo accept |
||||
# Allow people to ping us on LAN. |
||||
ip protocol icmp ip daddr $LAN accept |
||||
# Allow SSH over LAN. |
||||
tcp dport 22 ip daddr $LAN accept |
||||
# Reject all other output traffic. |
||||
reject |
||||
} |
||||
|
||||
chain output { |
||||
type filter hook output priority 0; |
||||
# Handle existing connections. |
||||
ct state invalid reject |
||||
ct state {established, related} accept |
||||
# Allow loopback for applications. |
||||
oifname lo accept |
||||
# Allow the Tor user to run its daemon, |
||||
# but only on WAN in case of compromise. |
||||
skuid tor ip daddr != $LAN accept |
||||
# Allowing pinging others on LAN. |
||||
ip protocol icmp ip daddr $LAN accept |
||||
# Reject all other output traffic. |
||||
reject |
||||
} |
||||
|
||||
chain forward { |
||||
type filter hook forward priority 0; |
||||
reject |
||||
} |
||||
} |
||||
|
||||
# Block all IPv6 traffic. |
||||
table ip6 filter { |
||||
chain input { |
||||
type filter hook input priority 0; |
||||
reject |
||||
} |
||||
|
||||
chain output { |
||||
type filter hook output priority 0; |
||||
reject |
||||
} |
||||
|
||||
chain forward { |
||||
type filter hook forward priority 0; |
||||
reject |
||||
} |
||||
} |
||||
''; |
||||
description = |
||||
'' |
||||
The ruleset to be used with nftables. Should be in a format that |
||||
can be loaded using "/bin/nft -f". The ruleset is updated atomically. |
||||
''; |
||||
}; |
||||
networking.nftables.rulesetFile = mkOption { |
||||
type = types.path; |
||||
default = pkgs.writeTextFile { |
||||
name = "nftables-rules"; |
||||
text = cfg.ruleset; |
||||
}; |
||||
description = |
||||
'' |
||||
The ruleset file to be used with nftables. Should be in a format that |
||||
can be loaded using "nft -f". The ruleset is updated atomically. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
###### implementation |
||||
|
||||
config = mkIf cfg.enable { |
||||
assertions = [{ |
||||
assertion = config.networking.firewall.enable == false; |
||||
message = "You can not use nftables with services.networking.firewall."; |
||||
}]; |
||||
boot.blacklistedKernelModules = [ "ip_tables" ]; |
||||
environment.systemPackages = [ pkgs.nftables ]; |
||||
systemd.services.nftables = { |
||||
description = "nftables firewall"; |
||||
before = [ "network-pre.target" ]; |
||||
wants = [ "network-pre.target" ]; |
||||
wantedBy = [ "multi-user.target" ]; |
||||
reloadIfChanged = true; |
||||
serviceConfig = let |
||||
rulesScript = pkgs.writeScript "nftables-rules" '' |
||||
#! ${pkgs.nftables}/bin/nft -f |
||||
flush ruleset |
||||
include "${cfg.rulesetFile}" |
||||
''; |
||||
checkScript = pkgs.writeScript "nftables-check" '' |
||||
#! ${pkgs.stdenv.shell} -e |
||||
if $(${pkgs.kmod}/bin/lsmod | grep -q ip_tables); then |
||||
echo "Unload ip_tables before using nftables!" 1>&2 |
||||
exit 1 |
||||
else |
||||
${rulesScript} |
||||
fi |
||||
''; |
||||
in { |
||||
Type = "oneshot"; |
||||
RemainAfterExit = true; |
||||
ExecStart = checkScript; |
||||
ExecReload = checkScript; |
||||
ExecStop = "${pkgs.nftables}/bin/nft flush ruleset"; |
||||
}; |
||||
}; |
||||
}; |
||||
} |
Loading…
Reference in new issue