graphene-os-server-infrastr.../nftables/nftables-matrix.conf
Daniel Micay 398acc6fe8 nftables: drop instead of reject for unused ports
This provides consistency with DDoS protection services placed in front
of the services rather than the behavior changing based on whether DDoS
protection is active. This doesn't help with protecting against attacks
since they'll almost always be targeting ports with services active or
exhausting inbound bandwidth via UDP reflection attacks. This appears to
be the standard approach used by most large tech companies.
2024-04-19 13:54:12 -04:00

133 lines
5.4 KiB
Plaintext

#!/usr/bin/nft -f
flush ruleset
table inet filter {
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-main {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-main {
type ipv6_addr
flags dynamic
}
chain prerouting-raw {
type filter hook prerouting priority raw
# drop packets without a reverse path (strict reverse path filtering)
fib saddr . iif oif missing counter drop
iif lo notrack accept
# drop packets to address not configured on incoming interface (strong host model)
#
# ordered after accepting loopback to permit using external IPs via loopback
fib daddr . iif type != { local, broadcast, multicast } counter drop
# handle new TCP connections beyond rate limit via synproxy to avoid conntrack table exhaustion
tcp dport { 22, 80, 443 } tcp flags syn limit rate over 1024/second burst 128 packets counter notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
tcp dport { 22, 80, 443 } goto input-tcp-service
iif lo accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { new : drop, established : accept, related : accept }
}
chain input-tcp-service {
iif lo goto input-tcp-service-loopback
# for synproxy, SYN is untracked and first ACK is invalid which are handled via fallthrough
ct state vmap { new : goto input-tcp-service-new, established : goto input-tcp-service-established, related : accept }
tcp dport 22 ip saddr @ip-connlimit-ssh counter reject with tcp reset
tcp dport 22 ip6 saddr and ffff:ffff:ffff:ffff:ffff:: @ip6-connlimit-ssh counter reject with tcp reset
tcp dport { 80, 443 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 80, 443 } ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-main counter reject with tcp reset
synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-tcp-service-new {
tcp dport 22 ip saddr @ip-connlimit-ssh counter reject with tcp reset
tcp dport 22 ip6 saddr and ffff:ffff:ffff:ffff:ffff:: @ip6-connlimit-ssh counter reject with tcp reset
tcp dport { 80, 443 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 80, 443 } ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-main counter reject with tcp reset
accept
}
# add connections established without synproxy to connection limit sets with limits enforced
chain input-tcp-service-established {
ct mark 0x1 accept
tcp dport 22 add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 80, 443 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 80, 443 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
ct mark set 0x1 accept
}
# add connections established with synproxy to connection limit sets with limits enforced
chain input-tcp-service-loopback {
tcp flags != syn accept
tcp dport 22 add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 80, 443 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 80, 443 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
ct mark set 0x1 accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo goto output-raw-loopback
skuid != { root, systemd-network, unbound, chrony, http, synapse, matterbridge } counter goto graceful-reject
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output-raw-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 th dport != 8008 notrack accept
skuid { chrony, synapse, matterbridge } meta l4proto { tcp, udp } th sport >= 1024 th sport != 8008 th dport 53 notrack accept
skuid postgres udp sport >= 1024 udp sport != 8008 udp dport >= 1024 udp dport != 8008 notrack accept
skuid synapse tcp sport 8008 tcp dport >= 1024 tcp dport != 8008 notrack accept
skuid http tcp sport >= 1024 tcp sport != 8008 tcp dport 8008 notrack accept
skuid mjolnir tcp sport >= 1024 tcp sport != 8008 tcp dport 8008 notrack accept
skuid http tcp sport 443 tcp dport >= 1024 tcp dport != 8008 notrack accept
skuid matterbridge tcp sport >= 1024 tcp sport != 8008 tcp dport 443 notrack accept
skuid synapse tcp sport >= 1024 tcp sport != 8008 tcp dport 443 notrack accept
skuid != root counter goto graceful-reject
notrack accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}