NET-110 · Lesson 6 of 12 · 28 min
IPv6
▶ Video coming soon A video version of this lesson is on the way.
When Sam logs into the firewall-router to look at Ridgeline's connection, the status page shows two addresses for the provider link: the familiar 203.0.113.42, and a much longer one beginning 2001:db8:5a00 with colons instead of dots. The provider has been offering IPv6 for over a year, and half of the phones that join the guest Wi-Fi already prefer it. Nobody at Ridgeline turned it on deliberately; the firewall's default settings did. Sam realizes that a network plan which ignores IPv6 describes only part of the network.
This lesson explains why IPv6 exists, how its 128-bit addresses are written and shortened, how they are divided into a routing prefix, a subnet and an interface identifier, the main address types, how devices configure their own addresses automatically, how IPv6 handles the jobs that ARP and broadcast do in IPv4, and how the two versions run side by side during the long transition.
Why IPv6?
IPv4's 32-bit address space holds about 4.3 billion addresses, fewer than one per person alive today, and far fewer than the number of phones, laptops, servers, cars, cameras and sensors that want to be online. The regional registries that hand out addresses ran out of new IPv4 blocks between 2011 and 2019. The internet has survived the shortage largely through network address translation, which lets a whole office or home share one public address, and through carrier-grade NAT inside providers' networks. Translation works, but it breaks the original design of the internet, in which any host could reach any other directly, and it adds cost and complexity to providers and applications alike.
IPv6, standardized in the late 1990s and updated since, uses 128-bit addresses: about 3.4 times 10 to the power 38 of them, enough to give every device its own globally unique address with plenty to spare. IPv6 also simplifies the packet header, drops broadcast in favour of multicast, builds automatic address configuration into the protocol, and removes fragmentation by routers. Adoption has grown steadily: large mobile networks, major content providers and many residential providers run IPv6 by default, and well over a third of the traffic reaching large websites now arrives over it.
Writing IPv6 addresses
An IPv6 address is written as eight groups of four hexadecimal digits separated by colons, each group representing 16 bits: 2001:0db8:5a00:0020:0000:0000:0000:0015. Two rules shorten that. First, leading zeros in any group may be dropped, so 0db8 becomes db8 and 0020 becomes 20 and 0000 becomes 0. Second, one run of consecutive all-zero groups may be replaced by a double colon. Applying both rules gives 2001:db8:5a00:20::15. The double colon may be used only once in an address, because otherwise the reader could not tell how many groups each one replaced; when there are two runs of zeros, the longer one is compressed, or the first if they are equal.
| Full form | Compressed form | Notes |
|---|---|---|
| 2001:0db8:5a00:0020:0000:0000:0000:0015 | 2001:db8:5a00:20::15 | Leading zeros dropped, longest zero run replaced |
| fe80:0000:0000:0000:3e22:fbff:fe10:0021 | fe80::3e22:fbff:fe10:21 | A link-local address |
| 0000:0000:0000:0000:0000:0000:0000:0001 | ::1 | The loopback address |
| 0000:0000:0000:0000:0000:0000:0000:0000 | :: | The unspecified address |
| 2001:0db8:0000:0000:0001:0000:0000:0001 | 2001:db8::1:0:0:1 | Two equal zero runs: only the first is compressed |
RFC 5952 recommends a single canonical way to write each address: lowercase letters, leading zeros removed, the longest run of two or more zero groups compressed. Python's ipaddress module follows those rules, so it is a handy way to check that addresses in documentation and configuration files are written consistently, and to expand a compressed address back to its full form when you need to count groups.
import ipaddress
for text in ('2001:0DB8:5A00:0020:0000:0000:0000:0015', 'fe80::3e22:fbff:fe10:21', '2001:db8:0:0:1:0:0:1', '::1'):
a = ipaddress.ip_address(text)
print(str(a).ljust(26), a.exploded)2001:db8:5a00:20::15 2001:0db8:5a00:0020:0000:0000:0000:0015 fe80::3e22:fbff:fe10:21 fe80:0000:0000:0000:3e22:fbff:fe10:0021 2001:db8::1:0:0:1 2001:0db8:0000:0000:0001:0000:0000:0001 ::1 0000:0000:0000:0000:0000:0000:0000:0001
Try it yourself
Expand a compressed IPv6 address
Without using the ipaddress module, write expand(addr) that returns the full form of an IPv6 address: eight groups of exactly four lowercase hexadecimal digits separated by colons. The input may drop leading zeros and may contain one ::.
Hint: split on :: first. The groups before and after it are known; fill the gap with as many 0000 groups as are needed to make eight in total.
def expand(addr):
return ':'.join(group.zfill(4) for group in addr.split(':'))
print(expand('2001:db8:5a00:20::15'))Prefixes, subnets and interface identifiers
IPv6 uses prefix lengths exactly as CIDR does for IPv4, but the conventional sizes are different and much more generous. A provider typically gives a business a /48 or a home a /56, and every LAN subnet is a /64. In a /64 subnet the first 64 bits are the network prefix and the last 64 bits are the interface identifier, which identifies the host. A /48 therefore leaves 16 bits, the fourth group, for numbering subnets: 65,536 subnets of /64 each, every one with room for 18 quintillion hosts.
Ridgeline's provider assigned 2001:db8:5a00::/48. Sam's plan simply reuses the VLAN numbers as subnet IDs: VLAN 10, the office, becomes 2001:db8:5a00:10::/64; VLAN 20, payments, becomes 2001:db8:5a00:20::/64; and so on. There is no need for subnetting arithmetic, no need to size subnets for their host counts and no risk of running out: every LAN gets a /64, always. That simplicity is one of IPv6's quiet advantages. (The prefix 2001:db8::/32 is reserved for documentation, which is why it appears in this course instead of a real provider's prefix.)
import ipaddress
site = ipaddress.ip_network('2001:db8:5a00::/48')
vlans = {10: 'office', 20: 'payments', 30: 'guest Wi-Fi', 40: 'roastery', 99: 'management'}
for vlan, name in vlans.items():
subnet = ipaddress.ip_network((int(site.network_address) + (int(str(vlan), 16) << 64), 64))
print(str(vlan).rjust(3), name.ljust(12), subnet)
print('subnets available in the /48:', 2 ** (64 - 48))10 office 2001:db8:5a00:10::/64 20 payments 2001:db8:5a00:20::/64 30 guest Wi-Fi 2001:db8:5a00:30::/64 40 roastery 2001:db8:5a00:40::/64 99 management 2001:db8:5a00:99::/64 subnets available in the /48: 65536
The subnet ID here is the VLAN number written as hexadecimal digits that look the same as the decimal number: VLAN 20 becomes the group 20, which is really hexadecimal 0x20, decimal 32. That is purely a convenience for people reading the addresses, and it works for VLAN numbers made only of the digits 0 to 9.
Address types
IPv6 has several kinds of unicast address, plus multicast and anycast. A single interface normally has more than one IPv6 address at the same time, which surprises people used to IPv4.
| Type | Prefix | Scope and use |
|---|---|---|
| Global unicast | 2000::/3 (addresses starting 2 or 3) | Routable on the internet, like a public IPv4 address |
| Link-local | fe80::/10 | Valid only on one link; every IPv6 interface has one; used for neighbour discovery and as the router's next hop |
| Unique local | fc00::/7 (in practice fd00::/8) | Private addressing inside an organization, similar in purpose to RFC 1918 |
| Loopback | ::1/128 | The host itself |
| Unspecified | ::/128 | No address yet, used as a source while a host configures itself |
| Multicast | ff00::/8 | Delivery to a group; replaces broadcast |
| Anycast | Any unicast prefix | The same address on several devices; packets go to the nearest one |
A few multicast addresses are worth recognizing: ff02::1 is all nodes on the link, ff02::2 is all routers on the link, and addresses beginning ff02::1:ff are solicited-node multicast groups used to find a neighbour's link-layer address efficiently. Anycast is used heavily by the root DNS servers and large public DNS resolvers: the same address is announced from dozens of locations, and the network delivers each query to the nearest one.
Try it yourself
What kind of IPv6 address is this?
Write ipv6_type(text) that returns one of 'loopback', 'link-local', 'unique local', 'multicast' or 'global' for an IPv6 address. Use the ipaddress module: check membership in the networks ::1/128, fe80::/10, fc00::/7 and ff00::/8; everything else counts as global for this exercise.
import ipaddress
def ipv6_type(text):
if text.startswith('fe80'):
return 'link-local'
return 'global'
print(ipv6_type('FE80::1'), ipv6_type('fd12:3456::9'))How IPv6 hosts get addresses
IPv6 hosts can configure themselves. When an interface comes up, it first creates a link-local address from fe80::/64 and checks that nobody else is using it, a step called duplicate address detection. It then sends a router solicitation to ff02::2, and routers reply with a router advertisement carrying the subnet's /64 prefix, the router's own link-local address to use as the default gateway, and flags saying how hosts should get the rest of their settings. With stateless address autoconfiguration, SLAAC, the host builds its own global address by combining the advertised prefix with an interface identifier it chooses itself.
Interface identifiers used to be derived from the MAC address by a method called modified EUI-64: split the 48-bit MAC in half, insert ff:fe in the middle and flip the seventh bit. That made addresses predictable and let devices be tracked across networks, so modern operating systems use random or stable-but-opaque identifiers instead, and also create short-lived temporary addresses for outgoing connections. The EUI-64 method is still used on many routers and still appears on exams.
def eui64(mac):
parts = [int(b, 16) for b in mac.split(':')]
parts[0] ^= 0b00000010 # flip the universal/local bit
eui = parts[:3] + [0xff, 0xfe] + parts[3:]
groups = [format(eui[i] << 8 | eui[i + 1], 'x') for i in range(0, 8, 2)]
return ':'.join(groups)
mac = '3c:22:fb:10:00:21'
print('MAC address ', mac)
print('interface ID ', eui64(mac))
print('link-local ', 'fe80::' + eui64(mac))
print('global (SLAAC) ', '2001:db8:5a00:20:' + eui64(mac))MAC address 3c:22:fb:10:00:21 interface ID 3e22:fbff:fe10:21 link-local fe80::3e22:fbff:fe10:21 global (SLAAC) 2001:db8:5a00:20:3e22:fbff:fe10:21
DHCPv6 also exists. In stateful DHCPv6, a server hands out addresses much as DHCP does for IPv4 and keeps a record of which host has which, which some organizations prefer for tracking. In stateless DHCPv6, hosts build their own addresses with SLAAC but ask a DHCPv6 server for other settings, such as DNS servers; router advertisements can also carry DNS servers directly. Ridgeline's firewall-router uses SLAAC with DNS servers included in its advertisements, the simplest arrangement and the default on most small business equipment.
Neighbour discovery replaces ARP
IPv6 has no ARP and no broadcast. Their jobs, and several others, are done by the Neighbor Discovery Protocol, part of ICMPv6. To find the link-layer address of a neighbour, a host sends a neighbour solicitation to the neighbour's solicited-node multicast address, which only a handful of devices listen to, and the neighbour answers with a neighbour advertisement containing its MAC address. Routers announce themselves with router advertisements, and hosts ask for them with router solicitations. Because these functions run over ICMPv6, firewalls must allow the necessary ICMPv6 messages; blocking ICMPv6 wholesale, a habit carried over from IPv4, breaks IPv6 completely.
Running IPv4 and IPv6 together
The transition from IPv4 to IPv6 has lasted more than two decades and will continue for many years. The most common approach is dual stack: every device and router runs both protocols at once, with both kinds of address, and applications use IPv6 when the destination supports it and IPv4 otherwise. Operating systems race the two in parallel and use whichever connects first, a technique called happy eyeballs, so a broken IPv6 path costs only a fraction of a second. Other mechanisms carry one protocol inside the other, called tunnelling, or translate between them, such as NAT64 combined with DNS64, which lets IPv6-only devices reach IPv4-only servers and is common on mobile networks.
Ridgeline runs dual stack: every VLAN will get both an IPv4 subnet and an IPv6 /64. The firewall must have rules for both. A rule that blocks guests from reaching the office over IPv4 is useless if the same traffic can flow over IPv6, a gap that is easy to leave open because the IPv6 side is often enabled by default and forgotten. Documentation, monitoring and troubleshooting must all cover both protocols.
Worked problem
Reading an interface with several IPv6 addresses
Sam runs the command that lists the office laptop's addresses and sees: 10.20.10.37/24, fe80::9a1c:4422:1b0e:7d10/64, 2001:db8:5a00:10:5c3e:91ff:2a40:8c11/64 and 2001:db8:5a00:10:e1d4:73b2:9a5c:4f02/64. Jordan asks whether the laptop is misconfigured. Explain each address.
Show solution
- 10.20.10.37/24 is the IPv4 address in the office VLAN, from DHCP.
- fe80::9a1c:4422:1b0e:7d10 is the link-local address that every IPv6 interface creates; it is used on the local link only, for neighbour discovery and to talk to the router.
- The first 2001:db8:5a00:10:: address is a global address built by SLAAC from the office prefix with a stable interface identifier; it stays the same on this network.
- The second 2001:db8:5a00:10:: address is a temporary privacy address, used for outgoing connections and replaced every day or so.
- Nothing is wrong: several IPv6 addresses per interface is normal and expected.
Answer: The laptop is dual stack and correctly configured: one IPv4 address, one link-local, one stable global and one temporary global IPv6 address.
Common mistakes
MistakeUsing :: more than once in one address.
InsteadCompress only one run of zero groups; the reader must be able to count the missing groups.
MistakeSubnetting LANs to sizes smaller than /64.
InsteadUse a /64 for every LAN; SLAAC and other features depend on it.
MistakeBlocking all ICMPv6 at the firewall.
InsteadAllow the ICMPv6 messages IPv6 needs, such as neighbour discovery and packet too big.
MistakeWriting firewall rules for IPv4 only on a dual-stack network.
InsteadApply equivalent rules to IPv6, or the same traffic simply goes around them.
MistakeExpecting one IPv6 address per interface.
InsteadInterfaces normally have a link-local address and one or more global addresses.
MistakeForgetting that hex digits a to f are part of IPv6 addresses.
InsteadTreat each group as four hexadecimal digits, and write them in lowercase.
Summary and key terms
- IPv6 uses 128-bit addresses to end the IPv4 shortage and restore end-to-end addressing.
- Addresses are eight groups of four hex digits; drop leading zeros and replace one zero run with ::.
- LAN subnets are /64: a 64-bit prefix (routing prefix plus subnet ID) and a 64-bit interface identifier.
- Key types: global unicast (2000::/3), link-local (fe80::/10), unique local (fd00::/8), multicast (ff00::/8), loopback ::1.
- Hosts configure themselves with SLAAC from router advertisements; DHCPv6 can add or replace this.
- Neighbor Discovery over ICMPv6 replaces ARP; IPv6 has no broadcast.
- Dual stack runs IPv4 and IPv6 together; security rules and documentation must cover both.
- IPv6
- Internet Protocol version 6, with 128-bit addresses.
- Hextet
- One 16-bit group of an IPv6 address, written as up to four hex digits.
- Interface identifier
- The host part of an IPv6 address, normally the last 64 bits.
- Global unicast address
- A publicly routable IPv6 address, from 2000::/3.
- Link-local address
- An address valid on one link only, from fe80::/10.
- Unique local address
- A private IPv6 address from fc00::/7, normally fd00::/8.
- SLAAC
- Stateless address autoconfiguration: hosts build their own addresses from advertised prefixes.
- Router advertisement
- An ICMPv6 message in which routers announce prefixes and themselves as gateways.
- Neighbor Discovery Protocol
- The ICMPv6-based protocol that replaces ARP and finds routers.
- Dual stack
- Running IPv4 and IPv6 at the same time on the same devices.
Practice problems
Work each problem on paper first, then reveal the answer to check.
How many bits are in an IPv6 address?
Show answer
128.
Compress 2001:0db8:0000:0000:0000:0000:0000:0042.
Show answer
2001:db8::42.
Why can :: appear only once in an address?
Show answer
Otherwise you could not tell how many zero groups each one replaces.
What prefix length is used for an IPv6 LAN?
Show answer
/64.
How many /64 subnets fit in a /48?
Show answer
2^16 = 65,536.
What does an address starting fe80 tell you?
Show answer
It is link-local, valid only on that link.
Which IPv6 range is similar in purpose to RFC 1918 private addresses?
Show answer
Unique local addresses, fd00::/8 in practice.
What replaces ARP in IPv6?
Show answer
Neighbor Discovery (neighbour solicitations and advertisements over ICMPv6).
What does SLAAC need from the router?
Show answer
A router advertisement carrying the /64 prefix (and its own address as gateway).
Why must IPv6 firewall rules be reviewed on a dual-stack network?
Show answer
Traffic blocked over IPv4 may still flow over IPv6 if equivalent rules are missing.
Lesson quiz · 5 questions
Score 60% or more to complete this lesson.
Create a free account to save your progress, take quizzes and earn a certificate.