Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UDP hole punching timeout

I need to implement a UDP protocol. The PC has to listen at a dedicated UDP port for incoming packets. It also sends packet (answers). The application runs on Windows XP, 7, 8, ....

The Windows firewall blocks incoming packets. This can be circumvent by UDP hole punching. So I have to send something that should not hurt. But I want to disturb as little as possible.

  • How can I determine the timeout until the firewall will close the hole?
  • Can I detect that the firewall has closed the firewall so that I have to resend to opening packet? Of course I won't receive anything when the firewall is closed but this might have other reasons.
like image 632
harper Avatar asked Feb 13 '13 15:02

harper


2 Answers

Here's how I measured this, with netcat:

On my Unix host (Mac OS X Darwin), no firewall (or on a Windows machine where the Windows firewall allows the netcat "nc" executable to listen on UDP ports), I run a UDP server with variable delay supplied by remote clients:

WINHOST=10.116.140.69
mkfifo f
nc -u -p 2222 $WINHOST 6666 < f | \
(while read secs; do for sec in $secs; do echo sleep $sec 1>&2; sleep $sec; echo SLEPT $sec; echo SLEPT $sec 1>&2; done; done) > f

On my Windows host (Windows 7 Professional SP1 64-bit), Windows Firewall, with cygwin installed to provide shell and netcat, I run a UDP client interactively:

UNIXHOST=192.168.181.1
nc -u -p 6666 $UNIXHOST 2222

You don't have to use cygwin; a Windows netcat should work fine, but the command lines may vary.

Then into that client I type a series of test intervals, observe the server sleeping then responding, observe whether the client gets the response. These worked: 1, 2, 10, 60, 120, 180. Then this failed: 240. Proceed with a binary search between 180 and 240.

Example 1: On the client side, I type:

10
60
120
180
240

and observe that request-response delay of up to 180 works, 240 doesn't.

Example 2: On the client side, I type:

180
181
182
182

and observe that request-response delay of up to 181 works, 182 doesn't.

Example 3: On the client side, I type (all on the same line):

180 180 180 181 181 181 182 182 182 183 183 183

which generates one UDP request from client, then a series of responses separated by 180, 181, 182, or 183 second intervals. It was observed that request-response delay of up to 181 worked, and in addition, continued responses (without new requests) at intervals up to 181 seconds worked also.

So the firewall hole has an inactivity timer, without regard to whether the inactivity is delay in initial response, or in subsequent additional traffic.

Results on multiple machines:

  • On that Windows 7 Professional SP1 64-bit desktop, the UDP response hole is open for 181 seconds. It's possible that I'm also measuring a network firewall between the two systems, since they are on separate networks -- but I think they are routed not firewalled. In any event, the Windows firewall hole is at least 181 seconds on this system.
  • Another Windows 7 Professional SP1 64-bit laptop, same network segment (so definitely no intervening firewall), the UDP response hole is open for 64 seconds.

I'd be interested in seeing similar measurements on other Windows machines at various OS levels and firewall configurations.

like image 186
Liudvikas Bukys Avatar answered Oct 07 '22 15:10

Liudvikas Bukys


A few tips on hole punching:

  1. On most firewalls (I assume Windows Firewall as well) hole punching only allows a specific IP to connect. Hole punching tricks firewalls/NATs into thinking that you are communicating with a particular IP so it allows packets coming back from that IP. If you are wanting to listen to any IP, than you can't use hole punching without a bridge computer who can coordinate the connection.
  2. Timing may vary between firewalls and/or NATs. Not only do you have to worry about the software firewall (like Windows Firewall), but if there is a hardware firewall and/or NAT device, than you have to worry about that timing as well. Hardcoding a value is not going to work unless you have a very specific network and software setup. Detecting that a firewall has closed the hole sounds like a great idea, except that most firewalls/NATs don't have a way for you to detect that they have closed the hole and as far as I know, there is no good way for you program to detect it.
  3. To do hole punching, you're going to have to send packets that have no function. They are typically a NOP (No OPeration) or KEEP_ALIVE packet that has no purpose and if a program receives one, it just discards it.

My suggestion is to implement a KEEP_ALIVE packet that the client program ignores, and to have the server periodically send a KEEP_ALIVE packet to the client to keep the firewall open. This assumes that you know the IP of the client so you can send it the KEEP_ALIVE packets. If you don't already know the client's IP, than you will either have to setup a publicly accessible bridge computer or disable the firewalls for you server program. Windows Firewall has a COM API or netsh commands that you can use to allow your program to listen for connections. For hardware firewalls/NATs, you can try using UPNP. If that doesn't work, than the best you can do is request that the user opens a specific port for your program.

like image 38
James Yoder Avatar answered Oct 07 '22 15:10

James Yoder