In my previous post I wrote about all the positives we get from the almost incomprehensibly massive IPv6 address space, all there for our enjoyment if we will just break free of our long-ingrained IPv4 address conservation mentality.
The place where we most often see the adverse effects of IPv4 conservatism is in addressing point-to-point links. I wrote about how we can be led into illogical thinking because we fail to grasp the scale we are working with: We seem to have no problem, on a LAN with 5000 addresses, wasting the other 264-5000 addresses but we just can’t bring ourselves to waste 264-2 addresses on a point-to-point link. On the scale of 18 million trillion addresses, the difference between 5000 and 2 is negligible.
A bit of illogic related to this issue of subnet address size is a question I hear frequently: “Why did they use up an entire 64 bits for the Interface-ID? Why not 32 bits, which still gives us more addresses on a subnet than we would ever use, and would leave us with 96 bits for prefixes?”
My answer is: Why do you care?
That’s still just a misplaced worry about waste. We could just as easily ask why they didn’t make IPv6 addresses 64 bits, with 32 bits for prefixes (location) and 32 bits for Interface-ID (identity). There would probably still be more than enough addresses for the foreseeable future. And you just know that if an IPv6 address were 64 bits, there would be people asking why they didn’t make the Interface-ID 16 bits (65,536 addresses should still be more than enough for any subnet!) so that we could have 48 bits for prefixes.
Do you see the kind of rut you can get stuck in by worrying about address waste? IPv6 addresses are 128 bits, evenly divided between prefix and Interface-ID, precisely because it gives us more addresses than we can ever conceivably use. The designers hit the problem of address depletion with a really, really big hammer. Unlike IPv4, there is no expectation that you will efficiently use all the interface addresses available on a /64 subnet.
So really. Stop worrying about it.
Are There Other Reasons to Use a /127 on a Point-to-Point Link?
Well, yes there are.
Here’s some background: RFC 4291, Section 2.5.4, explicitly states that the IPv6 Interface-ID is /64 for all global unicast addresses. It doesn’t say “except if you’re worried that you’re being wasteful.” And just to make things clearer for folks that were insisting on using /127s on point-to-point links, we had RFC 3627 that says, right in the title, “Use of /127 Prefix Length Between Routers Considered Harmful.” Then along comes RFC 6164 that says the use of /127 prefixes on point-to-point links is just fine and dandy after all. In fact RFC 6547 moves 3627 to historical (obsolete) status, superceded by 6164.
Confused yet? It’s really not that complicated.
RFC 3627 Is Obsolete for Good Reason
The main justification for the RFC 3627’s conclusion that /127 prefixes are harmful has to do with Subnet-Router Anycast addresses. These are addresses in which the prefix is intact, but the Interface-ID bits are all set to zero. So the address is scoped to a specific subnet by the prefix, but the identity portion of the address is unspecified. A device can send packets to the Subnet-Router Anycast address and they will be picked up by a router attached to the subnet. RFC 4291 requires that routers support the Subnet-Router Anycast address; the idea is that an application can use this address to communicate with “any one of the set of routers” on a subnet, although it isn’t made clear why an application would use this Anycast rather than the All-Routers multicast address.
Here’s the scenario that supposes /127 prefixes to be harmful:
- You connect two routers, RA and RB, with a point-to-point link.
- You configure RA’s interface with address 2001:db8:1:2:a:b:c:1/127. The router runs Duplicate Address Detection (DAD) on the link for this address, and the address passes.
- RA, in compliance with RFC 4291, adds the Subnet-Router Anycast address 2001:db8:1:2:a:b:c:0/127. RFC 2462, Section 5.4, specifies that DAD is not run for Anycast addresses (which makes sense, because by definition an Anycast address can reside on more than one interface). So no DAD is run for this address.
- Now you go to RB and configure the other address for that /127 prefix: 2001:db8:1:2:a:b:c:0/127. Does the router object that it cannot use that address as its unicast, because it’s the Subnet-Router Anycast address for that prefix? Does it accept the address, and then add the same address as its required Subnet-Router Anycast? If it does, and performs a DAD, the address will fail because it already is on RA.
That sounds like a big problem, but there’s a couple of things to know
- Subnet-Router Anycast, as vague as it’s purpose appears, clearly is for use on a multiaccess network. Why would it ever be used on a point-to-point link?
- Even though RFC 4291 makes the address mandatory, the fact is that it isn’t very widely implemented. Even RFC 3627, after laying out the above scenario, acknowledges that it hasn’t been observed in the wild. I’ve configured many /127 addresses, and have yet to have a problem with it.
DAD is useful for Address Autoconfiguration mechanisms and for Neighbor Discovery Protocol, both of which have limited utility on point-to-point links. An easy bit of insurance, if your router operating system supports it, is to disable DAD on your point-to-point links. Many point-to-point technologies such as SONET do not use NDP, but if you are using Ethernet for point-to-point links, you probably will need to manually disable NDP.
Neighbor Cache Attacks
There is another reason for insuring that NDP is disabled on Ethernet point-to-point links. If the link is a /64 subnet, an attacker can send a stream of packets onto the link with destination addresses that belong to the link’s subnet but which have unused Interface-IDs. For each address received, the router creates an INCOMPLETE entry in its neighbor cache and sends an NDP Neighbor Solicitation message onto the link to try to resolve the entry. By streaming enough different unused addresses, the attacker can cause the neighbor cache to fill up and the link to be congested with unanswered NS messages.
RFC 6164 cites this vulnerability as a reason for using /127s on your point-to-point links. While it’s true that this will stop this particular attack (because there are no unused addresses on the subnet), simply disabling NDP on your point-to-point links also eliminates the vulnerability. More importantly, the vulnerability exists on any subnet that supports NDP, and you can’t disable NDP on your LAN subnets. ICMPv6 rate limiting and intelligent edge filtering are needed to control the effects of a neighbor cache attack.
The more important reason cited by RFC 6164 for using /127s is the exposure to ping-pong attacks.
A ping-pong attack exploits a problem with older implementations of ICMPv6 compliant with RFC 2463. Here’s the problem:
- You connect two routers, RA and RB, with a point-to-point link.
- RA is given the address 2001:db8:1:2::1/64.
- RB is given the address 2001:db8:1:2::2/64.
- A packet arrives at RA with the destination address 2001:db8:1:2::3.
- The destination is for the subnet of the point-to-point link, but it isn’t RA’s interface address. So RA forwards the packet into the link. Ping.
- RB receives the packet.
- The destination is for the subnet of the point-to-point link, but is not RB’s address, so RB forwards the packet back onto the link. Pong.
- RA receives the packet, and the cycle repeats itself.
You can see how this could be exploited: An attacker floods packets with unused destination addresses onto the subnet, and the packets bounce back and forth between the two routers until their Hop Limit expires. Flood enough of these packets -- and a /64 provides a lot of unused addresses to hit -- and the capacitive effects bouncing packets effect will eat up bandwidth and router resources.
There are two things to observe about this behavior:
- RA and RB cannot determine whether the destination address belongs to an existing device on the subnet, because there is no Neighbor Discovery on most point-to-point links.
- A simple split-horizon rule would assume that if you receive a packet on a subnet that belongs on the subnet but does not belong to the receiving interface, there is no need to forward the packet back out the same interface. Presumably if the destination exists on the subnet, it already received the packet.
As it turns out, this vulnerability exists in IPv4 also; it’s just that there was never much risk exposure, because most everyone uses /30 or /31 subnets on IPv4 point-to-point links in order to conserve addresses.
RFC 4443 obsoletes RFC 2463, and in its Section 3.1 explicitly requires that a router receiving a packet whose destination address belongs to a subnet of the receiving interface, but whose Interface-ID does not belong to the interface, must not send the packet back out the same interface. Problem solved.
Is Your Vendor Running Obsolete Code?
What gets my goat about this issue is that some vendors prefer to continue running the obsolete version of ICMPv6 rather than upgrading their code to RFC 4443-compliant ICMPv6. Their answer to the problem is to tell you to use /127s on your point-to-point links instead.
The IETF standards recommend using /64 subnets everywhere. The RIRs support your running /64 subnets everywhere. So are you going to disrupt the nice, consistent simplicity of your IPv6 address design in order to accommodate a router vendor who does not want to modernize their code? Or are you going to tell your vendors to stop using obsolete code?
You have a few options for dealing with this issue:
- If you are running older, “pre-RFC 4443” Cisco IOS, upgrade to a newer version. Cisco supports RFC 4443.
- Run IPv6 unnumbered on your point-to-point links. This isn’t a good solution for many operators, because it complicates monitoring and tracing. It also complicates running EBGP over the links.
- Block access to point-to-point subnets from any untrusted zones. You probably don’t want the IP addresses of your point-to-point interfaces reachable from outside your network anyway.
Even if you take the “stand up to your vendors” approach I recommend, it’s going to take them some time to modernize. An interim solution, if you have concerns about the ping-pong vulnerability, is to assign /64 subnets to each point-to-point link, but select a /127 out of the /64 and configure that subnet on the link interfaces. This approach allows you to alleviate immediate concerns about security vulnerabilities, but also allows you with minimal network disruption to change your /127 subnets to their corresponding /64s when the time is right.
You’ll be living with your address design for a long time. Don’t let a vendor’s short-term laziness disrupt your long-term plans.