Ip addresses and subnets calculation

Many people do not clearly understand how IPv4 CIDR notation actually works.
Let me explain it for you in binary arithmetic.
Let's take a very common class C ip address: 192.168.1.1
Its binary representation is:  11000000.10101000.00000001.00000001
IP address actually consists of 32 bits. Those dots are splitting 32 bit value in 4 chunks:
192 -  11000000
168 - 10101000
1 - 00000001
1 - 00000001
Easy, huh?
Now let's take the subnet 192.168.1.0/24.
So what does /24 actually mean? It means that 24 bits  used to identify network and all other bits (8 in this case) are used to identify IP address.
Binary representation of 192.168.1.0 is
11000000.10101000.00000001.00000000
As I've mentioned above 24 bits are used to identify network (they are marked in bold). 8 bits are left to represent IP address and maximum value is 11111111 - 255 in decimal. Last IP address is reserved as broadcast. So network consists of 254 hosts.
More confusing example: 211.240.192.0/19
11010001.11110000.11000000.00000000
00000.00000000 - maximum value is 8191 - hosts = 8191 - 1 reserved = 8190
11010001.11110000.11000000.00000001 - first host - 209.240.192.1
11010001.11110000.11011111.11111111 - last host - 209.240.223.254

There is also a commonly used IP address representation - unsigned integer. To represent IP as integer just convert its binary value to integer.

The most efficient way of subnets calculation in programming languages is a bitwise operators family. Here is a sample Perl code:


use strict;
use Socket;
      
#Example subnet
my $net = '1.0.0.0/8';
#Split subnet to ip and mask chunks
my ($ip, $mask) = split(/\//, $net);
#Convert ip address to binary representation and then to integer
my $ipInt = unpack("N", inet_aton($ip));
#Shift 32 bits on 8positions right (00000000 111111111111111111111111) and than revert all bits with XOR (11111111 000000000000000000000000)

my $ipBits = 0b11111111111111111111111111111111;
my $maskBinary = $ipBits ^ ($ipBits >> $mask);
#Extract subnet bits (00000001 000000000000000000000000)
my $subnet = $ipInt & $maskBinary;
#First ip is 00000001000000000000000000000001
my $startIp = $subnet | 1;
 #Last ip is 00000001111111111111111111111111
my $endIp = $subnet | ($ipBits ^ $maskBinary);

Comments

Popular posts from this blog

Memory efficient array permutation in PHP 5.5 using generators

How to dump http request headers with PHP under CGI/FastCGI SAPI

Zend Framework 2 AJAX: return JSON response from controller action. The proper way.