Is there a way to force client to use a specific port instead of ephemeral port

I’m playing around with setting up a direct P2P game with NGO.

My set up looks like following:
I have one machine A serving as the host, and another machine B joining as the client. A and B are behind their own NATs and I’m trying to let B join the game hosted on A by using A’s public IP.

What I’m looking for:
A and B can have a direct P2P game without needing to port forward on A. Also I’d like to avoid using UPnP.

What I have done so far:

  1. I wrote a STUN utility so that I can get the public IP and port of both A and B; (Made sure the NAT type on both machines are full cone, so in theory direct P2P should work)
  2. I wrote a test utility to do a NAT punch-through between A and B. This is successful and after the NAT punch-through, I verified that direct P2P via UDP can work properly between the two machines.
  3. But if I start the NGO server on A (having it listen on ANY IP with the port I got from STUN), the client CANNOT join by connecting to the server’s public IP.

I think what might be wrong is that the client uses ephemeral port, which is NOT punched-through between the client and the server.

But the challenge here is I don’t have a way to punch-through between client and host in this case, since I don’t have a way to specify a port for the client to use. Checking the implementation of UnityTransport, it seems that ClientBindAndConnect routine is a private method so my naive approach of simply inherit UnityTransport class and override this method doesn’t go very far…

Curious is there a more recommended way for achieving what I’m trying to do? Thank you very much for your time and help!

Ok I guess just to answer my own question, in case anyone else is interested:

I got inspired from this post: Can you get which source port the client has connected from?

Basically the idea is to create an extension to the UnityTransport class to expose some of the private fields (like the NetworkDriver object).

This way, I can then inherit the UnityTransport class to override the StartClient method to use my own version of the ClientBindAndConnectEx, which I can then make it bind to a specific port

And finally use this UnityTransportEx in the NetworkManager will then make StartClient method call into my own version which is able to take in a specific port. Not sure if this is the most appropriate solution, but it seems to work…