UDP 反向隧道

UDP reverse tunneling

我遇到了一个很难解决的问题,如果有人能提供帮助,我将不胜感激。

我在防火墙后面的本地网络中有一个 VPN 服务器,只允许出站连接。 我的目标是进行“UDP 性别更改”,并通过创建反向隧道使 VPN UDP 端口可用于我可以转发端口的外部服务器。使用 TCP 隧道执行此操作很简单,并且可以使用 socat、nc 甚至 ssh 隧道等工具轻松完成。但是,VPN 应始终由 UDP 数据包承载以避免 TCP 崩溃问题(TCP over TCP)。

使用 socat/nc 创建的 UDP 反向隧道不起作用,因为 UDP 是无连接协议。这意味着“client client”和“listen listen”配置将仅在客户端先发送数据包时才允许数据传输(在反向连接中不可能)。

我错过了什么吗?是否有任何实用程序可以在不使用第二个 VPN 连接的情况下完成此任务(例如,通过使用某些 headers 建立面向 UDP 连接)? 非常感谢

我在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)

即运行 这在任一服务器上(更改 REMOTE_SERVER_NAME 以指向适当的位置)并且它将在它们之间转发数据包,每 100 秒发送一个 "keep alive" 数据包。您的本地进程会将 UDP 数据包发送到 LOCAL_PORT,这些数据包将被转发到远程服务器,远程服务器将接收这些数据包并将它们发送到另一端的 LOCAL_SERVER_PORT。有 8 个流需要担心,因此命名变得尴尬:

DMZ <=> VPN <=> python <=> NAT <=> internet <=> NAT <=> python <=> VPN <=> DMZ

您也许可以使用 sock_local.recvfrom 检测 LOCAL_SERVER_NAMELOCAL_SERVER_PORT 并将地址信息隐藏起来,但我想我会把它们留在里面以便于理解

希望您理解Python!但我很难用语言表达出来

我改编了 Sam Mason 的答案来执行 UDP 反向连接。 这是配置:

HOST UDP-LISTEN <=> python cc <=> NAT <=> internet <=> server <=> python ll UDP-LISTEN

主机侦听一个 UDP 端口。您可以通过 python 脚本使用反向连接从有权访问服务器的任何第三方客户端访问主机。

第一部分是 listen 脚本。它将在 CC_PORT 上侦听客户端脚本并在 SERVICE_PORT 上转发任何内容。它还会丢弃来自 cc 脚本的 keepalive。

import socket
from select import select

CC_PORT = 8881
SERVICE_PORT = 8880
LISTEN_IP='x.x.x.x'

sock_cc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_cc.bind((LISTEN_IP,CC_PORT))

sock_serv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_serv.bind((LISTEN_IP,SERVICE_PORT))

sockets = (sock_cc, sock_serv)
for s in sockets:
    s.setblocking(0)

client_serv=None
client_cc=None

# loop forever forwarding packets between the connections
while True:
    avail, _, _ = select((sock_cc, sock_serv), (), (), 1)

    # send a keep alive message every timeout
    if not avail:
        continue

    for s in avail:
        # something from the local server, forward it on
        if s is sock_cc:
            msg = sock_cc.recvfrom(8192)
            client_cc=msg[1]
            if client_serv is not None:
                if msg[0] != b'keep alive':
                    sock_serv.sendto(msg[0], client_serv)

        # something from the remote server
        if s is sock_serv:
            msg = sock_serv.recvfrom(8192)
            client_serv=msg[1]
            if client_cc is not None:
                sock_cc.sendto(msg[0], client_cc)

客户端客户端脚本

import socket

from select import select

DEST_IP = 'x.x.x.x' 
DEST_PORT = 8881 
LOCAL_IP = '127.0.0.1' 
LOCAL_SERVICE = 8800

sock_remote = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock_remote.connect((DEST_IP,DEST_PORT)) sock_local = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock_local.connect((LOCAL_IP,LOCAL_SERVICE)) 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), (), (), 1)

    # 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)

再次感谢 Sam Mason 帮我解决了这个问题。