Wireshark can decode and filter IPv6 packets, but its real power lies in understanding the nuances of IPv6 addressing and header structures, which often trip up newcomers.

Let’s say we’re capturing traffic on an interface that’s part of an IPv6 network. We see a lot of packets, and we want to isolate just the IPv6 ones.

# On the command line, start tshark (Wireshark's CLI tool)
# capturing on interface eth0 and saving to a file
tshark -i eth0 -w ipv6_capture.pcap

# Then, open ipv6_capture.pcap in Wireshark and apply a display filter
# to see only IPv4 packets
wireshark -r ipv6_capture.p 1 -Y "ipv6"

This filter ipv6 is the simplest way to get just IPv6 packets. But what if we want to see specific types of IPv6 traffic? For example, Multicast Listener Discovery (MLD) messages are crucial for IPv6 multicast operation.

# Filter for MLDv2 reports (type 132)
ipv6.mld.type == 132

This shows us packets where the IPv6 Multicast Listener Discovery type field is set to 132. MLD is how routers learn which multicast group addresses have active listeners on their directly attached links. Without MLD, multicast traffic wouldn’t reach the intended recipients.

Now, let’s dive into what’s actually inside those packets. An IPv6 header is quite different from IPv4. It’s longer (40 bytes vs. 20 bytes) and has a fixed structure, but it also supports extension headers, which are like optional add-ons.

Consider a simple IPv6 packet. The header starts with the Version (always 6), Traffic Class, Flow Label, Payload Length, Next Header, Hop Limit, Source Address, and Destination Address.

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| Traffic Class |           Flow Label                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Payload Length        |  Next Header  |   Hops Left   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                         Source Address                        |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                      Destination Address                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The Next Header field is critical. It tells Wireshark what type of header comes after the current IPv6 header. If it’s 59 (No Next Header), then the current header is the last one. If it’s 43 (Fragment Header), 60 (Hop-by-Hop Options), 44 (Routing Header), 43 (Fragment Header), 51 (Authentication Header), or 50 (Encapsulating Security Payload), Wireshark knows to parse those extension headers before looking for the actual transport layer protocol (like TCP or UDP).

Let’s look at a packet with a Routing Header. We can filter for it:

# Filter for packets with a Routing Header (Next Header ID 43)
ipv6.ext.routing

When you expand the IPv6 details in Wireshark, you’ll see the Next Header field. If it indicates an extension header, Wireshark will show that extension header as a separate section. For a Routing Header, you’ll see fields like Routing Type and a list of Address fields, which are the intermediate nodes the packet should visit.

The sheer number of possible IPv6 addresses is astronomical (2^128). This means that simply looking at source and destination addresses isn’t always enough. Subnetting and scope are crucial. Global Unicast Addresses (GUCs) are routable on the internet, while Link-Local Addresses (LLAs) are only valid on the local network segment. LLAs always start with fe80::.

# Filter for packets using Link-Local Source Addresses
ipv6.src == fe80::/10

When troubleshooting, you might see a packet that seems to disappear. Often, this is because it’s using a Link-Local Address, and the router or intermediate device doesn’t have a fe80:: address on the next hop interface to forward it to. The fe80:: address is scope-limited to the link.

One common point of confusion is how IPv6 handles fragmentation. Unlike IPv4, where routers can fragment packets, in IPv6, only the source host can fragment a packet. If a router encounters an IPv6 packet that’s too large for the next link, it will drop the packet and send an ICMPv6 "Packet Too Big" message back to the source.

# Filter for ICMPv6 Packet Too Big messages
icmpv6.type == 2

This means you won’t see intermediate routers fragmenting packets in your Wireshark capture. If you see icmpv6.type == 2, it’s a strong indicator of a Path MTU Discovery issue, where the source isn’t aware of the smallest MTU along the path to the destination. The fix usually involves ensuring the Do Not Fragment (DF) bit is set correctly in the IPv4 equivalent (though IPv6 has no DF bit, the behavior is similar) or adjusting MTU settings on the source host or intermediate devices.

The next hurdle you’ll likely encounter is understanding the various ICMPv6 message types beyond "Packet Too Big," especially Neighbor Discovery Protocol (NDP) messages like Router Advertisements, Router Solicitations, Neighbor Advertisements, Neighbor Solicitations, and Redirects.

Want structured learning?

Take the full Wireshark course →