NATTunnel 0.7.3

dotnet add package NATTunnel --version 0.7.3
                    
NuGet\Install-Package NATTunnel -Version 0.7.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NATTunnel" Version="0.7.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NATTunnel" Version="0.7.3" />
                    
Directory.Packages.props
<PackageReference Include="NATTunnel" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NATTunnel --version 0.7.3
                    
#r "nuget: NATTunnel, 0.7.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NATTunnel@0.7.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NATTunnel&version=0.7.3
                    
Install as a Cake Addin
#tool nuget:?package=NATTunnel&version=0.7.3
                    
Install as a Cake Tool

NATTunnel

This program is currently a work in progress.

This is intended to be used to create a (mostly) decentralized peer-to-peer mesh network regardless of the NAT types that may be encountered. It's akin to tools like Hamachi and ZeroTier, but it implements some methods that are more capable of handling symmetric and CGNAT specifically, unlike these tools which often give up way too easily and simply fallback to relaying. Much of the info about how it works can be found in the OVERVIEW.md.

There are two ways to use NATTunnel:

  • As a daemon that creates a system WireGuard interface (the original mode).
  • As an embedded library that games / other UDP apps can link directly, with no WireGuard / kernel anything required (the embedded mode)

Daemon mode

The only prerequisite is the WireGuard client, which can be downloaded here.

Config Instructions

Here is an example config with the only settings you really need to care about:

alt text

Embedded library

The embedded library lets a host application (ex. game) join a NAT-traversed mesh network and treat each connected peer as a normal local UDP endpoint. Built atop System.Security.Cryptography's ChaCha20-Poly1305 and a Noise XX handshake (via Noise.NET).

Install

dotnet add package NATTunnel

Minimal example

using NATTunnel;
using System.Net;
using System.Net.Sockets;
using System.Text;

// 1. Host app binds its own UDP socket on a known loopback port — this is where
//    incoming packets from peers will arrive.
const int hostGamePort = 51000;
var hostSocket = new UdpClient(new IPEndPoint(IPAddress.Loopback, hostGamePort));

_ = Task.Run(async () =>
{
    while (true)
    {
        var pkt = await hostSocket.ReceiveAsync();
        // pkt.RemoteEndPoint is the loopback endpoint of the sending peer.
        Console.WriteLine($"Got {pkt.Buffer.Length} bytes from {pkt.RemoteEndPoint}");
    }
});

// 2. Configure + start the mesh node.
using var node = new MeshNode(new MeshConfig
{
    NetworkID = "my-game-lobby-42",
    NetworkSecret = "shared-secret",
    MediationEndpoint = "sync.milesthenerd.net:6510",
    HostGamePort = hostGamePort,
    // Optional: persistent identity, relay capacity, etc.
    // PersistentPeerID = playerAccountGuid,
    // MinLogLevel = LogLevel.Warning
    // Logger = line => Console.WriteLine(line),
});

node.PeerConnected += peer =>
{
    Console.WriteLine($"Peer joined: {peer.PeerID} via {peer.LoopbackEndpoint}");
    // Send to peer.LoopbackEndpoint as if it were any remote UDP endpoint.
    byte[] hello = Encoding.UTF8.GetBytes("hello!");
    hostSocket.Send(hello, hello.Length, peer.LoopbackEndpoint);
};

node.PeerDisconnected += peer =>
{
    Console.WriteLine($"Peer left: {peer.PeerID}");
};

node.Start();

// Block until you're done — e.g. wait for a shutdown signal.
await Task.Delay(-1);

Alternate example

using NATTunnel;
using System.Net;
using System.Net.Sockets;
using System.Text;

// 1. Host app binds its own UDP socket on a known loopback port — this is where
//    incoming packets from peers will arrive.
const int hostGamePort = 51000;
var hostSocket = new UdpClient(new IPEndPoint(IPAddress.Loopback, hostGamePort));

_ = Task.Run(async () =>
{
    while (true)
    {
        var pkt = await hostSocket.ReceiveAsync();
        // pkt.RemoteEndPoint is the loopback endpoint of the sending peer.
        Console.WriteLine($"Got {pkt.Buffer.Length} bytes from {pkt.RemoteEndPoint}");
    }
});

// 2. Configure + start the mesh node.
using var node = new MeshNode(new MeshConfig
{
    NetworkID = "my-game-lobby-42",
    NetworkSecret = "shared-secret",
    MediationEndpoint = "sync.milesthenerd.net:6510",
    HostGamePort = hostGamePort,
    LocalIdentity = Encoding.UTF8.GetBytes("server"), // 256 byte limit
    ReliableMessageTimeout = TimeSpan.FromSeconds(10), // default 5s
});

node.PeerConnected += peer =>
{
    var identity = Encoding.UTF8.GetString(peer.Identity);
    if (identity == "server")
    {
        // client connect logic here
    }
};

node.MessageReceived += async (peer, bytes) => {
    var str = Encoding.UTF8.GetString(bytes);
    Console.WriteLine($"Got msg {str} from {peer.PeerID}");

    // send same bytes back
    await node.SendMessageAsync(peer, bytes, reliable: true);
    // or
    await node.BroadcastAsync(bytes, reliable: false);
}

node.Start();

// Block until you're done — e.g. wait for a shutdown signal.
await Task.Delay(-1);

What you get

  • Direct UDP connectivity to every peer in the mesh, even across symmetric NAT and CGNAT (via the introducer-driven hole-punching protocol).
  • End-to-end encrypted transport. Noise XX handshake on first contact; ChaCha20-Poly1305 with explicit per-packet nonces (UDP-safe) for steady-state data.
  • Userspace relay forwarding for peer pairs that can't direct-connect (rare). Relay nodes only see ciphertext, never plaintext.
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.7.3 124 6/3/2026
0.7.2 95 6/2/2026
0.7.1 105 5/31/2026
0.7.0 96 5/31/2026
0.6.0 94 5/31/2026
0.5.2 104 5/31/2026
0.5.1 98 5/30/2026
0.5.0 96 5/30/2026
0.4.1 98 5/30/2026
0.4.0 97 5/30/2026
0.3.0 104 5/30/2026
0.2.5 93 5/26/2026
0.2.4 91 5/25/2026
0.2.3 87 5/25/2026
0.2.2 100 5/25/2026
0.2.1 95 5/24/2026
0.2.0 91 5/24/2026
0.1.3 92 5/24/2026
0.1.2 93 5/24/2026
0.1.1 93 5/24/2026
Loading failed