3
votes

Problem

I'm trying to develop a communication system where:

A, B are machines under NAT, A is the server B is the client S is the STUN server

S is running on a machine reachable on the Internet

The flow is as follows:

A hits S with an opcode saying he's the server
S registers A as server

B hits S with an opcode saying he's the client
S sends to A B's external infos (IP, PORT)
S sends to B A's external infos (IP, PORT)

A starts sending B an opcode saying he's the server every 500ms
and meanwhile listens for packets saying he's got a client

B starts sending A an opcode saying he's the client every 500ms
and meanwhile listen for packets saying he's got the server


Trouble

Here's where the troubles start, the STUN server does its job, since both ends receive correct infos about the other.

But then I do never receive the other end's message, so both ends keep listening without receiving the handshake opcode nor anything else.

NAT's Behaviour

I did examine this NAT's behaviour and seems it does like this

A is at 192.168.X.X, on port 4444 connects to the outside exposing N.N.N.N:4444 so the port number is kept as long as it's free, gets a new (random ?) one if not available.

Tests

The tests I run have seen both ends (A, B) hosted on the same machine, both bound to the machine's internal IP, tried to bind to 127.0.0.1, 0.0.0.0, nothing changed.

If while they're listening for handshakes I echo something with nc to localhost, it is received and displayed (as an unrecognised message) without any problem. The connection routed via the NAT doesn't wotk tough, every packet is discarded.

Also tried with A hosted on the machine, B on an Android phone under mobile data, with a simple app written ad-hoc. Still locks waiting for something, like the nodejs tests.


Update: Another thing I tried to do is to open an hole with nc

On two different machines under the same NAT I ran:

echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4567 -p 4568

echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4568 -p 4567

Different times for each machine. From my understanding this should punch an hole in the NAT with the first packets discarded and the subsequent forwarded. But nothing happened, no end got the message.

I've also tried:

from local machine echo "GREET UNKOWN PEER" | nc -u <PUBLIC IP> 4567 -p 4568

from public machine echo "GREET UNKOWN PEER" | nc -u <NAT IP> 4568 -p 4567

this one works, the local machine under NAT contacts the public one and after the first discarded packet is able to receive and send on the assigned port. I wonder why this doesn't work on two machines under the same NAT (???)


Code

I didn't show any code because I think there is some kind logic flaw in this, however here's the github project for that.

index.js contains the STUN server, the tests folder contains the test cases: test.js starts the stun server, PeerClientTest.js and PeerServerTest.js are mockups of the client and server.

Run node tests/test.js to start the server on a public machine (change IPs in config.js and tests/config.js)

then node tests/PeerServerTest.js to start the server ("A") and node tests/PeerClientTest.js to start the client ("B"). Both will recognize each other via STUN, then listen for the other end's handshake opcode while sending their own handshake opcode. This never happens so they just keep sending/listening forever.

Node is not required, so if there are better solutions in other languages just tell, will be appreciated.

1

1 Answers

1
votes

B's NAT is filtering A's packets and is not letting them through. NAT filters unknown packets sent to it. Your server A is sending packet to client B. But client B previously never sent a packet through NAT to A. So to B's NAT A's packets are unknown and being discarded.

You need to punch a hole in B's NAT for the NAT to allow the incoming packets. Send a packet from B to A NAT's IP:Port. After that when you send a packet from A to B, B's NAT won't discard A's packet.

This won't work if A and B's NAT has a combination like Symmetric and Symmetric/PRC NAT. In this case you will have to use a TURN relay server.