Last active 1 month ago

nftables.conf Raw
1#!/usr/sbin/nft -f
2
3flush ruleset
4
5define ip6_mask = ffff:ffff:ffff:ffff::
6define public_http = 8080
7define public_https = 8443
8define public_ssh = 3222
9define system_ssh = 49152
10
11table inet nat {
12 chain prerouting {
13 type nat hook prerouting priority dstnat; policy accept;
14
15 tcp dport 80 redirect to :$public_http
16 tcp dport 443 redirect to :$public_https
17 tcp dport 22 redirect to :$public_ssh
18 }
19}
20
21
22table inet firewall {
23 set ssh_ratelimit_v4 {
24 type ipv4_addr
25 size 65535
26 flags dynamic,timeout
27 timeout 60m
28 }
29
30 set ssh_ratelimit_v6 {
31 type ipv6_addr
32 size 65535
33 flags dynamic,timeout
34 timeout 60m
35 }
36
37 set blackhole_v4 {
38 type ipv4_addr
39 size 65535
40 flags dynamic,timeout
41 timeout 24h
42 }
43
44 set blackhole_v6 {
45 type ipv6_addr
46 size 65535
47 flags dynamic,timeout
48 timeout 24h
49 }
50
51 set public_ssh_ratelimit_v4 {
52 type ipv4_addr
53 size 65535
54 flags dynamic,timeout
55 timeout 10m
56 }
57
58 set public_ssh_ratelimit_v6 {
59 type ipv6_addr
60 size 65535
61 flags dynamic,timeout
62 timeout 10m
63 }
64
65 set public_ssh_connections_v4 {
66 type ipv4_addr
67 size 65535
68 flags dynamic
69 }
70
71 set public_ssh_connections_v6 {
72 type ipv6_addr
73 size 65535
74 flags dynamic
75 }
76
77 chain inbound_rules_v4 {
78 icmp type echo-request limit rate 15/second accept
79 }
80
81 chain inbound_rules_v6 {
82 icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
83 icmpv6 type echo-request limit rate 15/second accept
84 }
85
86 chain inbound_system_ssh_v4 {
87 ct state new tcp dport $system_ssh add @ssh_ratelimit_v4 \
88 { ip saddr limit rate 1/hour burst 1 packets } counter accept
89
90 counter drop
91 }
92
93 chain inbound_system_ssh_v6 {
94 ct state new tcp dport $system_ssh add @ssh_ratelimit_v6 \
95 { ip6 saddr & ffff:ffff:ffff:ffff:: limit rate 1/hour burst 1 packets } counter accept
96
97 counter drop
98 }
99
100 chain inbound_public_ssh_v4 {
101 # Set a concurrent cap for each ip
102 tcp dport $public_ssh ct state new add @public_ssh_connections_v4 { ip saddr ct count over 4 } counter reject with tcp reset
103
104 # Set a per ip connection ratelimit
105 tcp dport $public_ssh ct state new update @public_ssh_ratelimit_v4 { ip saddr limit rate over 20/minute burst 5 packets } counter reject with tcp reset
106
107 tcp dport $public_ssh accept
108 counter drop
109 }
110
111 chain inbound_public_ssh_v6 {
112 # Set a concurrent cap for each ip
113 tcp dport $public_ssh ct state new add @public_ssh_connections_v6 { ip6 saddr & $ip6_mask ct count over 4 } counter reject with tcp reset
114
115 # Set a per ip connection ratelimit
116 tcp dport $public_ssh ct state new update @public_ssh_ratelimit_v6 { ip6 saddr & $ip6_mask limit rate over 20/minute burst 5 packets } counter reject with tcp reset
117
118 tcp dport $public_ssh accept
119 counter drop
120 }
121
122 chain inbound_blackhole_v4 {
123 # blacklist tcp traffic for 24h
124 ct state new tcp flags & (fin | syn | rst | ack) == syn update @blackhole_v4 \
125 { ip saddr timeout 24h } counter drop
126
127 # blacklist udp traffic
128 ct state new meta l4proto udp update @blackhole_v4 \
129 { ip saddr timeout 24h } counter drop
130
131 counter drop
132 }
133
134 chain inbound_blackhole_v6 {
135 # TCP SYN to any unauthorized port: blacklist the /64 for 24h.
136 ct state new tcp flags & (fin | syn | rst | ack) == syn update @blackhole_v6 \
137 { ip6 saddr & $ip6_mask timeout 24h } counter drop
138
139 # UDP to any unauthorized port: blacklist the /64 for 24h.
140 ct state new meta l4proto udp update @blackhole_v6 \
141 { ip6 saddr & $ip6_mask timeout 24h } counter drop
142
143 counter drop
144 }
145
146 chain inbound {
147 type filter hook input priority filter; policy drop;
148
149 # Allow specific networks to go unblocked
150 iifname "lo" accept
151 iifname "tailscale0" accept
152
153 # Allow replies
154 ct state vmap { invalid : drop, established : accept, related : accept }
155
156 # Basic ping allowances
157 meta nfproto ipv4 jump inbound_rules_v4
158 meta nfproto ipv6 jump inbound_rules_v6
159
160 # Allow service ports
161 tcp dport { $public_http , $public_https } counter accept
162
163 # Ratelimit service ssh port (3222)
164 # Global ssh connection rate limiter
165 tcp dport $public_ssh ct state new limit rate over 120/minute burst 30 packets counter reject with tcp reset
166 meta nfproto ipv4 tcp dport $public_ssh goto inbound_public_ssh_v4
167 meta nfproto ipv6 tcp dport $public_ssh goto inbound_public_ssh_v6
168
169 # Block likely bots
170 ip saddr @blackhole_v4 counter drop
171 ip6 saddr & $ip6_mask @blackhole_v6 counter drop
172
173 # Fail2unban on vps' own ssh port
174 meta nfproto ipv4 tcp dport $system_ssh goto inbound_system_ssh_v4
175 meta nfproto ipv6 tcp dport $system_ssh goto inbound_system_ssh_v6
176
177 # Decide to add ip to blackhole list (incase of bot)
178 meta nfproto ipv4 goto inbound_blackhole_v4
179 meta nfproto ipv6 goto inbound_blackhole_v6
180
181 # Block other traffic (default to chain)
182 }
183
184 chain forward {
185 type filter hook forward priority filter; policy drop;
186 }
187}
188