1{ config, lib, ... }:
2
3with lib;
4let
5 cfg = config.modules.router;
6
7 intern = cfg.interfaces.internal;
8 trustedInterfaces = config.networking.firewall.trustedInterfaces;
9 internalInterfaces = lists.remove "lo" trustedInterfaces;
10
11 concatIfnames = strings.concatMapStringsSep ", " strings.escapeNixIdentifier;
12
13 capturePortsRules =
14 strings.concatStringsSep "\n"
15 (builtins.map (port: ''
16 iifname { ${concatIfnames internalInterfaces} } meta l4proto { tcp, udp } th dport ${toString port} redirect to ${toString port}
17 '') cfg.nftables.capturePorts);
18
19 blockForwardRules =
20 if intern != null then
21 strings.concatStringsSep "\n"
22 (builtins.map (mac: " iifname ${intern.name} oifname != ${intern.name} ether saddr == ${mac} drop") cfg.nftables.blockForward)
23 else "";
24in {
25 options.modules.router = {
26 nftables = {
27 enable = mkOption {
28 default = cfg.enable;
29 description = "Whether to enable Router NFTables config";
30 type = types.bool;
31 };
32
33 capturePorts = mkOption {
34 default = [ 53 ];
35 description = "Ports to capture and redirect to router";
36 type = types.listOf types.int;
37 };
38
39 blockForward = mkOption {
40 default = [];
41 description = "MAC Addresses of devices to block internet access for";
42 type = types.listOf types.str;
43 };
44 };
45 };
46
47 config = mkIf cfg.nftables.enable {
48 networking.useNetworkd = mkDefault true;
49 networking.firewall = {
50 enable = mkDefault true;
51 checkReversePath = "loose";
52 };
53
54 networking.nftables = {
55 enable = mkForce true;
56 checkRuleset = false;
57 flushRuleset = true;
58
59 tables.filter = {
60 family = "inet";
61 content = ''
62 chain prerouting {
63 type nat hook prerouting priority 0; policy accept;
64 ${capturePortsRules}
65 }
66
67 chain postrouting {
68 type nat hook postrouting priority 0; policy accept;
69 oifname != { ${concatIfnames trustedInterfaces} } meta protocol ip masquerade
70 }
71
72 chain input {
73 type filter hook input priority 0;
74 ct state { established, related } accept
75 ct state invalid drop
76 iifname { ${concatIfnames trustedInterfaces} } accept
77 iifname { ${concatIfnames trustedInterfaces} } pkttype { broadcast, multicast } accept
78 tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop
79 tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop
80 tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
81 ip protocol icmp \
82 icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } \
83 accept
84 meta l4proto ipv6-icmp accept
85 ip6 ecn not-ect accept
86 udp dport dhcpv6-client ct state { new, untracked } accept
87 udp dport 41641 ct state new accept
88 reject with icmpx type port-unreachable
89 }
90
91 chain forward {
92 type filter hook forward priority 0; policy drop;
93 ${blockForwardRules}
94 iifname { ${concatIfnames trustedInterfaces} } accept
95 oifname { ${concatIfnames trustedInterfaces} } ct state { established, related } accept
96 ct state invalid drop
97 }
98
99 chain output {
100 type filter hook output priority 0; policy accept;
101 iifname lo accept
102 ct state invalid drop
103 }
104 '';
105 };
106
107 tables.arp_filter = {
108 family = "arp";
109 content = ''
110 chain input {
111 type filter hook input priority 0; policy accept;
112 iifname != { ${concatIfnames trustedInterfaces} } limit rate 1/second burst 2 packets accept
113 }
114
115 chain output {
116 type filter hook output priority 0; policy accept;
117 }
118 '';
119 };
120
121 tables.tagging = {
122 family = "netdev";
123 content = ''
124 chain lan {
125 type filter hook ingress priority -150; policy accept;
126 jump tags
127 }
128
129 chain tags {
130 ip dscp set cs0
131 ip6 dscp set cs0
132
133 udp sport 53 ip dscp set cs5
134 tcp sport 853 ip dscp set cs5
135 udp sport 123 ip dscp set cs5
136 tcp dport {80, 443} ip dscp set cs3
137
138 udp dport 41641 ip dscp set cs4
139 udp dport {3478-3479, 19302-19309} ip dscp set cs4
140 udp sport {3478-3479, 19302-19309} ip dscp set cs4
141 ip6 nexthdr udp udp dport {3478-3479, 19302-19309} ip6 dscp set cs4
142 ip6 nexthdr udp udp sport {3478-3479, 19302-19309} ip6 dscp set cs4
143 udp dport {7000-9000, 27000-27200} ip dscp set cs4
144 udp sport {7000-9000, 27000-27200} ip dscp set cs4
145 ip6 nexthdr udp udp dport {7000-9000, 27000-27200} ip6 dscp set cs4
146 ip6 nexthdr udp udp sport {7000-9000, 27000-27200} ip6 dscp set cs4
147 }
148 '';
149 };
150 };
151 };
152}