Search code examples
c#socketsnetworkingudpnat

UdpClient method Receive gives wrong port number if sending client is behind NAT and server is run on Ubuntu .NET6


I am trying to implement NAT hole punching for UDP datagrams for a simple Unity game. I have a public-available server (example.com) which is listening on both TCP and UDP on port 8995.

The idea for algorithm follows:

  1. Client connects on TCP/8995 and specify the details of the game it want to host
  2. Server reply with token
  3. Client starts UDP socket via UdpClient class in C#
  4. Client sends UDP datagram to server from this socket with the token. The server learns NAT Ip/Port of the client
  5. When another client wants to connect, it asks server for the Ip/Port of the client it want to connect

The problem I have is step 4. I setup a client at my PC (192.168.1.1 port 9589) which is behind NAT and send my UDP packet to server. I received it via:

    _listener = new UdpClient(_settings.EndPoint);
    IPEndPoint source = new IPEndPoint(IPAddress.Any, 0);
    var datagram = _listener.Receive(ref source);
    _logger.LogDebug("Recevied UDP handshake from {EndPoint}", source);

The log I am getting here is Recevied UDP handshake from x.x.x.x:9589 where x.x.x.x is my correct public IP of the client.

Obviously the port I am getting in the log is not a temporary port on NAT, but a local port of the client behind NAT. So the Peer must have traversed the NAT to learn that (via UPnP maybe?). Is there any way to disable that behavior on server so I can learn the temporary port on NAT?

I am using Net Core 6 and Ubuntu server


Solution

  • Obviously the port I am getting in the log is not a temporary port on NAT, but a local port of the client behind NAT.

    You get the port assigned by NAT, not the port used by the client on the LAN. These ports can be the same, because many NAT implementation try to do port preservation if possible.