nixpkgs/nixos/modules/services/networking/nftables.nix

175 lines
5.1 KiB
Nix
Raw Normal View History

{ 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";
};
};
};
}