Reputation: 27218
Looking into nginx: ignore some requests without proper Host header got me thinking that it's not actually possible to close(2)
a TCP connection without the OS properly terminating the underlying TCP connection by sending an RST
(and/or FIN
) to the other end.
One workaround would be to use something like It turns out, that OpenBSD's tcpdrop(8)
, however, as can be seen from usr.sbin/tcpdrop/tcpdrop.c
on OpenBSD and FreeBSD, it's implemented through a sysctl-based interface, and may have portability issues outside of BSDs. (In fact, it looks like even the sysctl-based implementation may be different enough between OpenBSD and FreeBSD to require a porting layer -- OpenBSD uses the tcp_ident_mapping
structure (which, subsequently, contains two sockaddr_storage
elements, plus some other info), whereas FreeBSD, DragonFly and NetBSD use an array of two sockaddr_storage
elements directly.)tcpdrop
does appear to send the R
packet as per tcpdump(8)
, and can be confirmed by looking at /sys/netinet/tcp_subr.c :: tcp_drop()
, which calls tcp_close()
in the end (and tcp_close()
is confirmed to send RST
elsewhere on SO), so, it appears that it wouldn't even work, either.
If I'm establishing the connection myself through C, is there a way to subsequently drop it without an acknowledgement to the other side, e.g., without initiating RST
?
Upvotes: 5
Views: 2772
Reputation: 5907
Cheating an attacker in this way could be a good idea. Of course, in this case you are already reserving server resources for the established connection. In the most basic mode you can use netfilter to drop any TCP outgoing segment with RST or FIN flags set. This rule iptables rule could be an example:
sudo iptables -A OUTPUT -p tcp --tcp-flags FIN,RST SYN -j DROP
Of course, this rule will affect all your TCP connections. I wrote it just to provide a lead of how you can do it. Go to https://www.netfilter.org/ for getting more ideas working on your solution. Basically you should be able to do the same only for the selected connections.
Because of how TCP works, if you're able to implement it, the client (or attacker) will keep the connection open for a long time. To understand the effect it would have in a client read here: TCP, recv function hanging despite KEEPALIVE where I provide results of a test in which the other side doesn't return any TCP segment (not even an ACK). In my configuration, it takes 13 minutes for the socket to enter an error state (that depends on Linux parameters like tcp_retries1 and tcp_retries2).
Just consider a DoS attack will usually imply connections from thousands of different devices and not necessarily many connections from the same device. This is very easy to detect and block in the firewall. So, it's very improbable that you are going to generate resources exhaustion in the client. Also this solution will not work for cases of half-open connection attack.
Upvotes: 2
Reputation: 310875
If I'm establishing the connection myself through C, is there a way to subsequently drop it without an acknowledgement to the other side, e.g., without initiating RST?
No. Even if there was, if the peer subseqently sent anything it would be answered by an RST.
NB Normal TCP termination uses a FIN, not an RST.
Upvotes: 1