Hi everybody,
This post is meant to provide an overview of basic IPv6 troubleshooting approaches and commands, for three main operating systems: Windows, Linux & macOS. For these OSs (and some specific tasks only) it includes an updated version of the “IPv6 Rosetta Stone”, a website I often refer IPv6 beginners to in order to identify OS-specific flavors of relevant commands, but which is a bit outdated as of today.
I will also include some background explanations about the output of the commands and on IPv6 intricacies in general. Please note that – in contrast to some other pieces I’ve written – this one is supposed to be primarily for IPv6 rookies. I’d like to add further that, while I can somewhat work with all three OSs covered here, I don’t consider myself an expert in any of them, so there might be better ways of performing certain actions. Happy to learn about them via comments or other communication means (Twitter comes to mind…).
Determining the IPv6 Address Configuration of an Interface
Windows. I’m not aware of a simple way of using ‘ipconfig’ to display only a specific interface, but in general it’s the fastest way of looking at the main parameters of an adapter, like:
Connection-specific DNS Suffix . : hsd1.ca.comcast.net
IPv6 Address. . . . . . . . . . . : 2601:647:5b80:b60::d9cd
IPv6 Address. . . . . . . . . . . : 2601:647:5b80:b60:c165:b052:45b5:2d70
Temporary IPv6 Address. . . . . . : 2601:647:5b80:b60:6d58:d895:de31:494e
Link-local IPv6 Address . . . . . : fe80::c165:b052:45b5:2d70%17
IPv4 Address. . . . . . . . . . . : 10.0.0.193
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 10.0.0.1
On Linux I prefer using ‘ip -6’ over using ‘ifconfig’ and the most efficient way for a specific interface probably looks like this (the ‘a s’ abbreviates ‘address show’ and ‘wlp2s0’ is a specific interface):
enno@labbook$ ip -6 a s wlp2s0
wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 2601:647:5b80:b60::b8d0/128 scope global dynamic noprefixroute valid_lft 604678sec preferred_lft 604678sec
inet6 2601:647:5b80:b60:d003:344b:61ea:1da1/64 scope global temporary dynamic valid_lft 3582sec preferred_lft 3582sec
inet6 2601:647:5b80:b60:e7d5:f51b:f500:33cb/64 scope global dynamic mngtmpaddr noprefixroute valid_lft 3582sec preferred_lft 3582sec
inet6 fe80::edf9:e52e:686e:62b2/64 scope link noprefixroute valid_lft forever preferred_lft forever
On macOS I like to use ‘ifconfig en0 inet6’ (where ‘en0’ is a specific interface and the ‘-L’ option can be used to display the lifetimes):
bash-3.2$ ifconfig -L en0 inet6
en0: flags=8863 mtu 1500
inet6 fe80::474:2318:f169:b89%en0 prefixlen 64 secured scopeid 0xa
inet6 2601:647:5b80:b60:1086:2305:87bd:448b prefixlen 64 autoconf secured pltime 3599 vltime 3599
inet6 2601:647:5b80:b60:75e4:235e:b46c:d2e7 prefixlen 64 autoconf temporary pltime 3599 vltime 3599
inet6 2601:647:5b80:b60::18ba prefixlen 64 dynamic pltime 591997 vltime 591997
nd6 options=201<PERMORMNUD,DAD>
Let’s have a joint look at the above output from the three sample systems which are all in the same network. Alas, from an analysis perspective this is a bit complex one (but mostly the only one I had at hand when writing this; it’s my Comcast-provided home network). We can see that in each output there’s the so-called link-local address which always exists on an IPv6-enabled interface and which is used only for communication within the segment (e.g. within a VLAN). It always starts with a ‘fe80’ and usually it can’t/shouldn’t be manually configured. Furthermore each interface has three global unicast addresses (‘GUAs’). This is the result of a certain configuration approach for this particular network which can be described as follows, from the operator’s perspective:
– use DHCPv6 to both provide an address (the one with the ‘short’ interface identifier) from the prefix 2601:647:5b80:b60::/64 and to provide two DNS resolvers (as the later analysis of DHCPv6 packets will show).
– in addition the router advertisement contains a ‘prefix option’ (which they usually do, by default) and the announced prefix is actually used for address configuration (as the ‘a’ flag within the prefix option is set which again is the common default). They also contain both DNS resolvers in a specific option (‘number 25’).
For IPv6 aficionados here’s the RA itself (in Wireshark output, PCAP on request):

This configuration was probably chosen to support both Android devices (which don’t support DHCPv6) and Windows versions before Win 10 Creators Update (as older versions can only learn IPv6 DNS resolvers by means of DHCPv6, see also this post) in the same (home) network. For IPv6 pros: I have no idea why they do managed DHCPv6 and I don’t think it’s a good choice for this type of networks but this would be subject to another debate/post.
Point is that on all three OSs looked at here this leads to the creation of three global addresses (one from DHCPv6 and, as DHCPv6 and SLAAC can happily co-exist for parameter provisioning, two others from the classic IPv6 [address] auto-configuration approach called ‘stateless address auto-configuration’/SLAAC. One of the latter two is considered to be of a more stable nature and the other is considered a relatively short-lived throw-away address hence called ‘temporary address’ which is primarily to be used for outbound connections like web surfing from a browser). For an IPv6 beginner it might be difficult to spot in the above interface config output which one(s) is/are from DHCPv6 and which from SLAAC. In the Linux output the “/128” of the first address gives an indication (for the background one might look at these two posts on the intricacies of DHCPv6), on Windows “netsh int ipv6 sh add” will tell and on macOS the following one can be helpful (but the interpretation of the output might require some understanding of DHCPv6, we’ll get back to this in another post):
bash-3.2$ ipconfig getv6packet en0
DHCPv6 REPLY (7) Transaction ID 0x587c7a Length 151
Options[5] = {
IA_NA (3) Length 66 IA_NA IAID=0 T1=302400 T2=483840 Options[2] = {
IAADDR (5) Length 24 IAADDR 2601:647:5b80:b60::18ba Preferred 604800 Valid=604800
STATUS_CODE (13) Length 22 STATUS_CODE Success (0) ‘Assigned an address.’
} SERVERID (2) Length 14 DUID LLT HW 1 Time 625146838 Addr 00:50:f1:80:00:00
CLIENTID (1) Length 14 DUID LLT HW 1 Time 620212912 Addr 38:f9:d3:51:a1:e5
PREFERENCE (7) Length 1 Data ff
DNS_SERVERS (23) Length 32 2001:558:feed::1
2001:558:feed::2
}
In any case, from a user’s perspective the (operator-) chosen config approach leads to the fact that there’s three addresses, and it’s not obvious which is one(s) is/are going to be used for actual communication acts.
Also, as a side note, the Windows system (running 10.0.14393) loses all IPv6 configuration (note the absence of the IPv6 default gw below) once the initial lifetime (3600 seconds/1 hour) expires (despite RAs still coming in), but that again (w|sh)ould be subject of another post. Note to self: really an ‘interesting’ (in the Brit sense of the word…) config approach Comcast uses here.
Connection-specific DNS Suffix . : hsd1.ca.comcast.net
IPv6 Address. . . . . . . . . . . : 2601:647:5b80:b60::d9cd
Link-local IPv6 Address . . . . . : fe80::c165:b052:45b5:2d70%17
IPv4 Address. . . . . . . . . . . : 10.0.0.193
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 10.0.0.1
Determining Which Address is Used for Outbound Communication
That’s not an easy task. For the IPv6 beginners among the readers: you can & should safely assume that on all three OSs covered here the ‘temporary address’ is going to be used, *not* the nice short (DHCPv6-provided) one showing up as the first one on Windows and Linux and as the last one on macOS.
On Linux and macOS the following can be done to verify:
– ping an IPv6 address of your choice (e.g. 2620:fe::fe, which is IPv6 address of the resolver[s] of the Quad9 project) from one terminal window. The first line might display the source address being used. Else
– run ‘tcpdump -n host 2620:fe::fe’ in another terminal window (‘-n’ needed to see the actual source address, and address after ‘host’ must, of course, be the same as in 1st terminal window).
Who’s My Router?
Want to find out the IPv6 address of the actual router/default gateway?
Windows: look at “Default Gateway” part of ‘ipconfig’ output of the relevant interface.
Linux: ‘ip -6 r s | grep def’ is what I commonly use (‘r s’ abbreviates ‘route show’):
enno@labbook:$ ip -6 r s | grep def
default via fe80::250:f1ff:fe80:0 dev wlp2s0 proto ra metric 600 pref medium
macOS: ‘netstat -rn inet6 | grep def | grep en0’ (where ‘en0’ is the sample IPv6-enable interface) should give a good indication:
bash-3.2$ netstat -rn inet6 | grep def | grep en0
default 10.0.0.1 UGSc 79 0 en0
default fe80::250:f1ff:fe80:0%en0 UGc en0
Can I Reach It?
Pinging the router is a fairly common troubleshooting step.
Two things to keep in mind here:
– forcing the ping to use IPv6 isn’t strictly necessary on Windows & Linux (for both just ‘ping’ usually works nowadays, else it would be ‘ping6’ on Linux and ‘ping -6’ on Windows), but it is needed on macOS:
bash-3.2$ ping6 fe80::250:f1ff:fe80:0%en0
PING6(56=40+8+8 bytes) fe80::474:3308:f169:b89%en0 –> fe80::250:f1ff:fe80:0%en0
16 bytes from fe80::250:f1ff:fe80:0%en0, icmp_seq=0 hlim=64 time=11.572 ms
– given pinging the default gateway happens within the local subnet (the ‘local link’ as of IPv6 limbo), link-local addresses come into play. As they only have local significance within the context of a specific interface several such ‘contexts’ can exist on one single system (one for each IPv6-enabled interface). To differentiate between the various link-local contexts with their addresses and routing information a thing called zone identifier (defined in RFC 4007) is required. This is the piece behind a link-local address and separated from it by a ‘%’ sign. In most cases you’ll have to include this for link-local operations, like:
Windows (get interface number from ‘route print’ if needed):
E:>ping fe80::250:f1ff:fe80:0%17
Pinging fe80::250:f1ff:fe80:0%17 with 32 bytes of data:
Reply from fe80::250:f1ff:fe80:0%17: time=4ms
Reply from fe80::250:f1ff:fe80:0%17: time=5ms
DNS
This is a particularly interesting one. Point is that DNS is ‘protocol-agnostic’ – a server usually doesn’t care about the L3 protocol (IPv4 or IPv6) transporting an incoming request, so one can perfectly query a DNS server for an AAAA record (containing an IPv6 address) over IPv4. The DNS server in question might not even have IPv6 itself, and/or the client sending the request might not even know IPv6 addresses of any DNS server. Both, namely the latter, are common scenarios as of today (Nov 2019).
Display IPv6 DNS servers used by a system
Windows: perform ‘ipconfig /all’ and look at the bottom part of the section of a respective IPv6-enabled interface.
Linux: on a systemd-controlled system (which my lab system is, it’s an Ubuntu) the following comes to mind (‘wlp2s0’ = IPv6-enabled interface):
enno@labbook:$ resolvectl status | grep -C 15 wlp2s0
[…]
DNSSEC supported: no
Current DNS Server: 75.75.75.75
DNS Servers: 75.75.75.75
75.75.76.76
2001:558:feed::1
2001:558:feed::2
DNS Domain: ~.
hsd1.ca.comcast.net
macOS: probably ‘scutil –dns’ is your most reliable friend here, like in the following (the last ‘grep’ tries to catch only the v6-ones, assuming their addresses will have a double colon somewhere):
bash-3.2$ scutil –dns | grep nameserver | grep “::”
nameserver[0] : 2001:558:feed::1
nameserver[1] : 2001:558:feed::2
nameserver[0] : 2001:558:feed::1
nameserver[1] : 2001:558:feed::2
Ask for ‘AAAA’ record of a name, regardless if query is performed over v4 or v6
Linux & macOS: ‘dig +short AAAA heise.de’
Windows – there’s two options, one with nslookup (which I tend to avoid) and another with the Powershell command ‘resolve-dnsname’:
nslookup -q=aaaa heise.de
resolve-dnsname heise.de -type AAAA
Perform DNS resolution over IPv6, to/with a specific server:
Linux & macOS: ‘dig +short -6 @2001:558:feed::1 AAAA heise.de’ (using Comcast’s DNS), like:
enno@labbook$ dig +short -6 @2001:558:feed::1 AAAA heise.de
2a02:2e0:3fe:1001:302::
Windows:
nslookup -q=aaaa heise.de 2001:558:feed::1
resolve-dnsname heise.de -type AAAA -server 2001:558:feed::1
Summary of Commands Used
The following table provides an overview of the individual commands used in this post. In a potential follow-up I’ll go a bit more in the details of additional commands, and we’ll play with tcpdump. Thanks for reading so far 😉

Asking for a AAAA record on windows is possible using nslookup and then type set type=aaaa before you type your dns query.
LikeLike