How is a 128-bit IPv6 address written as text, and what rules govern compressing it with :: in RFC 5952 canonical form?
answer
- eight sixteen-bit groups
- leading zeros go, trailing stay
- one double colon only
- longest zero run, first on a tie
- never for a lone zero group
basics
~20 sAn IPv6 address is eight 16-bit hex groups separated by colons. RFC 5952 canonical form drops leading zeros, uses lowercase, and writes :: once, for the longest run of two or more zero groups, the first run on a tie.
solid answer
~40 sAn IPv6 address is 128 bits, written as eight 16-bit groups of one to four hex digits separated by colons. RFC 4291 lets you drop leading zeros inside a group and replace one run of all-zero groups with `::`, which may appear only once, because a parser could not otherwise tell how many groups each `::` hides. RFC 5952 then fixes one canonical output: lowercase, leading zeros always dropped, a zero group written `0`, `::` used to the maximum on the longest run of zero groups (the first if two runs tie), and never to shorten a single zero group. So `2001:0DB8:0000:0000:0001:0000:0000:0001` becomes `2001:db8::1:0:0:1`. Parsers must still accept every legal RFC 4291 form; the canonical rules govern what software writes.
go deeper
Know the shape: eight 16-bit hex groups, leading zeros dropped, :: once for a run of zero groups. Expand and compress a couple of addresses by hand until it is automatic.
Explain why :: may appear only once and apply all of RFC 5952's tie-breaks: longest run wins, first on a tie, never a single group, lowercase output.
Separate what parsers must accept from what software should emit, and push teams to store and compare addresses as 128-bit values rather than strings in logs and inventories.
Treat canonical form as a data-quality standard: inventory, logging and audit tooling across teams should emit RFC 5952 text so that searches, diffs and joins across systems agree.
## The 128 bits and the eight groups An **IPv6 address** is a 128-bit number. Written in full it is eight **groups** (RFC 4291 calls them 16-bit pieces) of four hexadecimal digits, separated by colons: `2001:0db8:0000:0000:0001:0000:0000:0001` Each hex digit is 4 bits, so each group is 16 bits and eight groups make 128. The text form exists for people, logs and configuration files: inside the packet header the address is always the full 128 bits, so compressing the text never changes what goes on the wire. ## What RFC 4291 allows RFC 4291 (the IPv6 addressing architecture) defines the legal text forms: - **Leading zeros** inside a group may be dropped: `0db8` can be written `db8`, `0001` can be written `1`. **Trailing** zeros may not: `cd30` is not `cd3`. - Every group must keep at least one digit, except where `::` stands in. - **`::`** means "one or more groups of zeros". It can compress leading zeros (`::1`), trailing zeros (`2001:db8::`) or a run in the middle. - `::` may appear **only once**. With two of them, as in `2001:db8::1::2`, the reader knows six groups are missing in total but not how they split, so the address is ambiguous and invalid. - Hex digits may be upper or lower case; RFC 4291 states no preference. That flexibility means one address has many legal spellings. RFC 5952 (2010) lists the damage: searches in spreadsheets and logs miss matches, configuration diffs show changes where none happened, and audit scripts need their own parsers. ## What RFC 5952 makes canonical RFC 5952 recommends one output form. Software SHOULD generate it, and every implementation MUST still accept any legal RFC 4291 form as input. | Rule (RFC 5952 section) | Correct | Not canonical | |---|---|---| | Leading zeros MUST be suppressed (4.1) | `2001:db8::1` | `2001:0db8::0001` | | A zero group is written `0` (4.1) | `2001:db8:0:1:1:1:1:1` | `2001:db8:0000:1:1:1:1:1` | | `::` is used to its maximum (4.2.1) | `2001:db8::2:1` | `2001:db8::0:2:1` | | `::` MUST NOT shorten a single zero group (4.2.2) | `2001:db8:0:1:1:1:1:1` | `2001:db8::1:1:1:1:1` | | The longest zero run gets `::` (4.2.3) | `2001:db8:0:1::1` | `2001:db8::1:0:0:0:1` | | On a tie, the first run gets `::` (4.2.3) | `2001:db8::1:0:0:1` | `2001:db8:0:0:1::1` | | Hex letters are lowercase (4.3) | `2001:db8::c0de` | `2001:DB8::C0DE` | Note the difference between "not canonical" and "invalid". `2001:db8::1:1:1:1:1` is a perfectly legal RFC 4291 address (the `::` hides one group); RFC 5952 only says a program must not print it that way. ## Worked compressions 1. `2001:0db8:0000:0000:0000:0000:0002:0001`: drop leading zeros, then one run of four zero groups becomes `::`, giving `2001:db8::2:1`. 2. `2001:0db8:0000:0001:0000:0000:0000:0001`: two zero runs, of one and three groups. The run of three wins, and the lone zero stays as `0`: `2001:db8:0:1::1`. 3. `2001:0db8:0000:0000:0001:0000:0000:0001`: two runs of two tie, so the first is compressed: `2001:db8::1:0:0:1`. 4. Expanding `2001:db8::8:800:200c:417a`: six groups are written, so `::` stands for two, giving `2001:0db8:0000:0000:0008:0800:200c:417a`. 5. The all-zero address is `::` (the unspecified address) and `0:0:0:0:0:0:0:1` is `::1` (loopback). A reliable method for expanding: count the written groups, subtract from eight, insert that many `0000` groups where `::` sits, then left-pad every group to four digits. ## Mixed notation, prefixes and ports - Addresses that embed an IPv4 address in their low 32 bits may end in dotted decimal. RFC 5952 section 5 recommends this for well-known embedding prefixes, with the leading hex part still canonical: `::ffff:192.0.2.1`, not `0:0:0:0:0:ffff:192.0.2.1`. - A **prefix** is written `address/prefix-length`, and the address part may use any legal form. The compression rules still bite: `2001:db8::cd30/60` puts `cd30` in the last group, not the fourth. - With a port number, RFC 5952 section 6 says the bracket style from URIs SHOULD be used: `[2001:db8::1]:443`. The form `2001:db8::1:443` is NOT RECOMMENDED, because the port reads as the last group. ## Why it matters in practice Treat addresses as 128-bit values and compare them as values. Canonical form is for what software writes: - **Logs**: one spelling per address means a plain text search finds every line about it. - **Configuration and inventories**: diffs show only real changes, not someone's preferred padding. - **Audits and joins across systems**: two tools that both emit RFC 5952 text agree without a custom parser. It is not a substitute for parsing what a user or a peer typed: input can arrive in any legal RFC 4291 form, and a program that compares raw strings will treat `2001:db8::1` and `2001:DB8:0:0:0:0:0:1` as different hosts.
- Is 2001:db8::1:1:1:1:1 a valid IPv6 address, given that RFC 5952 forbids :: for a single zero group?Yes. RFC 4291 defines `::` as one or more zero groups, so it parses to `2001:db8:0:1:1:1:1:1`. RFC 5952 governs output: software should not generate that spelling, but it MUST accept any legal RFC 4291 form as input. Rejecting it would be a parser bug.
- How do you write an IPv6 address together with a transport port number?Put the address in square brackets, as in `[2001:db8::1]:443`; RFC 5952 section 6 says this URI style SHOULD be used. Without brackets, `2001:db8::1:443` is ambiguous, because `443` reads as a final hex group and the `::` expands differently.
- Does compressing an address with :: make IPv6 packets smaller?No. The source and destination fields in the IPv6 header are always 128 bits each. `::` and dropped leading zeros exist only in the text form that people and configuration files use; the binary address is identical however it is spelled.
saying these in an interview costs you the question
- You can use :: twice if each zero run is short enough.
- Trailing zeros in a group can be dropped just like leading zeros.
- Canonical form compresses the first zero run even when a later run is longer.
- A single zero group should become :: to save characters.
- An address written in uppercase hex is invalid and must be rejected.