What changes in a service's own code and stored data when it starts accepting clients over IPv6?
answer
- fields sized for four bytes
- host and port with colons
- one client, many addresses
- which family outbound calls pick
basics
~20 sAddress handling: 16-byte addresses and longer text forms, bracketed literals before a port, and binary rather than string comparison. Client identity: no NAT, but rotating temporary addresses, so limits key on prefixes. Outbound calls may switch to IPv6 by default.
solid answer
~50 sFirst, storage and parsing: an IPv6 address is 16 bytes, its text form runs to 39 characters or 45 with an embedded IPv4 tail, and the same address has several valid spellings, so store it binary or canonicalise it per RFC 5952 before comparing. Literals next to a port need brackets, `[2001:db8::1]:443`, so splitting on the last colon breaks. Second, client identity changes: there is no NAT pooling many users behind one address, but hosts hold several addresses and rotate temporary ones (RFC 8981), which RFC 6724 prefers for outgoing connections, so per-address rate limits, allowlists and session binding should key on a prefix, at least the /64. Third, the service's own outbound calls: RFC 6724's default policy prefers IPv6 destinations, so dependencies with AAAA records start seeing the service's IPv6 source address, and their allowlists must include it.
go deeper
Recall the practical changes: 16-byte addresses, longer text, brackets around literals with ports, and comparing parsed values instead of strings.
Explain why client identity shifts: no shared NAT address, several addresses per host, rotating temporary addresses preferred for outgoing traffic.
Show the production consequences: prefix-based rate limits, broken allowlists and sessions, and outbound calls silently switching family under RFC 6724 defaults.
Weigh how coarse client aggregation should be against collateral blocking, and how to roll address-handling changes across services before enabling IPv6.
## Why this question matters Turning on IPv6 for a service is rarely just a listener change. Code written for IPv4 quietly assumes that an address fits in four bytes, has one spelling, and identifies roughly one customer site. Each assumption breaks in a different way. ## 1. Storing and parsing addresses - **Size.** An IPv6 address is **128 bits (16 bytes)**. Database columns, cache keys and log fields sized for a 32-bit integer or a 15-character dotted quad truncate or reject it. - **Text length.** The full form is eight groups of four hex digits plus seven colons: **39 characters**. A form with an embedded dotted-quad tail, such as an IPv4-mapped address in `::ffff:0:0/96`, can reach **45** (six groups and six colons, then up to 15 characters of dotted quad). - **Many spellings.** `2001:db8:0:0:1:0:0:1` and `2001:db8::1:0:0:1` are the same address. RFC 5952 defines a **canonical text form** (lowercase, leading zeros dropped, `::` for the longest zero run), and its security section warns that comparing addresses as text is a risk if used for access control. Parse to a 16-byte value, or canonicalise, before comparing. - **Ports.** RFC 5952 section 6 lists ambiguous ways to write an address with a port; `2001:db8::1:80` is the worst, because it is also a valid address. The bracket form `[2001:db8::1]:80` SHOULD be used and is mandatory inside URIs. Code that splits "host:port" on the last colon breaks. - **Validation and parsing code** that matches dotted quads with a pattern rejects every IPv6 client. ## 2. Who a client is IPv4 servers often see a NAT's shared address, so one address may stand for thousands of users. IPv6 changes the picture in two directions: | Assumption from IPv4 | IPv6 reality | |---|---| | Many users share one address | Each host normally has its own global address | | A client keeps one address for a while | Hosts rotate **temporary addresses** (RFC 8981) | | One address per host | An interface holds several addresses at once | | Blocking one address blocks one site | One site holds a whole prefix of addresses | RFC 8981 (which obsoletes RFC 4941) generates temporary interface identifiers with default lifetimes of one day preferred and two days valid, and RFC 6724's **Rule 7** prefers temporary addresses as the source of outgoing connections. Consequences: - **Rate limits and blocklists** keyed on the full /128 are trivial to evade: a host can use any address in its prefix. Aggregate at least by the **/64**, since RFC 4291 makes interface identifiers 64 bits for most unicast addresses, and treat that as an operational choice, because one subscriber may hold a much larger prefix. - **Allowlists** keyed on a single client address break when the address rotates. - **Session binding** to the client address logs users out when their temporary address changes. ## 3. The service's own outbound calls RFC 6724's default policy table gives native IPv6 destinations (`::/0`, precedence 40) priority over IPv4 ones (represented as `::ffff:0:0/96`, precedence 35). All else being equal (earlier rules cover unusable and mismatched-scope addresses), once the host has a global IPv6 address and a dependency publishes an **AAAA** record, the call typically goes over IPv6. That changes the **source address** the dependency sees, so partner allowlists, database access rules and egress filters need IPv6 entries. Running both families side by side and racing connection attempts is a transition topic in its own right; for the application the point is that the family can change without a code change. ## 4. What stays the same - TCP and UDP semantics, ports and the application protocol do not change. - DNS still resolves names; AAAA records simply return IPv6 addresses. - A service that only ever passes opaque address values through, without parsing, comparing or storing them, often needs nothing. ## A short checklist 1. Store addresses as 16-byte values or in a family-aware type; size text fields for 45 characters. 2. Compare parsed values, never raw strings. 3. Format literals with brackets wherever a port or URI follows. 4. Re-key rate limits, abuse controls and allowlists on prefixes. 5. Inventory outbound dependencies whose allowlists list only IPv4 sources.
- Should a service key its abuse rate limits on the full 128-bit client address?No. A host can source traffic from any address in its prefix, and RFC 8981 temporary addresses rotate on their own, so a per-/128 limit is easy to evade and resets for honest users. Key at least on the /64, the usual size of one link's prefix, and accept that one subscriber may hold a larger prefix, so heavier controls may aggregate further.
- How should an IPv6 address be written next to a port number?In brackets: `[2001:db8::1]:443`. RFC 5952 section 6 marks the unbracketed `2001:db8::1:443` as ambiguous, because it is also a valid address, recommends the bracket style by default, and requires it inside URIs. Parsers should split on the closing bracket, not on the last colon.
saying these in an interview costs you the question
- A 15-character text column is enough to store any client address.
- Two IPv6 strings that differ are always two different addresses.
- Each IPv6 client keeps one stable address, so per-address limits suffice.
- Writing 2001:db8::1:443 is a clear way to add a port.
- A service's outbound calls keep using IPv4 until the code changes.