有一个IGD-PCP IWF specification 试图解决类似的问题,尽管它假设您的“路由器 1”支持 PCP,而不是 UPnP。因此,让我们尝试从纯理论的角度使用两个普通的 UPnP 路由器/NAT 设备来解决这个问题。
根据UPnP Device Architecture version 2.0,UPnP 通信有几个不同的步骤:
寻址对我们来说没什么兴趣,让我们假设到处都有正确的 DHCP 并完成它。 Eventing 和 presentation 在我们的例子中也几乎没用。所以主要关注的是discovery、description和control。
发现通过 SSDP 消息交换工作。 SSDP 使用 UDP 进行传输,端口号为 1900(默认)和众所周知的多播地址。
描述从设备在发现阶段提供的 URL 开始,控制点(在我们的例子中是 PC)需要在这个 URL 上发出一个 HTTP GET 请求,这意味着它使用 TCP 作为具有设备 IP 地址的传输协议(单播)。
控件以设备在其描述中提供的 URL 开始,它在 TCP 之上的 HTTP 之上使用 SOAP,这反过来对我们来说也意味着单播 IP。
所以,对于双 NAT,所有这一切意味着在 UPnP 交互的描述和控制步骤中,我们从 PC 到路由器 1 的通信是零问题,因为所有这些只是具有单播 IP 地址的标准 TCP。但是要进入描述步骤,我们需要有一个Router 1的URL,所以让我们仔细看看这个URL是如何正常获取的。
有两种主要的发现机制——广告(当设备周期性地多播一些关于它的信息时)和搜索(当控制点发送多播搜索消息并且设备用单播响应来响应时)。显然,默认情况下,我们在路由器 2 后面的 PC 无法从路由器 1 获得多播广告,而路由器 1 也无法从 PC 获得多播搜索消息,所以我们这里有一个问题,现在的问题是是否有可能没有多播的通信。
幸运的是,同样的架构文档说:
此外,允许控制点将发现消息单播到端口 1900 上的特定 IP 地址或由可选的 SEARCHPORT.UPNP.ORG 标头字段指定的端口(其取代端口 1900 用于此用途),搜索用于该特定 IP 地址的 UPnP 设备或服务。
...
所有设备都应在端口 1900 或 SEARCHPORT.UPNP.ORG 标头字段中指定的端口号(如果提供)上侦听传入的单播搜索消息,并在其任何根设备、嵌入式设备或服务与搜索匹配时做出响应发现消息中的标准。
这意味着如果您知道路由器 1 的 IP 地址(当然是从路由器 2 端),您可以(最重要的是,规范允许)通过单播 UDP 消息与它通信,这也是 NAT-友好,所以不是从路由器 2 后面的 PC 完成的问题。
剩下的唯一事情就是获取路由器 1 的 IP 地址。不幸的是,没有简单的标准方法可以做到这一点,但您至少有两个选择:跟踪路由(以您想要的任何方式)和暴力 IP 扫描(很可能,路由器 1 的潜在 IP 集是有限的)。
现在您可以与路由器 1 进行通信,但在与路由器 1 进行通信时,您仍应始终记住一件小事——在任何内部 UPnP 消息中,您应该使用路由器 2 的 IP 地址(从路由器 1 端看)及其港口。就像在路由器 1 上的 AddPortMapping 操作的 NewInternalClient 参数中一样,您应该使用路由器 2 IP。顺便说一句,这引发了路由器 2 IP 的问题,但您可以通过路由器 2 UPnP ExternalIPAddress 变量 WANIPConnection service 获得该问题(此服务为 required for IGDs to implement)。
所以,总结一下:
- 这在技术上是可以做到的,尽管我怀疑任何标准库都会为您做到这一点
- 您需要两件事:
- Router 2“外部”IP,您可以通过
ExternalIPAddress 变量WANIPConnection UPnP 服务获得该IP
- 路由器 1“内部”IP(来自路由器 2 端),需要跟踪路由或扫描
- 给定路由器 1 IP,您只需要在发现步骤使用单播消息而不是多播
- 其他一切都应该正常工作,只是需要注意在 UPnP 消息中使用路由器 2“外部”IP 而不是 PC 的 IP