3

I have to convert 2 DWORDs, IP address and a network mask to CDIR format... So I have 2 DWORDs corresponding 1.1.1.1 and 255.255.255.255 and I want to come up with string 1.1.1.1/32

Any thoughts on this?

Thanks

Nemo
  • 70,042
  • 10
  • 116
  • 153
reza
  • 5,972
  • 15
  • 84
  • 126

5 Answers5

7

Simplest approach:

  static unsigned short toCidr(char* ipAddress)
  {
      unsigned short netmask_cidr;
      int ipbytes[4];

      netmask_cidr=0;
      sscanf(ipAddress, "%d.%d.%d.%d", &ipbytes[0], &ipbytes[1], &ipbytes[2], &ipbytes[3]);

      for (int i=0; i<4; i++)
      {
          switch(ipbytes[i])
          {
              case 0x80:
                  netmask_cidr+=1;
                  break;

              case 0xC0:
                  netmask_cidr+=2;
                  break;

              case 0xE0:
                  netmask_cidr+=3;
                  break;

              case 0xF0:
                  netmask_cidr+=4;
                  break;

              case 0xF8:
                  netmask_cidr+=5;
                  break;

              case 0xFC:
                  netmask_cidr+=6;
                  break;

              case 0xFE:
                  netmask_cidr+=7;
                  break;

              case 0xFF:
                  netmask_cidr+=8;
                  break;

              default:
                  return netmask_cidr;
                  break;
          }
      }

      return netmask_cidr;
  }
dngot_
  • 413
  • 4
  • 9
4

Since there are a small and fixed number of valid netmasks (32, to be exact), the fastest way is probably to just build a map of masks to prefix length once at init time, and the conversion is just a lookup in the map.

e.dan
  • 7,275
  • 1
  • 26
  • 29
3

Not efficient if you have a large amount of these to do, as it goes through the bits one at a time. But very straightforward way to count each bit in the netmask:

int cidr = 0;
while ( netmask )
{
    cidr += ( netmask & 0x01 );
    netmask >>= 1;
}

Then combine the IP address with this CIDR value.

Stéphane
  • 19,459
  • 24
  • 95
  • 136
3

The prefix-length is equal to the number of (leading) ones in the binary representation of the subnet mask. So you just need to count the number of (leading) ones.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 1
    Or the number of [trailing zeroes](http://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set) – Nemo Jul 11 '11 at 22:54
1

This isn't completely portable, but is likely the fastest way of doing this if your program is running on a chip that supports the Intel instruction set. (And a similar approach may work for other architectures). The Intel chips have an instruction called POPCNT, which returns the number of bits in a variable that are set to 1. Most compilers should provide an intrinsic to access this. For example, the Microsoft compilers give you __popcnt and GCC gives you __builtin_popcount. (With various flavors for different argument sizes).

Assuming a well-formed mask (as do all of the other solutions offered here), you can get the CIDR bit count with a single machine instruction.

inline uint32_t getBitCountFromIPv4Mask(uint32_t mask) {
    return __builtin_popcount(mask);    // presumes a well-formed mask.
}

You can do this with IPv6 masks as well. There's a 64-bit version of POPCNT, but since in6_addr won't give out address fragments in 64 bit chunks, it's probably best to not use it here.

uint32_t getBitCountFromIPv6Mask(const in6_addr &mask) {
    uint32_t bitCount = 0;

    for (uint32_t ii = 0; ii < 4; ii++) {
        bitCount += __builtin_popcount(mask.s6_addr32[ii]);
    }

    return bitCount;
}
Til
  • 5,150
  • 13
  • 26
  • 34