how to convert ipaddress/mask to CIDR using c++?

9.6k views Asked by At

I have a list of ipaddress/mask which needs to be converted to CIDR notation.

for e.g. 12.174.36.240/24 needs to be converted to 12.174.36.0/24 or something like what http://www.subnet-calculator.com/cidr.php does

How can this be acheived?

PS: the mask value is not always 24.

2

There are 2 answers

0
Elliot Robinson On BEST ANSWER

Just to lead you in the right direction, consider what an IPv4 address is (a 32-bit integer). Now, consider what a mask is (a bit field used in bitwise operations).

Take the address 127.0.0.1 on a big-endian system. In hex, that's 0x7f000001. A 24-bit mask is 0xffffff00 (24 bits of 1, 8 bits of 0, 32 bits total). The bitwise and of the address and the mask 0x7f000001 & 0xffffff00 = 0x7f000000 is the CIDR format.

I leave it to you to determine how best to parse the address, convert the IPv4 address to its integer form (and back), and create a bit mask from a routing prefix mask, though I will tell you that there are standard functions for at least the address manipulation.

1
Sylwester On

So basically an IPV4-address and netmask are 32 bit unsigned integer displayed in pairs of 8 bit with a dot between them.

So if you have "a.b.c.d" you could get the integer value by doing

(a<<24) + (b<<16) + (c<<8) + d 

If you're not used to the << it's shifts the bits in the number to the left the number of times as the right argument.. Thus a<<b is the same as a*2^b

Now in a CIDR the number after the slash tells you how many bits (of 32) that are the network part of the number before the slash. eg. 10.10.10.1/28 has 28 bits network and 32-28=4 bits host part. That means that if you take the ip and translate it to a number (=0x0A0A0A01) and do a logical & with 0xFFFFFFFF<<4 (= 0xFFFFFFF0) you get 0x0A0A0A00. If you translate that back to a ip with the following:

sprintf("%d.%d.%d.%d", (n>>24)&0xff, (n>>16)&0xff, (n>>8)&0xff, n&0xff) 

You get 10.10.10.0. Also if you translate 0xFFFFFFF0 to a ip with the same algorithm you get 255.255.255.248 which is the netmask that corresponds to mask length 28.

IPv6 is exactly the same, except it's 128 bits divided in 8 16 bit clusters displayed in hex with commas between them with some fancy shortcut for multiple runs of 0 (::)..

eg.

fe80::52e5:49ff:ffc9:1889/64 == 

;;convert the mask 
0xffffffffffffffffffffffffffffffff << (128-64) =
0xffffffffffffffff0000000000000000

;;convert the ip:
fe80::52e5:49ff:ffc9:1889 ==
fe80:0000:0000:0000:52e5:49ff:ffc9:1889 ==
0xfe8000000000000052e549ffffc91889 

  0xfe8000000000000052e549ffffc91889
& 0xffffffffffffffff0000000000000000
= 0xfe800000000000000000000000000000

;;convert first address in range back to string:
fe80:0000:0000:0000:0000:0000:0000:0000 = 
fe80::

I guess that on the basis of this you can make a function that does what you want.