【发布时间】:2017-08-27 16:09:26
【问题描述】:
现在,我的 UDP 打孔系统遇到了一个严重的问题,可能涉及我现在无法解决的问题。我会尽量准确地解释,因为这真的让我很困扰:
UDP 打洞方法涉及第三个主机 S,它基本上是公共的(不在任何类型的 NAT 或持久防火墙后面),两个客户端 A 和 B 将使用它来相互了解。客户端 A 向 S 发送一个 udp 数据包,这样 S 就可以知道它的公共 IP 和端口(由 A 的 NAT 映射)。客户 B 也是如此。然后S通过发送到A B的公共地址来匹配A和B,并将A的公共地址发送给B。因此,他们都知道彼此的地址,可以进行通信。
到目前为止一切都很好,但这里有一个问题:它只适用于特殊情况。
我知道由对称 NAT 引起的问题(NAT 将您的私有 IP 和端口映射到您想要到达的每个目标地址的特定不同地址,所以假设我向 S1 和 S2 发送数据包,S1 将查看带有端口 50263 的公共地址,而 S2 将看到 50264)。我还知道,一些非对称 NAT 要求您先将 UDP 数据包发送到特定地址,然后才能从同一地址接收数据包。
所以到目前为止我所理解的是,只要您的 NAT 不是对称的,当打开一个新套接字并发送任何字节数组时,您的 NAT 就会为其分配一个公共 IP 和端口。公共服务器告诉您的对等方这个公共地址,以便它可以与您通信。然后,您必须向该对等方发送一个数据包才能让他回复。
但实际上并非每次都有效。我在我的大学公寓里试过,并设法使用我的公共 IP 地址连接到自己,即使是在 NAT 后面。我还设法向朋友发送了一个 UDP 数据包,但在我进行的数百次测试中它只工作了一次。我现在正在家里尝试,它根本不起作用。
我在 Internet 上设置了 2 个公共 VPS,并向它们每个发送一个数据包,以查看我的 NAT 是否是对称的,但不是,它们显示的端口是相同的。我只能从那些公共服务器上联系到我自己。使用 Wireshark,我观察到数据包离开我的计算机,但似乎在返回之前它们被丢弃了。
我编写了简单的 python 脚本来尝试简单地发送给自己:
服务器
import socket
import sys
from helper import *
# This script is used to allow a client to know which external address it has.
def main():
# Port used to receive client requests
port = 6666
# We create a UDP socket on this port
sockfd = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sockfd.bind (("", port))
print ("Address discoverer started on port %d" % port)
# Server loop
while True:
# We wait for any client to request for his address.
data, addr = sockfd.recvfrom(1)
# Once a client has sent a request, we send him back his external address, which we obtained using the packet he sent us.
sockfd.sendto (addr2bytes(addr), addr)
print ("Client %s:%d requested his address" % addr)
if __name__ == "__main__":
main()
客户
import sys
import socket
from helper import *
def main():
master = ("xxx.xxx.xxx.xxx", 6666)
me = ("yyy.yyy.yyy.yyy", 6666)
sockfd = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sockfd.bind(('',6666))
sockfd.sendto (bytearray([0]), master)
data, addr = sockfd.recvfrom (6)
a = bytes2addr(data)
print ('My address is %s:%d' % a)
for i in range (0, 10):
sockfd.sendto ('hi myself'.encode('utf-8'), me)
data, addr = sockfd.recvfrom (1024)
print ("Received : " + data.decode('utf-8'))
if __name__ == "__main__":
main()
在我的一个公共 VPS 上执行,它可以工作。在家执行,我没有收到任何东西。似乎从公共主机发送会授予所有访问权限,但在 NAT 后面则完全不同。
我错过了一些基本的东西吗?我想我几乎做了所有可能的测试,但没有成功。
【问题讨论】:
-
您的 ISP 使用 CGN 吗?如果是这样,您有一个双重 NAT,这将是一个问题。
标签: python sockets networking udp nat