Did you know that “2130706433” is a valid IPv4 address, and pinging it from major OSes will yield a positive result? Let’s look into how it works.
Before we go any further, let’s try actually pinging it from my Linux laptop.
$ ping 2130706433 PING 2130706433 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.024 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms
Woah, it actually works. But why?
Let’s look into the man page for “inet_aton”, the standard library responsible for parsing human readable representations of IP addresses into binary:
a.b.c.d Each of the four numeric parts specifies a byte of the address; the bytes are assigned in left-to-right order to produce the binary address. a.b.c Parts a and b specify the first two bytes of the binary address. Part c is interpreted as a 16-bit value that defines the rightmost two bytes of the binary address. This notation is suitable for specifying (outmoded) Class B network addresses. a.b Part a specifies the first byte of the binary address. Part b is interpreted as a 24-bit value that defines the rightmost three bytes of the binary address. This notation is suitable for specifying (outmoded) Class C network addresses. a The value a is interpreted as a 32-bit value that is stored directly into the binary address without any byte rearrangement. In all of the above forms, components of the dotted address can be specified in decimal, octal (with a leading 0), or hexadecimal, with a leading 0X). Addresses in any of these forms are collectively termed IPV4 numbers-and-dots notation. The form that uses exactly four decimal numbers is referred to as IPv4 dotted-decimal notation (or sometimes: IPv4 dotted-quad notation).
In other words, there are several ways to represent IPv4 addresses, including using them in the decimal, octal and hexadecimal bases. Now, how can we leverage that to have fun?
Turns out it’s pretty easy. Let’s start by converting https://22.214.171.124, which is CloudFlare’s public DNS service into these fancy formats (your browser will automatically convert these links into the quad-octet dotted decimal format).
This one is pretty straightforward. Since the middle 2 octets are zeroes, we can just omit them.
Same as the previous example, but the octets are converted to their hexadecimal forms.
The bases can be combined across octets.
The whole IP address can be represented as a single number, without the dotted separators.
Same as the previous example, only in the octal base.
The previous example can be also represented in base 10.
Let’s do the same for a more complex address, like 192.168.0.1:
Many other combinations can be created.
Why should I care?
You might ask, what’s the purpose of writing addresses like this? Well for starters, it is important to take these forms of addresses into account while designing secure (and security) systems.
Imagine if you have a spam filtering system which looks for IP addresses in emails. Generally, you would look for a pattern like
[0-255].[0-255].[0-255].[0-255]. That sort of pattern would not match any of the aforementioned example combinations. Malicious actors would be easily able to circumvent this kind of filtering by using an address like “0300.0xa80001”.
Most importantly though, telling your networking minded friends that “IPv4+” is a real protocol and that it’s currently being deployed, while telling them to visit https://16777217 is a fun exercise.
Does this work on IPv6?
I was obviously curious if something like this is possible with IPv6 addresses as well.
Turns out that’s (un)fortunately not the case. The only sort of interesting addressing is possible using the IPv4-mapped IPv6 format:
$ ping 2001:4860:4860::0.0.136.136 PING 2001:4860:4860::0.0.136.136(2001:4860:4860::8888) 56 data bytes 64 bytes from 2001:4860:4860::8888: icmp_seq=1 ttl=57 time=8.44 ms