#!/usr/bin/env nft -f flush ruleset table ip Inet4 { set Knocked_1 { type ipv4_addr flags timeout timeout 10s gc-interval 4s } set Knocked_2 { type ipv4_addr flags timeout timeout 10s gc-interval 4s } set Knocked_3 { type ipv4_addr flags timeout timeout 10s gc-interval 4s } set Knocked_4 { type ipv4_addr flags timeout timeout 2m gc-interval 4s } chain Knock_1 { set add ip saddr @Knocked_1 } chain Unknock_1 { set update ip saddr timeout 0s @Knocked_1 } chain Knock_2 { set update ip saddr timeout 0s @Knocked_1 set add ip saddr @Knocked_2 } chain Unknock_2 { set update ip saddr timeout 0s @Knocked_2 } chain Knock_3 { set update ip saddr timeout 0s @Knocked_2 set add ip saddr @Knocked_3 } chain Unknock_3 { set update ip saddr timeout 0s @Knocked_3 } chain Knock_4 { set update ip saddr timeout 0s @Knocked_3 set add ip saddr @Knocked_4 log prefix "Port-Knock accepted: " } chain RefreshKnock { set update ip saddr timeout 2m @Knocked_4 } chain PortKnock { ct state new ip saddr @Knocked_4 goto RefreshKnock tcp dport 456 ct state new ip saddr @Knocked_3 goto Knock_4 tcp dport 345 ct state new ip saddr @Knocked_3 return ip saddr @Knocked_3 ct state new goto Unknock_3 tcp dport 345 ct state new ip saddr @Knocked_2 goto Knock_3 tcp dport 234 ct state new ip saddr @Knocked_2 return ip saddr @Knocked_2 ct state new goto Unknock_2 tcp dport 234 ct state new ip saddr @Knocked_1 goto Knock_2 tcp dport 123 ct state new ip saddr @Knocked_1 return ip saddr @Knocked_1 ct state new goto Unknock_1 tcp dport 123 ct state new goto Knock_1 } chain FilterIn { type filter hook input priority 0 policy drop # allow established/related connections ct state {established, related} accept # early drop of invalid connections ct state invalid drop # allow from loopback meta iif lo accept # allow icmp ip protocol icmp accept # port-knocking jump PortKnock # misc. filtering # ... } chain FilterOut { type filter hook output priority 0 policy accept } }