184

I am using the .NET Framework classes to get the IP addresses for my machine:

Dns.GetHostAddresses(Dns.GetHostName())

I have a VirtualBox adapter which has both an IPv4 and IPv6 address. Using the .NET code, I am getting the IPv6 address as fe80::71a3:2b00:ddd3:753f%16.

Notice the %16 at the end?

However, if I query the same using WMI, I get the address as fe80::71a3:2b00:ddd3:753f, without the %16.

Does the %16 have any special significance?

Edit:

I just made some more observations about this and they match pretty well with what Stephen Jennings said in his answer.

I installed VMware to see what IPv6 address it issued. The addresses were:

fe80::3dd0:7f8e:57b7:34d5%19

fe80::b059:65f4:e877:c40%20

Clearly, the numbers after % are not some hex representation. I checked all the properties available for a network adapter using WMI and found that the numbers are exactly the same as the InterfaceIndex property of each network adapter. As per MSDN, it uniquely identifies each network adapter and this property was introduced in Vista.

What still confused me was why would the IPAddress class allow you to create an IP address in that format unless it was valid. The answer was provided by Stephen: The number is the scope ID. IPAddress has a constructor that accepts the address AND a scope ID.

Oh, and all these three network adapters were link local. Confirmed it via ipconfig.

Cool. That was interesting!!

4
  • 3
    I had no idea what it was either before you asked. I learned something neat about IPv6 today too (what nerds we are). Commented Jan 23, 2010 at 23:12
  • @Stephen, so have you worked with ipv6 before? I was surpised at quickly you nailed it. I had googled for quite some time before posting the question here. Nice work! Commented Jan 23, 2010 at 23:24
  • Searching "ipv6 address percent" got me the name I needed, and from there searching around and trying to make sense of the confusing technical documentation took the most time. I get what IPv6 is trying to accomplish, but there are a lot of new concepts it has that I haven't gotten around to researching and understanding. This was one, and nothing gives you a better understanding than trying to explain to someone else. Commented Jan 23, 2010 at 23:43
  • An alternative notation might be fe80:10 (the 0x0010 being 16). I use that in my browser when working with link-local IPv6 addresses, but I am not 100% sure this is according to the standards. (Using the percent in URLs is messy in browsers; in fact I could not get that to work at all.)
    – Arjan
    Commented Feb 6, 2011 at 17:49

3 Answers 3

170

The number after the '%' is the scope ID.

IPv6 defines at least three reachability scopes for addresses:

  1. Globally addressable. This is an IPv6 address given to you by your ISP. It is available to use on the public Internet.

  2. Link-local. This is similar to the 169.254.X.X range. It is an address that a computer assigns itself in order to facilitate local communications. These addresses don't get routed around on the public Internet because they're not globally unique.

  3. Node-local. This is an address that identifies the local interface, similar to 127.0.0.1. Basically, this is the address ::1.

Microsoft has published this article describing IPv6 addressing, which is the least-confusing article I found. The article indicates that the presence of a scope ID in your address means it is a link-local address. You can also tell it is link-local because the address begins with fe80.

Clear, simply-understood information on this topic seems to be rare, so I'm putting the rest of this together based on my best understanding of RFC 4007 and the other information out there.

A computer can have multiple link-local addresses, each with a different scope. The scope ID indicates which scope the address is for. For example, imagine the scenario of a computer with two NICs, each with a link-local address on different networks. If you try to send something to another address beginning with fe80, how will the computer know which NIC to send out on? The scope ID appears to be the solution for this.

10
  • Nice answer. Let me see if I fully understood that. So a device with two NICs may connect to two different routers, and get assigned the very same DHCP address fe80::42. Also, the routers have the same address fe80::1. Now the fe80::1%X may be used to differentiate between the routers, but fe80::42%X is of minor use to the client, right? Commented Nov 27, 2012 at 8:27
  • 2
    @Pumbaa80 The client would send messages to fe80::1%1 to reach the router connected to NIC #1, and it would send messages to fe80::1%2 to reach the router connected to NIC #2. As an aside, Link-local addresses are configured automatically by the host computer, not via DHCP, so it probably wouldn't assign its two NICs the same IP. Also keep in mind that link-local addresses are not routable, so usually you won't be sending messages to a router, you'll be sending messages between two hosts. Commented Nov 28, 2012 at 6:33
  • by experimentation, it seems the trailing %nn can be omitted for at least some commands, e.g. ping, tracert. Commented Dec 30, 2012 at 5:23
  • 2
    But if IPv6 needs a scope ID, how does IPv4 work? It doesn't have scope ID. I wish the answers would address this.
    – Jez
    Commented Apr 24, 2020 at 7:28
  • 1
    @MatthiasBraun It’s to identify which of your link-local addresses should be used as the “from” address in the IPv6 header. Your computer assigns itself a scope ID when it chooses a link-local address, and then all routing table entries in your computer reference that scope ID to indicate which link-local address they’re for. Commented Nov 6, 2022 at 21:21
38

IPv6 addresses with the prefix fe80::/64 are link-local addresses that are constructed by combining that prefix with the hardware address of the network device, 71a3:2b00:ddd3:753f in your example. (The analog in IPv4 is 169.254.0.0/16.) Since the prefix is the same for all link-local addresses on a machine, routing might sometimes need to know which interface you are referring to. And that is what the number after the percent, called the zone index, specifies. Specifics depend on the operating system: On Windows, %16 is interface number 16; on Linux for example you might see something like %eth0.

Some tools or APIs will consider this zone index unimportant or implicit for their purposes. For example, on Linux the ifconfig tool doesn't show it because it is obvious which interface an address belongs to. But in general it should be taken into account.

1
  • Ahhh, so the value behind the % is the interface ID of the network adaptor, thx for this info
    – Radon8472
    Commented Aug 2, 2022 at 11:31
38

The characters after the % (which happen to be numbers in your example) are the "zone ID". (The "zone ID" is text that identifies which helps identify which network card to use. It may look like the name of a network card, or just be a number.)

Those characters are used to identify a "network interface", which people often call a "network card". For instance, it can help to determine whether a packet will be using a wired Ethernet card or a wireless Wi-Fi adapter.

I'm guessing that you're using Microsoft Windows. It uses numbers as the zone IDs. While Microsoft's documentation indicates different types of zone IDs (which I discuss later in this answer), for a link-local address (in fe80::/64), the “zone ID” is an “interface index” of a network card.

As a point in comparison, Unix-like systems may use letters after the % sign. e.g.: fe80::71a3:2b00:ddd3:753f%eth0

In that case, the zone ID, eth0, matches the name that the operating system typically uses to identify the network card.

In Microsoft Windows, you can get a list of the (numeric) zone IDs by using one of the command lines that check the routing table. I prefer "netstat -nr" since that also works on other operating systems, but Microsoft Windows also supports "route print". The resulting output, which gets reported, will likely be over a screen long, so be prepared to scroll back, unless you pipe to more.

e.g., on my system:

=========================================================================== Interface List 14...5c f9 dd 6d 98 b8 ......Realtek PCIe GBE Family Controller 12...e0 06 e6 7e fc 4e ......Bluetooth Device (Personal Area Network) 1...........................Software Loopback Interface 1 13...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter 15...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter #2 ===========================================================================

In this case, an address like fe80::71a3:2b00:ddd3:753f%14 would refer to the network card related to "zone ID" 14, which happens to be my Realtek PCIe GBE Family Controller. (The "GBE" refers to Gigabit Ethernet.)

(You can also see these “interface index” values, used by many Microsoft Windows versions, with something like: “WMIC NICCONFIG GET Caption,InterfaceIndex,IPAddress /FORMAT:LIST”. People trying that in PowerShell should remember to use back-quotes before each comma.)

Now, here's the tricky part: If you want to ping a remote address, you may need to use the remote system's IPv6 address, but the local system's “zone ID”. So, for example, if I am using Computer A and I have a local IPv6 address of fe80::1 attached to Interface number 14, and I want to ping Computer B and it has a local IPv6 address of fe80::2 attached to its Interface number 16, then this is what I would use:

ping fe80::2%14

So the ping command will send the ICMPv6 packet to the remote IPv6 address (fe80::2), which belongs to the remote computer, and will use the Interface zone ID 14 to do it. The zone ID 14 is a number from the system I'm using, not the remote system. So the remote system's address, and the specified zone ID, are coming from different computers.

Now, let's look at why this might be necessary.

If I want to ping Google's IPv6 address (which is 2607:f8b0:400a:802::200e at the time I wrote this answer), then the routing table will check which network card handles addresses that start with 2607:f8b0:400a:802. The routing table will indicate that none of my network cards are connected directly to a network using addresses that start with 2607:f8b0:400a:802, so my computer will end up using a "gateway" address. If I was connecting to another network that is part of the organization I'm working for, I might have a special "gateway" address that routes traffic to a private network. In this case, I don't have a more specific gateway, so I will use the IPv6 "default gateway". That is how IPv6 works most of the time, except for link-local addresses. This is also how IPv4 worked most of the time. (I did simplify this example by assuming an IPv6 subnet size of /64, since describing the whole process would have made this description even longer.)

According to RFC 4291 section 2.8, every computer using IPv6 should assign a link-local address to every network interface. RFC 4291 section 2.5.6 shows the bits that link-local addresses must start with, which cause the link-local addresses to start with "fe80:0000:0000:0000:" (although many of those zeros get collapsed to a double colon). The fact that those addresses start with "fe80:" is also described by RFC 4291 section 2.4.

If you try to ping a remote system (e.g., "2607:f8b0:400a:802"), the general process is usually to figure out a network or subnet that the address is a part of, which is done by looking at the bits at the start of the address. Then, those bits are used to determine how to route the traffic.

However, that process doesn't work for an IPv6 link-local address, because every single (operational, active) network interface has a link-local address starting with "fe80:" on a subnet using the subnet prefix/size of "/64". If you are on a laptop, you are likely to find that both your Ethernet card and your Wi-Fi adapter are expected to have such an IPv6 address.

Now, when you send your ping to fe80::2, you want your computer to send that packet out the right network card. If you have a printer that is connected to a wired network, you don't want to send the traffic out your Wi-Fi card, using a network path/route that won't result in the traffic getting to the printer. And if you are trying to communicate to a wireless device using your Wi-Fi card, you don't want your traffic to go out the Ethernet card.

The solution is to have you specify which network device you want the traffic to use. So, that is the purpose of the zone ID.

Answer Updates:

  • The original version of this answer (which happened to be a rather highly-rated answer out of the ones I provided) initially used the term "interface identifier" instead of "zone ID".
    • I think that the term “interface identifier” was simply a term that I had personally made up, and was based on the term “interface index”, which is used by Microsoft Windows to identify a specific network card. However, the term “interface ID” turned out to be a choice that was less than ideal, since IETF RFC documents have used that term for something else:
      • RFC 1884: “IP Version 6 Addressing Architecture” uses that phrase for some bits at the end of an IPv6 address. (The number of bits seemed to vary in some different examples, but this identifier was typically based on the MAC-48 address of a network card.)
      • RFC 5453: Reserved IPv6 Interface Identifiers says (early on), “An IPv6 unicast address is composed of two parts: a subnet prefix and an interface identifier (IID) that identifies a unique interface within the subnet prefix.”
    • The term “zone ID” comes from RFC 4007: “IPv6 Scoped Address Architecture”, section 11, “Textual Representation” (and, in particular, sub-section 11.2) used the term “zone_id”. While I consider an IETF RFC like that to be most authoritative, I also came across Microsoft Windows Server 2003 Documentation: Updates to Understanding IPv6, PDF page 11 (printed page 7) which calls this a “zone identifier (ID), also known as a scope ID”. It gives an example where a “zone ID” in the fe80::/64 range “is the interface index of the interface attached to the link containing the destination address”, but a different example from the fec0::/48 range where the “zone ID” “is the site ID of the organization site containing the destination address.”

    Upon me stumbling across a different term used by the IETF RFCs, I decided to immediately update this popular answer to be more compliant with such a more official set of standards. (Although the initial version was helpful as written, I preferred not to have my documentation differ from how the same phrase was documented by official pre-existing IETF RFC standards on IPv6 addresses. So this was the main reason for the January 19, 2020 update.)

  • Besides updating “interface identifier” to “zone ID”, other minor changes occurred in the January 19, 2020 update:
    • Added the WMIC command to get index identifiers (in Microsoft Windows)
    • A typo in an address (which said fd80 instead of fe80) was fixed
    • Minor adjustments, intended to clarify some text just a bit easier
    • Added hyperlinks to related technical documentation. (Actually, such hyperlinks mainly included in this section which describes how various parts of this answer got updated.)
1
  • 2
    Okay, upon re-reading Peter Eisentraut's answer, it looks like his is technically correct. Hopefully my details provide some more clarity. I disagree with Stephen Jennings's answer, because that answer makes it look like the "scope ID" identifies "link local" as the scope. However, two different network interfaces can both be "link local" but they will not be using the same "scope" (per the examples shown in his numbered list). Instead, I say those numbers identify the network "interface".
    – TOOGAM
    Commented Apr 24, 2016 at 4:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .