IPv6 versus NAT (by )

I was enthusiastic about IPv6 when I first read of it, in the late 1990s. Mainly, I liked the autoconfiguration, and the inbuilt support for anycast and multicast, which are used to great effect: there is s standard IPv6 address for "my nearest time server" and the like, which has various benefits.

However, it comes at a cost. It's a whole new Internet that has to be built alongside the existing one and a careful handover done with complex mechanisms to let them coexist transparently. And the better autoconfiguration of IPv6 isn't that useful in the presence of recent developments such as automatic IPv4 address assignment, mDNS for finding things, and of course, good old DHCP for managed networks.

And it's not working. More than a decade has passed, and IPv6 is still a toy. It's extra work to set up, and the IPv4/IPv6 migration mechanisms you need to be able to still access the IPv4 Internet actually break existing stuff, mainly because the IPv6 side isn't being maintained well (so often breaks without being noticied) and hosts using the mechanisms will prefer IPv6 over IPv4 (as otherwise, IPv6 would never get used, as almost everything that offers IPv6 also offers IPv4) if it's advertised.

So there's little motivation for people to bother turning on IPv6 - it's more work, and it breaks your Internet access (or, if you're a service provider, unless you're careful, it offers an alternate way to access your site that is more work to maintain, but breaks more often as you won't be putting as much effort into maintaining it). This means that the critical feedback loop of people wanting IPv6 because there are good things that are only on IPv6 will never kick in. It'd be stupid to try and be IPv6-only, but until useful things are IPv6-only, there's little incentive to even support IPv6 alongside IPv4.

Now, the main reason people say we should move to IPv6 is because of the IPv4 address space exhaustion. But there are other solutions.

The widespread one is Network Address and Port Translation (or "NAT" for short). Under NAT, an entire network has a single public IPv4 address and the devices inside the network are assigned addresses from a special private range (that can be reused for every private network), and outgoing connections get their source address and port rewritten so they all come from that one address, and when the replies come back, they're mapped back into the private address of the actual device. This means an entire network (which could be an entire organisation with millions of PCs, or an entire ISP with millions of customers) can use just one (or a few, if they need more ports to support all the connections at once) public IPs.

There are issues with this - the NAT device needs to remember what external ports are used by what connections, and it needs to keep track of when those connections are still being used so it can re-use the ports. But if a device is switched off or unplugged or dies, it will never explicitly close the connection,. so the NAT device has to discard connections that just aren't used for a long time, assuming the owner to have died. However, this means that long-lived connections that aren't used much tend to get killed. But since NAT is so widespread now, most apps that open those kinds of connections nowadays send "keep-alives", empty messages that just keep the connection alive so the NAT device doesn't forget them.

And it also means that devices behind NAT can't accept incoming connections; the NAT device only lets incoming connections out and remembers the return path for replies - if an incoming connection comes in, it has no way of knowing what device "wants" it unless it's been specifically configured with a "port forward". Standards like UPnP exists to allow devices to find their nearest NAT router and ask for a port forward to be set up, but they suck for various reasons I shan't elaborate right now.

This isn't a great issue, though. As a laptop user, I am resigned to being behind NAT most of the time. Almost everything I do from my laptop is based around connecting out to remote servers, and for the exceptions, I have an N2N VPN that lets my peers connect to me via an encrypted IP-level relay server. My long-lived SSH connections have keepalives turned on. It works out OK in practice.

However, I think it could easily be improved...

Before NAT became popular, the standard way of doing the same thing was via a SOCKS5 proxy. This worked much like NAT - you'd have a network using private addresses, and a single border device on that network that also had an Internet connection with a public IP. The border device ran some software - the SOCKS5 proxy.

When applications on devices inside the network wanted to connect to somewhere outside of the local network, rather than trying to reach it directly, they'd instead connect to the SOCKS5 proxy. Over that connection they'd send a request for the connection to be forwarded on. The SOCKS5 proxy would then open a connection, from its public IP address, to the destination server. It would then forward traffic between the two halves of the connection, making the device's connection to the SOCKS5 server in effect be a connection to the remote server - and back again in the opposite direction.

So it basically did the job of NAT, except that it required the devices to know about SOCKS5, and to know where the SOCKS5 server was. NAT won, as it was transparent: the NAT box just pretended to be a router offering access to the Internet (the "default route" you have to put in when manually configuring a network, or configured automatically via DHCP or PPP). SOCKS5 didn't really require you to modify the application (although many applications did add support to SOCKS5), as it was possible to write a "socksify" tool that pretended to be the OS's normal interface to the network (the "sockets API"), but which actually made connections via SOCKS where applicable.

But SOCKS5 doesn't have NAT's problems with keepalives. And it has a big advantage over NAT - the SOCKS5 protocol lets a client request an incoming connection, in which case the SOCKS5 server opens an incoming connection port on the public side and reports its address back to the app, along with a notification when the connection is taken up. It's a bit limited, as it only lets a single connection in (while a proper listening port lets multiple connections).

Also, SOCKS5 actually makes it easier to adopt IPv6. When an outgoing connection is requested, the app can specify an IPv4 address, an IPv6 address, or a hostname - and in the latter case, the SOCKS5 server could in principle find an IPv6 server at that hostname (with an AAAA record) and open an IPv6 connection, even though the application has connected to the SOCKS5 server via IPv4 - or vice versa, if the client connects to it via IPv6.

And unlike NAT, SOCKS5 has a login phase:: each connection can supply a username and password to identify the user. Under NAT, all you have is the private IP address of the device. This means that SOCKS5 servers can give better connections to more important users, and better log who did what (where that matters).

So perhaps it's time for a SOCKS5 comeback. The protocol has been extended to support IPv6, but I think it could do with a bit more sprucing up to make it more powerful and modern. Here's what I'd suggest:

  • Proper listening socket support. It should be possible to request a listening socket, and if you are accepted, then be sent messages every time a client connects; but rather than your connection then becoming the relayed client connection, the accept message just gives you a magic token identifying the connection. You can then open another connection to the SOCKS5 server and, rather than requesting an outgoing connection, offer up the magic token to accept the incoming connection and have it relayed. Or just reply on the original listening-socket connection to reject the request.

  • Listening sockets should be able to request a specific port to listen on, along with a flag to specify whether they're happy to accept another, or should just give up the attempt if they can't have the one they request. Such a request might be rejected due to it being already in use, or certain listening ports might be reserved for specific users.

  • Better UDP support. The current UDP support in SOCKS5 amounts to asking the SOCKS5 server to set up a UDP relay. All your UDP traffic must then be sent to an IP+PORT the SOCKS5 server sends in the reply, with a header added to authenticate it; this eats up some of the limited available size of a UDP packet. It'd be nice if the UDP packets could tunnel over the SOCKS5 connection, like TCP connections are, with suitable framing.

  • Ubiquitous support for SOCKS5-over-SSL in clients and servers. Then it can be used as a simple VPN - offer a SOCKS5 server on the public side of your SOCKS5 relay, too, that lets authenticated users who are outside of the office connect in to access servers on the private network. Or just trust your internal network less, as some SOCKS5 connections are better than others (due to being optionally authenticated to a specific user) so are worth stealing. For this use, it'd be nice if a SOCKS5 server could announce (when it's connected to) what addresses it provides access to - for a normal Internet gateway, it'd reply "all addresses"; for a VPN, it'd just report the private IP range.

  • Better support in devices. SOCKS5 should be a standard feature of the sockets library, not something you need to hack in under an app. SOCKS5 should be in smartphones and tablet computers. There should be the option to specify a list of SOCKS5 servers as well as a default route (they can be connected to and asked what address ranges they provide, and connections made via them accordingly). DHCP servers should announce SOCKS5 proxies (there doesn't seem to be a DHCP option for SOCKS5 proxies; am I looking in the right place?).

I think that extending SOCKS5 in the above way (to make SOCKS6!) and then getting a good implementation of it open-sourced under a BSD license and thence it device OSes as standard would be a LOT less work than migrating to IPv6, while also offering an improvement over IPv4 with NAT - and yet also able to coexist happily with IPv4+NAT, as non-SOCKS devices can still be NATed via the default route.

So, how about it? If somebody volunteers to write a decent "SOCKS Next Generation" server (using nice scaleable event-driven IO and all that) and client, I'll volunteer to help you as best I can, and write up a proper draft RFC for the enhanced protocol. If we can get the server into consumer and small office ADSL routers (whose manufacturers seem to be quite open to adding extra features to the brochures), along with advertising themselves as such via DHCP option that clients listen to, it can be come ubiquitous and useful; then we can work on getting the ISPs that to support it (making sure our SOCKS server is happy to pass connections on to an upstream SOCKS server, for when we are proxying to an ISP's own private network). I reckon that'd be a few weeks' development time, at most, then it's all about the lobbying to get it accepted into OSes and routers.

Fame and glory await!

6 Comments

No comments yet.

RSS feed for comments on this post.

Leave a comment

WordPress Themes

Creative Commons Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales
Creative Commons Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales