As you know, we participated in the Google summer of code 2015. One of the projects accepted for our organization was "NAT traversal via hole punching Set of Rules" by the student Max Mertens. In this post, Max tells us about his experience. Thanks!

Peer-to-peer software is a great idea, as you do not need a central server and save bandwidth necessary for relaying. As I have been interested in networking and protocol development for a few years, I was happy to find the P2PSP organization and that it is participating in the Google Summer of Code 2015. So I asked the P2PSP developers if they would need an implementation of NAT traversal in their software, and applied for GSoC with the project "NAT traversal via hole punching Set of Rules as a Python implementation". The main idea of the NAT Traversal Set of rules (NTS) is that two peers (computers) that are each behind a different router (Network Address Translator, NAT) can connect to each other, without prior configuration of port forwarding and without UPnP or similar techniques. This enables multimedia to be streamed between such peers, e.g. between PCs or mobile devices each behind a home router.
The mentors Vicente González Ruiz and Juan Pablo García Ortiz accepted the project ("any improvement in the NAT's war is also interesting for us") and I was very happy to be able to work with this organization over the summer.

I began with the project by examining existing NAT traversal software and setting up a testing environment. Then I worked on a simple Python script doing nothing but NAT traversal. After testing and improving it, I added the NTS classes to the P2PSP software and added more and more functionality, until NAT traversal was working for all theoretically possible combinations.

Virtual network setup used for testing; each box represents a virtual machine or Linux network namespace.
Virtual network setup used for testing; each box represents a virtual machine or Linux network namespace.


During the project, I sent status report emails once or several times a week, and my mentors Vicente and Juan Pablo helped me if I was unclear about P2PSP code or principles, and they had creative ideas on extending the NTS code. Also they were always open to merge changes to existing P2PSP code that were necessary or helpful during development.
A few practices emerged that were helpful during development: To stick closely to the timeline that was planned in the proposal and to keep track of outstanding tasks, I had a frequently updated task list with finished tasks for each week and a to-do list sorted by priority. This way it was easy for my mentors and me to see how many tasks are left and what is to be done next. Documentation can turn out to be much more work than necessary if you document any change you made to the project. So I aimed at documenting each small part of the code just after it was finished and was not likely to be changed much anymore, and finalized the documentation before the midterm and the final evaluation to fully match the code.

 

As scheduled in my timeline, the coding and testing was mostly done one week before the final deadline, so all goals were accomplished in time. I was very happy to see that my mentors merged the pull requests after the final evaluation. Now after the summer I plan on staying in touch with the team and collaborating further a bit to the organization as far as the free time alongside studying permits.
I want to thank my mentors Vicente and Juan Pablo for their great support and supervision throughout the project, and wish them much success for the further development of their organization. 

 

Detailed description of the project (as short as possible; for the complete documentation see NAT traversal documentation):

The project emerged to have four major parts, and from time to time during the project some minor modifications were made to the existing P2PSP code to let the NTS classes integrate nicely.
The main part, NAT traversal itself, was implemented as the classes Splitter_NTS, Peer_NTS and Monitor_NTS, that are subclasses of the respective DBS classes. So they just add the necessary code to punch a hole into the NATs and create mappings to ensure a working connection between each two peers behind NATs. It was first a partial implementation of the algorithms described in the P2PSP protocol specification [#], and later more functionality was added to work with as many NAT types as possible. Now after finishing the project, the NTS classes can traverse all NAT type combinations that are theoretically possible, and automatically retry when traversal fails.

Apart from the initialization phase of the protocol, where configuration parameters are transmitted over TCP, the P2PSP software relies solely on UDP communication to decrease the overhead of TCP sockets. UDP packets are not guaranteed to arrive (so there is some packet loss), NAT traversal however requires reliable data transmission, so reliable message sending over UDP was developed: A peer sends a message repeatedly (once a second), until the destination peer sends an acknowledging message. After a timeout of a few seconds the sending peer just drops the message. The splitter however is crucial to the multimedia broadcasting and should handle many peers simultaneously, so it just sends a message a few times at once without keeping track of which peer has received which message, and hopes that at least one of the message arrived at the destination. 

P2PSP NAT traversal with retry
Terminal recording of a colorized test running on real routers (DSL and mobile internet); see the video.

NATs are called "symmetric", if their source port (the public port towards the internet to receive replies) differs for each connection to a new destination. For NAT traversal with this type, the source port chosen next has to be predicted. This is done by measuring the source port distance of two sockets to different destinations, and assuming that the next (or several) source port might be taken by another software behind the same NAT. So for the measured port distance, a magic formula suggests a few source ports that are most probable to be chosen next, so NAT traversal works even if frequently sockets are created to different destinations, by PCs behind the same NAT.

Of course the functionality of the developed code had to be tested. So a virtual network with two PCs, each behind a NAT, and servers for the splitter and the monitor peers was set up, with each part running in its own virtual machine and the NAT types configured by iptables chains. At first each possible NAT type combination was tested by hand (working/not working), later by a script, and the final test script does several test runs per combination in parallel and counts in how many cases NAT traversal was successful. As running 6 virtual machines puts a bit of load on my old laptop, a script was created to set up the testing network using Linux namespaces instead of VMs, which runs much more smoothly (it should even be possible to run a few P2PSP teams in parallel on a Raspberry Pi).

Final test results for all possible combinations of NAT types
Final test results for all possible combinations of NAT types; for NAT type description, see NAT traversal documentation

By Max Mertens, a student of the GSoC 15 with P2PSP.org. Author of the project "NAT traversal via hole punching Set of Rules as a Python implementation"