How can I drop the first SYN packet received by my server (or the first
SYN/ACK packet sent by the server)?
I have a test VPS set up to capture and analyze malicious traffic
directed to non-standard TCP ports, for example attacks on sshd running
on a high port. Using BGP, an IPv4 /23 is routed to the VPS. With the
nftables rules below, connection attempts to any port 20000-60000 are
redirected to sshd.
flush ruleset
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
tcp dport 20000-60000 counter redirect to 22
}
chain postrouting {
type nat hook postrouting priority 100;
}
}
table filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
This works and results in ~20,000,000 address/port combinations that
will connect to sshd.
The problem is that I'm only interested in attacks that retransmit an
unanswered SYN (the vast majority probe with only one SYN, as scanning
all ports on all IPv4 addresses is quite expensive). I've tried various
methods, based on conntrack state, packet count and even expiration, all
to no avail. I suspect that they are somehow interacting with the redirect.
For example, adding this to the output chain:
tcp sport 22 ct expiration > 55 counter drop
causes all SYN packets to be dropped. Using 'conntrack -E', you can see
the expiration timer going down with each subsequent SYN, but when it
gets below 55, the packets keep getting dropped.
Environment: Debian bullseye, kernel 5.10.0, nftables v0.9.8, conntrack
v1.4.6.
What am I doing wrong? TIA for any suggestions.