Do you have any UDP tunnelling code anywhere ?
I thought I had but that wiki is down. But really, it's just that simple. Send UDP to other client. Send UDP back. The second or third attempt will go through the router just fine. (Not the first attempt, that will get blocked until both have send one packet each).
You also have to make sure you keep the connection alive by sending a packet every few seconds. Times are different depending on router so might need some research.
My testcode, not tested for years:
// --------------------------------- //
// Project: NetUDPThruRouter
// Start: Tuesday, September 15, 2009
// IDE Version: 7.104
// Works if you send a message from inside the firewall to the outside IP of the other client
// And then send a message from that client on the outside of the firewall to the inside.
// Both clients can be behind a firewall.
GLOBAL sock% // The socket connection
GLOBAL port% = 15000 // Port number to use
LOCAL ok%, ip%, rv%, msg$
LOCAL src_ip%, src_port% // The ip-address and port of the last packet
myip$ = NETGETIP$() // Get our local IP just for the show
log("Our IP: "+ myip$)
STDOUT "\nDestination IP: "
destip$ = STDIN$()
// Just for less typing when testing
IF destip$ = "" THEN destip$ = "10.10.0.11"
ok = SOCK_INIT() // Init network
sock = SOCK_UDPOPEN(port) // Get the socket so we can send/recieve on the port
IF sock <> -1
SOCK_SETBLOCKING sock, FALSE // Set socket to blocking(true), wait until message was sent or recieved
ip = SOCK_GETIP(destip$) // Convert the string to an integer IP
// Send 32 packets, waiting one second for an answer between each send
FOR n = 0 TO 31
log("Sending message: "+"Hello from "+myip$+" To: "+destip$)
ok = SOCK_UDPSEND(sock, "Hello from "+myip$, ip, port)
IF ok <> -1
log("message sent with "+ok+" bytes")
timeout = GETTIMERALL() + 1000 // Start timer for one second
WHILE rv <> -1 AND GETTIMERALL() < timeout
rv = SOCK_RECV(sock, msg$, 999)
src_ip = SOCK_GETREMOTEIP(sock)
src_port = SOCK_GETREMOTEPORT(sock)
IF rv>0 THEN log("message recieved: ["+src_ip+"]["+src_port+"]["+msg$+"]")
log(NETGETLASTERROR$()) // Didn't work, tell user why
FUNCTION log: str$