Hello IPv6: a minimal tutorial for IPv4 users

Hello IPv6: a minimal tutorial for IPv4 users

Introduction

It might be a bit funny to call this post “Hello IPv6”, since the first draft of IPv6 was published in late 1998; however, it is ratified as a standard only in 2017. When I first heard about IPv6 many years ago, I thought it only provides a larger address space than IPv4. This is correct, but there is more. Even for a home network, or for a small network, there are some basic differences. Some of the terms, protocols etc. that was so much in use in IPv4, that most of us learned and maybe internalized, either radically changed or disappeared in IPv6.

In this post, I explain how the well-known IPv4 concepts work in IPv6. This post is aimed for home and small office networks. So if you know about ARP, DHCP, and NAT, and if you wonder how these work in IPv6 networks, this post is perfect for you. If you already know about IPv6 addresses, NDP, RA, PD, SLAAC, and DHCPv6, there is nothing new here.

This post is far from a complete description of IPv6, even for small networks. It is only for understanding the basics from a practical point of view. I try to do my best to introduce and use consistent terminology with IPv6 specs.

I only consider unicast addresses in this post, not multicast, which is used for TV broadcasts etc. However, I mention multicast addresses in a few places when needed (for broadcast functions).

All command examples are from Ubuntu 18.04.4 Linux. I am using a Ubiquiti EdgeRouter 4, an HPE 1920 Switch and an embedded Linux Computer PC Engines apu4d4 with 4 ethernet ports running Ubuntu 18.04.4 Linux and my ISP is init7. The fiber cable from OTO is terminated at the SFP module plugged to HP 1920. This port is mirrored to another one which is connected to apu4d4. The SFP port is connected to the WAN port of the router. apu4d4 is also connected to LAN. That is how I use tcpdump both on WAN and on the LAN side.

There is a list of RFCs in the Resources section, which should be referred for more and detailed information. This post is basically a very brief summary of these RFCs with examples.

Summary

Here is an extremely short summary.

  • IPv6 has a different Ethernet frame type.
  • IPv6 address is 128-bit with 64-bit (network) prefix and 64-bit interface id.
  • IPv6 does not use ARP but NDP.
  • IPv6 has no broadcast address concept; some multicast addresses play this function.
  • IPv6 addresses can be dynamically configured like DHCPv4 but also, and probably more often, they can be configured without keeping a state, using a combination of DHCPv6, RA, PD, and SLAAC.
  • NAT is not necessary for IPv6.
  • If needed, for privacy reasons, a random and temporary IPv6 address can be used.

Here is a simple diagram of what is going on.

IPv6 Address Configuration (omitting NDP Neighbor messages)

Ethernet: different ethernet frame type

Both IPv4 and IPv6 can and do work with networking technologies other than Ethernet, such as FDDI, but Ethernet is the most relevant one for the purpose of this post.

IPv6 works over ethernet like IPv4, and since ethernet is designed to be agnostic to the higher level (Layer 3) protocol (such as IP) carried in its payload, there is no surprise here. The only difference is the type field in Ethernet frame is 0x0800 for IPv4, but 0x86DD for IPv6.

The output below is generated by ping6 2001:4860:4860::8888. This is one of Google’s public DNS servers (IPv6 address of 8.8.8.8).

$ sudo tcpdump -vv -i enp1s0 -n -e icmp6

17:31:47.792214 00:0d:b9:55:66:08 > b4:fb:e4:8a:fa:de, 
ethertype IPv6 (0x86dd), length 118: 
(flowlabel 0x5640f, hlim 64, next-header ICMPv6 (58) payload length: 64) 
2a02:168:91d5:1:20d:b9ff:fe55:6608 > 2001:4860:4860::8888: 
[icmp6 sum ok]

ICMP6, echo request, seq 1 17:31:47.793637 b4:fb:e4:8a:fa:de > 00:0d:b9:55:66:08, ethertype IPv6 (0x86dd), length 118: (flowlabel 0x5640f, hlim 56, next-header ICMPv6 (58) payload length: 64) 2001:4860:4860::8888 > 2a02:168:91d5:1:20d:b9ff:fe55:6608:

[icmp6 sum ok]

ICMP6, echo reply, seq 1

You can see ethertype is 0x86dd.

IP addressing: from v4 to v6, from 4-bytes to 16-bytes, scope and lifetime

IPv6 addresses are 128-bit or 16 bytes. They are written as x:x:x:x:x:x:x:x, where x is a 2-byte hexadecimal number written as one to four hexadecimal number. Examples:

  • 2a02:168:91d5:1:20d:b9ff:fe55:6608, leading zeroes in fields can be omitted (e.g. 168 and 1, instead of 0168 and 0001), but there has to be at least one number, a zero field 0000 has to be written as single 0.
  • 2001:4860:4860::8888, :: is a shortcut for a long string of zeroes from the left to the right, it may span multiple fields. There can be only one :: in an address. This address is actually 2001:4860:4860:0000:0000:0000:0000:8888.
  • ::1, means all zeroes with a single 1 at the right, 0000:0000:0000:0000:0000:0000:0000:0001.

IPv6 addresses consist of a subnet prefix and an interface identifier. IPv6 addressing is essentially classless, meaning some number of bits represents prefix (but for unicast addresses it is 64-bit, more on this soon).

subnet prefix [0-n]interface id [n-128]

The subnet prefix is also represented similar to IPv4, in /x format, where x is the number of bits from the left.

These are the important address types:

  • ::1/128, loopback address (e.g. localhost)
  • fe80::/10, link-local unicast addresses (subnet prefix fe8)
  • ff00::/8, multicast addresses (subnet prefix ff)
  • all other addresses are global unicast addresses (with a few exceptions)

All IPv6 addresses have a scope. The most common ones and the only two scopes used by unicast addresses are link-local and global. A link-local address is permitted to be used only in one LAN segment (subnet). A global address can be used on the internet.

An interface has to have at least one link-local address, and it can have many addresses. This is one of the things it looks strange for IPv4 users because we are used to seeing only one IP on one interface, whereas on IPv6, an interface usually has two (one link-local, one global) or more (more than one global) addresses.

The interface identifier naturally has to be unique within a subnet. For all unicast addresses, the interface identifier has to be 64-bit, that means prefix also has to be 64-bit. The most common method to generate an interface identifier is from the MAC address, but it can be generated also in different ways. There is a simple algorithm called modified EUI-64 to generate a 64-bit interface id from a 48-bit MAC address.

After configured, all addresses are checked in the subnet for potential duplicates.

For global unicast addresses, subnet prefix is composed of a routing prefix and a subnet id. The routing prefix is typically something assigned to the link (meaning to your connection) by the ISP, and you can then freely choose different subnet ids.

global routing prefix [0-n]subnet id [n-64]interface id [64-128]

The global routing prefix is, as far as I know, something between /48 and /64, and this is decided by the ISP. If it is /64, it means you have only one subnet which is already given to you by the ISP. My ISP gives /48, so I have a 16-bit subnet id, and I can have 2^16=65536 subnets. After IPv4, the vast size of IPv6 feels strange, in each of 65536 subnets, I can have 2^64=a really big 20-digit number global IPv6 addresses.

For a link-local address, the prefix is fixed, fe8 (10-bit) plus zeroes (54-bit) to fill 64-bit and then 64-bit interface id. So link-local addresses usually looks like fe80::... because of the zeroes.

All IPv6 addresses (even the loopback one) have a lifetime, which can be infinite/forever. This is similar to DHCPv4, but it is enforced by the host itself independent of a DHCP service is used or not.

ip command in Linux with -6 option shows only IPv6 related configuration.

$ ip -6 address

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000

    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000

    inet6 2a02:168:91d5:1:20d:b9ff:fe55:6608/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 3252sec preferred_lft 3252sec

    inet6 fe80::20d:b9ff:fe55:6608/64 scope link 
       valid_lft forever preferred_lft forever

The interface lo is the loopback interface. The loopback address is always ::1/128. It says scope=host above, but technically loopback address has link-local scope. This is 127.0.0.1 in IPv4.

The interface enp1s0 has two IPv6 addresses:

  • First is a global dynamically configured address. Pay attention to scope global and dynamic flags. The prefix of the global address is 2a02:168:91d5:1 and it is received from the routers, we cannot know the routing prefix and subnet id only from the address, more about this later.
  • Second is a link-local address. Pay attention to scope link flag. The link-local address is always in the fe80::/10 network.

You may have already realized that the last 64-bit (20d:b9ff:fe55:6608) of both global and link-local addresses is the same. This is because both of these addresses are autoconfigured and the autoconfiguration uses the same algorithm (modified EUI-64) deriving interface id from the MAC address.

As you can see, all three addresses have (two) lifetimes (valid_lft and preferred_lft). After duplicate address detection, the address becomes preferred and used for preferred_lft seconds, then it becomes deprecated, and it is only kept for a total of valid_lft seconds then it becomes invalid. Above, valid_lft and preferred_lft is the same, so there is no deprecated state; it goes from preferred to invalid. As you see loopback and link-local addreses have infinite (forever) lifetimes.

Note: There is actually also a tentative state and a tentative flag. This is when an address is autoconfigured but did not pass duplicate address detection yet. It is difficult to see this flag since autoconfiguration and duplicate address detection happen very quickly.

You might wonder if IPv6 also has a concept of private IP address space (like 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 in IPv4). In a way, the answer is yes, fc00::/7 space is for a private network and an address in this space is called unique local address (ULA). This space is divided to two parts, and the first part is currently undefined, so fd00::/8 can be used for private networks. However, you will see later, the use of private addresses is not needed as much as in IPv4, or maybe it is not needed at all.

Address resolution: from ARP to NDP

IPv4 address to MAC address resolution is done using ARP in IPv4. There is a significant change here because there is no ARP for IPv6. IPv6 uses a new protocol, Neighbor Discovery Protocol (NDP), particularly Neighbor Solicitation (Type 135) and Neighbor Advertisement (136) packet types.

NDP Type 135 and Type 135 is functionally similar to ARP, one host asks all hosts for a link-address (MAC address) of an IPv6 address, and if a host has this IPv6 address, it replies with its link-address. A major difference is while ARP messages have their own ethertype (different than IPv4 ethertype), NDP is based on ICMPv6 (i.e. it defines new ICMP packet types), which are carried in an ethernet packet with IPv6 type. So ARP is an OSI Layer 2 (L2) protocol, whereas NDP is L3.

The output below is generated by ping6 2a02:168:91d5:1:b6fb:e4ff:fe8a:fade. This is a host in my home network.

$ sudo tcpdump -vv -i enp1s0 -n -e "(icmp6 && (ip6[40] >= 133 && ip6[40] <= 137))"

17:59:09.195679 00:0d:b9:55:66:08 > 33:33:ff:8a:fa:de, 
ethertype IPv6 (0x86dd), length 86: (hlim 255, next-header ICMPv6 (58) payload length: 32) 
2a02:168:91d5:1:20d:b9ff:fe55:6608 > ff02::1:ff8a:fade: 
[icmp6 sum ok]

ICMP6, neighbor solicitation, length 32, who has 2a02:168:91d5:1:b6fb:e4ff:fe8a:fade source link-address option (1), length 8 (1): 00:0d:b9:55:66:08 0x0000: 000d b955 6608 17:59:09.195925 b4:fb:e4:8a:fa:de > 00:0d:b9:55:66:08, ethertype IPv6 (0x86dd), length 86: (hlim 255, next-header ICMPv6 (58) payload length: 32) 2a02:168:91d5:1:b6fb:e4ff:fe8a:fade > 2a02:168:91d5:1:20d:b9ff:fe55:6608:

[icmp6 sum ok]

ICMP6, neighbor advertisement, length 32, tgt is 2a02:168:91d5:1:b6fb:e4ff:fe8a:fade, Flags [router, solicited, override] destination link-address option (2), length 8 (1): b4:fb:e4:8a:fa:de 0x0000: b4fb e48a fade

The first message (Neighbor Solicitation) asks the link-address of the interface having IPv6 address 2a02:168:91d5:1:b6fb:e4ff:fe8a:fade (sending its link layer address in option 1), and a host replies with its link layer address b4:fb:e4:8a:fa:de in option 2.

As in ARP, neighbors are cached in IPv6 as well. You can see the contents of this cache and add/delete entries or flush all the cache:

$ ip -6 neigh show dev enp1s0

fe80::b6fb:e4ff:fe8a:fade lladdr b4:fb:e4:8a:fa:de router STALE
2a02:168:91d5:1:b6fb:e4ff:fe8a:fade lladdr b4:fb:e4:8a:fa:de router STALE

$ sudo ip -6 neigh flush dev enp1s0

You can see above the reply message has router flag because this IPv6 address belongs to one of the interfaces on my router.

Address configuration: from DHCPv4 to DHCPv6, RA, PD and SLAAC

If you do not configure statically (manually), DHCP (DHCPv4) is the only and probably the most popular way to dynamically configure IPv4 addresses.

An IPv6 address can also be configured manually or by using DHCPv6, when the exact address is important for some reason (e.g. you may want to have a DNS record for it). In addition to these methods, it is possible to configure IPv6 addresses automatically and in a stateless fashion. This is probably much more common because we usually do not care about the exact addresses of the hosts (think about your laptop, tv, mobile phone at home). This mechanism is called StateLess Address AutoConfiguration (SLAAC). It is stateless because nothing keeps track of IP addresses (like a stateful DHCP server assigning IP addresses), but they are generated by the hosts theirselves. SLAAC works together with Prefix Delegation (PD), and PD is possible both with Router Advertisement (RA) and DHCPv6. If DHCPv6 is used only for PD, and not for assigning complete IPv6 addresses, then it is called stateless DHCPv6 or DHCPv6-PD.

A summary might be helpful, here are the options:

  • static: You can configure the address manually.
  • stateful DHCPv6: DHCPv6 can configure (assign) the address and provide other configurations (DNS etc.).
  • stateless DHCPv6: DHCPv6 does not configure the address, only provides PD and other configurations. Hosts use SLAAC to autoconfigure IPv6 addresses.
  • RA only: There is no DHCPv6. RA provides prefix and hosts use SLAAC to autoconfigure IPv6 addresses. Some of the other configurations can also be distributed by RA such as DNS.

So basically when you want maximum control on address configuration, you do static or stateful DHCPv6, which enables you to know the exact address, but if you do not want or do not need that much control and prefer an easy configuration, you do RA only or stateless DHCPv6, or a combination of them if needed.

Note: DHCPv4 uses MAC address to identify the hosts, but DHCPv6 uses another id that may or may not derived from the MAC address. It is called DHCP unique identifier (DUID).

Router Advertisement is another protocol defined in NDP, with Router Solicitation (Type 133) and Router Advertisement (Type 134) message types. Router may periodically send Router Advertisements and it is also possible a host sends a Router Solicitation and router replies to that.

I think the address configuration is a bit difficult to understand or confusing than IPv4, because there are multiple ways to do it, and they can work at the same time. Also, the address configuration of the router and the hosts behind the router are a bit different things, and they can be achieved by different means. I think it might be better to describe them separately.

How does the router configure its IPv6 address ?

As mentioned above, there are multiple ways to do this. Lets see some of them. First, RA only.

Below is a dump of NDP RA coming from my ISP.

$ sudo tcpdump -i enp4s0 -e -n -vv "icmp6 and ip6[40]==134"
tcpdump: listening on enp4s0, link-type EN10MB (Ethernet), capture size 262144 bytes

20:22:00.737774 1c:df:0f:6c:01:3f > 33:33:00:00:00:01, 
ethertype IPv6 (0x86dd), length 118: (class 0xe0, hlim 255, next-header ICMPv6 (58) payload length: 64) 
fe80::1edf:fff:fe6c:13f > ff02::1: 
[icmp6 sum ok]

ICMP6, router advertisement, length 64 hop limit 64, Flags [none], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms source link-address option (1), length 8 (1): 1c:df:0f:6c:01:3f 0x0000: 1cdf 0f6c 013f mtu option (5), length 8 (1): 1552 0x0000: 0000 0000 0610 prefix info option (3), length 32 (4): 2a02:168:2000:28::/64, Flags [onlink, auto], valid time 2592000s, pref. time 604800s 0x0000: 40c0 0027 8d00 0009 3a80 0000 0000 2a02 0x0010: 0168 2000 0028 0000 0000 0000 0000

It sends this prefix 2a02:168:2000:28::/64 so it can be used by the router to autoconfigure the IPv6 address of its WAN interface (and also the hosts behind the router).

An interesting feature of this message is Flags (it says none). The flags may contain M (Managed address configuration), meaning the address is configured by DHCPv6, and O (Other configuration), meaning DHCPv6 may provide configuration other than address.

Lets look at the addresses configured:

$ show interfaces ethernet eth2

eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b4:fb:e4:8a:fa:e0 brd ff:ff:ff:ff:ff:ff
<omitted>
    inet6 2a02:168:2000:28:b6fb:e4ff:fe8a:fae0/64 scope global mngtmpaddr dynamic 
       valid_lft 2591940sec preferred_lft 604740sec
<omitted>

Note: This is what happens when ER4 is configured with ipv6 { address { autoconf } } on its WAN interface.

This is enough for the router. It has a global IPv6 address. However, how will the hosts configure their addresses ? The only option is to use ULA and use fd00::/8 space, but then there is a need for some type of NAT. This is not what I want and not something I believe usually done.

Note: We cannot use this prefix for the hosts behind the router. This prefix is for the WAN interfaces of all routers connected to the ISP.

Lets see how stateless DHCPv6 or DHCPv6 with Prefix Delegation (DHCPv6-PD) works. It works similar to normal DHCP, the host (interface) sends a DHCPv6 solicit message (request) and the DHCPv6 server sends back a DHCPv6 advertise and/or reply message. The messages are sent to the special IPv6 (multicast) address ff02::1:2 which means All_DHCP_Relay_Agents_and_Servers in link-local scope.

The broadcast addresses are quite interesting in IPv6. In IPv4, there is only one broadcast address for a subnet. In IPv4, multicast addresses are used, there is no concept of broadcast address, and there are different multicast addresses for different purposes. Like this one, ff02::1:2 is a kind of broadcast address but it goes only to the DHCP Relays and Servers. There are some of such multicast addresses, addressing different type of services.

$ sudo tcpdump -i enp4s0 -e -n -vv "udp and ((src port 547 and dst port 546) or (src port 546 and dst port 547))"
tcpdump: listening on enp4s0, link-type EN10MB (Ethernet), capture size 262144 bytes

23:13:21.465095 b4:fb:e4:8a:fa:e0 > 33:33:00:01:00:02, 
ethertype IPv6 (0x86dd), length 147: 
(flowlabel 0xf9b06, hlim 1, next-header UDP (17) payload length: 93) 
fe80::b6fb:e4ff:fe8a:fae0.546 > ff02::1:2.547: 
[udp sum ok]

dhcp6 solicit (xid=7c7793 (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (rapid-commit) (elapsed-time 0) (option-request DNS-server DNS-search-list) (IA_PD IAID:0 T1:0 T2:0 (IA_PD-prefix ::/48 pltime:4294967295 vltime:4294967295))) 23:13:21.468417 1c:df:0f:6c:01:3f > b4:fb:e4:8a:fa:e0, ethertype IPv6 (0x86dd), length 183: (class 0xe0, hlim 255, next-header UDP (17) payload length: 129) fe80::1edf:fff:fe6c:13f.547 > fe80::b6fb:e4ff:fe8a:fae0.546:

[udp sum ok]

dhcp6 advertise (xid=7c7793 (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (server-ID hwaddr/time type 1 time 627576541 525400c1edce) (DNS-server 2001:1620:2777:1::10 2001:1620:2777:2::20) (IA_PD IAID:0 T1:1000 T2:2000 (IA_PD-prefix 2a02:168:91d5::/48 pltime:3000 vltime:4000))) 23:13:22.466613 b4:fb:e4:8a:fa:e0 > 33:33:00:01:00:02, ethertype IPv6 (0x86dd), length 161: (flowlabel 0xf9b06, hlim 1, next-header UDP (17) payload length: 107) fe80::b6fb:e4ff:fe8a:fae0.546 > ff02::1:2.547:

[udp sum ok]

dhcp6 request (xid=61267d (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (server-ID hwaddr/time type 1 time 627576541 525400c1edce) (elapsed-time 0) (option-request DNS-server DNS-search-list) (IA_PD IAID:0 T1:0 T2:0 (IA_PD-prefix 2a02:168:91d5::/48 pltime:3000 vltime:4000))) 23:13:22.475227 1c:df:0f:6c:01:3f > b4:fb:e4:8a:fa:e0, ethertype IPv6 (0x86dd), length 183: (class 0xe0, hlim 255, next-header UDP (17) payload length: 129) fe80::1edf:fff:fe6c:13f.547 > fe80::b6fb:e4ff:fe8a:fae0.546:

[udp sum ok]

dhcp6 reply (xid=61267d (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (server-ID hwaddr/time type 1 time 627576541 525400c1edce) (DNS-server 2001:1620:2777:1::10 2001:1620:2777:2::20) (IA_PD IAID:0 T1:1000 T2:2000 (IA_PD-prefix 2a02:168:91d5::/48 pltime:3000 vltime:4000)))

Note: The 4 messages exchange above can actually be done in 2 messages. This is done by sending rapid-commit option (you can see in the first message, commit here means committing the DHCP assignment received). However, it seems the DHCPv6 server at ISP side does not support it, and it continued with the exchange with 4 messages. The last two messages are basically confirmation (it is useful if there are multiple DHCP servers in the network).

So basically the router asks for DNS-server, DNS-search-list and a ::/48 Prefix (IA_PD option). Then server replies with these information:

  • DNS-server: 2001:1620:2777:1::10 and 2001:1620:2777:2::20
  • DNS-search-list: nothing
  • Prefix: 2a02:168:91d5::/48

I actually do not use the ISPs DNS servers and I do not need DNS search list, so normally I would not request these, but I cannot control this on my router, this is the default setting.

You might have realized the (home) router sends the prefix-length in the request, that is why it has to be configured on the router, and you have to know this to configure IPv6 for your environment. Ask to your ISP if you do not know it. This is, for example, what my ISP says.

Now at this point, we have a prefix, not a IPv6 address. So we can think that we can use that to autoconfigure the WAN interface. However, this is the result:

eth2:
    link/ether b4:fb:e4:8a:fa:e0 brd ff:ff:ff:ff:ff:ff
    inet6 2a02:168:2000:28:b6fb:e4ff:fe8a:fae0/64 scope global mngtmpaddr dynamic 
       valid_lft forever preferred_lft forever

as you see this is not the prefix from DHCPv6 but it is the one from RA. It is actually obvious why we cannot use the prefix from DHCPv6 as the prefix of WAN interface, because it is 48-bit. An IPv6 global unicast address needs 64-bit network prefix. So theoretically, it should be possible to just assign a 16-bit subnet id to that and use it since this prefix belongs to this connection. However, I could not find a way to do it on my router, I am not sure if it is just not supported or it is something not logical or illegal. So the point of prefix delegation is to use this for your subnet, not for your WAN interface.

This (configuring WAN interface with RA, learning the prefix with DHCPv6-PD and distributing this to my home network) is the configuration I would like to use for my connection, but before that, I can show one more thing.

You saw above IA_PD option for prefix. There is also IA_NA (IA is short for Identity Association) option in DHCPv6, and this is to request a full IPv6 address assignment. This is done by removing/not setting dhcpv6-pd { prefix-only } in ER4. Here is a capture from that (I omitted the last two messages):

23:56:17.702662 b4:fb:e4:8a:fa:e0 > 33:33:00:01:00:02, 
ethertype IPv6 (0x86dd), length 163: 
(flowlabel 0xf9b06, hlim 1, next-header UDP (17) payload length: 109) 
fe80::b6fb:e4ff:fe8a:fae0.546 > ff02::1:2.547: 
[udp sum ok]

dhcp6 solicit (xid=7b23c6 (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (IA_NA IAID:0 T1:0 T2:0) (rapid-commit) (elapsed-time 0) (option-request DNS-server DNS-search-list) (IA_PD IAID:0 T1:0 T2:0 (IA_PD-prefix ::/48 pltime:4294967295 vltime:4294967295))) 23:56:17.707183 1c:df:0f:6c:01:3f > b4:fb:e4:8a:fa:e0, ethertype IPv6 (0x86dd), length 227: (class 0xe0, hlim 255, next-header UDP (17) payload length: 173) fe80::1edf:fff:fe6c:13f.547 > fe80::b6fb:e4ff:fe8a:fae0.546:

[udp sum ok]

dhcp6 advertise (xid=7b23c6 (client-ID hwaddr/time type 1 time 634823279 b4fbe48afadd) (server-ID hwaddr/time type 1 time 627576541 525400c1edce) (IA_NA IAID:0 T1:1000 T2:2000 (IA_ADDR 2a02:168:2000:28::1c pltime:3000 vltime:4000)) (DNS-server 2001:1620:2777:1::10 2001:1620:2777:2::20) (IA_PD IAID:0 T1:1000 T2:2000 (IA_PD-prefix 2a02:168:91d5::/48 pltime:3000 vltime:4000)))

It is similar to what I showed before. The difference is that IA_NA option is added to the request, and the reply includes IA_ADDR for IA_NA, 2a02:168:2000:28::1c in addition to the prefix. Now if I check the interfaces:

eth2:
    link/ether b4:fb:e4:8a:fa:e0 brd ff:ff:ff:ff:ff:ff
    inet6 2a02:168:2000:28::1c/128 scope global 
       valid_lft forever preferred_lft forever
    inet6 2a02:168:2000:28:b6fb:e4ff:fe8a:fae0/64 scope global mngtmpaddr dynamic 
       valid_lft 2591996sec preferred_lft 604796sec
    inet6 fe80::b6fb:e4ff:fe8a:fae0/64 scope link 
       valid_lft forever preferred_lft forever

as expected 2a02:168:2000:28::1c shows up, but maybe more interesting is that the address configured using the prefix advertised with RA 2a02:168:2000:28:b6fb:e4ff:fe8a:fae0 is also here. This is the case with IPv6. There are multiple ways to configure addresses, and all are done at the same time. As you see, the IA_NA address has no relation with the link-address (MAC address). Actually, if I renew the lease, a new one ending with 1d comes. So it is probably a range, like how DHCPv4 is usually used.

Before going forward with the host configuration, I rollback my configuration to one before, so the router is getting PD from DHCPv6-PD (or stateless DHCPv6) and autoconfiguring its address using the prefix advertised with RA.

Before looking into how the hosts do the address configuration, lets go back to example IPv6 address 2a02:168:91d5:1:f85a:cfc8:1576:989. Now we know more about the prefix:

  • 2a02:168:91d5 is assigned to me by my ISP.
  • 1 is added by my router, so the network prefix for the hosts behind the router is 2a02:168:91d5:1.
  • The remaining f85a:cfc8:1576:989 is the link identifier, generated automatically by this host.

It is possible to use static or dynamic (DHCPv6) configuration like in IPv4, but I think SLAAC is more common that them and it is used with NDP’s Router Solicitation (Type 133) and Router Advertisement (Type 134) messages or with DHCPv6-PD. I am using only RA in my home network, no DHCPv6 (neither stateful nor stateless).

How does a host behind the router configure its IPv6 address ?

I am using RA and SLAAC so it is totally stateless, there is no DHCPv6 server in the home network. Lets see RA in the home network:

$ sudo tcpdump -i enp1s0 -e -n -vv "icmp6 and ip6[40]==134"
tcpdump: listening on enp1s0, link-type EN10MB (Ethernet), capture size 262144 bytes

20:31:24.050448 b4:fb:e4:8a:fa:de > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 166: (class 0xc0, flowlabel 0x4f380, hlim 255, next-header ICMPv6 (58) payload length: 112) fe80::b6fb:e4ff:fe8a:fade > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 112
	hop limit 64, Flags [none], pref medium, router lifetime 0s, reachable time 0ms, retrans timer 0ms
	  prefix info option (3), length 32 (4): 2a02:168:91d5:1::/64, Flags [onlink, auto], valid time 2779s, pref. time 0s
	    0x0000:  40c0 0000 0adb 0000 0000 0000 0000 2a02
	    0x0010:  0168 91d5 0001 0000 0000 0000 0000
	  mtu option (5), length 8 (1):  1500
	    0x0000:  0000 0000 05dc
	  source link-address option (1), length 8 (1): b4:fb:e4:8a:fa:de
	    0x0000:  b4fb e48a fade
	  rdnss option (25), length 24 (3):  lifetime 4294967295s, addr: fe80::b6fb:e4ff:fe8a:fade
	    0x0000:  0000 ffff ffff fe80 0000 0000 0000 b6fb
	    0x0010:  e4ff fe8a fade
	  dnssl option (31), length 24 (3):  lifetime 4294967295s, domain(s): home.arpa.
	    0x0000:  0000 ffff ffff 0468 6f6d 6504 6172 7061
	    0x0010:  0000 0000 0000

No M or O flags, so DHCPv6 provides no information. The network prefix is 2a02:168:91d5:1::/64, remember the first 48-bit is coming from the ISP and the router adds the last 16-bit :1. In addition to these, it contains rdnss option (DNS server) fe80::b6fb:e4ff:fe8a:fade which is the router itself, and dns search list containing home.arpa.

With only this, a host can configure its IPv6 address, finds out the DNS server and DNS search list. Lets see the host:

$ ip -6 address

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2a02:168:91d5:1:20d:b9ff:fe55:6608/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 3495sec preferred_lft 388sec
    inet6 fe80::20d:b9ff:fe55:6608/64 scope link 
       valid_lft forever preferred_lft forever

It has 2a02:168:91d5:1:20d:b9ff:fe55:6608.

There is also a way to generate a random and temporary interface id, so with the same prefix, there can be a different, random and temporary address. More about this in the next section.

Network address translation: to NAT or not to NAT and privacy

As we all know, NAT is used everywhere in IPv4 networks. As it might already be obvious now, there is no need for NAT in an IPv6 network. The address space is enormous; there is really an IPv6 address for everything.

However, this might raise a concern about privacy, since the real IPv6 address of the host is exposed to the internet (and it might be permanent or stays the same for a long time). In IPv4, because the end-user devices were almost always behind NAT, their IPv4 address was not visible outside.

This is solved by using what is called Privacy Extensions for SLAAC in IPv6. It is actually very simple. Instead of using an interface identifier derived from the MAC address, just use a randomly generated identifier, and use this identifier temporarily.

On Ubuntu 18.04, the use of privacy extensions is disabled by default. It can be enabled in netplan config by ipv6-privacy: bool option. When it is set to true, there is going to be two IPv6 addresses, one is configured like before, and the other is temporary (marked as such as well) and generated without using the MAC address, like this:

$ ip -6 address
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2a02:168:91d5:1:ac2e:6ea8:d962:3051/64 scope global temporary dynamic 
       valid_lft 3507sec preferred_lft 3507sec
    inet6 2a02:168:91d5:1:20d:b9ff:fe55:6608/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 3507sec preferred_lft 3507sec
    inet6 fe80::20d:b9ff:fe55:6608/64 scope link 
       valid_lft forever preferred_lft forever

The first address is marked as temporary (created because of privacy extensions) and the second is marked as mngtmpaddr. temporary means it is created because of privacy extensions. mngtmpaddr means this address is the template (I believe it means to use the prefix of this address) for temporary addresses. You can also see both link-local address (last one) and non-temporary global address (second one) ends with the same value :20d:b9ff:fe55:6608 because this part is generated from the MAC address. On the other hand, temporary address is totally different because it is randomly generated.

If you remember IA_NA in DHCPv6, there is also a IA_TA option that requests a temporary address based on privacy extensions. However, my router does not support this yet, so I cannot show an example.

Read more