iptables reject tcp-reset on loopback

I am trying to check how a software would behave if there is a network failure. That software is using tcp send() and recv() to communicate.

Previously I was making the software communicate by putting them in 2 different machine on a lan network. So, to simulate a network failure I was using the below rule.

sudo iptables -A INPUT -p tcp -s 10.100.52.234 -j REJECT --reject-with tcp-reset

Lets suppose 10.100.52.234 is the IP of one of the systems. This was leading to a failure in an instant. All well and good.


Now, I am trying to simulate this in one machine using loopback address 127.0.0.1. Everything is working same just like the previous setup, but the above command is not working. It is not failing the network connection and the software just hangs. There is no communication happening but it does not fail either.

I have used the command

sudo iptables -A INPUT -p tcp -s 127.0.0.1 -j REJECT --reject-with tcp-reset

and

sudo iptables -A INPUT -p tcp -i lo -j REJECT --reject-with tcp-reset

both are not working. The software takes a very long time to fail.

Is there a different way to fail the connection for loopback address immediately?


Solution 1:

I reproduced your result (with SSH connection attempt to 127.0.0.1 while my sshd was listening). It is true that the software just hangs.

I think the software awaits a response or an error message, but the error message falls into the same rule and is rejected. I don't know whether there is some chain reaction of error messages or not -- I did not investigate that far. I may get it wrong in the first place, so if someone has better explanation I will be happy to read it.


Here's the solution that works in my Debian:

You should connect to 127.0.0.2 (explanation here) and make your rule as follows:

sudo iptables -I INPUT 1 -p tcp -d 127.0.0.2 -j REJECT --reject-with tcp-reset

Note the -I INPUT 1 fragment that ensures the rule to be inserted at the first position to take precedence over any ACCEPT rule you may already have on your loopback interface (as I have in my Debian).

I repeated the test (with SSH connection attempt, this time to 127.0.0.2). It failed immediately with

Connection refused

I think it works as you wish because now the error message is destined to 127.0.0.1, thus not being caught by the rejection rule and able to pass.