3

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 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.) It turns out, that OpenBSD's 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?

cnst
  • 25,870
  • 6
  • 90
  • 122
  • What would be the point of that? By the way, the tool you linked actually is a way to administratively close a connection. It **does** send a notification. – spectras Sep 11 '17 at 02:26
  • @spectras the point is to leave the connection hanging on the other end (e.g., to waste the resources of the attacker) – cnst Sep 11 '17 at 03:03
  • 1
    > the connection would be also hanging on your end, on all your network equipment. Properly sending closure notification allows your routers and firewalls to put the connection on the fast-aging line, freeing precious entries in their tables. Assuming an attacker has more equipment than you, you're effectively putting more strain on your infrastructure than theirs (more precisely, on their side the strain is spread out). – spectras Sep 11 '17 at 03:21
  • Thanks for the http://labrea.sourceforge.net/labrea-info.html link (whoever it was that deleted their own message); basically, yes, but I don't have any unused IP addresses that could be fully dedicated to this; was looking for writing an nginx module or patch. P.S. Unfortunately, the link to CVS web on that page appears to be broken, any idea where the code is at? – cnst Sep 11 '17 at 03:26
  • @spectras not true; the only stateful firewall is at the machine terminating the connections, so, the whole idea here is to just completely drop the connection without sending any packets around. – cnst Sep 11 '17 at 03:28
  • @spectras you're right -- just tested tcpdrop on OpenBSD; it does appear to send an `RST` – cnst Sep 11 '17 at 03:41
  • It seems very unlikely you don't have any stateful equipment before your machine (which I assume is a reverse proxy). Any router with failover? Certain it's in stateless mode? Hardware firewall? Load balancer? Most of those are used in stateful mode, which offers more convenience and more security. How about on your ISP side if you have a dedicated uplink? If you actually have none of that, either it is because you have a tiny architecture and attempts at resource-starving spammers is futile, or you have a large, atypical setup for something uncommon and helping will be really hard. – spectras Sep 11 '17 at 04:01
  • @spectras yes, I have a really tiny architecture; it's just a matter of principle; I want to be able to drop connections without sending the RST packet – cnst Sep 11 '17 at 04:49
  • You would waste your time pursuing this. For the reasons I explained, it's very unlikely you find readily available tools to do that. If spammers concern you, the sensible solution is not to skip sending one small packet, it's to make sure to block further connection attempts, the dozens larger packets they will consume, along with CPU and memory usage, pollution of your log files. Not to mention the opportunity that lets them to vary their attempts until they work around your security measures. – spectras Sep 11 '17 at 12:30
  • @spectras it is hardly a good option to block the whole IP — what if it was a bad user of a major ISP that's doing CGN over a limited set of IP addresses? Or someone intentionally performing a request to get their whole proxy blocked from service? Programming is done not only to solve business needs, but for fun, too; and I think this case of silently dropping TCP is one of those questions that satisfies both uses-cases. – cnst Sep 11 '17 at 19:31
  • If you are concerned about CGN, do them a favor and send that closure notification. By design, all forms of NAT are stateful, CGN not being an exception. I do agree the idea makes for a fun challenge, it will involve either kernel hacking or user-space reimplementation of TCP over a RAW socket. It's plain useless for business needs though. I have never met any business infrastructure not using stateful firewalls and routers and, once again, defender's resources are more valuable that attacker's so failing to send the closure does more damage to one's infrastructure than the attacker's. – spectras Sep 12 '17 at 14:25

2 Answers2

1

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • The idea is to waste the resources of the attacker; also, I believe it's up to the firewall settings on whether or not communication without a properly established state would be acknowledged at all. – cnst Sep 11 '17 at 03:09
  • @cnst Of course it's up to the firewall, but your question is about established connections, which have therefore already penetrated the firewall. If you're now just asking about firewall rules, (a) you've changed the question completely and (b) you're off topic. The best way to waste the resources of the attacker without consuming any of your own is not to allow the connection in the first place, by having the firewall drop everything. – user207421 Sep 11 '17 at 04:31
  • No, the question is the same -- firewall runs in the kernel; I want to drop the connection, which will entirely drop it from the kernel, including from the firewall, without sending any RST back; if the client will try to communicate again over the same connection, it'll be as if the connection was never established, hence, the firewall would not send anything back at all; same question, and nothing about the firewall rules. – cnst Sep 11 '17 at 04:35
1

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.

rodolk
  • 5,606
  • 3
  • 28
  • 34
  • Not only is this solution entirely incomplete and even Linux-specific at that, but if this is simply done at the firewall level, without appropriately terminating the connections on which the webserver expects termination through a multipacket `FIN` sequence (e.g., without inserting `RST` back to the local server, or some such), then this will effectively cause a DoS of your own web-server as well. – cnst Sep 19 '17 at 23:21
  • @cnst the idea is that the web server is closing the connection on its side. but the TCP segments with FIN and RST will not reach the client. What you say is that the server socket will stay forever waiting for FIN/ACK? And yes iptables and netfilter are Linux specific. Why do you think the response is incomplete? – rodolk Sep 20 '17 at 16:19