You are here

Testing your NAT boxes for compatibility with Knock

Primary tabs

With reference to Knock, we would like to move to the next stage towards having fully-authenticated TCP connections over the Internet. However, we need your help in order to get an estimation of how well the average home gateways are able to handle the data which is sent out by Knock. We thus provide code which performs the needed measurements for GNU/Linux, OSX, Windows and Android as well as their compiled equivalents, which can be downloaded at the end of this article.

What data do we collect?

We collect the MAC address of your NAT box, ISN and TCP timestamp values as generated by your device and received by our server, a timestamp, a boolean if the received data was valid (simple checksum) and an identifier of the country to which the IP address you were running the test from is assigned to. We believe that none of this information (including the combination) is really sensitive. For why we need exactly this data, please refer to the technical details below.

Running the Client

For those who just want to help us collect the data we need, we quickly outline how to run the precompiled client on each platform.

Linux, Mac OS X

All you need to do is to download the file for your operating system at the end of this page, unpack and run it with root permissions. If you are not familiar with the command line, follow the instructions below.

  1. Open a terminal. The following commands determine the operating system, then download and unpack the client:
    $ os=$(echo $OSTYPE | sed 's/darwin/osx/;s/[0-9].//;s/-gnu//')
    $ curl "$os.tar_0.gz" -o "client_$os.tar.gz"
    $ tar -xzf client_$os.tar.gz

    Optional: Verify the signature of the binary using GnuPG. Download the public key from this website to the same directory where you saved the client, execute
    $ gpg --import 6D451038.asc
    $ gpg --verify client_$os.sig

    and look for a line stating Good signature from "Julian Kirsch" or similar. It should be followed by the following primary key fingerprint: F949 CFBD 140A 6DD0 71E9 0B8C DC24 396B 6D45 1038.

  2. Execute the client with root permissions to collect the data (If you do not want the client to transmit the Ethernet address of your NAT router, add --disable-mac to the end of the command line):
    $ sudo ./client_$os
  3. Optional: If your Linux distribution does not use sudo you need to execute the client with su -c "./client_linux"

  4. Done.


  1. Download the Windows version of the client to a directory of your choice.
  2. Download & install winpcap. (Optional: A great opportunity to learn more about the network stack is Wireshark, which also needs winpcap installed on your machine.)
    Optional: If you want to check the authenticity of the provided signature, download and install GnuPG for Windows. (Use a separate guide when needed. Especially make sure that GnuPG is included in your %PATH% variable) Then, fire up a command line and enter:
    $ gpg --import 6D451038.asc
    $ gpg --verify client_windows.sig
  3. Navigate to the location where you stored the client (client_windows.exe) and double click it to start the execution. (Optional: If you do not want the client to transmit the Ethernet address of your NAT router, create a shortcut to the client_windows.exe program by dragging it while holding down the right button of your mouse. Right click the newly created shortcut and choose "Properties". Add --disable-mac to the end of the path name displayed in the "Target" field.)
  4. Done.

Compiling the Client

We give brief instructions on how to compile the client which collects the data for each platform. If you do not want to or are unable to compile the code on your own, then you can also download the precompiled binary for the operating system of your choice. (instructions, see above)


Download the client.c file from the attached list. Make sure that the development files (headers and libraries) of libpcap are installed. (Most likely called libpcap-dev or libpcap-devel in your favorite distribution.) Afterwards compile the code and explicitly link with libpcap and libpthread:

$ gcc -lpcap -lpthread client.c -o client_linux

Then, type as root:

# ./client_linux

You can use --disable-mac to explicitly keep the program from sending out the ethernet address of your NAT box. However, this would prevent us from detecting double-submissions.

Mac OS X

Download the client.c file from the attached list. As OSX comes with libpcap preinstalled, you can directly compile the code either using clang or gcc as desired:

$ clang -lpcap -lpthread client.c -o client_osx
$ gcc -lpcap -lpthread client.c -o client_osx

Running the code requires either to be root or to be member of the access_bpf group.

# ./client_osx


In order to be able to compile the code for windows you need to download two files from the list below: client.c and windows_helpers.h. Place them together in one directory. Get the newest winpcap dev's package from and install it on your machine. Download the latest version of the POSIX thread library and unzip the directory tree. Then, using gcc, open a command prompt and enter

$ gcc -I<path_to_pcap_include_dir> -I<path_to_winpthread_include_dir> ^
-L<path_to_pcap_lib_dir> -L<path_to_winpthread_lib_dir> ^
-lwpcap -lpthread -lws2_32 -liphlpapi client.c -o client_windows

replacing the names in brackets with the correct locations within your file system. If you are using Visual Studio instead, create a new empty console application and add the client.c and windows_helpers.h files to the newly created project. Then, open the project properties (Alt+F7) and add the paths to the "include" and "lib" directories of winpcap and winpthread under Configuration PropertiesVC++ DirectoriesInclude Directories and Configuration PropertiesVC++ DirectoriesLibrary Directories. Then compile and run the code using the designated buttons in VS.

Technical Background

In this section we explain what we are trying to measure and why.

Knock and TCP headers

We are interested in how your NAT box at home treats two special TCP header fields:

  • The initial sequence number (ISN), see rfc793 (Pages 16, 27ff.)
  • The TSval field of the optional TCP timestamp header, see rfc1323 (Pages 12ff.)

Knock uses these two field in order to authenticate TCP connections. It embeds data derived from a pre-shared key in the outgoing ISN of a connection that should be secured and also takes the TCP timestamp (if present) into account in
order to establish replay awareness. Please refer to the research paper or the implementation of Knock for further details how this is done.

NAT boxes could be hazardous

This is where Network Address Translation (NAT) comes into play. In a typical home network, NAT boxes replace the source IP address and the source TCP/UDP port of a packet with the public IP address that was assigned to the network gateway by your Internet service provider (ISP) and a port chosen according to some rules. Knock was designed to be aware of this and therefore does not rely on the source IP or the source TCP port. However, as stated above, Knock does rely on other information contained in the TCP header. If this information gets corrupted by the NAT box, Knock cannot operate as intended. We thus need to find out to what extent the NAT implementations "in the wild" perform changes to the relevant TCP header fields.

Measuring your NAT box

The code we would like you to run does one very simple thing: It sends out a TCP SYN packet (a probe) to one of our testing machines on the internet and extracts the following information from the packet as it is put onto the wire using libpcap:

  • The source address of the IP header. We need this to determine if the packet as it is received by the server has been NATed at all.
  • The ISN field of the TCP header (see above)
  • The TSval field of the (optional) TCP timestamp header (see above)
  • The ethernet address of your NAT box. We would like to be able to group the results by the manufacturer of the NAT box and detect duplicate submissions. Note that you can use the --disable-mac switch in order to only transmit the OUI (wiki) part of the ethernet address. However, the full ethernet address helps us to not double-count your probes.

This 4-tuple gets transmitted after the successful TCP handshake to the server. The server does the following:

  1. Listening for SYN packets sent to the designated port
  2. Extraction of the received source IP, ISN and TSval fields
  3. Extraction of the sent source IP, ISN, TSval and the gateway's ethernet address from the first packet carrying the payload sent by the client
  4. Checking if the probe is valid (just a simple fletcher checksum to keep out random port scans / potential exploits carrying data for a different network service)
  5. Checking if the source IP in the payload does not match the source IP observed by the server (i.e. that the probe has been NATed). If the source IP didn't change, the probe and all data is discarded.
  6. Performing a Geo IP lookup to get the originating country of the probe
  7. Storing of the tuple (hwaddr_sent, isn_sent, isn_recv, tsval_sent, tsval_recv, UNIX_tstamp, checksum_valid, geo_string)

Afterwards the connection is closed as all relevant data has been collected.


So, all in all, we would like you to run the attached code in order to find out how realistic it is to assume that Knock can be deployed on home devices. In order to find out, we collect data such as the TCP header fields before and after passing the NAT box as indicated above. We also try to fetch the ethernet address of the NAT box in order to prevent double-counting and to obtain the manufacturer of your NAT box. As uncomfortable you may feel with this decision, you may well have noticed that we do not store your remote IP address. This means that there is no connection between the ethernet address and the public IP address, and clearly without this information we can not track you (however, you need to trust us that we do not store your IP). Also, your ethernet address is transmitted in the clear over the Internet. The ethernet address effectively turns into a semi-random-ID which gives us some additional hints but does not harm your privacy too much. If you only want to share the OUI of your NAT box, then the option --disable-mac is for you. Lastly, we store the two letter country code of the originating IP and discard all information but the 8-tuple introduced above.

For those who are unwilling to install the libraries needed to compile the source, we provide statically linked binaries signed using PGP. Please note that the program needs root access to work on GNU/Linux and Windows users need to have winpcap installed on their machines (this might be a great opportunity to check out wireshark which also depends on winpcap and allows you to improve your networking-ninja-skills). We also are interested how carrier-grade NAT behaves and therefore provide a binary for ARM-based devices running Linux. We tested it on some popular Android devices and also found it working on the Raspberry Pi. Note that you need root access in order to run the code --- your favorite Android device thus needs to be rooted.

Last but not least we would like to thank all people who are willing to run our code on their devices. As we believe in the strength of open research, all results including the raw data will be published on this website (however, after deduplication MACs will be truncated to the OUI) .


Haven't found windows_helpers.h anywhere, had to hack up the program myself. Here's the result:
Beside that, "closesocket" should be used to close sockets on W32, not "close".

Build in MinGW-w64 MSYS shell with:
gcc -I pcap_includedir -L pcap_libdir client_0.c -o client_w32 -lwpcap -lpthread -lws2_32 -liphlpapi
(assuming that winpthreads-provided libpthread.a is part of mingw-w64)

Hey LRN,

thanks for mentioning. I totally forgot to upload the windows_helpers.h file, which defines

#define close		closesocket

in order to do what you propose. Dirty hack, I know, but worked flawlessly for me. :-)