使用UPnP配置SDN端口转发

2020-07-21 ⏳2.3分钟(0.9千字)

上海电信的光猫只能通过一款叫网络管家的APP设置。如果想通过公网访问内网的服务,需要配置虚拟服务器或者DMZ主机。它们在本质上都是端口转发。这些网络管家都支持。但是,端口转发需要指定局域网机器的IP和端口。局域网设备的IP由光猫自动分配,网络管家上居然不支持给设备绑定IP。如果设备重启,就可能使用新的IP,这样之前配置的端口转发就失效了。最简单的办法是直接给内网主机设置固定IP。如果你不想折腾,读到这里就可以结束了。但这种方法可能产生IP冲突。虽然概率很小,但总觉得不优雅。更好的方案是利用 UPnP 实现自动端口映射。

UPnP 是干什么的呢?简单来说就是一种通信协议,局域网内主机的程序可以使用它告诉光猫,说请你把公网某某端口的流量转发到我的IP的端口上。说白了就是动态配置光猫的端口转发规则

UPnP 协议比较复杂,没有必要深入了解所有细节,惟一要做的是找找有没有现成的工具。

我现在主要用 Go 语言,简单 google 了关键字upnp client golang,排在首位的是英国一哥们开源的软件 goupnp1

使用网络管家打开光猫的 UPnP 功能,运行 goupnp 的cmd/discoverall命令可以看到如下输出:

Location: http://*:5400/rootDesc.xml
USN: uuid:*::urn:schemas-upnp-org:service:WANPPPConnection:1
  Root v1.0 @ http://*:5400/rootDesc.xml
  Type: urn:schemas-upnp-org:device:InternetGatewayDevice:1
  Friendly name: XXX Dual Band Wireless Router XXX
  Num devices: 1
...

我就随手访问了这个 http://*:5400/rootDesc.xml链接,内容 XML,各字段含义我都不知道,但有一些内容引起我的注意:

<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WANConnectionDevice</friendlyName>
<manufacturer>MiniUPnP</manufacturer>
<manufacturerURL>http://miniupnp.free.fr/</manufacturerURL>
<modelDescription>MiniUPnP daemon</modelDescription>
<modelName>MiniUPnPd</modelName>
<modelNumber>20150528</modelNumber>
<modelURL>http://miniupnp.free.fr/</modelURL>
<serialNumber>00000000</serialNumber>
<UDN>uuid:*</UDN>
<UPC>000000000000</UPC>

看起来这个光猫的 UPnP 功能是用 MiniUPnP 实现的。打开对应的网站2,果然是个 UPnP 的开源实现,同时提供服务器和客户端工具。因为 MiniUPnP 用是标准C语言,比较容易移植到不同的设备,也难怪电信光猫使用它实现 UPnP 功能。

我用的是 Macos,不知道能不能使用homebrew安装 MiniUPnP。Google 关键字miniupnp homebrew找到了对应的软件包3

执行brew install miniupnpc完成安装。

好了,准备工作结束,现在表演正式开始

假设你的公网IP是1.1.1.1,局域网IP是192.168.1.9,你本机的 nginx 监听在*:8080端口, 你想把公网的8888端口映射到本机的8080端口,你可以

upnpc -a 192.168.1.9 8080 8888 tcp

这里的upnpc就是 MiniUPnP 的客户端工具。-a表示添加

如果执行成功,你会在网络管家看到如下记录

网络管家UPnP记录

这个时候你访问1.1.1.1:8888就能看到 Nginx 的页面了。

如果想关闭端口映射,则可以执行

upnpc -d 8888 tcp

最后,你可以写一个脚本,在电脑开机连网后自动查询本机IP,然后通过upnpc将端口映射规则写入光猫;等电脑关机的时候再自动删除映射关系。一切都是那么的自然。

好了,感紧动手试试吧。


  1. https://github.com/huin/goupnp↩︎

  2. http://miniupnp.free.fr/↩︎

  3. https://formulae.brew.sh/formula/miniupnpc↩︎