39

Currently I am redirecting all users except for the IP 12.345.678.90 using:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/maintenance$
RewriteCond %{REMOTE_HOST} !^12\.345\.678\.90
RewriteRule $ /maintenance [R=302,L]

What syntax would I use to allow a range? In my Allow list I have:

Allow from 123.45.678.90/28

Would it work if I just update the REMOTE_HOST line to:

RewriteCond %{REMOTE_HOST} !^12\.345\.678\.90/28
xylar
  • 7,433
  • 17
  • 55
  • 100

5 Answers5

37

If you're using Apache HTTPD 2.4 or later, you can use expressions to match REMOTE_ADDR against a CIDR mask.

The short form looks like this:

RewriteCond expr "-R '192.168.1.0/24'"

The following longer form is also available, but the documentation suggests it is less efficient:

RewriteCond expr "%{REMOTE_ADDR} -ipmatch '192.168.1.0/24'"

That makes the full solution to your example something like this:

RewriteEngine On
RewriteCond %{REQUEST_URI} !/maintenance$
RewriteCond expr "! -R '12.345.678.90/28'"
RewriteRule $ /maintenance [R=302,L]
zts
  • 1,461
  • 16
  • 10
  • Question: Could you give an example to the short form? It's unclear how it references `%{REMOTE_ADDR}`, whereas `%{REMOTE_ADDR}` is explicitly noted in the longer form. – jeffmaher May 04 '17 at 20:19
  • @plusjeff I'm not sure what you mean - the example of the short form is included above. From the linked documentation, -R is `Same as "%{REMOTE_ADDR} -ipmatch ...", but more efficient`. – zts May 05 '17 at 15:29
  • Is `-R` in the short form representative of `%{REMOTE_ADDR}`? If so, how does one use the high performance short form for checking a different variable (i.e. say I wanted to check a variable called `%{CLIENT_IP}` with the short form? If I use a different variable, do I always have to use the longer form? – jeffmaher May 05 '17 at 20:02
  • Yes, for other variables you will have to use the longer form. `-R` is specifically for `REMOTE_ADDR`. – zts May 08 '17 at 11:03
32

You probably want the %{REMOTE_ADDR} to match against, but you can't use CIDR notation as the %{REMOTE_ADDR} is literally the remote address and you can use a regular expression to try to match against it. So for 123.45.67.89/28, (123.45.67.80 - 123.45.67.95), you'd have to do something like this:

RewriteCond %{REMOTE_ADDR} !^123\.45\.67\.8[0-9]$
RewriteCond %{REMOTE_ADDR} !^123\.45\.67\.9[0-5]$
Jon Lin
  • 142,182
  • 29
  • 220
  • 220
  • 2
    If you want to match a wider range - e.g., indeterminate third and fourth octets - you could do `!^123\.45\.[0-9]{1,3}\.[0-9]{1,3}$` -- this will match any number from 0-255 in the third and fourth octets but let you define the first half of the IP. Recently had to do this on a WordPress I was developing, to allow WordPress JetPack servers to connect in to the XML-RPC endpoint while still redirecting regular visitors to a separate site. – Chris Woods Jan 17 '19 at 02:33
  • Very inefficient `RewriteCond`, [@zts answer is way better](https://stackoverflow.com/a/36024233/797495) – Pedro Lobito May 12 '20 at 00:26
  • This was answered when Apache 2.2 was widely used, now everything's 2.4 so using the expr is way better – Jon Lin Jun 12 '20 at 14:57
1

Although this is an old question, I find it still very relevant. An alternative that does allow CIDR notation is the following (example is in a virtualhost apache conf file):

<VirtualHost *:80>
    .
    .
    .
    <Files maintenance>
        Require all denied
        Require ip 12.345.678.90/28
    </Files>
    .
    .
    .
</VirtualHost>

As a sidenote, I suspect, without having done any testing or finding any evidence, that this method is "faster" than the RewriteCond expr "-R '192.168.1.0/24'" methods mentioned.

This is for the simple reason that at this high level there appears to be less computational steps involved.

N.B. a requester from an IP that is denied will see a "Permission denied" or "Forbidden" type response. You can make this prettier by adding in a custom 404 page that responding with a 200/OK (this way Google won't penalise your domain). The 200/OK has to be the first line of your custom 404 page. For example in PHP, the first line would read:

<?php header("Status: 200 OK"); ?>

You'd want to do this for a legit page you redirect to. Actual 404s should respond with 404 to keep us from ending up with a ton of useless search engine results down the road.

J-a-n-u-s
  • 1,469
  • 17
  • 20
1

Try this in .htaccess. It's working.

RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.[0-255]
0

I like to use the following which allows partial address matching. In Your virtualHost/htaccess file

SetEnvIf HOST "siteYouAreworkingON.com" ACCESS_CONTROL<br>
SetEnvIf Remote_Addr "list of full or partia ipadresses separated by |"<br>
RewriteCond %{ENV:ACCESS_CONTROL} 1<br>
RewriteRule .* http://gohere.instead [L,R]

Hope it helps.

Jaime Caffarel
  • 2,401
  • 4
  • 30
  • 42