Developing firewall and NAT friendly network applications
When I worked on ISA Server I’ve seen network applications that were incompatible with firewalls and NAT and were difficult or impossible to configure the firewall for, even when the firewall administrator wanted the application to pass through. Below are some design considerations that can help make network applications more “firewall/NAT friendly”.
For a client-server application that has request-reply semantics, the obvious choice would probably be to use HTTP since it is so commonly available. Be warned that it is not a good idea to use port 80 for traffic which is not HTTP. While port 80 is usually open in firewalls, content is often inspected for validity or transparently redirected to proxy servers for caching purpose so using port 80 for a protocol which is not HTTP is not a good idea.
Things get more complicated if both the hosts that need to communicate could both be behind a NAT device or a firewall. From the firewall administrator point of view (and the end user who needs to request the administrator to open ports), it is better to have outbound connections than an inbound connection, and a fixed port is better than a port range. It is even better if you do not need to open any new port at all for that matter. Again, be warned against overloading a well-known port with traffic that does not conform to the standard. I once encountered a P2P application that tried to use port 21 (assigned to FTP). ISA Server blocked this application because it knows how to filter FTP and this P2P application was definitely not FTP.
Now if you absolutely have to receive inbound connections to your client application, here are few rules to consider
1. Have plan B ready. Firewall and routers from different vendors will behave differently, some will work, some will not. Even with same vendor some will have stricter policy which will not allow inbound connections at all. Plan for a fall-back to outbound connection or different protocol.
2. gethostbyname() on the local machine does not return the address for the local machine. What this API returns is a list of addresses. If the machine happens to have a single NIC you get the address. If the machine is multi-homed (as would be the case if the machine is used for sharing Internet connections) then you get a list of addresses. The first address on the list could be the internal private address that is not accessible from the outside world. So how do you get this address? If you already have a connection with the other host, or with a host that is accessible to both, you can use getsockname() on that socket. If the client is behind an ISA Server and using ISA Firewall Client, using this method will retrieve the “external” IP address of the ISA server. This is good because you can later also bind() using this address which will cause the firewall client to send a bind request to the ISA server. If you call bind() with 0.0.0.0 as the IP address, the firewall client software has to guess whether this is a local or remote bind() and may guess wrong.
3. UPnP – ICF and modern routers support configuration of port mapping via UPnP. There are APIs that can help. This works great with home routers, but is not good for WANs or any network with more than one segment because UPnP is based on broadcasts and works only on a LAN.
4. Allocate from a port range. While for the outbound case, a single port is preferred, for inbound you should take into account that a single port could already be in use by another user on the same machine (think about XP home with multiple user sessions open), or by another application on the machine. In case of NAT, the port could be in use by another machine. You may want to allocate from a range of ports instead of letting the system select an available port. This can help the configuration of firewalls by limiting the outbound ports that need to be opened.
5. UDP sessions. Some NAT devices and firewalls generate a UDP “session” when a packet is sent outbound. By sending a single UDP packet it may be possible to enable a UDP mapping on the NAT device. Teredo, for example, uses this technique.
This posting is provided “AS IS” with no warranties, and confers no rights.