首页 > 解决方案 > UDP反向隧道

问题描述

我有一个问题,我很难弄清楚,如果有人能提供一些帮助,我将不胜感激。

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

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

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

标签: udptunnelingsocat

解决方案


我在 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 秒发送一个“保持活动”数据包。您的本地进程将发送 UDP 数据包LOCAL_PORT并将这些数据包转发到远程服务器,远程服务器将接收这些数据包并将它们发送到LOCAL_SERVER_PORT另一端。有 8 个流程需要担心,所以命名会变得很尴尬:

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

您可能能够检测到LOCAL_SERVER_NAMELOCAL_SERVER_PORT使用 asock_local.recvfrom并将 addrinfo 隐藏起来,但我想我会把它们留在里面以便于理解

希望你懂 Python!但我很难用语言表达


推荐阅读