Network Address Translation (NAT) and Network Address Port Translation (NAPT) are technologies many people have a strong opinion about. For years, they have been the necessary evil and invaluable (yet massive) hacks that kept IPv4 from falling apart in the face of its abysmally small 32-bit address space — which was, to be honest, absolutely OK for the time the protocol was designed, when computers cost a small fortune, and were as big as lorries.
IPv4 has been abused for quite some time now. We made it into the fundamental building block of the modern Internet; a network of a scale it was never designed for. It is due time to put it to rest and replace it with its controversial, yet problem-solving, 128-bit grandchild, IPv6.
So, what should be the place for NAT in the new Internet, which makes the return to the end-to-end principle one of its main tenets?
NAT66 misses the point
Well, none, according to the IETF, which has for years tried to dissuade everyone from dabbing with NAT66 (the name NAT is known on IPv6); this is with good reason, though. For too long, the supposedly stateless, connectionless level 3 IP protocol has been made into an impromptu ‘stateful’, connection-oriented protocol by NAT gateways, just for the sake of meeting the demands of an infinite number of devices trying to connect to the Internet.
This is without considering the false sense of security that address masquerading provides; I cannot recall how many times I’ve heard people say that (gasp!) “NAT was a fundamental piece in the security of their internal networks” (it’s not).
Given that the immensity of IPv6 address space allows providers to give out full /64s to customers, I’d always failed to see the point in NAT66 — it always felt to me as a feature fundamentally dead in the water, a solution seeking a problem, ready to be misused.
Well, this was before discovering how cheap some hosting services could be.
Being cheap: the root of all evils
I was quite glad to see a while ago that my Virtual Private Server (VPS) provider had announced IPv6 support. Thanks to this, I could finally provide IPv6 access to guests of the VPNs I host on that VPS, without having to incur delay penalties caused by tunnelling the traffic on good old services such as Hurricane Electric and SixXS (the latter of which ironically closed last June because “many ISPs offer IPv6 now”). Hooray!
My excitement was, unfortunately, not going to last for long, and it was indeed barbarically butchered when I discovered that despite having been granted a full /32 (296 IPs), my provider decided to give its VPS customers just a single /128 address.
JUST. A. SINGLE. ONE.
Given that IPv6 connectivity was something I really wished for my OpenVPN setup, this was quite a setback. I was left with only two reasonable choices:
- Get a free /64 from a Hurricane Electric tunnel, and allocate IPv6 addresses for VPN guests from there; or
- Be a very bad person, set up NAT66, and feel ashamed.
Hurricane Electric is, without doubt, the most orthodox option between the two: it’s free of charge, it gives out /64s, and it’s quite easy to set up.
The main showstopper here is definitely the increased network latency added by two layers of tunnelling (VPN > 6to4 > IPv6 Internet). And, given that by default native IPv6 source IPs are preferred to IPv4, it would have been bad if having a v6 public address incurred a slow down of connections with usually tolerable latencies, especially if there was a way to get decent RTTs for both IPv6 and IPv4.
So, with a pang of guilt, I shamefully committed the worst crime, and set up NAT66.
How to get away with NAT66
The process of setting up NAT usually relies on picking a specially reserved, privately-routable IP range, to avoid internal network structures conflicting with outer networking routing rules (it still may happen, though, if under multiple misconfigured levels of masquerading).
The IPv6 equivalent to 10.0.0.0/8
, 172.16.0.0/12
and 192.168.0.0/16
has been defined in 2005 by the IETF (with a whole deal of confusion at first) with the Unique Local Addresses (ULA) specification. RFC4193 defines the unique, not publicly routable fc00::/7
that is supposed to be used to define local subnets, without the unicity guarantees of 2000::/3
(the range from which Global Unicast Addresses (GUA) — that is, the Internet — are allocated from for the time being). From it, fd00::/8
is the only block really defined so far, and it’s meant to define all of the /48s your private network may ever need.
The next step was to configure my OpenVPN instances to give out ULAs from subnets of my choice to clients, by adding at the end of my config the following lines:
server-ipv6 fd00::1:8:0/112
push "route-ipv6 2000::/3"
I resorted to picking fd00::1:8:0/112
for the UDP server and fd00::1:9:0/112
for the TCP one, due to a limitation in OpenVPN only accepting masks from /64 to /112.
Given that I also want traffic towards the Internet to be forwarded via my NAT, it is also necessary to instruct the server to push a default route to its clients at connection time.
$ ping fd00::1:8:1
PING fd00::1:8:1(fd00::1:8:1) 56 data bytes
64 bytes from fd00::1:8:1: icmp_seq=1 ttl=64 time=40.7 ms
The clients and servers were now able to ping each other through their local addresses without any issue, but the outer network was still unreachable.
I continued the creation of this abomination by configuring the kernel to forward IPv6 packets. This is achieved by setting the net.ipv6.conf.all.forwarding = 1
with sysctl or in sysctl.conf (from now on, the rest of this article assumes that you are under Linux).
# cat /etc/sysctl.d/30-ipforward.conf
net.ipv4.ip_forward=1
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1
# sysctl -p /etc/sysctl.d/30-ipforward.conf
Afterwards, the only step left was to set up NAT66, which can be easily done by configuring the stateful firewall provided by Linux’s packet filter.
I personally prefer (and use) the newer nftables to the {ip,ip6,arp,eth}tables
mess it is supposed to supersede, because I find it tends to be quite less moronic and clearer to understand (despite the relatively scarce documentation available online, which is sometimes a pain. I wish Linux had the excellent OpenBSD’s pf…).
Feel free to use ip6tables, if that’s what you are already using, and you don’t really feel the need to migrate your ruleset to nft.
This is a summarized snippet of the rules that I’ve had to put into my nftables.conf to make NAT66 work; I’ve also left the IPv4 rules in for the sake of completeness.
PS: Remember to change MY_EXTERNAL_IPVx with your IPv4/6!
table inet filter {
[...]
chain forward {
type filter hook forward priority 0;
# allow established/related connections
ct state {established, related} accept
# early drop of invalid connections
ct state invalid drop
# Allow packets to be forwarded from the VPNs to the outer world
ip saddr 10.0.0.0/8 iifname "tun*" oifname eth0 accept
# Using fd00::1:0:0/96 allows to match for
# every fd00::1:xxxx:0/112 I set up
ip6 saddr fd00::1:0:0/96 iifname "tun*" oifname eth0 accept
}
[...]
}
# IPv4 NAT table
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
ip saddr 10.0.0.0/8 oif "eth0" snat to MY_EXTERNAL_IPV4
}
}
# IPv6 NAT table
table ip6 nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
# Creates a SNAT (source NAT) rule that changes the source
# address of the outbound IPs with the external IP of eth0
ip6 saddr fd00::1:0:0/96 oif "eth0" snat to MY_EXTERNAL_IPV6
}
}
table ip6 nat table and chain forward in table inet filter are the most important things to notice here, given that they respectively configure the packet filter to perform NAT66 and to forward packets from the tun* interfaces to the outer world.
After applying the new ruleset with the nft -f <path/to/ruleset>
command, I was ready to witness the birth of my little sinful setup. The only thing left was to ping a known IPv6 from one of the clients, to ensure that forwarding and NAT are working fine. One of the Google DNS servers would suffice:
$ ping 2001:4860:4860::8888
PING 2001:4860:4860::8888(2001:4860:4860::8888) 56 data bytes
64 bytes from 2001:4860:4860::8888: icmp_seq=1 ttl=54 time=48.7 ms
64 bytes from 2001:4860:4860::8888: icmp_seq=2 ttl=54 time=47.5 ms
$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=55 time=49.1 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=55 time=50.8 ms
Perfect! NAT66 was working, in its full evil glory, and the client was able to reach the outer IPv6 Internet with RTTs as fast as IPv4. What was left now was to check if the clients were able to resolve AAAA records; given that I was already using Google’s DNS in /etc/resolv.conf, it should have worked straight away:
$ ping facebook.com
PING facebook.com (157.240.1.35) 56(84) bytes of data.
^C
$ ping -6 facebook.com
PING facebook.com(edge-star-mini6-shv-01-lht6.facebook.com (2a03:2880:f129:83:face:b00c:0:25de)) 56 data bytes
^C
What? Why is ping trying to reach Facebook on its IPv4 address by default instead of trying IPv6 first?
One workaround always leads to another
Well, it turned out that Glibc’s getaddrinfo() function, which is generally used to perform DNS resolution, uses a precedence system to correctly prioritize source-destination address pairs.
I started to suspect that the default behaviour of getaddrinfo() could be to consider local addresses (including ULA) as a separate case than global IPv6 ones; so, I tried to check gai.conf, the configuration file for the IPv6 DNS resolver.
label ::1/128 0 # Local IPv6 address
label ::/0 1 # Every IPv6
label 2002::/16 2 # 6to4 IPv6
label ::/96 3 # Deprecated IPv4-compatible IPv6 address prefix
label ::ffff:0:0/96 4 # Every IPv4 address
label fec0::/10 5 # Deprecated
label fc00::/7 6 # ULA
label 2001:0::/32 7 # Teredo addresses
What is shown in the snippet above is the default label table used by getaddrinfo(). As I suspected, a ULA address is labelled differently (6) than a global Unicast one (1), and, because the default behaviour specified by RFC3484 is to prefer pairs of source-destination addresses with the same label, the IPv4 is picked over the IPv6 ULA every time.
Damn, I was so close to committing the perfect crime.
To make this mess finally functional, I had to make yet another ugly hack (as if NAT66 using ULAs wasn’t enough), by setting a new label table in gai.conf that didn’t make distinctions between addresses.
label ::1/128 0 # Local IPv6 address
label ::/0 1 # Every IPv6
label 2002::/16 2 # 6to4 IPv6
label ::/96 3 # Deprecated IPv4-compatible IPv6 address
label ::ffff:0:0/96 4 # Every IPv4 address
label fec0::/10 5 # Deprecated
label 2001:0::/32 7 # Teredo addresses
By omitting the label for fc00::/7
, ULAs are now grouped together with GUAs, and natted IPv6 connectivity is used by default.
$ ping google.com
PING google.com(par10s29-in-x0e.1e100.net (2a00:1450:4007:80f::200e)) 56 data bytes
In conclusion
So, yes, NAT66 can be done and it works, but that doesn’t make it any less than the messy, dirty hack it is. For the sake of getting IPv6 connectivity behind a provider too cheap to give its customers a /64, I had to forgo end-to-end connectivity and hack ULAs to achieve something they weren’t really devised for.
Was it worthwhile? Perhaps. My ping under the VPN is now as good on IPv6 as it is on IPv4, and everything works fine, but this came at the cost of an overcomplicated network configuration. This could have been much simpler if everybody had simply understood how IPv6 differs from IPv4, and that giving out a single address is simply not the right way to allocate addresses to your subscribers anymore.
The NATs we use today are relics of a past where the address space was so small that we had to break the Internet in order to save it. They were a mistake made to fix an even bigger one — a blunder whose effects we now have the chance to undo. We should just start to take the ongoing transition period as seriously as it deserves, to avoid falling into the same wrong assumptions yet again.
Original post appeared on mcilloni’s blog.
Marco Cilloni is a research fellow at the Center for Industrial Research on Information and Communication Technologies Lab of the University of Bologna.
The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.
Very interesting….
I stopped reading when you started implying NAT provides no security. Even worse, you are one of those people that try to make it sound like anybody who believes NAT provides any kind of security is a fool.
People from your side completely fail to understand that while NAT was not designed for security, it did bring security, in particular for home users. If NAT had not existed, I am confident the Internet would not have been such a huge commercial success because of how insecure it’d have been.
While a comprehensive security policy would not rely exclusively on NAT for any company, clamoring that “NAT is not security” is plain wrong.
Still believe NAT provides no security whatsoever ? Let’s see what Cisco has to say about it :
Benefits
“Enhances network security — Provides a first layer of defense from external attackers by hiding IP addresses and application ports”
“Cisco IOS Network Address Translation (NAT) is primarily designed for IP address conservation and network design simplification, but it also serves as a security mechanism by hiding a host’s IP address and ports as part of a private network”
“Doing this effectively hides the internal network from the world, giving you some additional security.”
“This ability provides additional security by effectively hiding the entire internal network behind that one address.”
Shouting “NAT IS NOT SECURITY” endlessly won’t make it true. And a final quote for you : “Whenever you find yourself on the side of the majority, it is time to pause and reflect. ” – Mark Twain
Hi Julien,
“I stopped reading when you started implying NAT provides no security.”. Me too. You gave all the arguments I wanted to give. A lot of respected network people I know fall in this seemingly religious trap to denounce the implicite defense that NAT offers.
NAT does not provide security, and calling people who say so religious only serves to illustrate lack of insight in the matter.
It’s really not that hard to understand why they do so.
The principal reasoning (not religion, thank you very much) behind it is that it is by very name and definition an ‘obfuscation’ measure.
And as the adagium goes, security through only obscurity is no security at all.
Note that that does not mean that obfuscation can not be a valuable enhancement to security; but security it is not, full stop.
NAT obfuscates IP addresses in IP packet headers; those headers contain src-gw IP rather than src IP. That’s exclusively what one ‘wins’ with NAT.
NAT’s not doing a thing to stop anyone.
I cannot address your LAN IP from a global one without going through your gateway; that’s a universal standard router enforcement, not NAT.
I cannot point at any arbitrary address or port behind your gateway; That’s what your firewall is doing, which ís a security feature which *always* has to be right, regardless of NAT (sic).
Considering the lack of NAT in IPv6 a security downside is also ignoring IPv6’s obfuscating elements, specifically designed for the purpose rather than as ugly connectivity hacks:
* By design even a lowly consumer gets at least a /64, containing 18 septillion addresses. Range-scanning that is only slightly more difficult than warp travel.
* Regularly Re-Randomized MAC addresses and privacy IPv6 addresses; any computer can have an arbitrary amount of arbitrary addresses in the subnet at any time
* Unique Local Addresses, by standard not globally routable comparable to LAN IPv4 ranges
So anyone hot for obfuscation should still enthousiastically ditch NAT and flip to IPv6 😛
But even if NAT obfuscation is your holy grail with which to keep IPv6 at bay, consider just how valuable such information is:
Physical intruders (government) will just demand your NAT session logs intermediately. And rly, they won’t just come in with some IP headers. Or just take the NAT session logs or that one computer.
Inside intruders (bribed employees, compromised hw) aren’t really impacted by NAT in any way.
Link intruders (ISP’s, MitM) are sniffling and/or manipulating the routing and contents for endless troves of bugs and information about people, hosts, services and applications. They could care less about the IP headers for info, especially when one can scan the entire IPv4 address space in a matter of minutes with modest hardware and connection.
Endpoint intruders (malicious/tracking sites et.al.) don’t care much about IP header info either, you’ve already opened an application session with them with a lot more opportunities.
While no doubt there’s some intel value in the actual src IP at the very least it’s obvious ubiquitous NAT (and these days even carrier NAT) did very little to quell the offensive landscape.
I regularly consider NAT an additional security risk in fact. Julien’s favourite experts Cisco used to have this ASA ‘security’ product line that we managed to break multiple times a day per appliance over it’s HORRIBLE connection tracking and the abuse we suffered on it.
There’s also been plenty critical CVE’s and endless bugs against the multitude of all the separate connection trackers needed to keep up the charade on any protocol containing ip/port renegotation.
So yeah. NAT is not security, and we who think so are not religious zealots. We will happily try & explain again tho
Not only cheap VServer providers are a problem, but especially ISP which only provide dynamic IPv6 prefixes to their customers.
Why do they do that? Clearly so customers could not easily use there home internet connection to host services.
But it is also a pita for using OpenVPN together with IPv6.
Either the Ipv6 community sobers up and starts actively supporting NAT or you can kiss the Ipv6 protocol goodbye. I’ve put many many hours into ipv6 integration and I’m starting to realize it’s a doomed protocol and should be scraped. Why are we implementing a protocol implemented from 20 years ago? Lets start fresh with something that not only works right but that people can grasp better.
I appreciate the guide, but I dont agree with your view on NAT66.
I will try to explain my reasons, as you deserve an explanation for my view.
True that NAT’s purpose is to move traffic between local and wide area subnets via address translation. False however to say it provides on security benefit, it should never be used as security device primarily, but as a side effect it does add a security layer. It can be subverted, but its still a layer. Of course one should never ever substitute a firewall with NAT.
However lets explain for a moment on the uses of NAT, one might assume the only reason for NAT is to address the shortage of ip address space, however NAT is also very useful tool for redirecting traffic.
Currently there is a DNS war, everyone wants your DNS lookups, because DNS is used as a means to direct traffic, and is a means of logging what people are doing. Because of this we have software that does “not” honour configured DNS. Some examples?
My android phone adds google dns to the end of the DNS servers it gets from dhcp(6).
Chrome has been known to forcefully use google dns ignoring what you configured.
Various apps including netflix will force dns via specific dns servers.
You get the picture?
On my ipv4, I use outbound nat to “force” “all” dns requests to 12.7.0.0.1 which is the local dns resolver on my router. This overides dns routing, no matter how its configured LAN side, each and every ipv4 dns request will go to 127.0.0.1 on my router. I am in control of my network which is how it should be
However ipv6 is a different game, due to lack of NAT66 support on pfsense (my router) I have no ability (at least via official UI) to divert outgoing ipv6 dns requests to my own local resolver. I can pass on my requested resolver ip via dhcp6, I can manually add it to OS configuration on each device, however software can (and does) choose to ignore it. I added a firewall rule that blocks (and logs) requests to external ipv6 dns servers initiated from my LAN, there is many requests been blocked from my windows machine alone, to dns servers that are not in my configuration.
The lack of ability for a admin to control his network, and plug things like dns leak’s is a security issue, and as such NAT66 has security benefits.
But as usual we have silly politics, we need consistent standards across devices, instead ipv6 standards are all over the place because people cannot agree with each other on how things should be implemented, and this is one of the reasons many isps wont rollout ipv6, they see it as “not ready” for as long as things are not implemented. NAT66 should be on every routing device out there, by all means disable it by default, hide it away, but it should be there. Once cannot declare ipv6 as an upgrade over ipv4 if it doesnt have all the features of ipv4.
Most people think about NAT from the ISP or corporate network perspective and IPv6 generally solves these or provides an alternative. But I have a scenario where only NAT appears to do the job effectively.
At work, I operate a service where self-contained lab environments of virtual machines are delivered to users to demonstrate our product functionality in a hands-on way. These VMs use one or more private layer 2 networks to communicate with each other, and an edge gateway to allow remote access in via RDP directed to an internal host (inbound NAT) and access for the VMs inside the network to talk outside their environment (masquerading). Most of the VMs run server operating systems and have static addressing to facilitate documentation.
For repeatability and a few other reasons, the VMs are EXACT duplicates of each other, right down to the MAC addresses used in their private networks. Only the gateway’s external interface has a unique MAC and dynamic address. Trying to take this configuration and switch to IPv6 with globally unique addressing would be a nightmare to create, document, and operate for the users. We would have to spend significant amounts of time trying to reengineer the labs to use dynamic addressing and service location protocols and in the end may not be successful if the software in the lab doesn’t support this configuration. NAT66 would work out of the gate with minimal changes.
The point is not security, it’s internal network manage, especially when the ISP only provides dynamic IPv6 prefix, all the router, firewall is hard to manage the internal service network, that’s unacceptable.
I don’t think IPv6 is likely to succeed, because it doesn’t care about reality.
One huge security-impact on ipv6 clearly is making IoT devices directly addressable from the internet.
Even worse, forcably changed GUA’s by ISP’s break any existing firewall distri today so far. For instance pfSense to call it by name. And it won’t even possible to fix because of BSD’s underlaying packitfilter can’t handle it by design. Netfilter at least allows for masking the prefix wich at least allows one to keep rules bount to an address, but doesn’t make it secure either.
So while NAT does at least obfuscate the network, ISP’s abuse IPv6 in a way that makes it impossible for customers to do any little more advanced security at all.
I thought the lack of shame in handing over a /64 was just an old Brazilian problem with being a rogue. I’m less embarrassed to know that this is a worldwide problem, even more so when I need 2 links, because where I work there can’t be an internet failure, and configuring a failover with 2 links giving me a /64 is embarrassingly ridiculous, made me lose sleepless nights, hours of tech support fights, and finally NAT66! Judge me if you want, but it was the only solution.
Duh…without nat how you gonna enforce router dns?
Without nat how you gonna redirect traffic?
Traffic control related to security right, so it’s logical to say that it indeed increase security.
The only reason people against nat maybe because they like your devices to be opened to the public so it’s easier for them to hack. Lol
I have the same problem at my desktop. ${WORK} provides a VPN that only extends a single IPv6 address (and a single IPv4 address) to the client. To get IPv6 support in virtual machines I have to configure NAT66. It breaks the end-to-end principle, which bothers me a lot.