IPv6 addresses, like IPv4 addresses, internally are just strings of bits (128 of them in the case of IPv6). But humans are not good at working with long strings of bits, so we have “external data representation” for displaying IPv6 addresses in output for humans or accepting them as input from humans.

IPv6 uses “Coloned-Hex” notation for external data representation (like “Dotted-Decimal”, but with colons instead of dots, and hexadecimal instead of decimal), which breaks the 128 bits into *eight* groups of *sixteen* bits each. Compare to IPv4 which has *four* groups of *eight* bits each. Fortunately the creators of IPv6 gave people more credit than the creators of IPv4 did. They didn’t worry about people asking “why are there letters in my numbers?” The creators of IPv6 chose to represent each sixteen bit group with an up to 4 digit *hexadecimal* (base 16) number. Sixteen bits can hold binary values from 0000 0000 0000 0000 to 1111 1111 1111 1111. In hexadecimal this is from 0x0000 to 0xffff. Nobody cares what 0xffff is in decimal! (If you must know, it’s 65,535.) If you just ran the eight hexadecimal groups together with no separators, you would not be able to leave off leading zeros and the result would be a bit much for most people. Without separators, a typical IPv6 address would look like this:

20010470003d30000000000000000021

They added the “colon” as a separator between the eight sixteen-bit groups, which makes it much more readable, and also allows dropping leading zeros in each sixteen-bit group. With colons, and dropping the leading zeros, the above address looks like this:

2001:470:3d:3000:0:0:0:21

Already this is a big improvement in readability (not to mention easier to enter). However, many IPv6 addresses have a long run of fields that are all zero (like this one). There is one more optimization with IPv6 external data representation – you can replace up to one run of zero fields with two colons (::). In effect, everything before the “::” is *left* justified in the 128 bits, and everything after the “::” is *right* justified. The part in between is all zeros. You can’t replace two runs of zero fields in a single address, because that would be ambiguous. So, the final external data representation of our IPv6 address looks like this:

2001:470:3d:3000::21

This is now a major improvement over just 32 hex digits in a row.

**Mixed Mode IPv6 Address Text Representation**

There is one obscure option in IPv6 external data representation called “mixed mode”. The first 96 bits are conventional IPv6 notation, but the bottom 32 bits are conventional *IPv4 notation*! You actually specify four decimal groups (from 0 to 255) separated by dots, as usual, at the end of the IPv6 part. This is useful for IPv6 mapped IPv4 addresses (and not much else). You could represent one of those as *::ffff:192.168.1.100*. You can even specify a regular IPv6 unicast address using this notation. Say you wanted to have the address suffix contain the IPv4 address 192.168.1.100 in the low 32 bits. You could enter the string: *2001:470:3d:3000::192.168.1.100*. This is exactly equivalent to *2001:470:3d:3000::c0a8:164* using conventional IPv6 notation. Remember that the IPv4 fields are only eight bits each, so the four IPv4 fields make two IPv6 fields.

This notation is mostly for entering addresses that happen to have an IPv4 address in the low 32 bits. When you convert an IPv6 address to external format, there is no way to choose whether to use mixed mode or not. The standard C# conversion routine (.ToString()) for IPv6 addresses will try to use mixed mode if the top 32 bits of an interface identifier are zero (which sometimes results in odd looking output), or if it contains 0x0000ffff (in other words, it is a valid IPv6-mapped IPv4 address). It should really use mixed-mode format only for the second case, as the first case (“IPv6-*compatible* IPv4 addresses”) was deprecated.

**What If They Had Gone With “Dotted Decimal” for IPv6?**

Just for fun, if the creators of IPv6 had gone with “dotted decimal” , instead of “coloned hex” (using the same 8 fields of 16 bits), the address *2001:470:3d:3000::21* would instead look like: *8193.1136.61.12288.0.0.0.33*. If they had gone with 16 groups of 8 bits, it would have looked like: *32.1.71.0.0.61.48.0.0.0.0.0.0.0.0.33*. Now those are both *just plain ugly*. Aren’t you glad they went with hex?

**A Few Observations Regarding IPv6 External Data Representation**

- It’s OK for an IPv6 address to start with “::”, as in “::1” (the IPv6 loopback address)
- It’s OK for an IPv6 address to end with “::”, as in “2001:470:3d:3000::” – this just means all of the bits after the specified part are zeros. You could also have “2001:470:3d:3000:4:5::”.
- There is one IPv6 address that both starts and ends with “::”. In fact the entire number in IPv6 external data representation is just “::”. It is the
*unspecified address*which is 128 bits of zero. This is the extreme case of compression in IPv6 external data representation. - The six “extra” digits in hex (“a” through “f”) are not case sensitive – on output, usually lower case is used. On input, either is accepted.
- IPv6 prefixes are written in CIDR notation, e.g. 2001:470:3d:3000::/64.
- When used as an IP literal in a web browser URL, IPv4 can be entered as usual (
*http://123.45.67.89*), but IPv6 must have the address surrounded by square brackets (so the colons in the address won’t be confused with the colon used before a port number). For example,*http://[2001:db8:100:200::1]*.

**Converting Between Hexadecimal and Binary**

Every hex digit converts cleanly into exactly 4 bits and 4 bits convert cleanly into one hex digit. This is because *log base 2 of 16* is exactly 4 (2 to the 4th is 16). Here are the 16 hex digits and their binary equivalents:

To convert any hex number to binary, you just convert each hex digit into four bits using the above table. To convert any binary number to hex, convert every 4 bit group (starting at the right and working left) into one hex digit using the same table in reverse.

So, convert 0x52465dff to binary:

Hex: 5 2 4 6 5 d f f

Binary: 0101 0010 0100 0110 0101 1101 1111 1111

Or, convert 1111 1110 0110 1011 0111 1010 0101 0100 to hex:

Binary: 1111 1110 0110 1011 0111 1010 0101 0100

Hex: f e 6 b 7 a 5 4

You can only do a simple table based conversion like this between binary and numeric bases that are powers of two (base 4, base 8, base 16, etc). For every other base, you have to do it the hard way, based on place value notation. Too bad humans didn’t evolve with 16 fingers. Networking would have been so much simpler.

**Programmer Calculators**

In the early days of handheld calculators (yes, I’m that old) some of the nicer models had a “programmer mode” that allowed you to do numeric calculations in various bases (base 10, base 8, base 16 and even base 2). They would also convert between any two supported bases, such as decimal and hex. It had Boolean functions, like NOT, AND, OR, and XOR. These were in high demand by computer geeks. I actually bought a Sharp calculator recently, a Sharp EL-W506X, that includes these features. If you are going to do much network engineering (or programming) you may want to consider getting one of these. My first calculator (a TI SR-50) was $150 and had to be charged nightly. That was back when gold was $41 an ounce – so based on the current spot price of gold, that works out to $4,939 in 2013 dollars! My new Sharp actually has more features, and the battery lasts almost forever (it even runs on solar). Quite a deal for less than $15 (and that’s in 2013 dollars).

Well, guess what. You have one of those amazing devices and probably don’t even know it. The GUI calculator app that comes free with Windows has a “programmer mode” in addition to its basic and scientific modes. Just click *View* / *Programmer*. When you select “Hex” six new digit keys (A-F) activate. It even shows the binary for any value displayed in the accumulator. Note the operator keys (And, Not, Or, Xor, etc). If you are going to be working with IPv6 you should get to know your trusty old Windows calculator’s Programmer view. It’s really quite useful. Unfortunately it can only hold 64-bit values, so no full IPv6 addressees. That will hold an entire interface identifier, or an entire prefix (but not both). Maybe someday I will create an IPv6 calculator app. My NetConf app does a lot of the things one of those would do – it just doesn’t look like a calculator. I even had to create an 128-bit unsigned integer data type for C# to do math on IPv6 addresses. As good a deal as my Sharp calculator was, free beats even $15 (of course you have to have a computer running Windows to use either the calculator app or NetConf).