'IP-addresses stored as int results in overflow?
I'm writing a chat-server in node.js, and I want to store connected users IP-addresses in a mysql database as (unsigned) integers. I have written a javascript method to convert an ip-address as string to an integer. I get some strange results however.
Here is my code:
function ipToInt(ip) {
var parts = ip.split(".");
var res = 0;
res += parseInt(parts[0], 10) << 24;
res += parseInt(parts[1], 10) << 16;
res += parseInt(parts[2], 10) << 8;
res += parseInt(parts[3], 10);
return res;
}
When I run call the method as ipToInt("192.168.2.44"); the result I get is -1062731220.
It seems like an overflow has occurred, which is strange, because the expected output (3232236076) is inside the number range in javascript (2^52).
When I inspect -1062731220 in binary form, I can see the 3232236076 is preserved, but filled with leading 1's.
I'm not sure, but I think the problem is with signed vs. unsigned integers.
Can any of you explain what is going on?
And possibly how to parse -1062731220 back to an string ip?
Solution 1:[1]
The result of the "<<" operator is always a signed, 32-bit integer, as per the spec.
When you shift back, use ">>>" to do an unsigned right shift.
Solution 2:[2]
You might also find this pattern useful:
ip.toLong = function toInt(ip){
var ipl=0;
ip.split('.').forEach(function( octet ) {
ipl<<=8;
ipl+=parseInt(octet);
});
return(ipl >>>0);
};
ip.fromLong = function fromInt(ipl){
return ( (ipl>>>24) +'.' +
(ipl>>16 & 255) +'.' +
(ipl>>8 & 255) +'.' +
(ipl & 255) );
};
If you're using something like node.js where you can add functionality through something like Npm then you can simply do:
npm install ip
To get that functionality from the source which is here:
https://github.com/indutny/node-ip/blob/master/lib/ip.js
You will also get a bunch of other IP utility functions with that.
Solution 3:[3]
You shifted left to get the original number - which is just 4 sets of bits regardless of the sign.
Shift right to get back to the IP. Doesn't matter what the sign is.
Solution 4:[4]
const ip2int = (x) => (x.split('.').reduce((a, v) => ((a << 8) + (+v)), 0) >>> 0);
Solution 5:[5]
One-Liner:
const ipToLong = ip => ip.split('.').map(parseFloat).reduce((total, part) => total * 256 + part);
Solution 6:[6]
Use this
function num2string(ip) {
return [24,16,8,0].map(n => (ip >> n) & 0xff).join(".")
}
function string2num(ip) {
return ip.split(".").reduce((sum,x,i) => sum + (x << 8*(3-i)), 0)
}
Solution 7:[7]
IP Addresses in the V4 space are unsigned 32 bit numbers, hence the IP address of FF.FF.FF.FF is 2^32 and cannot be greater then that number. Please see:
This stack overflow article on the same subject
To turn that number back into an IP address you must break the number down into its 4 parts since each byte is one octet of the address so convert the number to hex and then parse out each pair. You may or may not have to add a leading zero for the first octet.
Additionally you may have to deal with byte order of the integer ( endien issues ) but since most systems are intel based these days you might not have to deal with that.
Solution 8:[8]
var aaa = Number("0b"+ "192.168.2.44".split(".").map(
function(dec){
return ("00000000" + Number(dec).toString(2)).slice(-8);
}).join(""));
aaa.toString(2).match(/.{1,8}/g).map(
function(bin){
return Number("0b"+bin);
}).join(".");
Solution 9:[9]
I revised Evan's final answer a bit, particularly dot2num. It functions the same but might be more readable and is marginally slower.
function ip2num(ip) {
var parts = ip.split('.');
var num = 0;
num += d[0] * Math.pow(2, 24);
num += d[1] * Math.pow(2, 16);
num += d[2] * Math.pow(2, 8);
num += d[3];
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i=3; i > 0; i--) {
num = Math.floor(num / 256);
ip = num % 256 + '.' + ip;
}
return ip;
}
Solution 10:[10]
Try this solution, it might help:
function IpToInteger(ipAddr)
{
var parts = ipAddr.split('.');
return (((parts[0] ? parts[0] << 24 : 0) |
(parts[1] ? parts[1] << 16 : 0) |
(parts[2] ? parts[2] << 8 : 0) |
(parts[3])) >>> 0);
}
Solution 11:[11]
function IpAddressToLong(ip){
return ip.split('.').map((octet, index, array) => {
return parseInt(octet) * Math.pow(256, (array.length - index - 1));
}).reduce((prev, curr) => {
return prev + curr;
});
}
Taken from repo
Solution 12:[12]
function ip2num(ip) {
var d = ip.split(".");
var num = 0;
num += Number(d[0]) * Math.pow(256, 3);
num += Number(d[1]) * Math.pow(256, 2);
num += Number(d[2]) * Math.pow(256, 1);
num += Number(d[3]);
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i = 3; i > 0; i--) {
num = Math.floor(num / 256);
ip = (num % 256) + "." + ip;
}
return ip;
}
console.log(ip2num("192.168.0.1"));
console.log(num2ip(3232235521))
<h1>YOU IS WELCOME</h1>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
