How to Find Out the CIDR Notation for a Subnet, Given an IP and Netmask

In the process of working on some contributions to Salt (a fantastic new configuration management system), I needed to figure out how to find the CIDR notation for a subnet, given only an IP address and netmask. There is a python module called netaddr which is good for this sort of stuff, but the module is not a core module and using it would have required this module to be added to Salt’s dependency list. So, I needed to find a good way of calculating this information without the aid of a Python module. To my surprise, documentation on how to do this doesn’t appear to be that common on the web, so I thought I’d share it.

But first, a little bit of explanation for those that may need it. An IPv4 address contains 4 octets, each ranging from 0 to 255 (for example, 56.78.123.45). However, this notation is really just shorthand, designed be easier for humans to read. An IP address is really just a a 32-bit number, with bits 1-8 making up the first octet, 9-16 making up the second, etc. 255 in binary is 11111111, while 0 would be 00000000. The network mask (or netmask) uses the same notation as an IP address. When converted from that notation to binary, the number of zeros at the end will let you know the size of the network. A network mask (in binary) will be several 1s followed by (in most cases) several 0s. In the case of 255.255.255.0, there are 24 1s followed by 8 0s:

CIDR notation for a network would be the starting IP of the network followed by /NN, where NN is equal to 32 – the number of zeros. Since there are 8 zeros at the end, a netmask of 255.255.255.0 would be a /24 network. These are quite common. For the IP address 56.78.123.45, the CIDR notation for the network would be 56.78.123.0/24. /24 networks are easy because they always start at zero, but what if the netmask was 255.255.252.0? How would you find the start of that network?

The answer lies in bitwise operations, specifically the bitwise AND. A bitwise AND will take two binary numbers and compare the first bit of both numbers to each other, then the second bit of each number, etc., and will yield a 1 when both are 1, and 0 if either (or both) are not 1. Remember that a netmask will always be 1s up to a certain point. That point represents the start of the network. So executing a bitwise AND on the IP and netmask will give you 1s where there were 1s in the IP address, but only up to the point where the network began. The rest of the bits in the result will all be zeros.

As you can see, the result is 56.78.120.0. Because there are 10 zeros at the end of the netmask, this is a /22 (32 – 10) network, making the CIDR notation for this network 56.78.120.0/22.

Of course, it’s not too fun to do these conversions every time you want to get this information. There is a command-line tool called ipcalc which does this for you quite easily (The link was for a web version, but you can get a command-line version of the same tool in most Linux distributions).

Let’s make a programming exercise out of this, though. In python, the bitwise operator is a single ampersand.

So, the below python code will give you the CIDR notation:

And here’s the output: