NAT Traversal Solutions for Independent Developers
Yesterday I read a white paper on something called the Ingate SIParator. I bet whoever came up with that title chuckled for half an hour, thinking he was oh-so-clever. To quote the white paper itself, the SIParator is a firewall specifically for SIP traffic. (SIP – Session Initiation Protocol – is a protocol for initiating media sessions; Voice over IP, video, music, etc. It acts as a wrapper around SDP, which in turn often intiates RTP traffic.) The SIParator is an addon to a company’s existing firewall, which will analyze SIP traffic and correctly convert the external and internal addresses, as well as provide security features against known SIP spoofing methods. It does sound like an excellent product for allowing VoIP in enterprise and company networks, but I’m still not very happy with products like this.
Let’s start at the beginning… NAT and firewall traversal is a major issue these days. Here’s a good summary of the problem, and here are some papers on NAT traversal in combination with SIP. While I’m professionally interested in the SIP and VoIP problem, I’m not overly concerned about this particular issue; after all, there are many products available for solving this. The real problem lies with home users.
Almost everyone has a router of some sort at home; a DSL router, a WLAN router and so on, and the vast majority use internal LAN IP addresses which are translated to the external IP address inside the router. (That’s the NAT part – Network Address Translation.) The main problem with NAT is incoming traffic: how can a router know where to direct an incoming request when several computers share the same external IP? The answer is of course that it’s not possible. IPv4 has a limited amount of addresses, and specific LAN address ranges are necessary. The only simple solution to this is to configure the router so that it directs requests to certain ports to certain LAN computers. This works well for static servers and such, but is a total pain in the nether regions of the back for other applications like games and peer to peer software.
Oh, and there’s another part of the NAT traversal problem as well: protocols that carry IP addresses inside their payload cause a crapload of problems, as they also need translating. But thinking about solutions to this is just depressing, so I’m ignoring that.
Instead, I’ve been looking at some solutions to the basic NAT problem. There’s of course STUN for UDP traffic – but that one has problems, since it won’t work on all NAT implementations. UPnP is another proposed solution to this, used in Gaim for example; but UPnP’s not exactly wide-spread and supported in all cases. Other solutions like TURN include proxies of various kinds, but that’s not exactly feasible for a hobby developer – or even for most companies, due to the relatively unnecessary extra cost of a dedicated server.
The only reasonable solution for an independent developer seems to be a combination of the proxy idea and UDP punching methods. One such UDP traversal method seems to be used by the nat-traverse package; it uses garbage UDP packets to establish NAT entries, and then uses UDP for the actual traffic. This ought to work very well since NAT implementations need to have a relatively long timeout – 30 minutes is the standard on some NATs – since UDP is stateless.
Theoretically, the following ought to work and requires nothing more than a webserver:
- A client sends an HTTP request to a known server, indicating that it wants to connect to another client for a game or a transfer or something.
- The server has a PHP script that processes the request, and places it in a pool of clients waiting for a game/transfer/whatever – possibly with their desired destination client specified as well. The server responds with a “yo, keep it up” message.
- The client repeatedly sends HTTP requests to show that it’s ready. Once the PHP script determines that there’s a match in the pool, it responds with a “yo, here’s your destination’s IP and port” message. This means unnecessary traffic, but possibly affordable if there’s not much data.
- The clients (who hopefully both have received responses with IP/port) start sending 10 garbage UDP packets.
- Allow for some delay and possible delivery problems: resend if no connection is established the first time. A maximum of five attempt sequences ought to be enough.
- If the connection is established, data UDP packets can be sent.
Now all I need is time to implement my various multiplayer game ideas. Dammit, I knew I forgot something!