9 cfg = config.networking.firewall;
11 ifaceSet = lib.concatStringsSep ", " (map (x: ''"${x}"'') cfg.trustedInterfaces);
15 lib.concatStringsSep ", " (
16 map (x: toString x) ports ++ map (x: "${toString x.from}-${toString x.to}") portRanges
25 networking.firewall = {
26 extraInputRules = lib.mkOption {
27 type = lib.types.lines;
29 example = "ip6 saddr { fc00::/7, fe80::/10 } tcp dport 24800 accept";
31 Additional nftables rules to be appended to the input-allow
34 This option only works with the nftables based firewall.
38 extraForwardRules = lib.mkOption {
39 type = lib.types.lines;
41 example = "iifname wg0 accept";
43 Additional nftables rules to be appended to the forward-allow
46 This option only works with the nftables based firewall.
50 extraReversePathFilterRules = lib.mkOption {
51 type = lib.types.lines;
53 example = "fib daddr . mark . iif type local accept";
55 Additional nftables rules to be appended to the rpfilter-allow
58 This option only works with the nftables based firewall.
65 config = lib.mkIf (cfg.enable && config.networking.nftables.enable) {
69 assertion = cfg.extraCommands == "";
70 message = "extraCommands is incompatible with the nftables based firewall: ${cfg.extraCommands}";
73 assertion = cfg.extraStopCommands == "";
74 message = "extraStopCommands is incompatible with the nftables based firewall: ${cfg.extraStopCommands}";
77 assertion = cfg.pingLimit == null || !(lib.hasPrefix "--" cfg.pingLimit);
78 message = "nftables syntax like \"2/second\" should be used in networking.firewall.pingLimit";
81 assertion = config.networking.nftables.rulesetFile == null;
82 message = "networking.nftables.rulesetFile conflicts with the firewall";
86 networking.nftables.tables."nixos-fw".family = "inet";
87 networking.nftables.tables."nixos-fw".content = ''
89 comment "Temporarily opened ports"
90 type inet_proto . inet_service
95 ${lib.optionalString (cfg.checkReversePath != false) ''
97 type filter hook prerouting priority mangle + 10; policy drop;
99 meta nfproto ipv4 udp sport . udp dport { 67 . 68, 68 . 67 } accept comment "DHCPv4 client/server"
100 fib saddr . mark ${lib.optionalString (cfg.checkReversePath != "loose") ". iif"} oif exists accept
104 ${lib.optionalString cfg.logReversePathDrops ''
105 log level info prefix "rpfilter drop: "
111 chain rpfilter-allow {
112 ${cfg.extraReversePathFilterRules}
116 type filter hook input priority filter; policy drop;
118 ${lib.optionalString (
120 ) ''iifname { ${ifaceSet} } accept comment "trusted interfaces"''}
122 # Some ICMPv6 types like NDP is untracked
125 established : accept,
127 new : jump input-allow,
128 untracked: jump input-allow,
131 ${lib.optionalString cfg.logRefusedConnections ''
132 tcp flags syn / fin,syn,rst,ack log level info prefix "refused connection: "
134 ${lib.optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) ''
135 pkttype broadcast log level info prefix "refused broadcast: "
136 pkttype multicast log level info prefix "refused multicast: "
138 ${lib.optionalString cfg.logRefusedPackets ''
139 pkttype host log level info prefix "refused packet: "
142 ${lib.optionalString cfg.rejectPackets ''
143 meta l4proto tcp reject with tcp reset
151 ${lib.concatStrings (
155 ifaceExpr = lib.optionalString (iface != "default") "iifname ${iface}";
156 tcpSet = portsToNftSet cfg.allowedTCPPorts cfg.allowedTCPPortRanges;
157 udpSet = portsToNftSet cfg.allowedUDPPorts cfg.allowedUDPPortRanges;
160 ${lib.optionalString (tcpSet != "") "${ifaceExpr} tcp dport { ${tcpSet} } accept"}
161 ${lib.optionalString (udpSet != "") "${ifaceExpr} udp dport { ${udpSet} } accept"}
166 meta l4proto . th dport @temp-ports accept
168 ${lib.optionalString cfg.allowPing ''
169 icmp type echo-request ${
170 lib.optionalString (cfg.pingLimit != null) "limit rate ${cfg.pingLimit}"
171 } accept comment "allow ping"
174 icmpv6 type != { nd-redirect, 139 } accept comment "Accept all ICMPv6 messages except redirects and node information queries (type 139). See RFC 4890, section 4.4."
175 ip6 daddr fe80::/64 udp dport 546 accept comment "DHCPv6 client"
177 ${cfg.extraInputRules}
181 ${lib.optionalString cfg.filterForward ''
183 type filter hook forward priority filter; policy drop;
187 established : accept,
189 new : jump forward-allow,
190 untracked : jump forward-allow,
195 chain forward-allow {
197 icmpv6 type != { router-renumbering, 139 } accept comment "Accept all ICMPv6 messages except renumbering and node information queries (type 139). See RFC 4890, section 4.3."
199 ct status dnat accept comment "allow port forward"
201 ${cfg.extraForwardRules}