6

I have a defined zone in Nginx for limiting requests, it's plain straight forward as described in their documentation:

limit_req_zone $binary_remote_addr zone=leash:10m rate=18r/s;

So far so good.

It works great with clients who act offensively, but recently some of them have started rotating their IP addresses while accessing my service, mostly within a /24 range, so I was wondering is it possibble to apply the zone connection count limit to a whole IP range (not just per IP), something like a --connlimit-mask 24 flag would do with iptables...?

Istvan Prosinger
  • 145
  • 2
  • 11

2 Answers2

2

The easiest way would be a nginx combo of map and geo directives which would also give you the most flexibility, IMHO.

geo $geoRateBlacklist {
    default        0;
    192.0.0.0/24   1;
    10.0.0.0/24    1;
    172.0.0.0/24   1;
}

map $geoRateBlacklist $rateBlacklist {
    1              $binary_remote_addr;
    0              "";
}

limit_req_zone $rateBlacklist zone=leash:10m rate=18r/s;

Quickly done from memory but should work.

Shawn C.
  • 6,446
  • 3
  • 34
  • 38
  • 1
    Thanks for the idea. This might partially do the job. The problem is that in the geo block you've took the incomming IP blocks as a constant. While it actually is a constant at some point, they can change it, so my assumption is that the IP block is initially unknown – Istvan Prosinger Apr 26 '18 at 09:45
  • 1
    @IstvanProsinger I would really like to know if you found the answer to this. – user1265125 Feb 25 '19 at 17:08
  • 1
    Correct me if I am wrong, but wouldn't this still be blocking per IP? The geo block creates a new $geoRateBlacklist variable from the client IP. This variable will be 0 or 1. The map block will map that 0 or 1 to a new $rateBlacklist variable that is either "" or $binary_remote_addr. Doesn't this mean that, for the cases where that variable is not empty, it will still always be equivalent to "limit_req_zone $binary_remote_addr zone=leash:10m rate=18r/s", i.e. limiting per IP and not subnet? – andresp Mar 27 '19 at 11:05
1

It is possible to use the map directive with regex to extract the subnet for $binary_remote_addr. For example, for a slash 16 subnet:

map $binary_remote_addr $bin_slash16 {
"~^(?P<a>..)..$" "$a";
}

Source: https://forum.nginx.org/read.php?2,271483,271788#msg-271788

nwarp
  • 731
  • 4
  • 8
  • 17