10

I there any way to check that 32 bit netmask is valid or not using bitwise operator?

I have to check from msb side that '1' are in continuous stream or not. eg 11111111.0.0.0 (255.0.0.0)is valid but 11111101.0.0.0 (253.0.0.0) is not.

Vid
  • 137
  • 1
  • 2
  • 13

2 Answers2

18

First thing to do is to check for the netmask being non zero (a nasty edge case). Given this is ok, you need to take the bitwise inverse.

uint32_t y = ~x;

Then add one

uint32_t z = y + 1;

Then if x was a proper netmask, there will be at most 1 bit set in this.

To test that, simply and z with z - 1, which happens to be y. The result will be zero if all is OK, non zero otherwise.

valid = (z & y) == 0;
Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
  • 1
    (Was about to give the same answer :-) But I would use `unsigned int` or `uint32_t` to avoid undefined overflow behaviour at `z = y + 1`. – Martin R Jul 01 '13 at 09:38
  • oops, yes. brain dead this morning and it's only monday - editting as suggested. – Tom Tanner Jul 01 '13 at 09:47
  • I had some not that efficient version, which has the advantage of being easier comprehensible. Could you please explain _why_ this works? Even after scribbling some netmasks on paper and writing all in between values, I could not figure the math behind your algorithm. – LeSpocky Feb 26 '15 at 17:15
  • 1
    if x is a proper netmask, it consists of all ones, followed by all zeros. Bitwise inversion gives all 0s followed by all ones. Adding one will give a single one bit followed by all zeros. Anding that with the previous mask is clearly zero. If however it is not a valid bitmask, there will be a pattern like this: .... 1 (at least one 0) 1 ... Adding one to that will stop changing things at the 0 so you'll get ....1 (0 or 1) ..... Anding the two together gives you at least one 1 bit set. – Tom Tanner Mar 02 '15 at 08:24
  • This is a really good answer and I found it extremely helpful so thanks for that! For anyone who had the same question as me, this function will work regardless of whether or not your mask is big or little endian. I verified on paper, so correct me if I'm wrong, but it should still work! – L-S Apr 05 '18 at 20:12
10

To check for an invalid netmask, you can use the following simple algorithm:

mask & (~mask >> 1)

This will evaluate to 1 for an invalid netmask and 0 for a valid netmask.

A valid netmask cannot have a zero with a one to the right of it. All zeros must have another zero to the right of it or be bit 0. If you take the ones complement (~) of a netmask that has a zero with a one to the right of it and shift it to the right by one bit position, you will align a one in the netmask with a one in the shifted one’s complement of the netmask. AND'ing these two values together will produce a one which indicates an invalid netmask.

Be sure to use ntohl() to convert the netmask to host byte order before applying this algorithm if it is in network byte order. Also, you need to make special checks for 0xffffffff and 0x00000000 if you wish to exclude them.

Note: Due to C's precedence and associativity rules for operators, the parentheses shown in the algorithm are not necessary but I've added them to make the code easier to understand in case you don't always remember the precedence and associativity rules.

int is_netmask_valid(uint32_t mask)
{
    if (mask == 0) return 0;
    if (mask & (~mask >> 1)) {
        return 0;
    } else {
        return 1;
    }
}
Paul Walrath
  • 101
  • 1
  • 3