Skip to main content

[Humbledown highlights] Finding IPv6 Addresses Derived from SLAAC

Originally published by myself on 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) ④
>   '
  1. DAD messages are ICMPv6
  2. 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.
  3. Neigbour Solicitation messages have ICMPv6 type number 135.
  4. 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.
More info on using TCPDump with ICMPv6 is on my post Capturing Particular ICMPv6 Packets using TCPdump.

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)
This should work for SLAAC addresses, manually assigned addresses, "temporary" privacy addresses, and basically any unicast global address.


Popular posts from this blog

Use IPTables NOTRACK to implement stateless rules and reduce packet loss.

I recently struck a performance problem with a high-volume Linux DNS server and found a very satisfying way to overcome it. This post is not about DNS specifically, but useful also to services with a high rate of connections/sessions (UDP or TCP), but it is especially useful for UDP-based traffic, as the stateful firewall doesn't really buy you much with UDP. It is also applicable to services such as HTTP/HTTPS or anything where you have a lot of connections...

We observed times when DNS would not respond, but retrying very soon after would generally work. For TCP, you may find that you get a a connection timeout (or possibly a connection reset? I haven't checked that recently).

Observing logs, you might the following in kernel logs:
kernel: nf_conntrack: table full, dropping packet. You might be inclined to increase net.netfilter.nf_conntrack_max and net.nf_conntrack_max, but a better response might be found by looking at what is actually taking up those entries in your conne…

ORA-12170: TNS:Connect timeout — resolved

If you're dealing with Oracle clients, you may be familiar with the error message
ERROR ORA-12170: TNS:Connect timed out occurred I was recently asked to investigate such a problem where an application server was having trouble talking to a database server. This issue was blocking progress on a number of projects in our development environment, and our developers' agile post-it note progress note board had a red post-it saying 'Waiting for Cameron', so I thought I should promote it to the front of my rather long list of things I needed to do... it probably also helped that the problem domain was rather interesting to me, and so it ended being a late-night productivity session where I wasn't interrupted and my experimentation wouldn't disrupt others. I think my colleagues are still getting used to seeing email from me at the wee hours of the morning.

This can masquerade as a number of other error strings as well. Here's what you might see in the sqlnet.log f…

Getting MySQL server to run with SSL

I needed to get an old version of MySQL server running with SSL. Thankfully, that support has been there for a long time, although on my previous try I found it rather frustrating and gave it over for some other job that needed doing.

If securing client connections to a database server is a non-negotiable requirement, I would suggest that MySQL is perhaps a poor-fit and other options, such as PostgreSQL -- according to common web-consensus and my interactions with developers would suggest -- should be first considered. While MySQL can do SSL connections, it does so in a rather poor way that leaves much to be desired.

UPDATED 2014-04-28 for MySQL 5.0 (on ancient Debian Etch).

Here is the fast guide to getting SSL on MySQL server. I'm doing this on a Debian 7 ("Wheezy") server. To complete things, I'll test connectivity from a 5.1 client as well as a reasonably up-to-date MySQL Workbench 5.2 CE, plus a Python 2.6 client; just to see what sort of pain awaits.

UPDATE: 2014-0…