IPv6 Protocol

On this page

One device has a fe80:: address but cannot access the Internet; another has a global address but cannot resolve domain names. These two situations are not contradictory: addresses, next hops, DNS, and path packet sizes come from different mechanisms. Understanding IPv6 requires connecting these states item by item, rather than assuming that "automatic configuration success" means all network capabilities are ready simultaneously.

Question to InvestigateCore Criterion
How long is a packet exactly?40 B base header plus Payload Length; extension headers also count toward payload length
Where are the TCP/UDP headers?Parse along the Next Header chain; do not always assume offset 40
Why can't I access the Internet with an address?Check address status, routing, neighbors, DNS, and PMTU separately
Who fragments large packets?The source; intermediate routers respond with Packet Too Big
Must SLAAC use the MAC address?No; stable opaque IIDs and temporary addresses both have uses
Is IPv6 automatically secure?Evaluate address space, IPsec capabilities, and actual access control separately

Addresses: Distinguish Notation, Scope, and Interface

An IPv6 address is 128 bits, usually written as eight groups of hexadecimal digits. Leading zeros in each group can be omitted, and consecutive groups of all zeros can be compressed with a single ::; this can only appear once, otherwise it is impossible to determine how many groups were omitted at each location. For example, 2001:0db8:0001:0000:0000:0000:0000:000a and 2001:db8:1::a represent the same address.

Address/PrefixMeaningCannot Infer
::Unspecified address, can be used as the source address for specific initialization packetsCannot be used as a routable host address
::1Loopback addressCannot be forwarded to another device
fe80::/10Link-local unicast scopeCannot be accessed across routers; common address construction uses a 64-bit IID
ff00::/8Multicast, includes scope informationNot all multicast is limited to the current link
Global Unicast AddressProvides addresses for cross-link unicast communicationHaving an address does not guarantee route advertisement, firewall allowance, or service listening

IPv6 has no broadcast address; Neighbor Discovery and others use corresponding multicast groups. Anycast addresses are allocated from the unicast address space; the same address can provide services in multiple locations, with routing selecting one of them; "closest" refers to routing significance, not guaranteed geographical proximity. RFC 4291: Address Architecture

In fe80::1%eth0, %eth0 is the local identifier used to specify the scope interface, not part of the online 128-bit address. fe80::1 may exist on the links where both network interfaces reside, so providing just the address may not be sufficient. For standard Ethernet SLAAC, a /64 prefix works with a 64-bit IID; this does not mean the IPv6 routing table only allows /64; aggregated routes and host routes still have their respective lengths.

Base Header: The Entry is Fixed, Not the Total Header Length

FieldBitsReading Method
Version4Value is 6
Traffic Class8DSCP and ECN classification, congestion semantics
Flow Label20Assists in identifying flows along with source/destination, etc.
Payload Length16Number of bytes after the base header
Next Header8Next extension header or upper-layer protocol number
Hop Limit8Decrements with each routing forward; discarded when exhausted
Source / Destination128 eachSource address and destination address
Base header is fixed at 40 B; subsequent length is determined by the actual header chain IPv6 Base Header: 40 B Next Header = 0 Hop-by-Hop: 8 B Next Header = 17 UDP: 8 B + Data In this example, UDP data is 100 B Payload Length = 8 + 8 + 100 = 116 B Total IPv6 packet = 40 + 116 = 156 B Next Header indicates the type immediately following; Payload Length includes extension headers, but not the 40 B base header.

For ordinary non-jumbogram packets, the maximum Payload Length is 65535, and the entire packet adds another 40 B for the base header. Do not simply copy the meaning of IPv4 Total Length. Jumbograms have additional rules; do not treat a length field of zero universally as "any large packet" or as a bypass switch for parsers.

IPv6 has no base header checksum and no IHL; options are expressed via extension headers. TCP/UDP, etc., still have their own checksum rules, where the pseudo-header includes IPv6 address information, but checksums do not provide cryptographic authentication. Supporting IPsec does not mean every IPv6 packet is encrypted or authenticated. RFC 8200: Base Header and Upper-Layer Interface

What Can Flow Label Do?

Using a consistent non-zero label for the same flow at the source helps networks perform flow classification or load balancing without deeply reading transport ports; zero labels are still defined. The 20-bit space may collide; devices usually combine it with fields like source/destination, so do not use the label as a globally unique connection ID.

Labels do not automatically reserve bandwidth or increase priority; resource scheduling requires network policies. Application, kernel version, and configuration all affect label generation, so do not generalize a specific Linux default behavior into a protocol requirement. RFC 6437: Flow Label

Extension Headers: Must Decode by Type

Base Header Next Header=6 can directly follow TCP; if it is 0, it first enters Hop-by-Hop Options, then continues based on that header's Next Header. In the diagram above, UDP starts at byte 48; if a parser fixedly reads ports from byte 40, it will treat extension header fields as ports.

Header TypeNumberLength Parsing Key Points
Hop-by-Hop / Destination Options0 / 60Total length is (Hdr Ext Len+1)×8
Routing43General header contains length and routing type; specific content interpreted by type
Fragment44Fixed 8 B, no general Hdr Ext Len field
AH51Has its own Payload Len rules, in units of 4 B
ESP50Has independent encapsulation format; Next Header is located in its tail structure
No Next Header59No further protocol header follows

Therefore, you cannot execute the same "read second byte, multiply by eight, jump over" loop for all extension headers. Secure parsing also requires checking actual remaining length, allowed header chains, and resource limits; encountering uninterpretable encrypted payloads should not lead to guessing ports.

RFC 8200 provides recommended ordering; if Hop-by-Hop exists, it must immediately follow the base header. Different headers are processed at different nodes; ordinary forwarding nodes do not need to interpret every type of destination option. Extension header support affects actual path reachability; endpoints and intermediate devices should be verified separately, rather than just proving packet bytes conform to format. RFC 8200: Extension Headers

Why does UDP not always start at byte40?

Treat the chain as a type-driven cursor. The second Options byte encodes length, while Fragment cannot use that rule. Even the first fragment puts its header before UDP. Truncation distinguishes missing bytes from a reached next-protocol boundary.

Preparing the visual
Why does UDP not always start at byte40?

Next Header determines the length rule. Options and Fragment differ; guessing ports at a fixed offset can read the wrong object.

Fragmentation Example: No DF Bit, Only Source Fragmentation

When a forwarding exit cannot accommodate the current IPv6 packet, the router does not fragment IPv6; instead, it drops the packet and generates the corresponding ICMPv6 Packet Too Big (Type 2, Code 0). Simplifying this as "DF is always 1" misleads field parsing: IPv6 does not have a DF bit at all. The source adjusts send size via PMTUD and can generate a Fragment Header when needed. RFC 8201: IPv6 PMTUD

Below is an independent teaching example: original packet 3000 B, including 40 B base header and 2960 B fragmentable part, with no other extension headers; the source knows PMTU=1280. Each fragment additionally requires an 8 B fragment header, and the non-last fragment data capacity is floor((1280−40−8)/8)×8=1232 B.

Source fragmentation: 3000 B original packet, path MTU is 1280 B Original packet: 40 B base header + 2960 B fragmentable part This example has no other extension headers; each fragment adds an 8 B Fragment Header 1232 B Data offset=0, M=1 1232 B Data offset=154, M=1 496 B Data offset=308, M=0 Total packet 1280 B Total packet 1280 B Total packet 544 B Offset unit is 8 B; each fragment has a 40 B base header and an 8 B fragment header; routers do not complete this step for the source.
FragmentData RangeOffsetMPayload LengthTotal Packet Length
10~12310112401280
21232~2463154112401280
32464~29593080504544

The last fragment's 308×8+496=2960 gives the length of the original fragmentable part. Reassembly waits for all preceding ranges to arrive; do not look only at M=0; overlapping fragments result in the entire reassembly being discarded according to IPv6 rules. If other headers must be carried with each fragment, capacity needs to be deducted again; do not permanently apply 1232. The first fragment must contain the complete IPv6 header chain and upper-layer headers; do not arbitrarily split them to later fragments. RFC 8200: Fragmentation and Reassembly

1280 B is the minimum link MTU requirement for IPv6; smaller physical transmission units require adaptation at the lower link layer; it is not the actual maximum value for all paths. Filtering necessary ICMPv6 will break size feedback; TCP MSS cannot solve all packetization problems for UDP applications.

Automatic Configuration: Four Types of Information Established Separately

First, form a usable link-local address; the host can request RA via RS, or receive actively multicast RA from routers. The destination of RA is not always unicast. Below distinguishes the most easily confused information: RFC 4861: Router Discovery

InformationMain SourceLifespan or Condition
Default RouterRA Router Lifetime, etc.Zero lifetime does not mean all prefixes in RA are invalid
Prefix on LinkPIO L FlagJudge separately from whether an address is generated
SLAAC AddressPIO A Flag, suitable prefix, and local IIDConstrained by preferred/valid lifetime
DNS ServerRA RDNSS, DHCPv6, or static configurationNot automatically derived from "having an address"

For example, receiving a suitable PIO with A=1, L=0 allows the host to form an address, but you cannot assume all destinations on that prefix can directly perform neighbor resolution based solely on this PIO. The M flag indicates stateful address configuration, and O indicates other configuration; O does not specifically refer to DNS, and M does not mean "acquire DNS additionally." Whether to enable the corresponding client also depends on host implementation and administrative configuration.

Addresses usually start in the tentative state and can only be used according to corresponding rules after DAD. After the Preferred Lifetime expires, the address is deprecated; it is usually avoided for new communications, but still has usage significance before the Valid Lifetime expires; after the validity expires, it is no longer used as a valid address. This allows prefix updates to gradually migrate connections rather than immediately cutting off all old addresses. RFC 4862: SLAAC

The RDNSS option in RA can directly provide recursive DNS servers, so "SLAAC must run DHCPv6 to have DNS" is incorrect. Conversely, receiving only one address configuration result does not prove that default routing and DNS are both present. RFC 8106: RA DNS Options

What Stable Addresses and Temporary Addresses Solve

IIDs do not need to embed MAC addresses. Stable addresses benefit address persistence; temporary addresses reduce cross-time correlation through rotation. Temporary addresses have constraints such as preferred/valid lifetime and pre-generated alternative addresses; specific lifespans cannot be uniformly hardcoded to 24 hours, nor can it be assumed that all established connections immediately switch source addresses after rotation.

Actual source address selection is also affected by destination scope, address status, policy, and application binding. Temporary addresses do not hide application accounts, DNS queries, or other tracking signals, nor do they render inbound firewalls meaningless. RFC 8981: Temporary Addresses

IPv4 Coexistence: Encapsulation and Translation Change Different Things

MechanismData PathSuitable for Explaining
Dual StackHost and network provide both protocolsWhy a failure in one address family is masked by the other
DS-LiteB4 encapsulates IPv4 into IPv6; AFTR decapsulates and handles NAT44How the access network carries shared IPv4 exit over IPv6
NAT64 + DNS64Synthesizes corresponding AAAA; IPv6 traffic converts to IPv4 at the translatorHow IPv6 clients access IPv4-only services
464XLATCLAT performs stateless translation; PLAT performs stateful NAT64How IPv4 applications traverse IPv6 access networks

DS-Lite preserves IPv4 semantics inside the tunnel; NAT64 changes the network layer address family; the two are not the same kind of "wrapping an IPv6 header." For NAT64, DNS64 helps access by name, but when applications hardcode IPv4 literals, they do not go through this AAAA synthesis; 464XLAT can provide bridging for corresponding IPv4 applications. DS-Lite RFC 6333, NAT64 RFC 6146, 464XLAT RFC 6877

Dual-stack applications can use Happy Eyeballs to arrange candidate connections, reducing wait times caused by the failure of one address family; it involves resolution, sorting, and delayed startup competition, not all requests sending both families completely simultaneously. Successful fallback may mask IPv6 failures; diagnosis still requires looking at the paths and connection results of both families separately. RFC 8305

Local Recalculation: Length, Fields, and Data Ranges

import struct
from ipaddress import IPv6Address

src = IPv6Address('2001:db8:1::a')
dst = IPv6Address('2001:db8:2::b')
assert src.exploded == '2001:0db8:0001:0000:0000:0000:0000:000a'
traffic_class, flow_label = 0xBA, 0x12345
word = (6<<28) | (traffic_class<<20) | flow_label
header = struct.pack('!IHBB16s16s', word, 116, 0, 64, src.packed, dst.packed)
assert len(header) == 40
assert word>>28 == 6 and (word>>20)&255 == 0xBA
assert word&0xfffff == flow_label
assert 40 + struct.unpack('!H', header[4:6])[0] == 156

payload = bytes(i%251 for i in range(2960))
capacity = ((1280-40-8)//8)*8
pieces = []
for start in range(0,len(payload),capacity):
    data = payload[start:start+capacity]
    more = int(start+len(data)<len(payload))
    offset = start//8
    frag_header = struct.pack('!BBHI', 17, 0, (offset<<3)|more, 123456)
    assert len(frag_header) == 8
    pieces.append((offset,more,8+len(data),48+len(data),data))
assert [x[:4] for x in pieces] == [(0,1,1240,1280),(154,1,1240,1280),(308,0,504,544)]
assert b''.join(x[4] for x in pieces) == payload
assert pieces[-1][0]*8 + len(pieces[-1][4]) == 2960
print('IPv6 fields, length, fragmentation offset, and range checks passed')

The example verifies local encoding and calculation relationships; random payload is not a complete UDP packet; no data is sent to the network or interface configuration modified.

Continue Reading