Do you really need IPv4 anymore?

April 9, 2024

Setting up and maintaining access networks today requires double the effort due to the parallel coexistence of IPv6 and IPv4. Dual-stack has network engineers and sysadmins do twice the amount of work, so there must be a good reason for it, right?

The answer is “probably not”! The IPv4 network is not really needed, with the exception of LANs with devices that do not support IPv6 after almost 30 years. And even there, solutions can minimize the impact of that considerably.

We’ll go over the current state of the art for removing IPv4 networking from the access. How it can happen, what it takes, and how to deal with most problems during such a transition.

First of all, let’s start with stating the obvious: most devices will have to talk to legacy services. This post will not argue against this, despite excuses for this decreasing.

Luckily, IPv6-only devices can still talk to IPv4-only ones, and this is getting easier than ever before. But how?

NAT64

Because IPv6 has just shockingly more addresses available for use than its legacy counterpart, we can map every single IPv4 address in the world into a tiny fraction of a single IPv6 subnet. We can have 1.1.1.1 be mapped to 2a0d:3dc0::1.1.1.1, and 8.8.8.8 be mapped to 2a0d:3dc0::8.8.8.8, etc.

What we achieved with that is that a device with an IPv6 address, and no IPv4 whatsoever, can still send packets to legacy hosts. It just needs to send this to a different address than before.

But how will this packet get to the intended destination?

We need a device that has both IPv6 and IPv4 that will make this translation for us. This device can simply be the local router, or even live across the Internet. What it has to do is easy:

For incoming IPv6 packets to this special translation prefix, create an IPv4 packet whose destination is the one encoded in the IPv6 destination. For the source address, use one of your own addresses.

For incoming IPv4 packets to these special IPv4 NAT addresses, look up who made it, and then convert it to IPv6, and send it back to them.

This is identical to how NAT works in the IPv4 world, there’s no difference whatsoever, with the exception of the inter-protocol conversion. If you are doing NAT for IPv4 right now, you’re not losing anything with this method. Everything still works the same way, including port forwarding.

But how do you know this magic prefix where you can send packets to it, and they will magically turn into IPv4 packets?

The quick answer is that there’s a special prefix assigned to this exact purpose, 64:ff9b::/96. But this would require devices to know it, and it’s not guaranteed to work, and it can be a bit tricky. Some devices will try to see if the conversion happens, and use it, but it’s not the best way. There’s something better:

DNS64

It’s a clever hack in the DNS. You are using a special DNS resolver that does the following: if you receive a question about a non-A (IPv4) DNS record, then respond normally. If someone is asking about the address of a domain name that has AAAA (IPv6) records, just give it to them, and since they have IPv6, they’ll connect just fine. If however you get asked about an A record, then “lie” to them. Tell them that the address of one.one.one.one is not 1.1.1.1, but it’s instead an AAAA record of 64:ff9b::1.1.1.1.

What we achieve now is the following:

If I connect to daknob.net and it has IPv6, I’ll be fine.

If I connect to github.com that does not have IPv6, I’ll be told that it has, and I just need to reach it at 64:ff9b::A.B.C.D. My device will send packets to that address, and NAT64 that we saw earlier will magically convert them into IPv4 packets.

Every connection that is established now to any domain name will work like magic. But what about hard-coded IPv4 addresses? If my computer has no IPv4, and I ping or ssh e.g. 8.8.8.8, I will get an error message, and it won’t work. Why? Because I never asked the smart DNS64 server, I attempted to connect directly to an IP address, and this is not fine.

What can we do about this?

CLAT

Since a lot of mobile networks (5G, 4G, etc.) in the world are IPv6-only, and have no IPv4, there’s luckily a solution for this already. It’s baked into devices such as iPhones, Androids, and Macs, and it’s part of their operating system. The only difference is that they enable it on WiFi too, instead of just on the data connection.

When this mechanism, called CLAT, is enabled, the devices will assign an IPv4 address to a local interface, usually 192.0.0.2, and anything sent to this IPv4 address will go through the operating system’s IPv4->IPv6 translation.

Although this is not a real IP address, and it’s not assigned into a real physical interface, everything still works fine. If there’s a packet going to 8.8.8.8 without using DNS, the application will deliver it to the OS, which is lying and telling it IPv4 exists, and it will convert this into an IPv6 packet, and send it over IPv6 behind the scenes.

This is great: all applications, unmodified, even those that reach out to IPv4 hosts directly, without DNS, will work just fine. All of the legacy traffic will be carried over IPv6, and they don’t even have to know what IPv6 is!

But when is this “CLAT” thing turned on? Surely, it can’t be on all the time…

This actually differs slightly depending on the operating system, with some trying to determine this by checking for the presence of DNS64 and working NAT64, but there’s a better and more reliable mechanism for this:

PREF64

When a device connects to a network, and it needs to receive an IPv6 address, a mechanism called SLAAC is used. There’s also DHCP for IPv6, but it’s not really as good. Some of the things that the router is sending to the devices along the prefix, much like with IPv4, include the DNS servers to use, etc.

One of these properties that can be transmitted is called PREF64. This can include the NAT64 magic prefix, so all of the clients can be informed that such service is offered, and it can be used.

For Apple operating systems and devices, and for a few major versions now, the presence of this value automatically enables CLAT. For Android and Windows, this is usually also enough, but both are more fragmented and it’s not as easy to be absolutely certain.

What about devices, however, that can’t even get an IPv6 address?

Translation at the router

Unfortunately, even if it’s been almost 30 years since IPv6 was introduced, there are still devices out there that cannot get an IPv6 address. They are almost always IoT / “smart” things or very old equipment. These still need to be connected, so we have to come up with a solution.

The answer is simple: have the router do the translation for them. For the LANs that require it, you add an IPv4 address, you set up DHCP, like you normally would, but instead of routing that network, you just convert it to IPv6 the moment it gets in.

There are two ways to do this:

CLAT + NAT44

The first one is by doing CLAT on your router, too, and doing NAT44 (traditional IPv4 NAT) to the virtual IP address. Now all of the IPv4 traffic coming in will be converted into IPv6, and then sent across the network.

This is actually what mobile devices will do if you use the hotspot functionality and connect devices there.

SIIT

The other way is by using SIIT. This is a stateless mechanism where all IPv4 traffic is encoded in IPv6 packets, be it source or destination. To understand this better, let’s look at the following diagram:

How SIIT works

The “smart” light bulb has an IPv4 address. This address only needs to be unique within its router. It’s okay if you have 100 routers and all of them have 10.1.1.0/24 attached to them.

This device now sends all of its traffic to the local router, which has IPv6 connectivity, but it also has a special IPv6 prefix. When the IPv4 traffic is received, all packets are statelessly converted into IPv6 by setting the last 32 bits to the Source IPv4 of the device. The destination is also stateless: it’s the NAT64 magic prefix plus the last 32 bits of the Destination IPv4.

When that packet is forwarded to the NAT64, it will get statefully translated and mapped in a public IPv4 address and allocated a port number.

After continuing its path on the local network and/or the Internet, it will reach the destination, it will get a response, and the NAT64 will send its response:

The Source IP will be 64:ff9b::8.8.8.8, and the Destination IP will be 2a0d:3dc0::10.1.1.2 (the SIIT prefix of the router, plus 10.1.1.2).

When the router receives this, it will statelessly convert it back to IPv4, and send to the light bulb a packet with a Source IP of 8.8.8.8, and a Destination IP of 10.1.1.2.

Side Note: You may notice that the SIIT prefix is /96 (32 bits), while we only have an IPv4 /24 (8 bits). This may seem wasteful, but given how many IPv6 addresses we have, it’s okay to map all of IPv4 instead of individual LANs. A typical residential customer gets 72 bits of public IPv6 anyways ;)

As access routers tend to be smaller, and can even be cheap CPEs, stateless translation tends to require less resources overall.

Mixed Access

This is all great, and we can get end-to-end connectivity with both the modern and the old Internet using our IPv6-only devices. But sometimes we may have a LAN where some devices play nicely, while some others still require IPv4. Or, it can be a migration to IPv6(-only) which is done in several phases.

The moment we turn on DHCP, all devices will get an IPv4 address too, and they may not take full advantage of our IPv6-only infrastructure, or may unnecessarily offload a lot of the translation tasks to the router, when they’re perfectly capable of performing them themselves.

This is where the IPv6-only Preferred DHCP option comes in. It’s a standard (RFC8925) where any devices that are able to operate in an IPv6-only environment include this information to a DHCP Request for an IPv4 address. Basically, when they ask for an IPv4 address, they tell the network that they don’t need it, unless there’s no support for IPv6-only operation.

If the DHCP server is aware of this, or just blindly configured to reply, it will tell them that it understands the request, and will not assign them an IPv4 address.

The good thing here is that we now are able to have a single LAN, and all devices that feel confident about their IPv6-only abilities can skip the IPv4 part completely, while all other devices that don’t know what’s going on will do a best effort IPv6-only, or they will fall back to IPv4 (aaS over IPv6) for connectivity.

According to a 2022 post by APNIC, in one of their events, where the WiFi network was running using this DHCP option, 65% of the devices did not get an IPv4 address because they sent this to the server. This is the same range that my former colleague Jen reported in her IETF draft about this technology (60%-70%). From my own experience, operating a handful of public / open WiFi networks this can reach as high as 85% for some environments.

DHCP Option 108, as it’s also called, has several benefits:

  • It reduces the need for IPv4 (2x-4x smaller subnets required)
  • It surfaces issues with IPv6 connectivity (as they are no longer masked by graceful fallback into IPv4)
  • It allows for a slower, smoother, and more controlled migration to IPv6

NAT64 vs NAT44

Since IPv4 addresses are limited, most networks will require some sort of NAT to reach IPv4 anyways. Whether you translate IPv4 into IPv4 or IPv6 into IPv4, the end result is the same. But it’s actually easier operationally to run NAT64 gateways instead of NAT44 or CGNAT ones.

The way NAT44 works, there’s a device on the critical path of the traffic, rewriting source IPs and ports. All traffic that has to be NATed needs to go through these devices, and unless you carry out complicated policy routing, they have to sit between the private IP space and the Internet.

With NAT64, this is not the case. All traffic that has to reach an IPv4 network will go to the NAT64 prefix, which can be anywhere on the network. In fact, if you use a public IPv6 address, it can also be outside your network, on the Internet! As far as all routers are concerned, this is IPv6 unicast traffic.

This allows a great deal of flexibility: the critical path, between access devices and the Internet, can run on 100% stateless IP routers, using high end silicon, or even Terabit-class software routing. The IPv4-destined packets can then branch off to a completely separate path, to be translated. The way to these NAT64 gateways can be controlled with your IGP, such as OSPF, IS-IS, or BGP, and they can be managed the same way as any high availability, horizontally scalable service.

You don’t need to split your traffic across 50 CGNAT boxes, and try to do that evenly, when you can instead just add 50 NAT64 gateways, all advertising the NAT64 prefix over OSPF, with their own pools of IPv4s and Ports, and let ECMP deal with the rest. When one of them goes down, the prefix is withdrawn, and new connections hit the remaining gateways, without any intervention, and in seconds.

You can also operate NAT64 services in various locations. An ISP could, for example, have these gateways in every city, keeping all translation local to its users. If there’s a server (but not network) outage in a city, or simply there are updates that require a reboot, the nearest city’s translators pick up the slack.

Single-IPv4 installations

Deploying an IPv6-first or IPv6-only network does not require advanced routing, an Autonomous System, BGP, or your own addresses. Everything described here can happen in a residential Internet connection that takes an IPv4 address via PPPoE and a /56 of IPv6 space over DHCPv6-PD. In fact, I’ll soon publish a post on how to achieve this here, so subscribe to my RSS Feed :)

Update: The post is published, but you should still subscribe ;)

But where do you translate your IPv6 to, in that case?

You can add a private IPv4 address in your router’s loopback interface, e.g. 10.10.10.10, and then NAT64 to that. Now all IPv6 traffic will get translated to 10.10.10.10, which will in turn be masqueraded by your WAN IPv4 address.

You don’t need static IPv4 addresses or even more than one main address, you just need to make sure –just like with IPv4– that you have enough source ports for the amount of traffic you’re having.

What about existing ACLs?

If you are running a corporate network, you may have a lot of Access Control Lists and Firewall rules all over the place referencing your IPv4 addresses. In a move to IPv6-mostly, especially if the access network goes first, you may need NAT64 to reach other parts of your infrastructure.

For example, IT may use 10.0.0.0/24, Developers may use 10.0.1.0/24, and depending on the source IP, they may get or not get access to various services in a 10.0.10.0/24 LAN.

When IT and Developers migrate to IPv6, your NAT64 can check the source IPv6 address, and then map each LAN to an IPv4 address from within that network. You can assign a new address (e.g. 10.0.0.254), or you can also use the router’s address (e.g. 10.0.0.1). Now all of IT appears as 10.0.0.254 to servers in 10.0.10.0/24, which should still be within their existing ACLs and allowed.

A hopeful future present

With existing IPv6 Transition Mechanisms and the current state of OS and software support, not only in network gear, but also end devices, I honestly believe that many modern access LANs can operate with IPv6-only setups without problems. I have seen that happen in the real world, in large corporate and enterprise deployments, with extremely few problems, most of which can be solved trivially.

Moreover, the transition can happen smoothly. In existing IPv4-only networks, you can simply turn on IPv6, for dual-stack operation. You can start with small timers in SLAAC, e.g. 5 or 10 minutes, and with your more tech-savvy users first. You’re then ready to turn it off at a moment’s notice if something is not working.

You can then set up NAT64. Verify it’s working by manually changing your DNS servers to some devices. If it’s not, revert it. Then progressively move more LANs to the NAT64 DNS servers, which can again happen with small timers, and it’s easily reversible.

The next step can be to add PREF64 into SLAAC, and see a lot of devices start moving to IPv6-only. You guessed it! This can happen with small timers too, and can also be easily reverted. And you can do this to a few VLANs first, and then gradually roll it out.

Finally, you can have your DHCPv4 server send Option 108, which if you look carefully into has a single 32-bit value: a timer, in seconds, again! So even this can lead to a smooth rollout.

This document goes into much more detail and it’s a very good resource of how this can be done, and I’d love to hear stories of people attempting it, and how it turned out for them. It’d be great to hear what was difficult, what didn’t work, what you learned, so we can make this even easier in the future for everyone.

Feel free to contact me about IPv6 deployments, as I’d love to help!