简体   繁体   English

如何通过可靠的UDP隧道TCP?

[英]How to tunnel TCP over reliable UDP?

Assume I have a reliable UDP library, and want to tunnel arbitrary TCP connections over it. 假设我有一个可靠的UDP库,并希望通过它隧道任意TCP连接。 This is my current approach to doing so, but I feel that it may not be very efficient. 这是我目前的做法,但我觉得它可能效率不高。 Any suggestions are very welcome. 任何建议都非常欢迎。

  1. Client establishes a reliable UDP connection to server. 客户端与服务器建立可靠的UDP连接。
  2. Client runs a local SOCKS5 proxy, which receives data from any app that connects to it and forwards it through the reliable UDP connection. 客户端运行本地SOCKS5代理,该代理从连接到它的任何应用程序接收数据,并通过可靠的UDP连接转发它。 Each packet includes a 4-byte id unique to each SOCKS connection. 每个数据包包括每个SOCKS连接唯一的4字节ID。
  3. Server receives data. 服务器接收数据。 If the 4-byte id is new, it makes a new connection to its local TCP socket and sends the data, and spawns a new thread which receives any replies from the server and forwards them through the reliable UDP connection with the appropriate id. 如果4字节的id是新的,则它与其本地TCP套接字建立新连接并发送数据,并生成一个新线程,该线程接收来自服务器的任何回复,并通过具有适当id的可靠UDP连接转发它们。 If the 4-byte id is old, it simply sends the data over the existing TCP connection. 如果4字节的id是旧的,它只是通过现有的TCP连接发送数据。
  4. Client receives data, sending it over the existing SOCKS connection to whatever app started it. 客户端接收数据,通过现有的SOCKS连接将其发送到任何启动它的应用程序。

Right now, this seems to work for making simple HTML requests from a browser, but since the server isn't directly connected to the client, it is unable to tell when the client terminates a connection. 现在,这似乎适用于从浏览器发出简单的HTML请求,但由于服务器没有直接连接到客户端,因此无法判断客户端何时终止连接。 Is there a better way to do this? 有一个更好的方法吗?

EDIT: No, this is not homework. 编辑:不,这不是功课。 And please don't bother replying if you aren't aware of the advantages of reliable UDP libraries, or for that matter, haven't heard of them before. 如果你不了解可靠的UDP库的优点,或者就此而言,之前没有听说过它们,请不要打扰回复。 Thanks. 谢谢。

there are a few ready to use options: 有几个随时可用的选项:

  • OpenVPN : tunnels either IP or ethernet Frames on top of UDP OpenVPN :在UDP之上隧道IP或以太网帧
  • Teredo : tunnels IPv6 on top of UDPv4, manages both NAT traversing and full compatibility with IPv6 Teredo :在UDPv4之上隧道化IPv6,管理NAT遍历和与IPv6的完全兼容性
  • UDT : non-standard, reliable, high-performance, multi-transport, TCP-like protocol on top of UDP. UDT :UDP之上的非标准,可靠,高性能,多传输,类TCP协议。 Optionally lets you manage NAT traversal and then takes it from there (可选)允许您管理NAT遍历,然后从那里获取它

The most efficient way is when the two endpoints directly communicate to each other. 最有效的方式是两个端点直接相互通信。 If they communicate with different protocols, you need at least one proxy / gateway / traffic converter / whatever. 如果他们使用不同的协议进行通信,则至少需要一个代理/网关/流量转换器/等等。 In this case, there is no way around two of these converters, as you now have 3 parts involved: End point client, network traffic, endpoint server. 在这种情况下,无法绕过其中两个转换器,因为您现在涉及3个部分:端点客户端,网络流量,端点服务器。 I don't see how you could make it more efficient under the given circumstances. 我不知道如何在特定情况下提高效率。

As for the terminated connections, if you use a tunnel then use it for all traffic, ie communicate all kinds of requests of both client and server to the other side. 对于已终止的连接,如果您使用隧道,则将其用于所有流量,即将客户端和服务器的各种请求传递给另一方。 If a termination can't be communicated to the server, then the problem is sitting on the client side -- the client end point does not communicate its termination to the client tunnel entry. 如果终止无法传送到服务器,则问题出在客户端 - 客户端端点不会将其终止传递给客户端隧道条目。 If it would, then you can transfer this termination to the server. 如果可以,那么您可以将此终止转移到服务器。

You're going to have to communicate the loss of the client TCP connection to the server side across your UDP tunnel (and the opposite, if the server should happen to close the connection first). 您将不得不通过UDP隧道将服务器端的客户端TCP连接丢失(相反,如果服务器应该首先关闭连接)。

Otherwise, quite apart from the fact that the HTTP server doesn't know the client has disconnected, you will be leaking connections on the side that didn't initiate the connection closure. 否则,除了HTTP服务器不知道客户端已断开连接之外,您将在未启动连接关闭的一侧泄漏连接。

One way to do this would be to reserve a special value of your 32 bit connection ID field - say 0x00000000 or 0xffffffff - as representing a control packet rather than connection data. 一种方法是保留32位连接ID字段的特殊值 - 比如0x000000000xffffffff - 表示控制数据包而不是连接数据。 Following that is another 4-byte field representing a connection ID, and following that is an opcode field. 接下来是另一个表示连接ID的4字节字段,然后是操作码字段。 The first opcode you could define is "Connection terminated". 您可以定义的第一个操作码是“Connection terminated”。

  • If your client-side of the tunnel detects that the client application has closed its TCP connection, it sends a Connection-Terminated packet for the corresponding connection ID over the tunnel; 如果隧道的客户端检测到客户端应用程序已关闭其TCP连接,则它会通过隧道发送相应连接ID的Connection-Terminated数据包;
  • If your client-side of the tunnel gets a "Connection terminated" opcode from the server side, then it closes its connection with the client application; 如果隧道的客户端从服务器端获取“连接已终止”操作码,则它将关闭与客户端应用程序的连接;

and similar for the server-side of the tunnel. 并且类似于隧道的服务器端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM