Tuesday, November 1, 2011

This article explains why you must sometimes use CIDR netmask notation to ban an IP address range using Apache .htaccess, and how to do it. It is intended to supplement the basic Apache information about mod_access in the documentation at http://httpd.apache.org/docs/1.3/mod/mod_access.html.

An IP address is a 32-bit binary number that uniquely identifies a computer on the internet

32-bit binary is hard to remember : 11000000010000000000000000000000

Decimal notation isn't much easier: 3225419776

So it is usually written like this : 192.64.0.0

You get this "dotted-quad notation" by breaking the 32 bits into 4 groups of 8 and then converting each group to decimal:

11000000

01000000

00000000

00000000

192

64

0

0

192.64.0.0

That makes it easier to remember, but it creates problems if you try to use it for calculations.

An IP address contains two pieces of information:

The leftmost binary digits are the unique ID of the network (usually your Internet Service Provider, ISP) through which you are connected to the internet.

The remaining binary digits are your unique ID as an individual user on that network.

The number of leftmost digits used for network ID is not the same for every network. In CIDR notation, the /nn part says how many of the leftmost bits indicate the network.

If the network uses exactly the leftmost 8, 16, or 24 bits for its ID, then the dividing line between network and user falls on one of the period boundaries of the dotted-quad notation, and one of the partial IP notations will work:

.htaccess partial IP address

Equivalent CIDR

deny from 192

deny from 192.0.0.0/8

deny from 192.64

deny from 192.64.0.0/16

deny from 192.64.0

deny from 192.64.0.0/24

Each quad that you don't specify is treated as a wildcard that can take any value from 0 to 255. So the first example bans any IP address that starts with 192., followed by anything.

When to use CIDR notation

If the network doesn't use exactly 8, 16, or 24 bits for the network part of the IP address, the dividing line between network and user does not fall on a period boundary of dotted-quad notation, and you need to use a CIDR netmask.

Example CIDR/netmask:

192.64.0.0/10

This says the base address of the network is 192.64.0.0 and the first 10 bits are the network:

192 64 0 0 = 11000000 01000000 00000000 00000000

192 is the first 8 bits, but two more bits are part of the network ID, too. The 9th bit is 0 and the 10th is 1, and that is where the 64 comes from.

The full range of this network in quad notation is 192.64.0.0 - 192.127.255.255. Note that the 64 in the second position doesn't remain constant. The first 2 bits are always the same, but the righthand 6 will be different for different users.

The simple notations for an .htaccess ban won't work. Why not?

deny from 192 would ban the range 192.0.0.0 - 192.255.255.255, which will ban some users that are not coming from this network.

deny from 192.64 would ban the range 192.64.0.0 - 192.64.255.255, which is insufficient to ban all the users that are coming from this network.

So the answer is CIDR notation and an .htaccess line that says:

deny from 192.64.0.0/10

This says the base address is 192.64.0.0, and the first 10 bits identify the network (those are always the same for all users who are on that network).

To ban a specific IP range in htaccess

Figure out, from your website access logs or elsewhere, the IP addresses you want to ban. Look them up in a WhoIs database such as http://whois.domaintools.com/.

Determine whether you need to use a CIDR netmask. If the IP address range in the report looks like one of these, with each quad after the leading one(s) showing a rull range of 0-255, then you can use one of the simpler methods:

192.0.0.0 - 192.255.255.255 -- Use deny from 192

192.64.0.0 - 192.64.255.255 -- Use deny from 192.64

192.64.128.0 - 192.64.128.255 -- Use deny from 192.64.128

For anything else, you need CIDR. At Domain Tools, the CIDR netmask is sometimes shown in the report for that IP address, several lines down in the report. If it is, that's all you need. You're ready to create the line in your .htaccess file. Go to Step 5.

b) You can simply determine the netmask (the /nn part) by trial and error, or you can calculate the minimum size to start with: take the rightmost nonzero quad of the base address and convert it to binary in your head or in Windows Calculator. Find the rightmost "1". The netmask will have to be sufficient to include all of the previous quads (at 8 bits each), plus all the digits in this quad up to its rightmost "1". That's the minimum. But it might include some of the trailing zeroes, too.

c) Keep using trial and error for the netmask until HostMin and HostMax match the IP address range you saw in the Domain Tools report.

Note that final quads of 0 and 255 are reserved, so:

The calculated HostMin will be nnn.nnn.nnn.1, not nnn.nnn.nnn.0

The calculated HostMax will be nnn.nnn.nnn.254 not nnn.nnn.nnn.255

The Hosts/Net line tells you how many users this network might have, which can help decide whether you really want to ban the entire range.

Edit your public_html/.htaccess file to add the "deny from" line:

Go to cPanel > File Manager.

Navigate to the file public_html/.htaccess.

Click on its file name (not the icon next to it).

In the upper right corner of the screen, click Edit File.

Make a backup copy: Copy all the text in the file, and save it into a file on your local computer so you can put it back into .htaccess if something goes wrong.

Backup made? Ok, now you can edit the file. On a blank line in a part of the file that is not between HTML-style tags like <tag></tag>, type the line:

deny from nnn.nnn.nnn.nnn/nn

Replace the nnn's with the IP/netmask you calculated for this range.

Further explanation: some lines of your .htaccess file might be contained between tags that look like HTML tags where the opening tag looks like <tag> and the closing tag looks like </tag>. Insert this new line in a part of the file that is not between any of these pairs of tags.

Depending on what is in your .htaccess, you might need to use your judgment whether to use the order and allow directives that are also provided by mod_access. See the link to Apache at the top of this article for more information. That is beyond the scope of this article, and it will require your judgment. I'd suggest adding only the "deny from" line at first and seeing if it works as expected. What is expected: you can access your website; most other people can, too; when the denied party tries, your logs will show a result code of 403 Forbidden.