Compare commits

...

27 Commits

Author SHA1 Message Date
Tommy 49ca30f3f6
Merge eeaaf12886 into 8a4e4f334f 2024-04-14 01:15:11 +02:00
Daniel Micay 8a4e4f334f reorder configuration 2024-04-13 18:20:14 -04:00
Daniel Micay 56f169cbba increase max TCP send buffer size for matrix server 2024-04-13 18:20:12 -04:00
Daniel Micay 35e776f867 increase max TCP send buffer size for update servers 2024-04-13 14:27:31 -04:00
Daniel Micay 711e432a67 remove unnecessary local-reserved-ports.conf template 2024-04-13 14:17:23 -04:00
Daniel Micay f9bce64060 enable TCP window shrinking
The default is a potential denial of service issue via TCP memory
exhaustion.
2024-04-13 13:52:08 -04:00
Daniel Micay 6a325f8798 update python dependencies 2024-04-12 21:33:35 -04:00
Daniel Micay bd6f127acf move nftables configuration to a directory 2024-04-12 21:33:35 -04:00
Daniel Micay c412fec336 simplify rate limited synproxy bypass 2024-04-12 21:33:33 -04:00
Daniel Micay ca35fcc648 add python-pydantic package for matrix.grapheneos.org 2024-04-11 22:45:55 -04:00
Daniel Micay b928b197b0 nftables: add comments explaining adding to connlimit sets 2024-04-11 15:59:07 -04:00
Daniel Micay edbf50a3da nftables: rename tcp service chains 2024-04-11 11:59:27 -04:00
Daniel Micay 3d886dea43 nftables: split out TCP service chain 2024-04-11 11:49:22 -04:00
Daniel Micay b152574da8 nftables: avoid unnecessary connection marking 2024-04-11 11:38:43 -04:00
Daniel Micay 832a430954 nftables: handle non-TCP case in input-new chain 2024-04-11 10:34:10 -04:00
Daniel Micay 8f047de0c3 nftables: explain synproxy untracked/invalid cases 2024-04-11 10:19:39 -04:00
Daniel Micay 26a58b2492 nftables: explain synproxy bypass rate limit 2024-04-11 09:56:30 -04:00
Daniel Micay ecd14bddff nftables: explain ordering of strong host model check 2024-04-11 09:51:10 -04:00
Daniel Micay b21ea0a23f raise synproxy bypass burst to 128 packets from 5
Our network servers are spiking over the default burst limit of 5
packets during regular usage. It's unclear high this should be but 5
packets is definitely too low.
2024-04-10 15:08:45 -04:00
Daniel Micay b38736ca74 enable nftables-based DDoS protection for all TCP services
Now that the usage of synproxy is gated behind a SYN packet rate limit,
we can expand this to all our TCP services to have always enabled DDoS
protection instead of needing to deploy a stricter set of rules when the
servers are under attack. This is far better because there isn't always
a system administrator available to handle an ongoing attack.

We already used per-IP connection limits in nginx across the board but
those limits are applied far too late after a TLS connection has been
established and headers are sent rather than before. Using IPv6 /64
blocks means this is much more aggressive for IPv6, but many clients
will fall back to IPv4 due to the happy eyeballs approach. The nginx
limits are still useful due to HTTP/2 multiplexing and we'll need to
think over how to address IPv6 there.
2024-04-10 14:48:10 -04:00
Daniel Micay 14c0128910 add rate limited synproxy bypass 2024-04-10 12:15:19 -04:00
Daniel Micay ef63ff82d2 use consistent name for main connlimit
This will be extended to other services when under attack, which can be
automated in the future.
2024-04-09 20:29:11 -04:00
Daniel Micay 275d63e8b3 certbot: add ns2 variant of staging authoritative DNS 2024-04-08 17:06:43 -04:00
Daniel Micay 5106ec7f4a remove redundant vm.max_map_count configuration
The same value we were using is now the default.
2024-04-07 15:11:35 -04:00
Tommy eeaaf12886
Typo fix 2023-09-07 19:57:24 -07:00
Tommy 4a985cbe29
Typo fix 2023-09-07 19:56:43 -07:00
Tommy 1bc32489f1
Use curve secp384r1 2023-09-07 19:51:41 -07:00
31 changed files with 990 additions and 719 deletions

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name grapheneos.network \
-d grapheneos.network \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name grapheneos.org \
-d grapheneos.org \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name releases.grapheneos.org \
-d releases.grapheneos.org \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name attestation.app \
-d attestation.app \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name discuss.grapheneos.org \
-d discuss.grapheneos.org

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name grapheneos.social \
-d grapheneos.social \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name matrix.grapheneos.org \
-d matrix.grapheneos.org \

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name mta-sts.mail.grapheneos.org \
-d mail.grapheneos.org \

View File

@ -3,4 +3,6 @@ certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name ns1.staging.grapheneos.org \
-d ns1.staging.grapheneos.org \
-d ns1.staging.attestation.app
-d ns2.staging.grapheneos.org \
-d ns1.staging.attestation.app \
-d ns2.staging.attestation.app

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name staging.attestation.app \
-d staging.attestation.app

View File

@ -1,5 +1,5 @@
certbot certonly --webroot --webroot-path /srv/certbot --no-eff-email \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" \
--key-type ecdsa --reuse-key --must-staple --preferred-chain "ISRG Root X1" --elliptic-curve secp384r1 \
--deploy-hook "certbot-ocsp-fetcher -o /var/cache/certbot-ocsp-fetcher" \
--cert-name staging.grapheneos.org \
-d staging.grapheneos.org

View File

@ -1,11 +1,23 @@
declare -Ar hosts_reserved_ports=(
[staging.attestation.app]=8080
[attestation.app]=8080
[matrix.grapheneos.org]=8008
[0.grapheneos.network]=7275
[1.grapheneos.network]=7275
[2.grapheneos.network]=7275
[3.grapheneos.network]=7275
[staging.attestation.app]=8080
[attestation.app]=8080
[matrix.grapheneos.org]=8008
)
declare -Ar hosts_tcp_wmem_max=(
[0.releases.grapheneos.org]=16777216
[1.releases.grapheneos.org]=16777216
[2.releases.grapheneos.org]=16777216
[3.releases.grapheneos.org]=16777216
[4.releases.grapheneos.org]=16777216
[5.releases.grapheneos.org]=16777216
[6.releases.grapheneos.org]=16777216
[7.releases.grapheneos.org]=16777216
[matrix.grapheneos.org]=16777216
)
declare -Ar hosts_ssh_users=(
@ -85,11 +97,11 @@ declare -Ar hosts_ipv4_address=(
[5.releases.grapheneos.org]=141.94.71.72
[6.releases.grapheneos.org]=135.125.183.155
[7.releases.grapheneos.org]=141.95.0.242
[staging.attestation.app]=198.98.57.157
[attestation.app]=51.79.66.27
[matrix.grapheneos.org]=51.79.51.42
[discuss.grapheneos.org]=51.79.52.38
[grapheneos.social]=51.222.30.159
[staging.attestation.app]=198.98.57.157
[attestation.app]=51.79.66.27
)
declare -Ar hosts_ipv6_address=(
@ -116,11 +128,11 @@ declare -Ar hosts_ipv6_address=(
[5.releases.grapheneos.org]=2001:41d0:304:200::a687
[6.releases.grapheneos.org]=2001:41d0:701:1100::2ec9
[7.releases.grapheneos.org]=2001:41d0:701:1100::3e56
[staging.attestation.app]=2605:6400:10:aa9:1c0f:44d3:da15:c0ec
[attestation.app]=2607:5300:205:200::7e9
[matrix.grapheneos.org]=2607:5300:205:200::26e1
[discuss.grapheneos.org]=2607:5300:205:200::3c4
[grapheneos.social]=2607:5300:205:200::2706
[staging.attestation.app]=2605:6400:10:aa9:1c0f:44d3:da15:c0ec
[attestation.app]=2607:5300:205:200::7e9
)
readonly hosts_dns=(
@ -144,11 +156,11 @@ readonly hosts_certbot=(
0.grapheneos.org
0.grapheneos.network
0.releases.grapheneos.org
staging.attestation.app
attestation.app
matrix.grapheneos.org
discuss.grapheneos.org
grapheneos.social
staging.attestation.app
attestation.app
)
readonly hosts_grapheneos=(
@ -179,10 +191,10 @@ readonly hosts_web=(
"${hosts_grapheneos_all[@]}"
"${hosts_network[@]}"
"${hosts_releases[@]}"
"${hosts_attestation[@]}"
matrix.grapheneos.org
discuss.grapheneos.org
grapheneos.social
"${hosts_attestation[@]}"
)
readonly hosts_all=(
@ -204,8 +216,8 @@ readonly hosts_ovh=(
{0,2,3}.grapheneos.org
{0,2,3}.grapheneos.network
{0..7}.releases.grapheneos.org
attestation.app
matrix.grapheneos.org
discuss.grapheneos.org
grapheneos.social
attestation.app
)

View File

@ -1,111 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-http {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport 443 notrack accept
tcp dport { 22, 80 } tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport 443 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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 ip saddr @ip-connlimit-http counter reject with tcp reset
tcp dport 80 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 80 add @ip-connlimit-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 80 add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport 443 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, attestation } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 th dport != 8080 accept
skuid { chrony, attestation } meta l4proto { tcp, udp } th sport >= 1024 th sport != 8080 th dport 53 accept
skuid attestation tcp sport 8080 tcp dport >= 1024 tcp dport != 8080 accept
skuid http tcp sport >= 1024 tcp sport != 8080 tcp dport 8080 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -1,111 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-http {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
# IPv6 interacts badly with IP-based spam filtering
meta nfproto ipv6 tcp dport { 80, 443 } reject with tcp reset
tcp dport 443 notrack accept
tcp dport { 22, 80 } tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport 443 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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 ip saddr @ip-connlimit-http counter reject with tcp reset
tcp dport 80 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 80 add @ip-connlimit-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 80 add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport 443 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, flarum, flarum-admin, geoipupdate } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, http, flarum, flarum-admin, geoipupdate } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -1,108 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-http {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport { 25, 465, 993 } notrack accept
tcp dport { 22, 80, 443 } tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport { 25, 465, 993 } accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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-http counter reject with tcp reset
tcp dport { 80, 443 } ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80, 443 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 80, 443 } add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport { 25, 465, 993 } notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, postfix, dovecot, dovenull, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, postfix, opendkim, opendmarc, policyd-spf } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -1,113 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
51.222.159.116, # 0.grapheneos.network
}
define ip6-allowlist-ssh = {
::1,
2607:5300:205:200::2584, # 0.grapheneos.network
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-supl {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-supl {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport { 80, 443 } notrack accept
tcp dport { 22, 7275 } tcp flags syn notrack accept
udp dport 123 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport { 80, 443 } accept
udp dport 123 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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 7275 ip saddr @ip-connlimit-supl counter reject with tcp reset
tcp dport 7275 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-supl counter reject with tcp reset
tcp dport { 22, 7275 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 7275 add @ip-connlimit-supl { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 7275 add @ip6-connlimit-supl { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport { 80, 443 } notrack accept
udp sport 123 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, http } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -1,110 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-http {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport 443 notrack accept
tcp dport { 22, 80 } tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport 443 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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 ip saddr @ip-connlimit-http counter reject with tcp reset
tcp dport 80 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 80 add @ip-connlimit-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 80 add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport 443 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, mastodon } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, mastodon } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid postgres udp sport >= 1024 udp dport >= 1024 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -1,112 +0,0 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
51.222.156.101, # 0.grapheneos.org
167.114.114.114, # 0.releases.grapheneos.org
}
define ip6-allowlist-ssh = {
::1,
2607:5300:205:200::29c6, # 0.grapheneos.org
2607:5300:201:3100::6210, # 0.releases.grapheneos.org
}
set ip-connlimit-ssh {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-ssh {
type ipv6_addr
flags dynamic
}
set ip-connlimit-http {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
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)
fib daddr . iif type != { local, broadcast, multicast } counter drop
tcp dport 443 notrack accept
tcp dport { 22, 80 } tcp flags syn notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport 443 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
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 ip saddr @ip-connlimit-http counter reject with tcp reset
tcp dport 80 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80 } synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
tcp flags != syn accept
tcp dport 22 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 80 add @ip-connlimit-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 80 add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
}
chain forward {
type filter hook forward priority filter
policy drop
}
chain output-raw {
type filter hook output priority raw
oif lo notrack accept
tcp sport 443 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid chrony meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -0,0 +1,139 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
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 : goto graceful-reject, 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, attestation } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 th dport != 8080 accept
skuid { chrony, attestation } meta l4proto { tcp, udp } th sport >= 1024 th sport != 8080 th dport 53 accept
skuid attestation tcp sport 8080 tcp dport >= 1024 tcp dport != 8080 accept
skuid http tcp sport >= 1024 tcp sport != 8080 tcp dport 8080 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -0,0 +1,136 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
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 : goto graceful-reject, 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, flarum, flarum-admin, geoipupdate } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, http, flarum, flarum-admin, geoipupdate } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

136
nftables/nftables-mail.conf Normal file
View File

@ -0,0 +1,136 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
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, 25, 80, 443, 465, 993 } 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, 25, 80, 443, 465, 993 } goto input-tcp-service
iif lo accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { new : goto graceful-reject, 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 { 25, 80, 443, 465, 993 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } 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 { 25, 80, 443, 465, 993 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 25, 80, 443, 465, 993 } 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 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, postfix, dovecot, dovenull, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, postfix, opendkim, opendmarc, policyd-spf } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -21,12 +21,12 @@ table inet filter {
flags dynamic
}
set ip-connlimit-http {
set ip-connlimit-main {
type ipv4_addr
flags dynamic
}
set ip6-connlimit-http {
set ip6-connlimit-main {
type ipv6_addr
flags dynamic
}
@ -40,10 +40,13 @@ table inet filter {
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
tcp dport 443 notrack accept
tcp dport { 22, 80 } tcp flags syn notrack accept
# 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
}
@ -51,25 +54,51 @@ table inet filter {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport 443 accept
tcp dport { 22, 80, 443 } goto input-tcp-service
iif lo accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
ct state vmap { new : goto graceful-reject, 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 ip saddr @ip-connlimit-http counter reject with tcp reset
tcp dport 80 ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-http counter reject with tcp reset
tcp dport { 22, 80 } synproxy mss 1460 wscale 7 timestamp sack-perm
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-loopback {
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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport 80 add @ip-connlimit-http { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport 80 add @ip6-connlimit-http { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 32 } counter reject with tcp reset
accept
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 {
@ -81,7 +110,6 @@ table inet filter {
type filter hook output priority raw
oif lo notrack accept
tcp sport 443 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}

View File

@ -0,0 +1,141 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
51.222.159.116, # 0.grapheneos.network
}
define ip6-allowlist-ssh = {
::1,
2607:5300:205:200::2584, # 0.grapheneos.network
}
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, 7275 } tcp flags syn limit rate over 1024/second burst 128 packets counter notrack accept
udp dport 123 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain input {
type filter hook input priority filter
policy drop
tcp dport { 22, 80, 443, 7275 } goto input-tcp-service
iif lo accept
udp dport 123 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { new : goto graceful-reject, 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, 7275 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 80, 443, 7275 } 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, 7275 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 80, 443, 7275 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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, 7275 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 80, 443, 7275 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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, 7275 } add @ip-connlimit-main { ip saddr ct count over 32 } counter reject with tcp reset
tcp dport { 80, 443, 7275 } 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 notrack accept
udp sport 123 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, http } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -40,10 +40,15 @@ table inet filter {
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
udp dport 53 notrack accept
tcp dport { 22, 53, 80, 443, 853 } tcp flags syn notrack accept
# handle new TCP connections beyond rate limit via synproxy to avoid conntrack table exhaustion
tcp dport { 22, 53, 80, 443, 853 } tcp flags syn limit rate over 1024/second burst 128 packets counter notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
@ -51,25 +56,52 @@ table inet filter {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport { 22, 53, 80, 443, 853 } goto input-tcp-service
iif lo accept
udp dport 53 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
ct state vmap { new : goto graceful-reject, 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 { 53, 80, 443, 853 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-main counter reject with tcp reset
tcp dport { 22, 53, 80, 443, 853 } synproxy mss 1460 wscale 7 timestamp sack-perm
synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
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 { 53, 80, 443, 853 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip-connlimit-main { ip saddr ct count over 16 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 16 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip-connlimit-main { ip saddr ct count over 16 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 16 } counter reject with tcp reset
accept
ct mark set 0x1 accept
}
chain forward {

View File

@ -42,13 +42,18 @@ table inet filter {
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
# reject SSH packets via anycast IP
tcp dport 22 ip daddr 198.251.90.93 reject with tcp reset
udp dport 53 notrack accept
tcp dport { 22, 53, 80, 443, 853 } tcp flags syn notrack accept
# handle new TCP connections beyond rate limit via synproxy to avoid conntrack table exhaustion
tcp dport { 22, 53, 80, 443, 853 } tcp flags syn limit rate over 1024/second burst 128 packets counter notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
@ -56,25 +61,52 @@ table inet filter {
type filter hook input priority filter
policy drop
iif lo goto input-loopback
tcp dport { 22, 53, 80, 443, 853 } goto input-tcp-service
iif lo accept
udp dport 53 accept
meta l4proto { icmp, ipv6-icmp } accept
ct state vmap { established : accept, related : accept, new : goto graceful-reject }
ct state vmap { new : goto graceful-reject, 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 { 53, 80, 443, 853 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } ip6 saddr and ffff:ffff:ffff:ffff:: @ip6-connlimit-main counter reject with tcp reset
tcp dport { 22, 53, 80, 443, 853 } synproxy mss 1460 wscale 7 timestamp sack-perm
synproxy mss 1460 wscale 7 timestamp sack-perm
}
chain input-loopback {
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 { 53, 80, 443, 853 } ip saddr @ip-connlimit-main counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip-connlimit-main { ip saddr ct count over 16 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 16 } 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh add @ip6-connlimit-ssh { ip6 saddr and ffff:ffff:ffff:ffff:ffff:: ct count over 1 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip-connlimit-main { ip saddr ct count over 16 } counter reject with tcp reset
tcp dport { 53, 80, 443, 853 } add @ip6-connlimit-main { ip6 saddr and ffff:ffff:ffff:ffff:: ct count over 16 } counter reject with tcp reset
accept
ct mark set 0x1 accept
}
chain forward {

View File

@ -0,0 +1,138 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
}
define ip6-allowlist-ssh = {
::1,
}
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 : goto graceful-reject, 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http, mastodon } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid { chrony, mastodon } meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid postgres udp sport >= 1024 udp dport >= 1024 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

140
nftables/nftables-web.conf Normal file
View File

@ -0,0 +1,140 @@
#!/usr/bin/nft -f
flush ruleset
table inet filter {
define ip-allowlist-ssh = {
127.0.0.1,
51.222.156.101, # 0.grapheneos.org
167.114.114.114, # 0.releases.grapheneos.org
}
define ip6-allowlist-ssh = {
::1,
2607:5300:205:200::29c6, # 0.grapheneos.org
2607:5300:201:3100::6210, # 0.releases.grapheneos.org
}
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 : goto graceful-reject, 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 ip saddr != $ip-allowlist-ssh add @ip-connlimit-ssh { ip saddr ct count over 1 } counter reject with tcp reset
tcp dport 22 ip6 saddr != $ip6-allowlist-ssh 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 notrack accept
meta l4proto { icmp, ipv6-icmp } notrack accept
}
chain output {
type filter hook output priority filter
oif lo goto output-loopback
skuid != { root, systemd-network, unbound, chrony, http } counter goto graceful-reject
}
chain output-loopback {
skuid unbound meta l4proto { tcp, udp } th sport 53 th dport >= 1024 accept
skuid chrony meta l4proto { tcp, udp } th sport >= 1024 th dport 53 accept
skuid != root counter goto graceful-reject
accept
}
chain graceful-reject {
meta l4proto udp reject
meta l4proto tcp reject with tcp reset
reject
}
}

View File

@ -32,6 +32,7 @@ postgresql-old-upgrade
pv
python-pip
python-psycopg2
python-pydantic
rsync
sshpass
strace

View File

@ -100,9 +100,9 @@ charset-normalizer==3.3.2 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via requests
idna==3.6 \
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
# via requests
ovh==1.1.0 \
--hash=sha256:108f9b5a3b471193ce4a4589c7782f4bccbffe0ba03169774eb0472ac28ef679 \

View File

@ -1 +0,0 @@
net.ipv4.ip_local_reserved_ports = {{local_reserved_ports}}

View File

@ -10,6 +10,7 @@ net.ipv4.conf.*.rp_filter = 0
net.ipv4.tcp_ecn = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_shrink_window = 1
net.ipv4.tcp_notsent_lowat = 131072
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_rfc1337 = 1
@ -35,7 +36,6 @@ net.netfilter.nf_conntrack_tcp_timeout_established = 14400
kernel.yama.ptrace_scope = 2
vm.max_map_count = 1048576
vm.mmap_rnd_bits = 32
vm.mmap_rnd_compat_bits = 16