gpt4 book ai didi

python - TCP Hole Punching(绕过监听套接字)

转载 作者:可可西里 更新时间:2023-11-01 02:40:33 24 4
gpt4 key购买 nike

为了获得某种可靠的行为,我已经有几天没玩过打洞了,但我现在陷入了死胡同。

UDP 打洞效果很好:只需先向远程发送一个数据包,然后让远程发送一个数据包,因为它将通过源 NAT 到达。根据我的尝试,它相当可靠。

但是现在出现了 TCP...我不明白。

现在,我可以通过 NAT 建立连接,但只能使用连接套接字:

A.connect(B) -> Crash agains't B's NAT, but open a hole in A's NAT.
B.connect(A) -> Get in A's NAT hole, reach A's connecting socket.

但是现在,发送SYN数据包进行连接的两个套接字已经连接了。

你会认为我会做到这一点,通过 2 个 NAT 建立连接,万岁。

但问题是这不是正常行为,并给出了本文:http://www.brynosaurus.com/pub/net/p2pnat/ ,我应该能够有一个与连接 socket 并联的监听 socket 。

所以我确实绑定(bind)了一个监听套接字,它将接受入站连接。

但是入站连接总是被连接套接字捕获,而不是被监听套接字捕获...<​​/strong>

例如:

#!/usr/bin/env python3
from socket import *
from threading import Thread
Socket = socket

# The used endpoints:
LOCAL = '0.0.0.0', 7000
REMOTE = 'remote', 7000

# Create the listening socket, bind it and make it listen:
Listening = Socket(AF_INET, SOCK_STREAM)
Listening.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
Listening.bind(LOCAL)
Listening.listen(5)

# Just start in another thread some kind of debug:
# Print the addr of any connecting client:
def handle():
while not Listening._closed:
client, addr = Listening.accept()
print('ACCEPTED', addr)
Thread(target=handle).start()

# Now creating the connecting socket:
Connecting = Socket(AF_INET, SOCK_STREAM)
Connecting.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
Connecting.bind(LOCAL)

# Now we can attempt a connection:
try:
Connecting.connect(REMOTE)
print('CONNECTED', Connecting.getpeername())
except Exception as e:
print('TRIED', type(e), e)

现在有了这个脚本,只需与 friend 或其他人商定一个端口,然后在一端执行它,Connecting.connect(...) 应该运行一会儿(等待超时,因为SYN包撞到远处的NAT,幸好在自己的NAT开了个洞),同时在另一端执行脚本,此时Connecting.connect(...)会返回因为它将连接。

最奇怪的部分是:Listening 套接字从未被触发

为什么?如何让监听套接字通过连接套接字捕获入站连接?

注意:关闭连接套接字确实会在网络上发送一些东西,这会立即关闭漏洞,至少在我的网络上是这样。

第二个注意事项:我在 Windows 上。

编辑:主要问题是在任何情况下,此脚本都会输出CONNECTED [...] 而不是CLIENT [...],这在一些讲座中是不应该发生的。

最佳答案

所以,经过更多的测试和阅读,这就是我的结论:

事实上,可以在同一个地址(ip、端口)上绑定(bind)一个监听套接字和一个出站连接套接字。

但是套接字的行为在很大程度上取决于系统/TCP 堆栈的实现,如 http://www.brynosaurus.com/pub/net/p2pnat/ 中所述在§4.3:

What the client applications observe to happen with their sockets during TCP hole punching depends on the timing and the TCP implementations involved. Suppose that A's first outbound SYN packet to B's public endpoint is dropped by NAT B, but B's first subsequent SYN packet to A's public endpoint gets through to A before A's TCP retransmits its SYN. Depending on the operating system involved, one of two things may happen:

  • A's TCP implementation notices that the session endpoints for the incoming SYN match those of an outbound session A was attempting to initiate. A's TCP stack therefore associates this new session with the socket that the local application on A was using to connect() to B's public endpoint. The application's asynchronous connect() call succeeds, and nothing happens with the application's listen socket.
    Since the received SYN packet did not include an ACK for A's previous outbound SYN, A's TCP replies to B's public endpoint with a SYN-ACK packet, the SYN part being merely a replay of A's original outbound SYN, using the same sequence number. Once B's TCP receives A's SYN-ACK, it responds with its own ACK for A's SYN, and the TCP session enters the connected state on both ends.

  • Alternatively, A's TCP implementation might instead notice that A has an active listen socket on that port waiting for incoming connection attempts. Since B's SYN looks like an incoming connection attempt, A's TCP creates a new stream socket with which to associate the new TCP session, and hands this new socket to the application via the application's next accept() call on its listen socket. A's TCP then responds to B with a SYN-ACK as above, and TCP connection setup proceeds as usual for client/server-style connections.
    Since A's prior outbound connect() attempt to B used a combination of source and destination endpoints that is now in use by another socket, namely the one just returned to the application via accept(), A's asynchronous connect() attempt must fail at some point, typically with an “address in use” error. The application nevertheless has the working peer-to-peer stream socket it needs to communicate with B, so it ignores this failure.

The first behavior above appears to be usual for BSD-based operating systems, whereas the second behavior appears more common under Linux and Windows.

其实我属于第一种情况。在我的 Windows 10 上。

这意味着为了为 TCP Hole Punching 做一个可靠的方法,我需要在连接套接字的同时绑定(bind)一个监听套接字,但我稍后需要检测哪个触发(监听或连接)并通过它沿着应用程序的流程向下移动。

关于python - TCP Hole Punching(绕过监听套接字),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44012683/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com