使用UPnP配置SDN端口转发
涛叔上海电信的光猫只能通过一款叫网络管家的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
表示添加
- 第一个参数是局域网主机
- 每二个是局域网主机端口
- 第三个是公网主机端口
- 第四个表示使用 TCP 还是 UDP 协议
如果执行成功,你会在网络管家看到如下记录
这个时候你访问1.1.1.1:8888
就能看到 Nginx 的页面了。
如果想关闭端口映射,则可以执行
upnpc -d 8888 tcp
最后,你可以写一个脚本,在电脑开机连网后自动查询本机IP,然后通过upnpc
将端口映射规则写入光猫;等电脑关机的时候再自动删除映射关系。一切都是那么的自然。
好了,感紧动手试试吧。