我正在建立一个点对点协议,其中节点通过共享它们所连接的 IP 地址来通告其他节点的存在。此功能称为“对等发现”。我正在运行的一个节点具有静态 IPv4。我们将这台机器称为“A”。
当我通过 IPv4 从办公室中已连接 WiFi 的机器连接到 A 时,这些办公室机器无法正常连接,对等发现无法工作。但是当我通过 IPv6 连接时,对等发现工作得很好。办公室机器相互连接,而不仅仅是连接到 A。办公室机器和 A 位于不同的网络上。
使用 IPv6 时,办公室计算机上自我报告的 IP(ip -6 addr
)与 A 看到的 IP 相匹配。当我通过 IPv4 连接时,两个报告的地址不匹配。
这是因为办公室机器从办公室 WiFi 路由器获取 NAT 后的 IPv4 地址和全局唯一的 IPv6 地址吗?
其他 p2p 协议上也会发生这种行为吗?
我并不是在寻求针对 IPv4 的修复。我问的是 IPv4 与 IPv6 的典型 NAT 行为,以及其他 p2p 应用协议(例如 BitTorrent 或比特币)是否也会出现这种行为。
答案1
我构建的对等发现功能只需共享连接节点的 IP 地址及其用于传入连接的公布端口即可工作。
这样做有几个问题。假设服务器在 NAT 之外,而所有客户端都在 NAT 之内,这意味着服务器将只学习 NAT 网关的地址,这对服务器来说也不起作用或者即使对于任何其他客户端,即使该其他客户端在内部。(也就是说,客户端 B 必须连接到客户端 A 的内部地址,而不是连接到它们的公共 NAT 网关地址。)
据我所知,至少一些现代对等发现协议(例如 WebRTC)都要求客户端明确共享全部将其 IP 地址与发现服务器共享 - 例如,即使您通过 IPv4 连接,服务器(和其他对等方)也会了解您的 IPv6 地址、您的其他IPv4 地址(内部、外部、或许是内部 #2)等等。
IPv6 基本上避免了这个问题,因为(通常!)没有地址转换;然而,IPv6 主机有两组地址——一个全局地址和本地地址 – 因此报告两者仍然有用。
更一般地,假设两个对等体位于 NAT 的不同侧(或者更糟的是,两者都位于单独的 NAT 后面),“用于传入连接的已宣布端口”通常不会通过典型的 NAT 工作,除非客户端专门使用 NAT-PMP 或 UPnP IGD 从其本地 NAT 网关请求入站端口映射(并且这仅在只有一层 NAT、没有惰性“堆叠路由器”设置和没有 ISP 级 CGNAT 时才有效)。如果端口映射不可用,你需要一个“NAT穿越”机制。
当我通过 IPv4 连接时,两个报告的地址不匹配
是的,这意味着 NAT(至少是其中的一层)。实际上,NAT 在所有情况下都是“1:多”NAT,其中多个主机共享相同的外部 IP 地址,在这种情况下,从“外部”到该地址的新入站连接将无处可去,除非将某个 TCP 端口明确映射到某个内部地址(技术上,它们会转到 NAT 网关本身,网关会拒绝它们),而从“内部”到该地址的新入站连接将无处可去即使一个明确的映射(NAT-hairpin 本身就是一个很令人头痛的问题)。
因此,如果您希望“内部”连接能够正常工作(例如,同一办公室中的两台相邻 PC),则客户端必须自行报告其地址,而不是依赖“服务器看到的内容”。我远不是这个领域的专家,但webrtc ice candidates
可能是开始研究的地方。
同时,对于来自“外部”的连接,您的选择是 a) 让客户端尝试使用 NAT-PMP 和/或 UPnP IGD 保留端口映射 - 并且,再次自我报告不仅从网关收到的保留端口(可能与客户端正在监听的端口不同)而且还有“外部”地址;以及 b) 使用 NAT 遍历机制(例如 STUN),它们通常不适用于 TCP。