Exploring eduP2P: A Peer-to-Peer VPN Proof-of-Concept

Traditional client-server VPNs, such as eduVPN, route all client data through a centralized server. While this model is effective for many users, it has notable limitations. Geographical distance between users and the central server can result in increased latency and reduced throughput, adversely affecting performance, especially for bandwidth-intensive or real-time applications. Client-server VPNs deployed by organizations like universities often restrict users from customizing the VPN configuration, limiting flexibility for individuals who need tailored network setups to accommodate their specific infrastructure needs.

In contrast, peer-to-peer (P2P) VPNs, exemplified by products like Tailscale, offer several advantages that address the shortcomings of the client-server model. P2P VPNs establish direct connections between clients, minimizing the distance data must travel and thereby enhancing both latency and throughput. This decentralized approach improves scalability and redundancy, as each new peer can distribute the network load and the system remains resilient even if individual nodes go offline. Additionally, P2P VPNs provide greater flexibility and customization, allowing users to define their own network topologies without needing central administrative control. Overall, peer-to-peer VPNs deliver superior performance, scalability and flexibility, making them a compelling alternative to traditional client-server VPN architectures.

The eduP2P project is a new proof-of-concept for supporting P2P VPNs, currently under development as a “spin-off” of eduVPN. Originating from an initial concept by Jonathan de Jong, a student from Fontys, eduP2P enables Linux, Windows, and macOS devices to establish an overlay network. Henk Berendsen, a student from Radboud University, has recently been enhancing eduP2P with a comprehensive test suite to ensure its effectiveness in “the field” as part of an internship at SURF.

Continuous Integration and Testing

The test suite supports Continuous Integration, and tests both the network performance and functionality of eduP2P. A part of the functional tests, called the system tests, specifically focus on verifying whether a P2P connection can be established between eduP2P clients behind Network Address Translation (NAT).

To this end, the system tests require an environment with a private network for each of the two peers, also containing a router applying NAT. The routers act as the gateways to the public network, which contains the eduP2P control and relay servers. Each network is on the same machine, such that only one machine is necessary to run the system tests. To set up multiple interconnected networks on one machine, the system tests make use of Linux kernel features such as network namespaces and Virtual Ethernet (veth) device pairs. A slightly simplified version of this network setup is shown in the picture below:

Each private network is represented by a separate namespace. Furthermore, each router has its own namespace that connects the private and public namespaces using two veth device pairs.

These router namespaces allow the “Router Public” network interfaces within them to apply NAT using the nftables framework, since packets destined to the public namespace are classified as external when routed by these interfaces, and are therefore handled by the nat table in nftables.

Two types of NAT implemented in the test suite are Symmetric NAT and Restricted Cone NAT, which are defined in RFC 3489: https://datatracker.ietf.org/doc/html/rfc3489.

A symmetric NAT is one where all requests from the same internal IP address and port, to a specific destination IP address and port, are mapped to the same external IP address and port. If the same host sends a packet with the same source address and port, but to a different destination, a different mapping is used. Furthermore, only the external host that receives a packet can send a UDP packet back to the internal host.

Symmetric NAT has been implemented with the following nftables ruleset:

table ip nat {chain postrouting {type nat hook postrouting priority srcnat; policy accept;ip saddr 10.0.1.0/24 oif “Router_Public” masquerade random}}table inet filter {chain input {type filter hook input priority filter; policy drop;ct state established,related accept}}


The rule in the nat table’s postrouting chain causes a different mapping to be used for packets sent by the same internal host to different destinations. The rule and default policy of the filter table make it so that only external hosts that have received a packet from an internal host can send one back. This nftables configuration applies source NAT, whereas destination NAT is handled automatically by the conntrack module of the Linux kernel, which keeps track of network sessions.

A restricted cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Unlike a full cone NAT, an external host (with IP address X) can send a packet to the internal host only if the internal host had previously sent a packet to IP address X.

The nftables ruleset of the Restricted Cone NAT has a few differences with respect to the Symmetric NAT. To ensure all requests from the same internal host are mapped to the same external IP address and port, the target “masquerade persistent” is used instead of “masquerade random” in the nat table’s postrouting chain rule. To make it so that any external host with IP address X can send a packet back to an internal host that previously sent a packet to IP address X, a prerouting chain is added to the nat table. By observing conntrack events to monitor new sessions, rules are added to this chain dynamically. For example, suppose that Peer 1 sends a packet from port 37 to the Control Server on port 42, and that Peer 1 is behind a Restricted Cone NAT that maps this session (10.0.1.1:37, 192.168.0.1:42) to its external IP address 192.168.1.254 and port 1. The nftables ruleset of the Restricted Cone would then look as follows:

The dynamically added rule is applied to any packet sent from the IP address of the Control Server to 192.168.1.254:1, causing its destination to be translated back to 10.0.1.1:37 such that it is routed to Peer 1, instead of being dropped by the default policy of the filter table’s input chain.

The system tests verified whether a P2P connection could be established between one eduP2P client behind a Symmetric NAT, and another behind a Restricted Cone NAT. Surprisingly, this was not the case, even though the UDP hole punching method employed by eduP2P should be able to traverse these NATs.

Based on this finding, and an investigation of its root cause, eduP2P’s implementation of UDP hole punching was fixed by making each peer send more ping packets, with a small pause between each ping. With this fix, a P2P connection could be established between two peers respectively behind a Symmetric NAT and Restricted Cone NAT. Furthermore, the fix has improved the general robustness of eduP2P’s UDP hole punching implementation, since it has for example also become more resilient to packet loss.

Besides the Symmetric NAT and Restricted Cone NAT mentioned in this blog post, the eduP2P test suite also simulates other kinds of NAT in the system tests. More information about the system tests, and the other types of tests in the test suite, can be found in the documentation of the eduP2P test suite’s GitHub repository: https://github.com/hb140502/eduP2P_test_suite/blob/main/test_suite/README.md.

Tags
Skip to content