For reading and verification only. You may not copy, use, modify or redistribute this code. Full notice on the main page.
tunnel/deploy/nftables.conf
| 1 | #!/usr/sbin/nft -f |
| 2 | # nftables fragment for an ALL tunnel node (the design plan, section 5). It protects the PROCESS, not the product: the node decides who may |
| 3 | # have what (tunnel/limits.go), and these limits sit above its own on purpose, so that the kernel refuses only what the node would never have served: |
| 4 | # |
| 5 | # per source (an IPv4 address, or an IPv6 /64, as the node counts them) |
| 6 | # connections held 1024 the node's cap is node_limits.per_ip_concurrent (16), 8 times that for an address of the OpenAI list or of a device. |
| 7 | # The kernel counts EVERY connection a source holds: a device's control connection plus one data connection per open |
| 8 | # stream (up to node_limits.label_streams_max for each device behind one address), which the node stops counting when |
| 9 | # they attach. 1024 is room for 16 devices at their cap behind one NAT |
| 10 | # new connections 200/s the node's is node_limits.per_ip_new_per_s (10), 8 times that for the OpenAI list or a device |
| 11 | # whole node |
| 12 | # new connections 20000/s and 40000 of burst: a flood the process could not read fast enough anyway |
| 13 | # port 80 (the node's own ACME webroot and nothing else): 32 connections and 20 new a second per source |
| 14 | # |
| 15 | # nftables_test.go (TestNftables_*) checks that these numbers are never below the node's, so a retuned policy cannot leave the kernel stricter than the |
| 16 | # node. The file only ADDS drops: its chain accepts by default, so loading it cannot lock the operator out. SYN cookies are a sysctl, not an nftables |
| 17 | # rule: install deploy/sysctl.conf next to this file. |
| 18 | # |
| 19 | # Check it before loading it: nft -c -f /etc/nftables.d/all-tunnel.conf |
| 20 | # Load it with the system's own nftables service (include it from /etc/nftables.conf), never with a script of the node: the node holds no privilege. |
| 21 | # |
| 22 | # NOTE: written against nftables 1.0 (Ubuntu 24.04). It has been read, not run: the first deployment runs the check above and fixes what it says. |
| 23 | |
| 24 | # Loading the file twice must not stack its rules: the table is dropped and made again (the first line makes sure it exists, so the delete never fails). |
| 25 | table inet all_tunnel |
| 26 | delete table inet all_tunnel |
| 27 | |
| 28 | table inet all_tunnel { |
| 29 | # connections held per source, counted by the kernel's conntrack |
| 30 | set held4 { type ipv4_addr; flags dynamic; size 65536; } |
| 31 | set held6 { type ipv6_addr; flags dynamic; size 65536; } |
| 32 | # new connections per source and second |
| 33 | set rate4 { type ipv4_addr; flags dynamic,timeout; timeout 1m; size 65536; } |
| 34 | set rate6 { type ipv6_addr; flags dynamic,timeout; timeout 1m; size 65536; } |
| 35 | set held80_4 { type ipv4_addr; flags dynamic; size 65536; } |
| 36 | set held80_6 { type ipv6_addr; flags dynamic; size 65536; } |
| 37 | set rate80_4 { type ipv4_addr; flags dynamic,timeout; timeout 1m; size 65536; } |
| 38 | set rate80_6 { type ipv6_addr; flags dynamic,timeout; timeout 1m; size 65536; } |
| 39 | |
| 40 | chain input { |
| 41 | type filter hook input priority filter - 10; policy accept; |
| 42 | |
| 43 | ct state invalid drop |
| 44 | |
| 45 | # the whole node: more new connections than the process can read is a flood, whoever sends it |
| 46 | tcp dport { 80, 443 } ct state new limit rate over 20000/second burst 40000 packets drop |
| 47 | |
| 48 | # :443, per source |
| 49 | tcp dport 443 ct state new add @held4 { ip saddr ct count over 1024 } drop |
| 50 | tcp dport 443 ct state new add @held6 { ip6 saddr & ffff:ffff:ffff:ffff:: ct count over 1024 } drop |
| 51 | tcp dport 443 ct state new add @rate4 { ip saddr limit rate over 200/second burst 400 packets } drop |
| 52 | tcp dport 443 ct state new add @rate6 { ip6 saddr & ffff:ffff:ffff:ffff:: limit rate over 200/second burst 400 packets } drop |
| 53 | |
| 54 | # :80, per source |
| 55 | tcp dport 80 ct state new add @held80_4 { ip saddr ct count over 32 } drop |
| 56 | tcp dport 80 ct state new add @held80_6 { ip6 saddr & ffff:ffff:ffff:ffff:: ct count over 32 } drop |
| 57 | tcp dport 80 ct state new add @rate80_4 { ip saddr limit rate over 20/second burst 40 packets } drop |
| 58 | tcp dport 80 ct state new add @rate80_6 { ip6 saddr & ffff:ffff:ffff:ffff:: limit rate over 20/second burst 40 packets } drop |
| 59 | } |
| 60 | } |