6

I have the following IPTables with IPSet as rule source to block attacking IP, but when I add an attacking IP to IPSet, in my nginx access log, I still see continuous access of the attack IP. After a while,maybe 3~5 minutes, the IP was blocked.

iptables

~$ sudo iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 317K packets, 230M bytes)
num   pkts bytes target     prot opt in     out     source               destination
1     106K 6004K DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set Blacklist src

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            match-set Blacklist src

Chain OUTPUT (policy ACCEPT 350K packets, 58M bytes)
num   pkts bytes target     prot opt in     out     source               destination

ipset

sudo ipset -L
Name: Blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536 timeout 60
Size in memory: 13280
References: 2
Members:
xxx.xxx.xxx.xxx(attacker ip) timeout 0

I don't know why the rule has not effect immediately, which make me crazy just like the attacker is laughing at me.

I add ipset to the iptables rule with -I option which should keep the rule at the first position. So maybe the Chain INPUT(policy Accept) do the trick?

Please help me out, thanks so much.

BTW.

I use Nginx+Djano/uWSGI to deploy my application, and I use shell script to analyze nginx log to put evil ip to Blacklist ipset.

Fogmoon
  • 569
  • 5
  • 16
  • More details can be provided, please help me, thanks – Fogmoon Aug 01 '17 at 06:59
  • You should show your iptables rules after that you blacklisted the IP. – Fabien Aug 08 '17 at 05:32
  • @Fogmoon, did my answer provide sufficient background behind the question? If not, let me know what's still missing. If yes, could you please accept and/or award the bounty? If you perform no action, at least half of the bounty will be lost (in this case, since no answer has 2+, all of it will be lost). Thanks in advance! – cnst Aug 08 '17 at 17:45

2 Answers2

4

The reason that a firewall rule may have no immediate effect on blocking traffic may be due to stateful inspection of packets.

It may be inefficient for the firewall to analyse every single packet that arrives in the line, so, for performance reasons, what happens is that the rules the user creates often apply only to the initial packets that establish the connection (known as TCP's SYN, SYN+ACK, ACK) — subsequently, said connection is automatically whitelisted (to be more precise, it is the state that the original rule has created that is whitelisted), until terminated (FIN).

What likely happens here is that, due to pipelining and keep-alive connections, which nginx excels at, a single connection may be used to issue and process multiple independent HTTP requests.

So, in order for you to fix the issue, you could either disable pipelining and keep-alives in nginx (not a good idea, as it'll affect performance), or drop the existing whitelisted connections, e.g., with something like tcpdrop(8) on *BSD — surely there must be a Linux equivalent tool, too.

However, if you're simply having an issue with a single client performing too many requests, and as such overloading your backend, then the appropriate course of action may be to rate-limit the clients based on the IP-address, with the help of the standard limit-req directive of nginx. (Note, however, that some of your customers may be behind a carrier-grade NAT, so, be careful with how much you apply the limiting to ensure false-positives won't be an issue.)

cnst
  • 25,870
  • 6
  • 90
  • 122
  • Thanks for your so detailed answer. Can I check the connection state by some command? BTW, it is not easy to find a equivalent command like `tcpdrop` in Ubuntu server, should I just use [tcp_killer](https://github.com/google/tcp_killer) or I have missed something? Thank you. – Fogmoon Aug 02 '17 at 06:33
  • @Fogmoon, basically, yes — you might have to use a third-party tcpdrop on Linux. You can use [`lsof`](http://mdoc.su/f/lsof.8) to see all ongoing connections; e.g., `lsof -nP -c nginx | fgrep ESTABLISHED`. – cnst Aug 02 '17 at 21:35
  • So sorry for this too late accepted action. Your answer is helpful. But I need to say, I did not solve my problem, I just add rule to nginx configure file to avoid too much requests at same time. I don't know why the bounty lost, sorry again. Recently I am very very busy and have forgotten this question. If there is another method to give you the bounty, please let me know. Very Thanks. – Fogmoon Sep 07 '17 at 10:59
  • @Fogmoon have you looked into nginx 444 error codes? This is supposed to close the established connection forcing the next request to be dropped by the newly added IP rejection rule. https://stackoverflow.com/questions/41421111/http-444-no-response-instead-of-404-403-error-pages – Joseph Persico Jan 11 '20 at 09:19
0

Have you looked at this post here: https://serverfault.com/questions/523021/why-is-iptables-not-blocking-an-ip-address

This post shows shows the person's ip getting dropped using -A INPUT -p tcp --dport 80 -j LOG --log-prefix "HTTP: "

I haven't run into this issue personally so please let me know if this is helpful, good luck.

Paul_C
  • 26
  • 4
  • Thanks for your answer, but I am not clear hot to use this statement to drop ip. Can you description it more detailed? – Fogmoon Aug 01 '17 at 17:38
  • It should be something like sudo iptable -A xxxx -p tcp --dport 80 -j xxx --log-prefix "HTTP: " this will automatically trap and capture all data being accessed by ports 80 and etc. However that isn't exactly useful but, if the blocked ips and such want to access that area you can stop the traffic flow. To drop the ip from your server (hopefully) instantly you should use : iptables -A INPUT -s xxxxxxx -j DROP iptables -A INPUT -s xxxxxxx -j REJECT Sorry for not being clear in my first statement. – Paul_C Aug 01 '17 at 17:51