table inet filter { map if_input { type ifname : verdict elements = { "eth0" : jump public_input, "eth1" : jump home_input, "eth2.10" : jump home_input, "eth2.20" : jump home_input } } map if_forward { type ifname : verdict elements = { "eth0" : jump public_forward, "eth1" : jump trusted_forward, "eth2.10" : jump voip_forward, "eth2.20" : jump guest_forward } } map if_output { type ifname : verdict elements = { "eth0" : jump public_output, "eth1" : jump home_output, "eth2.10" : jump home_output, "eth2.20" : jump home_output } } set ipv4_blacklist { type ipv4_addr flags interval auto-merge } set ipv6_blacklist { type ipv6_addr flags interval auto-merge } set limit_src_ip { type ipv4_addr size 1024 flags dynamic,timeout } set limit_src_ip6 { type ipv6_addr size 1024 flags dynamic,timeout } chain PREROUTING_RAW { type filter hook prerouting priority raw; policy accept; meta l4proto != { icmp, tcp, udp, ipv6-icmp } counter packets 0 bytes 0 drop tcp flags syn jump { tcp option maxseg size 1-500 counter packets 0 bytes 0 drop tcp sport 0 counter packets 0 bytes 0 drop } rt type 0 counter packets 0 bytes 0 drop } chain PREROUTING_MANGLE { type filter hook prerouting priority mangle; policy accept; ct state vmap { invalid : jump ct_invalid_pre, related : jump rpfilter, new : jump ct_new_pre, untracked : jump ct_untracked_pre } } chain ct_invalid_pre { counter packets 0 bytes 0 drop } chain ct_untracked_pre { icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return counter packets 0 bytes 0 drop } chain ct_new_pre { jump rpfilter tcp flags & (fin | syn | rst | ack) != syn counter packets 0 bytes 0 drop iifname "eth0" meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 } } chain rpfilter { ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport 68 udp dport 67 return ip6 saddr :: ip6 daddr . icmpv6 type { ff02::1:ff00:0/104 . nd-neighbor-solicit, ff02::16 . mld2-listener-report } return fib saddr . iif oif 0 counter packets 0 bytes 0 drop } chain blacklist_input_ipv4 { ip saddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } counter packets 0 bytes 0 drop ip saddr @ipv4_blacklist counter packets 0 bytes 0 drop } chain blacklist_input_ipv6 { icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 return udp sport 547 ip6 saddr fe80::/64 return ip6 saddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } counter packets 0 bytes 0 drop ip6 saddr @ipv6_blacklist counter packets 0 bytes 0 drop } chain INPUT { type filter hook input priority filter; policy drop; iif "lo" accept ct state established,related accept iifname vmap @if_input log prefix "NFT REJECT IN " flags ip options flags ether limit rate 5/second burst 10 packets reject } chain public_input { icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 ip6 hoplimit 255 accept udp sport 547 udp dport 546 ip6 saddr fe80::/64 accept fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop counter packets 0 bytes 0 drop } chain home_input { icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept udp sport 68 udp dport 67 accept udp sport 546 udp dport 547 iifname { "eth1", "eth2.10", "eth2.20" } accept fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop icmp type echo-request accept icmpv6 type echo-request accept tcp dport 22 iifname "eth1" accept meta l4proto { tcp, udp } th dport 53 jump { ip6 saddr != { fd00::/8, fe80::/64 } counter packets 0 bytes 0 reject with icmpv6 port-unreachable accept } udp dport 123 accept tcp dport 8443 accept } chain FORWARD_MANGLE { type filter hook forward priority mangle; policy accept; oifname "eth0" jump { ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 } tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu } } chain blacklist_output_ipv4 { ip daddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } goto log_blacklist ip daddr @ipv4_blacklist goto log_blacklist } chain blacklist_output_ipv6 { icmpv6 type . ip6 daddr { nd-router-solicit . ff02::2, nd-neighbor-solicit . ff02::1:ff00:0/104, nd-neighbor-advert . fe80::/64, nd-neighbor-advert . ff02::1, nd-neighbor-advert . ff02::1:ff00:0/104, mld2-listener-report . ff02::16 } return udp dport 547 ip6 daddr ff02::1:2 return ip6 daddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } goto log_blacklist ip6 daddr @ipv6_blacklist goto log_blacklist } chain log_blacklist { log prefix "NFT BLACKLIST " flags ip options flags ether limit rate 5/minute burst 10 packets drop counter packets 0 bytes 0 drop } chain FORWARD { type filter hook forward priority filter; policy drop; ct state established,related accept fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop iifname vmap @if_forward log prefix "NFT REJECT FWD " flags ip options flags ether limit rate 5/second burst 10 packets reject } chain public_forward { udp dport { 5060, 7078-7097 } oifname "eth2.10" jump { ip6 saddr { 2001:db8::1-2001:db8::2 } accept meta nfproto ipv6 log prefix "NFT DROP SIP " flags ip options flags ether limit rate 5/second burst 10 packets drop } counter packets 0 bytes 0 drop } chain trusted_forward { oifname "eth0" accept icmp type echo-request accept icmpv6 type echo-request accept ip daddr { 192.168.3.30, 192.168.4.40 } tcp dport vmap { 22 : accept, 80 : drop, 443 : accept } ip daddr 192.168.2.20 jump { tcp dport { 80, 443, 515, 631, 9100 } accept udp dport 161 accept } } chain voip_forward { icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } oifname "eth0" accept ip6 daddr { 2001:db8::1-2001:db8::2 } jump { udp dport { 3478, 5060 } accept udp sport 7078-7097 accept tcp dport 5061 accept } tcp dport 587 ip daddr 10.0.0.1 accept tcp dport 80 oifname "eth0" counter packets 0 bytes 0 reject } chain guest_forward { oifname "eth0" accept } chain OUTPUT { type filter hook output priority filter; policy drop; oif "lo" accept ct state vmap { invalid : jump ct_invalid_out, established : accept, related : accept, untracked : jump ct_untracked_out } oifname vmap @if_output log prefix "NFT REJECT OUT " flags ip options flags ether limit rate 5/second burst 10 packets reject } chain ct_invalid_out { counter packets 0 bytes 0 drop } chain ct_untracked_out { icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return counter packets 0 bytes 0 drop } chain public_output { ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 } icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept udp dport 547 ip6 saddr fe80::/64 ip6 daddr ff02::1:2 accept udp dport { 53, 123 } accept tcp dport { 443, 587, 853 } accept } chain home_output { icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept udp sport 547 udp dport 546 ip6 saddr fe80::/64 oifname { "eth1", "eth2.10", "eth2.20" } accept udp sport 67 udp dport 68 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } accept tcp dport 22 ip daddr 192.168.1.10 accept } chain POSTROUTING_SRCNAT { type nat hook postrouting priority srcnat; policy accept; ip saddr { 192.168.1.0-192.168.4.255 } oifname "eth0" masquerade } }