IPv6 and system administration

It is year 2122, we’ve finally succeed to fight climate changes and some developers have just removed IPv4 support from Linux Kernel. Now when connecting to a WiFi access point, a computer only receives an IPv6 configuration. What are the differences from an IPv4 network ?

Introduction

Today, only a limited part of the Internet has adopted IPv6. If you are interested to get the details, Google makes live statistics about it: https://www.google.com/intl/en/ipv6/statistics.html
So in our current world, a host with only IPv6 configuration and no IPv4 access to internet would have some issues reaching a lot of websites.

But still, imagine a world where anything is reachable through IPv6.

Operating systems and most applications manage IPv6 pretty well. With a bit of luck, a regular user won’t notice any difference while surfing on an IPv6 network.

But what about computer science operations ? About system administration ? What does it change ?

This article explores the issues I met while doing my day-to-day business as a computer scientist.

A summary of the results is available at the end of the article.

Table of contents

Testing policies

Some of the following tools may have many implementation (GNU, BSD, Unix, …) Be aware that the GNU version is always used when there is a choice to be made.

The main goal is to determine how to make basic usage either with a Link-Local Address (LLA) or with a Global Unicast Address (GUA). Every time it is possible, an IPv4 example is provided as reference. An example is also showed to force a tool to use IPv6 when a FQDN or a hostname is provided.

A lot of these tools have a wide range of possibilities, the goal here is not to show that, but how to provide IPv6 addresses as input for these tools. And also showing the extra arguments needed to accomplish that.

Special considerations

Before digging further into what works and what doesn’t. There are two important concepts to be at ease with. You may skip this section if those have no more secret for you.

This family of IPv6 addresses are those starting with prefix fe80::/10.
Without going into details, here are the basic stuffs to know.

First thing a little bit confusing, it only has a link scope. That means no router will forward link-local traffic out of the link it comes from. Packets with LLA destination won’t leave the link where they were emitted. By link, it means an Ethernet area. It only allows to communicate with other hosts present on that link, it is the only purpose of these addresses. In an IPv4 context, this network area is called the broadcast domain.

Because of that link independence, a link-local address only has to be unique on the link where it exists. It means two different interfaces on the same host could have the exact same link-local address assigned.

Now come the important part, because of all of this, when asking an operating system to establish a communication to a link-local destination, it has no idea what outgoing interface to pick. The destination host could be on any of them. And most of the time, even if there is only a single interface configured with IPv6, operating systems plays dumb and won’t send a packet to a link-local address without a zone id.

So, here comes the zone id, it can be the interface name or the interface index. Even if it is way more explicit to use interface name, some people could prefer to use interface index, it can be easily retrieved with the ip command.

user@computer:~$ 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2001:db8:1::1/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 1763sec preferred_lft 563sec
    inet6 fe80::1/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2001:db8:2::1/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 1763sec preferred_lft 563sec
    inet6 fe80::1/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
user@computer:~$

The index number is the number printed just before the interface name:

user@computer:~$ ip -6 address
1: lo ...
2: eth0 ...
3: eth1 ...
user@computer:~$

Now that we know that a zone id is needed to use a link-local address, a way to use it is needed. The representation of that combination is standardized and looks like this:
<address>%<zone_id>.

By using data coming out of the ip command output, here comes some examples to target the host fe80::25 through the interface eth0:

fe80::25%eth0
fe80::25%2

Both example are valid and have exactly the same meaning, except the first one uses the interface name and the second uses the interface index.

Uniform Resource Identifier (URI)

An Uniform Resource Identifier is a standardized and really powerful way to represent structured information about a resource. Because an IPv6 contains colons in its representation and the colons is used by URI to separate the host part from the port part, URI like this could be ambiguous:

https://2001:db8::7:80

Is 80 the port number? or the last hextet of the IPv6 address ? Answer: None of that, in this case the address will be interpreted as a host name, not like an IPv6 address.

To represent an IPv6, the solution proposed is to surround it with brackets:

https://[2001:db8::7]:80

In this case, it becomes clear that 80 is the port number, and the IPv6 is correctly interpreted.

Now an issue may occur when representing a Link-Local address inside an URI. The % character used to separate the address from the zone id my need to be encoded. So sometime this works:

https://[fe80::1%eth0]:80

But sometimes it does not. Because the % character is used by percent-encoded octets. So the % character needs to be encoded, and because its hexadecimal ascii number is 25, the result is %25. The following becomes correct:

https://[fe80::1%25eth0]:80

Be aware that Link-Local addresses are badly supported by URI parsers and sometime it is just not possible at all to use Link-Local addresses.

Here is a summary of the possible representations:

ProtocolCommand
IPv4https://192.168.1.1:80
IPv6https://[2001:db8::7]:80
IPv6 LLAhttps://[fe80::1%eth0]:80
IPv6 LLA with % encoded https://[fe80::1%25eth0]:80

Operation tools

OpenSSH

Version

OpenSSH_8.2p1 Ubuntu-4ubuntu0.1, OpenSSL 1.1.1f 31 Mar 2020

Connection to a SSH server

In this case, brackets are NOT needed, and it does not work at all with them.

ProtocolCommand
IPv4ssh admin@192.168.1.1
IPv6ssh admin@2001:db8::1
IPv6 LLAssh admin@fe80::1%eth0
IPv6 hostnamessh -6 admin@target

Port redirection

The following example use Local port redirection and argument -L. But the syntax is exactly the same for Remote port redirection using argument -R.

ProtocolCommand
IPv4ssh -L 8080:192.168.1.1:80 distant_host
IPv6ssh -L 8080:[2001:db8::1]:80 distant_host
IPv6 LLAssh -L 8080:[fe80::1%eth0]:80 distant_host
IPv6 hostnamessh -6 -L 8080:[target_host]:80 distant_host
(partial support)

A small explanation about the IPv6 choice over a hostname. SSH allows to pick the version of the Internet protocol used between the current host and the distant host. But there is no way to force the distant host to pick IPv6 or IPv4 to connect the target host.

SCP

ProtocolCommand
IPv4scp user@192.168.1.1:/distant/path /local/path
IPv6scp user@[2001:db8::1]:/distant/path /local/path
IPv6 LLAscp user@[fe80::1%eth0]:/distant/path /local/path
IPv6 hostnamescp -6 user@target:/distant/path /local/path

SFTP

ProtocolCommand
IPv4sftp user@192.168.1.1
IPv6sftp user@[2001:db8::1]
IPv6 LLAsftp user@[fe80::1%eth0]
IPv6 hostnamesftp -6 user@target

Telnet

Version

basic telnet client 0.17

Connection to a host

ProtocolCommand
IPv4telnet 192.168.1.1
IPv6telnet 2001:db8::1
IPv6 LLAtelnet fe80::1%eth0
IPv6 hostnametelnet -6 target

Wget

Version

GNU Wget 1.20.3 built on linux-gnu.

Connection to a server

ProtocolCommand
IPv4wget http://192.168.1.1
IPv6wget http://[2001:db8::1]
IPv6 LLAnot supported
IPv6 hostnamewget -6 http://target

Apparently this lack of support for link-local address family is a known bug since a while. It should be resolved in future releases of wget.

Curl

Version

curl 7.68.0 (x86_64-pc-linux-gnu)

Connecting to a server

ProtocolCommand
IPv4curl http://192.168.1.1
IPv6curl http://[2001:db8::1]
IPv6 LLAcurl http://[fe80::1%enp0s31f6]
IPv6 hostnamecurl -6 http://target

Configuration tools

IP

This command allow to do a lot of stuff, from listing stats about interfaces to add routes inside routing table. It is not possible to list every possible actions. For most of them, it is not needed to specify to work with IPv4 or IPv6, the tool infers it depending the action.

Version

ip utility, iproute2-ss200127

Listing addresses assigned to each interface

ProtocolCommand
IPv4+IPv6ip address
IPv4ip -4 address
IPv6ip -6 address

The keyword address is a sub command of ip, it does not need to be replaced with a IPv4 ou IPv6 address.

UFW

Version

ufw 0.36

Allowing port tcp 456

ProtocolCommand
IPv4 + IPv6 (simplified)ufw allow 456/tcp
IPv4 + IPv6 (advanced)ufw allow proto tcp from any to any port 456
IPv4 onlyufw allow proto tcp from 0.0.0.0/0 to any port 456
IPv6 onlyufw allow proto tcp from ::/0 to any port 456

Diagnostic tools

Ping

Version

ping from iputils s20190709

Unicast

ProtocolCommand
IPv4ping 192.168.1.1
IPv6ping 2001:db8::1
IPv6 LLAping fe80::1%eth0
IPv6 hostnameping -6 target

Multicast

ProtocolCommand
IPv4ping -I 192.168.1.2 224.0.0.1
IPv6ping -I 2001:db8::1 ff02::1%eth0
(with 2001:db8::1, the address assigned on the outgoing interface eth0)
IPv6 LLAping ff02::1%eth0

Nmap

While nmap was really useful to discover hosts inside an IPv4 network, it is less interesting with IPv6 network. Indeed, an IPv6 subnet has way too many hosts to ping them all. (around 18 * 10^18 addresses to scan for a /64 subnet) To find IPv6 hosts, the simplest way is to send echo request to a multicast destination address called allnodes: ff02::1. It is possible to do it either with the ping command or with nmap nse script.

But even without host discovery, nmap stays a powerful tool to make other scans like the port scan or the version scan.

Version

Nmap 7.80 ( https://nmap.org ) at 2020-11-03 10:38 CET

TCP Syn port scan

ProtocolCommand
IPv4nmap -sS 192.168.1.1
IPv6nmap -6 -sS 2001:db8::1
IPv6 LLAnmap -6 -sS fe80::1%eth0
IPv6 hostnamenmap -6 target

Dig

There are two IP settings with Dig. The first setting specifies to talk to a DNS server through IPv4 or IPv6. And the second setting specifies to retrieve an IPv4 record or an IPv6 record.

Version

DiG 9.16.1-Ubuntu

Retrieving an IPv4 record (type A)

ProtocolCommand
IPv4dig @192.168.1.1 google.com A
IPv6dig @2001:db8::1 google.com A
IPv6 LLAdig @fe80::1%eth0 google.com A
IPv6 hostnamedig -6 @dns.google google.com A

Retrieving an IPv6 record (type AAAA)

ProtocolCommand
IPv4dig @192.168.1.1 google.com AAAA
IPv6dig @2001:db8::1 google.com AAAA
IPv6 LLAdig @fe80::1%eth0 google.com AAAA
IPv6 hostnamedig -6 @dns.google google.com AAAA

Netstat

Version

net-tools 2.10-alpha

Listing every TCP and UDP sockets

user@computer:~$ netstat -tunaW6
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp6       0      0 :::22                   :::*                    LISTEN     
tcp6       0      0 ::1:631                 :::*                    LISTEN     
tcp6       0      0 2001:db8::1:35160       2001:db8::2:443         ESTABLISHED
tcp6       0      0 2001:db8::1:56840       2001:db8::2:443         ESTABLISHED
udp6       0      0 :::45936                :::*                               
udp6       0      0 :::5353                 :::*                               
user@computer:~$

Two more arguments than usual need to be added. The argument -6 to specify to only output IPv6 information. And the argument -W to specify wide ouput, without that one, IPv6 addresses are truncated.

SS

Version

ss utility, iproute2-ss200127

Listing every TCP and UDP sockets

user@computer:~$ ss -tuna6
Netid  State      Recv-Q  Send-Q  Local Address:Port  Peer Address:Port  Process
udp    UNCONN     0       0       [::]:45936          [::]:*
udp    UNCONN     0       0       [::]:5353           [::]:*
tcp    LISTEN     0       128     [::]:22             [::]:*
tcp    LISTEN     0       5       [::1]:631           [::]:*
tcp    ESTAB      0       0       [2001:db8::1]:35160 [2001:db8::2]:443
tcp    ESTAB      0       0       [2001:db8::1]:56840 [2001:db8::2]:443
user@computer:~$

Only one more argument is needed with ss to only show IPv6: -6

TCPDump

Version

tcpdump version 4.9.3

Listening port 443

The IPv6 keyword for TCPDump is ip6. If no network protocol is specified, TCPDump captures both IPv4 and IPv6 packets. Here are example about capturing packet at destination to https servers:

ProtocolCommand
Both IPv4 and IPv6tcpdump -n -i eth0 "tcp dst port 443"
IPv4 onlytcpdump -n -i eth0 "ip and tcp dst port 443"
IPv6 onlytcpdump -n -i eth0 "ip6 and tcp dst port 443"

IPerf

Version

iperf version 2.0.13 (21 Jan 2019) pthreads

Server side

ProtocolCommand
IPv4iperf -s
IPv4 + IPv6iperf -s -V

Client side

ProtocolCommand
IPv4iperf -c 192.168.1.1
IPv6iperf -V -c 2001:db8::1
IPv6 LLAiperf -V -c fe80::1%eth0
IPv6 hostnameiperf -V -c target

IPerf3

Version

iperf 3.7 (cJSON 1.5.2)

Server side

ProtocolCommand
IPv4iperf3 -s -4
IPv6iperf3 -s -6
IPv4 + IPv6iperf3 -s

Client side

ProtocolCommand
IPv4iperf3 -c 192.168.1.10
IPv6iperf3 -c 2001:db8::1
IPv6 LLAiperf3 -c fe80::1%eth0
IPv6 hostnameiperf3 -6 -c target

Route tracing tools

Route tracing tools only have interest if a flow goes through at least one router. Packets with link-local address as destination should never goes through a single router. So studying this address family with these tool is not really relevant.

But even so, by only using ICMP echo requests, some of these tools are able to work with link-local addresses.

Traceroute

Version

Modern traceroute for Linux, version 2.1.0

Trace

ProtocolCommand
IPv4traceroute 203.0.113.1
IPv6traceroute 2001:db8::1
IPv6 LLAtraceroute -I fe80::1%eth0
IPv6 hostnametraceroute -6 target

Argument -I allows to use ICMP echo request in place of ICMP destination unreachable.

Traceroute6

Version

traceroute6: TCP & UDP IPv6 traceroute tool 1.0.4 ($Rev$)

Trace

ProtocolCommand
IPv4not supported
IPv6traceroute6 2001:db8::1
IPv6 LLAtraceroute6 -I fe80::1%eth0
IPv6 hostnametraceroute6 target

Argument -I allows to use ICMP echo request in place of ICMP destination unreachable.

My TraceRoute (MTR)

Version

mtr 0.93

Trace

ProtocolCommand
IPv4mtr 203.0.113.1
IPv6mtr 2001:db8::1
IPv6 LLAnot supported
IPv6 hostnamemtr -6 target

Paris traceroute

Version

version 1.0

Trace

ProtocolCommand
IPv4paris-traceroute --max-undiscovered=30 203.0.113.1
IPv6paris-traceroute --max-undiscovered=30 2001:db8::1
IPv6 LLAnot supported
IPv6 hostnameparis-traceroute -6 --max-undiscovered=30 target

Browsers

Firefox

Version

82.0 (64-bit)

Connexion to a website

ProtocolCommand
IPv4https://192.168.1.1:1234
IPv6https://[2001:db8::1]:1234
IPv6 LLAnot supported
IPv6 hostnamenot supported

Chromium

Version

83.0.4103.116

Connexion to a website

ProtocolCommand
IPv4https://192.168.1.1:1234
IPv6https://[2001:db8::1]:1234
IPv6 LLAnot supported
IPv6 hostnamenot supported

Safari

Version

Version 14.0 (15610.1.28.1.9, 15610)

Connexion to a website

ProtocolCommand
IPv4https://192.168.1.1:1234
IPv6https://[2001:db8::1]:1234
IPv6 LLAnot supported
IPv6 hostnamenot supported

Tools not tested

NMCli

The purpose of this tool is to configure anything related to networking on Linux, it was not possible to find relevant example. But be sure it manages IPv6 as well as IPv4.

Speedtest-cli

This tool does not support IPv6 and does not seem to be maintained anymore.

Dublin traceroute

This tool does not support IPv6.

A short story that happened to me the other day:
A faulty home router decided to only assigned Link-Local addresses on its network interfaces, its IPv4 stack stopped working for unknown reason. The only way to access its configuration was through a web page. How to proceed with no browser managing Link-Local addresses in their URI parser ?

Solution: SSH port forwarding

This solution consists of creating a ssh local port redirection similar to this:

ssh -N -L '8080:[fe80::25%eth0]:80' localhost

With fe80::25 being the link local address of the target reachable through the network interface eth0.
This will open the port 8080 on the localhost, and any connexion attempt on that port will be forwarded to the port 80 on the target.

Now the target is reachable through the loopback address on the port 8080. It just needs to open the following URL inside any browser:

http://[::1]:8080

Be aware that this solution have limitation. The address ::1 is sent to the target in the HTTP Header called host. Some HTTP server won’t allow to receive that value ans will reset the connection. Still, it is possible to trick the HTTP server by changing the header on the fly. Some extension like this one allow to do this.

Summary

ToolsLLA supportDoes it need Brackets ?Argument to Enable IPv6 supportArgument to force hostname resolution to IPv6
sshyesno-6
ssh port redirectionyesyes-6
scpyesyes-6
sftpyesyes-6
telnetyesno-6
wgetnoyes-6
curlyesyes-6
ip-6
ufw
pingyesno-6
nmapyesno-6-6
digyesno-6
netstat-W -6
ss-6
tcpdumpip6
iperfyesno-V-V
iperf3yesno-6-6
tracerouteyesno-6
traceroute6yesno
mtrnono-6
Paris Traceroutenono-6
Fiirefoxnoyes
Chromiumnoyes
Safarinoyes

Conclusion

To conclude, here is a list of things to keep in mind while using IPv6 with that kind of tool:

  • try IPv6 addresses with or without brackets
  • while using link-local address, a scope id must always be provided
  • the separation character between a link-local address and a scope id is almost always %, I have never observed %25 being used, but keep it in mind, it could appear in some places.
  • An extra argument is almost always needed to force a tool to use the IPv6 address when resolving a FQDN or a hostname. Most of the time the argument to use is -6.
  • Link-Local addresses may not be supported by some applications
  • If a service is only reachable through its link-local address and over HTTP, try SSH port forwarding to access it

Even if link-local addresses may be really useful, the biggest limitations occurred while using them. We could just hope improvement will come over time.

Sources

1 Comment

  1. Nice article, nice blog, great! Thanks for sharing!

    Reply

Leave a Reply to AndréCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.