IP/Network Address Validation Using Bitwise Operations
Always validate input. You’re sure to get burned at some point if you don’t.
192.168.1.1/24 - Valid 192.168.1.4/30 - Not Valid, sits on a network boundary
Converting IPs to Integers
To determine this, we must convert a valid IP address into an integer. To do this, we do a bitwise zero fill left shift on each octect by an amount of 32 - (Current Octect * 8), so 24 bits for the first octect, 16 bits for the second octet, etc. This gives us the integer value of each octet which we can add together to get the integer value of the IP address in question.
Great. Now we need to determine what the lower and upper network boundaries are: network address and broadcast address. In this case that would be 192.168.1.0 and 192.168.1.255, neither of which should be considered a valid value. In order to determine what those boundaries are, we’ll need to look at 3 things: IP address represented as bits, network mask represented as bits, and wildcard mask represented as bits. By doing a bitwise AND on the IP address and netmask and then a bitwise OR on the ip address and wildcard mask, we determine both boundaries as integers.
Our integer representation of 192.168.1.1 falls within the bounds but is not equal to our calculated boundaries so it is valid.
Let’s look at what this looks like in code. We can use a regex expression to identify if the passed input is even a valid IP address and if it is then group each part of the IP address into a match result. From there we can bitwise shift each octect to determine the integer representation of our IP address.
And if we run our test cases….
drew@Drews-MacBook-Pro[~/Desktop] ❯ node test.js --- Checking IP: 192.168.1.1/24 start: 3232235776 end : 3232236031 ip : 3232235777 result: true --- Checking IP: 192.168.1.4/30 start: 3232235780 end : 3232235783 ip : 3232235780 result: false
Checking Network Boundary Instead
In some cases the user input we want will actually be a network itself and not an IP. We can use the same the same exact logic but testing for our result case will be slightly modified. Before, we were checking to see if (lower < IP < upper) but to check to see if the provided input is a valid network we simply need to check that the integer value of the provided IP is the same as the result of the bitwise AND done on the IP and it’s netmask.
Now, if we run it again, the first value is no longer valid but the second example in our array is a valid network boundary.
drew@Drews-MacBook-Pro[~/Desktop] ❯ node test.js --- Checking IP: 192.168.1.1/24 start: 3232235776 end : 3232236031 ip : 3232235777 result: false --- Checking IP: 192.168.1.4/30 start: 3232235780 end : 3232235783 ip : 3232235780 result: true
And indeed our result set shows such is the case.
Some Notes on Regex and Integers
The regex match string is rather long in our example case, but it is needed for both accuracy and grouping. To read more about result grouping check out THIS link. We need our regex expression to capture the octet and netmask in a group so we can extract their values as elements in an array. We could have simply looked for a grouping of numbers seperated by a dot or slash, something like ^(\d+).(\d+).(\d+).(\d+)\/(\d+)$, and this would capture all 4 octets and our netmask. But this would also match 6126.96.36.199/35 and that’s clearly not a valid CIDR address.
Also, you may have noticed the »>0 in our example. This zero fill right shift will give us an unsigned integer so we aren’t dealing with negative values.