nixfiles/nixos/modules/firewall.nix

211 lines
6.7 KiB
Nix
Raw Normal View History

{ lib, options, config, ... }:
2022-02-13 13:10:21 +00:00
let
inherit (lib) optionalString concatStringsSep concatMapStringsSep optionalAttrs mkIf mkDefault mkMerge mkOverride;
2022-02-17 15:47:24 +00:00
inherit (lib.my) parseIPPort mkOpt' mkBoolOpt';
allowICMP = ''
icmp type {
destination-unreachable,
router-solicitation,
router-advertisement,
time-exceeded,
parameter-problem,
echo-request
} accept
'';
allowICMP6 = ''
icmpv6 type {
destination-unreachable,
packet-too-big,
time-exceeded,
parameter-problem,
mld-listener-query,
mld-listener-report,
mld-listener-reduction,
nd-router-solicit,
nd-router-advert,
nd-neighbor-solicit,
nd-neighbor-advert,
ind-neighbor-solicit,
ind-neighbor-advert,
mld2-listener-report,
echo-request
} accept
'';
allowUDPTraceroute = ''
udp dport 33434-33625 accept
'';
2022-05-28 21:50:26 +01:00
forwardOpts = with lib.types; {
options = {
proto = mkOpt' (enum [ "tcp" "udp" ]) "tcp" "Protocol.";
port = mkOpt' (either port str) null "Incoming port.";
2022-05-28 21:50:26 +01:00
dst = mkOpt' str null "Destination (ip:port).";
};
};
2022-02-13 13:10:21 +00:00
cfg = config.my.firewall;
2022-03-26 14:20:30 +00:00
iptCfg = config.networking.firewall;
2022-02-13 13:10:21 +00:00
in
{
options.my.firewall = with lib.types; {
2022-02-13 17:44:14 +00:00
enable = mkBoolOpt' true "Whether to enable the nftables-based firewall.";
2022-02-13 13:10:21 +00:00
trustedInterfaces = options.networking.firewall.trustedInterfaces;
tcp = {
allowed = mkOpt' (listOf (either port str)) [ ] "TCP ports to open.";
2022-02-13 13:10:21 +00:00
};
udp = {
2022-02-13 17:44:14 +00:00
allowed = mkOpt' (listOf (either port str)) [ ] "UDP ports to open.";
allowTraceroute = mkBoolOpt' true "Whethor or not to add a rule to accept UDP traceroute packets.";
2022-02-13 13:10:21 +00:00
};
2022-02-13 17:44:14 +00:00
extraRules = mkOpt' lines "" "Arbitrary additional nftables rules.";
2022-02-13 13:10:21 +00:00
nat = with options.networking.nat; {
2022-02-13 17:44:14 +00:00
enable = mkBoolOpt' true "Whether to enable IP forwarding and NAT.";
inherit externalInterface externalIP;
2022-05-28 21:50:26 +01:00
forwardPorts = mkOpt' (listOf (submodule forwardOpts)) [ ] "List of port forwards.";
};
2022-02-13 13:10:21 +00:00
};
2022-02-13 13:10:21 +00:00
config = mkIf cfg.enable (mkMerge [
{
networking = {
firewall.enable = false;
nftables = {
enable = true;
ruleset =
let
2022-03-26 14:20:30 +00:00
trusted' = "{ ${concatStringsSep ", " (cfg.trustedInterfaces ++ iptCfg.trustedInterfaces)} }";
openTCP = cfg.tcp.allowed ++ iptCfg.allowedTCPPorts;
openUDP = cfg.udp.allowed ++ iptCfg.allowedUDPPorts;
2022-02-13 13:10:21 +00:00
in
''
table inet filter {
chain wan-tcp {
${concatMapStringsSep "\n " (p: "tcp dport ${toString p} accept") openTCP}
2022-05-31 21:25:51 +01:00
return
2022-02-13 13:10:21 +00:00
}
chain wan-udp {
${concatMapStringsSep "\n " (p: "udp dport ${toString p} accept") openUDP}
2022-05-31 21:25:51 +01:00
return
2022-02-13 13:10:21 +00:00
}
2022-02-13 13:10:21 +00:00
chain wan {
${allowICMP}
2022-05-28 21:50:26 +01:00
ip protocol igmp accept
${allowICMP6}
${allowUDPTraceroute}
tcp flags & (fin|syn|rst|ack) == syn ct state new jump wan-tcp
meta l4proto udp ct state new jump wan-udp
return
2022-02-13 13:10:21 +00:00
}
2022-02-13 13:10:21 +00:00
chain input {
type filter hook input priority 0; policy drop;
2022-02-13 13:10:21 +00:00
ct state established,related accept
ct state invalid drop
2022-02-13 13:10:21 +00:00
iif lo accept
${optionalString (cfg.trustedInterfaces != []) "iifname ${trusted'} accept\n"}
jump wan
}
2022-02-13 13:10:21 +00:00
chain forward {
type filter hook forward priority 0; policy drop;
${optionalString (cfg.trustedInterfaces != []) "\n iifname ${trusted'} accept\n"}
ct state related,established accept
${allowICMP}
${allowICMP6}
${allowUDPTraceroute}
2022-02-13 13:10:21 +00:00
}
chain output {
type filter hook output priority 0; policy accept;
}
}
2022-05-28 21:50:26 +01:00
table inet nat {
2022-02-13 13:10:21 +00:00
chain prerouting {
2022-06-06 00:18:24 +01:00
type nat hook prerouting priority dstnat;
2022-02-13 13:10:21 +00:00
}
chain postrouting {
2022-06-06 00:18:24 +01:00
type nat hook postrouting priority srcnat;
}
2022-02-13 13:10:21 +00:00
}
2022-02-13 13:10:21 +00:00
${cfg.extraRules}
'';
};
2022-02-13 13:10:21 +00:00
};
}
(mkIf cfg.nat.enable {
assertions = [
{
assertion = with cfg.nat; (forwardPorts != [ ]) -> (externalInterface != null && externalIP != null);
message = "my.firewall.nat.forwardPorts requires my.firewall.nat.external{Interface,IP}";
2022-02-13 13:10:21 +00:00
}
];
2022-02-13 13:10:21 +00:00
# Yoinked from nixpkgs/nixos/modules/services/networking/nat.nix
boot = {
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = mkOverride 99 true;
"net.ipv4.conf.default.forwarding" = mkOverride 99 true;
} // optionalAttrs config.networking.enableIPv6 {
# Do not prevent IPv6 autoconfiguration.
# See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>.
"net.ipv6.conf.all.accept_ra" = mkOverride 99 2;
"net.ipv6.conf.default.accept_ra" = mkOverride 99 2;
2022-02-13 13:10:21 +00:00
# Forward IPv6 packets.
"net.ipv6.conf.all.forwarding" = mkOverride 99 true;
"net.ipv6.conf.default.forwarding" = mkOverride 99 true;
};
2022-02-13 13:10:21 +00:00
};
2022-02-13 13:10:21 +00:00
my.firewall.extraRules =
let
makeFilter = f:
let
2022-05-28 21:50:26 +01:00
ipp = parseIPPort f.dst;
in
"ip${optionalString ipp.v6 "6"} daddr ${ipp.ip} ${f.proto} dport ${toString f.port} accept";
makeForward = f:
let
ipp = parseIPPort f.dst;
2022-02-13 13:10:21 +00:00
in
2022-05-28 21:50:26 +01:00
"${f.proto} dport ${toString f.port} dnat ip${optionalString ipp.v6 "6"} to ${f.dst}";
2022-02-13 13:10:21 +00:00
in
''
table inet filter {
chain filter-port-forwards {
${concatMapStringsSep "\n " makeFilter cfg.nat.forwardPorts}
2022-05-28 21:50:26 +01:00
return
}
2022-02-13 13:10:21 +00:00
chain forward {
2022-02-17 15:47:24 +00:00
${optionalString
(cfg.nat.externalInterface != null)
"iifname ${cfg.nat.externalInterface} jump filter-port-forwards"}
2022-02-13 13:10:21 +00:00
}
}
2022-05-28 21:50:26 +01:00
table inet nat {
2022-02-13 13:10:21 +00:00
chain port-forward {
${concatMapStringsSep "\n " makeForward cfg.nat.forwardPorts}
2022-05-28 21:50:26 +01:00
return
2022-02-13 13:10:21 +00:00
}
chain prerouting {
2022-02-17 15:47:24 +00:00
${optionalString
(cfg.nat.externalIP != null)
"ip daddr ${cfg.nat.externalIP} jump port-forward"}
}
2022-02-13 13:10:21 +00:00
}
'';
})
]);
meta.buildDocsInSandbox = false;
2022-02-13 13:10:21 +00:00
}