Once in a while (like today) I have to go back and do something in traditional ASP (Active Server Pages). That’s when I realize how nice .NET is, with typed data and all those framework methods. Something seemingly trivial, like figuring out if an IP address is part of a network, turns out to be quite difficult. The normal approach here would be to convert the IP address, network and subnet into integers, do a bitwise AND of the two items, and then compare the result. Unfortunately, the “AND” operator in ASP only works with integers and “Long” integers (up to 2^31 or 2,147,483,647), and the integer representation of 255.255.255.0 is 4,294,901,760. Uh oh. So, I came up with a double-precision AND function which splits the double value into “high” and “low” chunks (basically, the part below 2^31 and the part above), performs a bitwise AND on the chunks, and then shifts the bits back into place and reassembles a Double value from this. This should be viable for the bits left of the decimal up to about 4.6E+18. At the very least, it’s working for the IP address example.
function DoubleAnd (d1,d2) ' bitwise AND for values potentially greater than the Long limit (2147483647) dim d1low, d1high, d2low, d2high, lowand, highand d1high = fix(d1 / (2^31)) d1low = fix(d1 - d1high * (2^31)) d2high = fix(d2 / (2^31)) d2low = fix(d2 - d2high * (2^31)) lowand = d1low and d2low highand = d1high and d2high DoubleAnd = highand * (2^31) + lowand end function
It’s called like this:
if (DoubleAnd(ipint,subnetint)) = (DoubleAnd(networkint,subnetint)) then response.write ("IP is on network") else response.Write ("IP is NOT on network") end if
Note that I’m ANDing both the ip address and the network address. This shouldn’t technically be necessary, but it helps in cases where the user types in another IP address on the network instead of the network address (e.g. 192.168.1.1 instead of 192.168.1.0).
Here are the helper functions required for the conversions:
function IsValidIpAddress (IP) dim aGroups, i, j aGroups = split(IP,".") if ubound(aGroups) <> 3 then IsValidIpAddress = false exit function end if for i = 0 to ubound(aGroups) j = aGroups(i) if not isNumeric (j) then IsValidIpAddress = false exit function end if if j < 0 or j > 255 then IsValidIpAddress = false exit function end if next IsValidIpAddress = true end function function IntegerFromIPAddress (IP) if (IsValidIpAddress(IP)) then dim aGroups aGroups = split(IP,".") IntegerFromIPAddress = aGroups(3) + aGroups(2) * 256 + aGroups(1) * 256^2 + aGroups(0) * 256^3 exit function else IntegerFromIPAddress = -1 end if end function
Note, all these function assume IPv4. Yes, there’s a potential Y2K-style problem lurking here, but I just can’t deal with the absurdity of making a traditional ASP application IPv6-aware at the moment.