Real-Time Web Log

Content-free

Storing and retrieving IPv4 and IPv6 addresses

I manage a network, and with IPv6 being something of a hobby of mine (as well as pretty relevant), our latest effort into upgrading our network management software means, at least in part, address-family agnosticism. In other words, I will want to treat IPv4 and IPv6 addresses exactly the same in as many places as possible.

One problem for those storing such addresses in a database is that of lack of native support for an “IP address” datatype in most relational databases (one notable exception being PostgreSQL) means we need to think a little harder about how to store both IPv4 and IPv6 addresses alongside one another. Additionally, because many of us are probably storing IP addresses as 32-bit integers, how can we make this “upgrade” as seamless as possible?

I came across a couple Stack Overflow answers which I combined into my solution.

I store an IP address as 4 columns, where each column is an unsigned 32-bit integer. I’ll name my example columns like this:

ip_uint32_4 | ip_uint32_3 | ip_uint32_2 | ip_uint32_1

I put them in that order because I’m storing the “high order integer” in the leftmost column. If, for whatever reason, the address size expands again, I can start with 5, 6, … but the naming isn’t too important, so don’t get too hung up on it :)

IPv4 addresses

As was cleverly pointed out in one of the Stack Overflow answer comments, a nice and compliant (see RFC 4291 ยง2.2 number 3) way of designating an IPv4 address in a mixed environment is to set what in my case is the ip_uint32_2 integer to 0x0000FFFF, and ip_uint32_1 to the 32-bit unsigned integer representation of the IPv4 address. ip_uint32_4 and ip_uint32_3 are set to 0.

With the above columns, the IPv4 address 192.0.2.1 looks like:

ip_uint32_4 | ip_uint32_3 | ip_uint32_2 | ip_uint32_1
0           | 0           | 65535       | 3221225985

If you’re having trouble understanding why this is necessary (why not just set the 3 highest-order integers to 0?), think about storing the IPv6 loopback address ::1. Without such a defined scheme, how might you differentiate this from 0.0.0.1 in a mixed environment?

Additionally, you can be sure that no valid IPv6 address will conflict with this, as 0000::/8 is reserved by the IETF for these and other purposes.

One more thing: if you’re migrating from an environment where you currently store an IPv4 address as an unsigned 32-bit integer, this should provide a quite natural upgrade path for you.

IPv6 addresses

Pretty straightforward. Encode the address as 4 32-bit unsigned integers, “high-order-integers” first (ip_uint32_4, ip_uint32_3, …).

Example!

Love it or hate it, I use PHP at work, so naturally I wrote a PHP class to help me deal with this. All of my applications strictly use such an IP address object which handles the above scheme (including presentation, and (un)marshalling from/to a database). I tried to keep it simple, and made good use of inet_pton. Let me know what you think :)

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.