9

In my Apache config I want to set an environment variable if I see that the visitor comes from an specific IP range. Currently I do it this way:

SetEnvIfNoCase Remote_Addr "^194\.8\.7[45]\." banned=spammer-ip
SetEnvIfNoCase Remote_Addr "^212\.156\.170\." banned=spammer-ip

What I would prefer is something like this:

SetEnvIfIpRange 194.8.74.0/23 banned=spammer-ip
SetEnvIfIpRange 212.156.170.0/24 banned=spammer-ip

... because I think that converting an IP address to a string and then do an regular expression is a total waste of ressources.

I could do an

Deny From 194.8.74.0/23

... but then I don't get a variable that I can check in my 403 error page - to find the reason why access has been denied.

Any suggestions what I might miss? Is there an Apache2 MOD that can set environment variables based on "IP Address Ranges"?

BlaM
  • 3,886
  • 5
  • 27
  • 28

4 Answers4

8

You may use CIDR formatting with Apache 2.4 which allows <If>:

<If "%{REMOTE_ADDR} -ipmatch 194.8.74.0/23">
    SetEnv banned = spammer-ip
</If>
Christian
  • 103
  • 3
Greg
  • 1,423
  • 2
  • 13
  • 13
  • 1
    Thanks your answer ! Note that there was a bug in my Apache version, so that I had to enclose the IP range in single quotes: http://mail-archives.apache.org/mod_mbox/httpd-docs/201406.mbox/%3C53AA034E.8020504@rcbowen.com%3E – Lucas Cimon Aug 28 '15 at 09:52
7

be aware that variables set through SetEnv are not visible on some operations (see matrix):

http://www.onlinesmartketer.com/2010/05/27/apache-environment-variables-visibility-with-setenv-setenvif-and-rewriterule-directives/

your solution is

SetEnvIfExpr "-R '10.0.0.0/8' || -R '172.16.0.0/12' || -R '192.168.0.0/16'" rfc1918

see https://httpd.apache.org/docs/trunk/mod/mod_setenvif.html#SetEnvIfExpr

3

What you've got (SetEnvIfNoCase Remote_Addr "^a.b.c." env_key=env_value) is the best you'll easily do. I've seen this configuration style implemented on a heavily loaded cluster of machines, without any noticeable performance degradation. I agree using regular expressions, when CIDR ranges are more appropriate is annoying. You could write a small program to automatically generate the config from a list of CIDR ranges.

If you're familiar with Perl, you could create a modperl handler, which would allow/deny requests in whichever way you choose. modperl allows your code to run at different points throughout a HTTP request - mod_perl 2.0 HTTP Request Cycle Phases. PerlAuthzHandler would be the appropriate handler to use.

Lockie

Lockie
  • 886
  • 5
  • 8
0

This is not really a solution to go from RegExp to IP Ranges, but I found a nice script hosted by Google to convert an IP range to a matching regexp. Could be of use for some of you, too...

How do I exclude traffic from a range of IP addresses?

[Update]

It looks as if Google has removed the IP Address Tool (or at least the link they have on their site is broken), but there is a similar tool here: http://www.analyticsmarket.com/freetools/ipregex

BlaM
  • 3,886
  • 5
  • 27
  • 28