I have a problem that I am having a serious hard time figuring out, and I would be very grateful if anyone could provide some help.
I have a VPN server inside a local network behind a firewall that allows only outbound connections. My goal it to do a “UDP gender change” and make the VPN UDP port available to an external server where I can forward ports, by creating a reverse tunnel. Doing this using a TCP tunnel is trivial and easy to accomplish by using tools such as socat, nc or even ssh tunnels. VPN, however, should always be carried by UDP packets to avoid TCP meltdown issue (TCP over TCP).
UDP reverse tunnel created with socat/nc does not work as UDP is a connectionless protocol. This means that “client client” and “listen listen” configuration will allow data transfer only when client sends a packet first (impossible in a reverse connection).
Am I missing something? Is there any utility that can accomplish this task (by for example making UDP connection oriented by the use of some headers) without using a second VPN connection? Thank you very much
I was thinking of something like this in Python:
import socket
from select import select
# immediately useful parameters are:
# REMOTE_SERVER_NAME other network server (which will be resolved by DNS)
# LOCAL_SERVER_PORT where forward network traffic to
REMOTE_SERVER_NAME = '8.8.8.8'
LOCAL_SERVER_PORT = 20
LOCAL_SERVER_NAME = '127.0.0.1'
REMOTE_PORT = 9990
LOCAL_PORT = REMOTE_PORT + 1
sock_remote = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_remote.bind(('', REMOTE_PORT))
sock_remote.connect((REMOTE_SERVER_NAME, REMOTE_PORT))
sock_local = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_local.bind(('', LOCAL_PORT))
sock_local.connect((LOCAL_SERVER_NAME, LOCAL_SERVER_PORT))
sockets = (sock_remote, sock_local)
for s in sockets:
s.setblocking(0)
# loop forever forwarding packets between the connections
while True:
avail, _, _ = select((sock_local, sock_remote), (), (), timeout=100)
# send a keep alive message every timeout
if not avail:
sock_remote.send(b'keep alive')
continue
for s in avail:
# something from the local server, forward it on
if s is sock_local:
msg = sock_local.recv(8192)
sock_remote.send(msg)
# something from the remote server
if s is sock_remote:
msg = sock_remote.recv(8192)
# don't forward keep alives to local system
if msg != b'keep alive':
sock_local.send(msg)
i.e. run this on either server (changing REMOTE_SERVER_NAME
to point to the appropriate place) and it'll forward packets between them, sending a "keep alive" packet every 100 seconds. your local process would send UDP packets to LOCAL_PORT
and these would be forwarded to the remote server, the remote server would receive these and send them on to LOCAL_SERVER_PORT
at the other end. there are 8 flows to worry about so naming gets awkward:
DMZ <=> VPN <=> python <=> NAT <=> internet <=> NAT <=> python <=> VPN <=> DMZ
you might be able to detect the LOCAL_SERVER_NAME
and LOCAL_SERVER_PORT
using a sock_local.recvfrom
and stashing the addrinfo away, but thought I'd leave them in for ease of understanding
hope you understand Python! but I was struggling to express it in words