Its been a few days since I'm playing around Hole Punching in order to have some kind of reliable behaviour, but I'm now at a dead end.
UDP Hole punching works great: simply first send a packet to the remote, and get the remote to send a packet the otherway as it will land through the source NAT. Its rather reliable from what I tried.
But now comes TCP... I don't get it.
Right now, I can establish a connection through NATs but only with connecting sockets:
A.connect(B) -> Crash agains't B's NAT, but open a hole in A's NAT.
B.connect(A) -> Get in A's NAT hole, reach A's connecting socket.
But now, the two sockets that sended the SYN packets for connection are connected.
You would think that I would have done it, got a connection through 2 NATs, hooray.
But the problem is that this is not a normal behaviour, and given to this paper: http://www.brynosaurus.com/pub/net/p2pnat/, I should be able to have a listening socket in parallel to the connecting socket.
So I did bind a listening socket, which would accept inbound connections.
But inbound connections are always caught by the connecting socket and not the by the listening one...
e.g:
#!/usr/bin/env python3
from socket import *
from threading import Thread
Socket = socket
# The used endpoints:
LOCAL = '0.0.0.0', 7000
REMOTE = 'remote', 7000
# Create the listening socket, bind it and make it listen:
Listening = Socket(AF_INET, SOCK_STREAM)
Listening.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
Listening.bind(LOCAL)
Listening.listen(5)
# Just start in another thread some kind of debug:
# Print the addr of any connecting client:
def handle():
while not Listening._closed:
client, addr = Listening.accept()
print('ACCEPTED', addr)
Thread(target=handle).start()
# Now creating the connecting socket:
Connecting = Socket(AF_INET, SOCK_STREAM)
Connecting.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
Connecting.bind(LOCAL)
# Now we can attempt a connection:
try:
Connecting.connect(REMOTE)
print('CONNECTED', Connecting.getpeername())
except Exception as e:
print('TRIED', type(e), e)
Now with this script, just agree on a port with a friend or whatever, and execute it on one end's, the Connecting.connect(...) should run for a bit (waiting for timeout, because SYN packet crashed into the distant NAT, but fortunately opened a hole in his own NAT), meanwhile execute the script on the other end, now the Connecting.connect(...) will return because it will have connected.
The weirdest part being: The Listening socket was never triggerred.
Why ? How to get the listening socket to catch inbound connections over the connecting socket ?
Note: Closing the connecting socket does send something on the network which immediately close the hole, at least it does on my network.
2nd-Note: I'm on windows.
Edit: The main problem is that in any circumstance, this script outputs CONNECTED [...] rather than CLIENT [...], which given some lecture should not happen.