# PHP Bitwise IP Handling

By Dag, on December 30th, 2016How to properly compare an IP address against a bitmask. Useful for e.g. blocking subnets without using abundant string comparisons.

$BlockedNetworks = array(ip2long("192.168.0.0"), ip2long("10.0.0.0")); $BlockRange = ip2long("255.255.0.0"); $VisitIP = ip2long($_SERVER['REMOTE_ADDR']); foreach ($BlockedNetworks as $BN) { if (($VisitIP & $BlockRange) == $BN) exit(); // or redirect or whatever you want. }

In the example above, any IP in the 192.168.x.x and 10.0.x.x ranges will be matched. The 255 numbers you see in masks represent all 8 bits in an octet being turned on, so comparing against it will always reserve the octet bits without turning them off. Meaning 192.168.1.10 & 255.255.0.0 equals 192.168.0.0 because the last two octets will be turned off during comparison.

**How Does It Work?**

*Bitwise AND(& operator)*. It's what network masks are all about. It's the bitwise operator used in programming if you need to turn off a bit, by comparing to a off-bit/0.

1 & 1 = 1 1 & 0 = 0 0 & 1 = 0

## In Detail

Let's investigate 192.168.1.10, and use that as our IP address of choice. To find out the binary version of this address, we just need to take an empty octet/set of 8 binary bits and turn some of them on so they add up to 192, 168, 1 and 10.Here's a turned off byte/octet:

[0 0 0 0 0 0 0 0]Which represents:[128 64 32 16 8 4 2 1]in decimal values when individually turned on.

To get

**192**we need to turn on

**128 + 64**. The octet now looks like this:

[1 1 0 0 0 0 0 0]

Now that we know how to convert binary into decimal, let's do the whole address:

[11000000].[10101000].[00000001].[00001010]=192.168.1.10

Let's put it on top of the mask and compare bits one by one:

[11000000].[10101000].[00000001].[00001010](192.168.1.10) &[11111111].[11111111].[00000000].[00000000](255.255.0.0) =[11000000].[10101000].[00000000].[00000000](192.168.0.0)

As you see, when comparing 1 AND 1 it will stay 1, while 0 turns it off. Hence why 192.168.1.10 will equal 192.168.0.0 when using bitwise AND comparison. This should give a deeper understanding of network masks works in general and how they work in normal networking.

Same thing works on IPv6 adresses, they are just bigger to deal with (128 bits vs 32) and use hexadecimal number groups instead of octets.

2001:0db8:85a3:0042:1000:8a2e:0370:7334 = 0010000000000001:0000110110111000:1000010110100011:0000000001000010:0001000000000000:1000101000101110:0000001101110000:0111001100110100 A bitmask could look something like: ffff:ffff:ffff:ffff:0000:0000:0000:0000 To match everything in the network when compared directly to it with the algorithm at the beginning of this document: 2001:0db8:85a3:0042:xxxx:xxxx:xxxx:xxxx

## A Quick Note on The Hexadecimal System

It's just a number system with a base of 16 instead of 2 and 10 (0-9 and a-f/A-F). E.g. a value like 0xABCD consists of a prefix (0x) to tell the parser it's actually a hexadecimal value, and the value itself. Since A follows after 9, its value is 10 - and so on up until 15(F). So you got 10, 11, 12 and 13. These are actually just easier ways of representing binary and decimal values since the base of 16 is bigger. A B C and D represents groups of 4 binary bits with a base of 2, and those bits represents the same decimal values with a base of 10 as in the binary system. Knowing this, a convertion between them is always possible even if you choose to do it through math or just value mapping/representation.**One Simple Illustration, To Rule Them All:**

Hexidecimal: 0xABCD = Binary: 0x[1010][1011][1100][1101] > [8+2=10][8+2+1=11][8+4=12][8+4+1=13]. = Decimal: 0x[32768+0+8192+0][2048+0+512+256][128+64+0+0][8+4+0+1] = 43981.