Originally published by myself on humbledown.org at Thu Feb 3 17:49:38 NZDT 2011
and since recovered to this location. It has not been tested since its original publication.There is a common desire, often derived from security requirements, to find out what IPv6 addresses are being used on the network, and who has them. Granted, many IPv6 host addresses can have their MAC address either inferred from the address itself, this is assuming the address is a SLAAC address, and not manually assigned, privacy address, or assigned by a stateful mechanism (ie. DHCPv6).
To take an IPv4 analog of the problem, let's say that we wanted to determine a table of mappings of MAC addresses, IP addresses, and perhaps the time at which that binding was valid. The easiest way to do this for address assignments managed via DHCP is to look at your DHCP server's leases file. In an IPv6 context, we could do exactly the same thing... or rather, we could, if only all clients used stateful assignment, and not all clients support DHCPv6 (at least by default) at this time.
SLAAC clients don't generate a "lease", in the IPv4 DHCP sence of the word. There is no "SLAAC server" that SLAAC clients report to. However, that's not to say that no traffic is generated. As part of the SLAAC process, every generated address has to go through the Duplicate Address Detection (DAD) process, which we can listen for using tools such as tcpdump.
You can't rely on listening for Router Solicitations, because not all clients might send out such a request, or they might wait a while before sending a RS. Though, to be honest, I'm not sure how common this is. But, listening in on DAD is more reliable.
This post describes a suitable PCAP expression that can be used for finding the Neighbour Discovery packets that are part of the DAD process, and finishes up with some discussion about what could be done later with them.
Listen to the networking using a PCAP expression such as the following to listen for neighbour advertisements. Here I'm looking for DADs regarding addresses inside the prefix 2001:470:d:b88/64. You would also get DADs for link-local fec0::/10 addresses, but I'm not particularly interested in those.
$ tcpdump -n -s0 -v -i eth0 -e -x ' > icmp6 ① > and (src host ::) ② > and (ip6[40+0] == 135) ③ > and (ip6[0x30:4] == 0x20010470 and ip6[0x30+4:4] == 0x000d0b88) ④ > '
- DAD messages are ICMPv6
- DAD messages are Neighbour Solicitation (NS) messages sent from ::, because the address being tested for is tentative, thus cannot be used as a source address.
- Neigbour Solicitation messages have ICMPv6 type number 135.
- If you use the -x option to tcpdump, you will see that the address being queried for is located at 0x30 (decimal 48) bytes into the ICMPv6 header. TCPdump allows us to to select 1, 2 or 4 bytes (:4 == 4 bytes) to compare. We want to match a prefix of /64, so we need to compare 8 bytes, or two sets of four bytes. You'll need to change this to suit the prefix(es) that you want. Note that this specific filter is not configured to report link-local addresses.
Parse the output according to your needs. You may also like to make stdout line buffered (tcpdump's -l option) if you want to process the results into some other tool, such as the shell's pipe (tcpdump ... | ...) or Perl's open() function (open TCPDUMP, '-|', "tcpdump ...").
You may like to extract the Source MAC address, and take note of the time. You could use this for determining:
- Which machines had which IPv6 address at which time. This could be particularly useful if you want/need to track privacy addresses on the local link.
- Which machines are operating IPv6 on the network (useful when they shouldn't). Because you now have the MAC (which in most cases you could infer from the address anyway), you can now track it down based on your inventory management records.
- DAD will be used for every unicast address used as a source address. By comparing that number from those that consult a DHCPv6 server, you could determine how many clients support DHCPv6 when the Router Advertisement (RA) has the Managed or Other flag set.
- You could, in theory, see which nodes DAD for a link-local address, but don't DAD for any other global addresses. Such nodes are probably routers. You could also detect IPv6 routers by looking for hosts which join the ip6-allrouters multicast group (ff02::2)