Storing IP addresses as integers
norbauer.com
norbauer.com
http://docs.python.org/library/socket.html#socket.inet_pton
Edit: Ooh, and Py3k has the ipaddr module:
I would think that integers would allow for better compatibility seeing as a numbers a number no matter what just expand that data type size of the column. The fact that ipv6 allows you to write the same address in multiple ways using the :: notion to denote a single span of zeros means there are a multitude of string representations of the same address.
inet_addr_t some_var = inet_aton("123.456.789.123");
The way you represent constants in code doesn't have to be a direct correlation with the way you store their representation.
I'm not super thrilled to debate the performance merits of optimizing 16-byte strings vs. 4-byte integers. I use whatever is most convenient. It's slightly easier to convert a charstar to a u_int32_t, but it's much easier to index a u_int32_t.
At any rate we are talking about two different things.
if you have the ipv6 address 1234:0000:5678:0000:0000:9212... you can write it a number of different ways, using the :: abbreviation for the various runs of zeros. ipv4 really doesn't have that pit fall in the string representation of its addresses.
So, if you store it as a string one way and then latter when you get input that has the same address written another way you are going to have problems if you don't normalize. Since we are talking about storing in a database, as the parent to this chain was you would likely want to normalize to the most compact representation to save space in your database. The precise type semantics of your language of choice are irrelevant.
http://www.postgresql.org/docs/8.4/static/datatype-net-types...
http://www.postgresql.org/docs/8.4/static/functions-net.html
You'll need a 128bit word for that. Plus some bignum math libraries for 32 machines that don't do 128 bits natively. (Do 64 bit machines handle 128 bits natively?)
Also watch out that you use an unsigned int. In PHP for example (and probably most other dynamic languages that don't do bignum as well) all ints are signed. So you'll have to work with the number as a string.
Plus, you can't do CIDR operations on strings, making it a pain to i.e. match all addresses within a given /27.
One thing that is really easy once the ip address (x) is in the integer space: private address determination becomes a simple integer comparison. e.g., 0.0.0.0 is simply x > 0, in the range 192.168.0.0 to 192.168.255.255 is written as: x >= 3232235520 && x <= 3232301055, etc.
ip.startswith('192.168.') or ip.startswith('10.')
No, it's not as fast, but are you really doing that many is_ip_private() calls?Personally I store a string until 128bit math becomes easier (so I can handle IPv6). But usually I just want to log it, not check netmasks.
if nothing else, storing ips in a sql database as integers will make searches on their indexes faster.
The difference between an integer and a fifteen byte string is eleven bytes. Our database has a few hundred-million row tables (barely considered big by today's standards) that store IPs. Storing IPs as integers saves us a GB per hundred million rows in addition to a substantial index size reduction.
Your application may not need to store that much data, but it's my experience that tables with IPs are the ones that tend to get big. :)
if(ip1 == ip2) is a lot faster as ints than strings.
I wouldn't populate an address trie with strings, but I also wouldn't give a second thought to passing them around a random C program as charstars either.
The point I guess is, you can keep 'em around as charstars, but eventually you'll have to do this cast to compare them...
I agree, int32 is faster. Like I said, it's just not "much" faster.
select count(*) from ipTable
where ip >= 167772160 and ip < 184549376
IP is four digits in a 256-base integer. You are looking for ips with the first digit 10. So, the value boundaries are: 167772160 = 256 * 256 * 256 * 10; 184549376 = 256 * 256 * 256 * 11. #include <stdio.h>
int
main (int argc,
char *argv[])
{
unsigned int ip = 3232235777u;
printf ("%d.%d.%d.%d\n",
(ip & 0xFF000000) >> 24,
(ip & 0x00FF0000) >> 16,
(ip & 0x0000FF00) >> 8,
(ip & 0x000000FF));
return 0;
}Converting "192.168.1.1" to an integer in Ruby involved creating multiple array, string, and integer objects, not to mention several multiply-indirected method calls.
int x = 5;
char *chp = (char*)&x;
printf("This value is endian-dependent: %hhd\n", *chp);If you're going to store IP addresses as 32 bit integers, or work with them that way in your C code, 192.168.1.1 should be "16885952", so you can do > and <.
But your point is well taken, and audiguy, I'm sorry for being such an asshole in my comment.