Skip to content

Instantly share code, notes, and snippets.

@mailinglists35
Last active October 18, 2017 09:10
Show Gist options
  • Save mailinglists35/7b0280165438f43f93cabf8d6dc1f4c7 to your computer and use it in GitHub Desktop.
Save mailinglists35/7b0280165438f43f93cabf8d6dc1f4c7 to your computer and use it in GitHub Desktop.
inet_aton
https://stuff-things.net/2014/09/25/magic-ip-address-shortcuts/
Stuff… And Things…
Blog
Archives
Strongbox
Spike
Search
SEP 25TH, 2014 2:49 PM | COMMENTS
Magic IP Address Shortcuts
TL;DR
In most cases, if you enter 0 for an IP address it will expand to 0.0.0.0. Likewise, 127.1 will expand to 127.0.0.1. Why? Magic.
Not Magic
But really, why do these shortcuts exist and how do they work? It can’t be as simple as adding zeros, if it was 127.1 would more logically expand to 127.1.0.0.
Turns out it’s a historic quirk in the inet_aton() function which is used, directly or indirectly, by most software to parse IP addresses in dotted-quad format into integers.
The familiar dotted-quad notation (AKA “dot-decimal notation”) is purely a human readable convenience. Each quad represents an octet, an 8 bit number. The four octets can then be combined into a 32 bit number which is the actual IP address.
Under the hood, integer IP addresses are always used. They are space efficient and reduce calculating networks from netmasks to applying a bitmask. If you’ve every entered a subnet mask in hex form (0xffffff00), you might have a sense of this.
The Math
To convert a dotted-quad into an integer, we need to put each octet in to the correct position in the integer. The first octet needs to go in bits 25 through 32, the second in 17 through 24 and so on. This is done with the Left Bitwise Shift Operator << in most languages.
Let’s take Google well known 8.8.8.8 DNS server address:
1
(8<<24) + (8<<16) + (8<<8) + 8 => 134744072
134744072 looks like nothing and yet:
1
2
% PING 134744072 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=50 time=18.016 ms
It’s not that simple
The conversion explains why 0 works, the integer version of 0.0.0.0 is 0:
1
(0<<24) + (0<<16) + (0<<8) + 0 => 0
But what about 127.1? How does it know where to put the zeros?
Turns out inet_aton() treats addresses differently depending on the how many dot separated numbers there are.
As we have seen, one number is the full integer IP address.
If there are two numbers, as in 127.1, the first number is the first octet and the second is a integer that fills in the remaining 24 bits. In the case of 127.1 it’s:
1
(127<<24) + 1 => 2130706433
Which is the same as:
1
(127<<24) + (0<<16) + (0<<8) + 1 => 2130706433
(And aren’t you glad you aren’t typing 2130706433 to get to localhost?)
A variation of this logic is applied in the case were three numbers are provided, the first two are octets and the third is the remaining 16 bits. Google’s 8.8.8.8 can be written as 8.8.2056
1
2
(8<<8) + 8 => 2056
(8<<24) + (8<<16) + 2056 => 134744072
Why does this exist?
Why on Earth would inet_aton() take such on construction? It’s not actually clear from the documentation, but I have a theory.
First consider that an IP address has two parts, the network and the host. In the dotted-quad format, given 192.168.0.1, the first three octets are the network, “192.168.0” and the last the host, “1”.
At the time inet_aton() was written, it was very common to receive Class B (/16) network allocations. Given the Class B network 10.10.0.0/16, your first 255 addresses would be 10.10.0.1 to 10.10.0.255 (.0.255 is not a broadcast address) with the 256th host being 10.10.1.0 (.1.0 is not a network address). However, if you used a dotted-triplet you could start at 10.10.1, continue through 10.10.256 all the way up to 10.10.65534. As with the dotted-quad, the last octet is the host and the rest is the network.
I don’t think this form was ever common and stopped making sense when subnetting became the norm. Yet, it exists and, if nothing else, can save you a little typing.
Added Bonus!
Here’s a C program to explore the various notations. Most modern languages provide inet_aton() either direct or indirectly, as in Ruby’s IPAddr#to_i. Still, there is something right about doing this in C.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char **argv) {
struct in_addr pin;
if (argc != 2) {
printf("%d\n",argc);
fprintf(stderr,"Usage: inet_aton dotted-quad\n");
exit(1);
}
int valid = inet_aton(argv[1],&pin);
if (!valid) {
fprintf(stderr,"inet_aton could not parse \"%s\"\n",argv[1]);
exit(1);
}
/* pin.s_addr is in network by order, convert to host byte order */
unsigned int address = ntohl(pin.s_addr);
unsigned int octet1 = (0xff000000 & address)>>24;
unsigned int octet2 = (0x00ff0000 & address)>>16;
unsigned int octet3 = (0x0000ff00 & address)>>8;
unsigned int octet4 = 0x000000ff & address;
printf("ping %u.%u.%u.%u\n",octet1,octet2,octet3,octet4);
printf("ping %u.%u.%u\n",octet1,octet2,(octet3<<8) + octet4);
printf("ping %u.%u\n",octet1,(octet2<<16) + (octet3<<8) + octet4);
printf("ping %u\n",address);
}
To use:
1
2
cc -o inet_aton inet_aton.c
./inet_aton 8.8.8.8
Now you can amaze and confuse your friends with inscrutable integer IP addresses.
Posted by Spike Sep 25th, 2014 2:49 pm curiosities, tips
Privacy Badger has replaced this Twitter button. Privacy Badger has replaced this FacebookLike button.
« Cross-Domain AJAX Request in Development Laziness: Remote SSH Usernames »
Comments
Recent Posts
Building Emacs 25 on macOS Sierra 2017 Update
How I Start Rails Projects V2
Sleepless Mac
Creating an S3 Website Redirect From the CLI
JWT Based “Sessions”
About Me
Founder and CTO of Indra
Developer
Hacker
Maker
GitHub Repos
Status updating…
@spikex on GitHub
Tweets
App Managment
Server Managment
Co-Location
Connectivity
Copyright © 2017 - Spike - - Privacy Policy
Powered by Octopress, customized with octostrap3.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment