一、参考资料

通用即插即用(UPnP)互联网网关设备-端口控制协议互通功能(IGD-PCP IWF)
UPnP基本原理以及在NAT中的应用
openwrt - UPnP(Universal Plug and Play,通用即插即用)
比特币源码分析–端口映射
miniupnpd最新版 NAT-PMP 和 UPnP 都无法使用
miniupnpd config
OpenWrt WIKI miniupnpd

二、upnp基本概念

UPNP意为通用即插即用协议,是由微软提出的一种NAT穿透技术。使用UPNP需要内网主机、网关和应用程序都支持UPNP技术。

UPnP全名是Universal Plug and Play,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这些设备彼此之间能互相沟通,更能直接使用或控制它,一切都不需要设定,完全的Plug and Play 。

UPNP通过网关映射请求可以动态的为客户分配映射表项,而NAT网关只需要执行地址和端口的转换。UPNP客户端发送到公网侧的信令或者控制消息中,会包含映射之后公网IP和端口,接收端根据这些信息就可以建立起P2P连接。

  1. UPNP开启后能方便智能监控设备直接透传到因特网,无需做烦琐的映射端口设置。
  2. UPNP开启后能方便智能网络存储设备与因特网进行数据传输,节省手动设置时间。
  3. UPNP开启后能方便在因特网使用ERP、CRM、第三方远程桌面等软件。
  4. UPNP开启后能提高AnyChat系统的P2P成功率,节省服务器的带宽。
    UPnP是一种对等即插即用网络协议,主要用于视频,音频领域的传输协议,对使用者来说,打开UPnP之后可以增加迅雷等下载软件的下载速度。

三、miniupnpd

3.1参数说明

3.1.1 config upnp 的配置参数表
是否必须设置 说明
enable_natpmp 1 开启 NAT-PMP 支持,1 表示开启
enable_upnp 1 开启 UPnP 支持,1 表示开启
secure_mode 1 安全模式,客户端只能给自己转发一个输入口
log_output 0 日志输出级别,0表示不输出日志,如果设置了将输出到syslog中
download 数字 允许来自wan口的数据输入带宽,单位是(KB/秒)。
upload 数字 允许输出到wan口的数据输入带宽,单位是(KB/秒)。
external_iface 字符串 外网的设备域,默认是wan
internal_iface 字符串 内网的设备域,默认是lan
port 数字 监听的端口
upnp_lease_file 文件名 upnp客户端租用记录文件
3.1.2 config perm_rule 许可设置配置参数表
是否必须设置 说明
action 字符串 设置是否许可:allow 许可,deny 不许可
ext_ports 字符串 外部端口范围
int_addr 字符串 ip 地址,如果 0.0.0.0/0 表示全部
int_ports 字符串 内部端口范围

3.2 windows上使用miniupnpc工具

下载地址:
MiniUPnP Project

选择win免安装包,下载好就可以用了,将其路径配置到环境变量就可以用了。


列出已有连接
upnpc-shared.exe -l
增加一条规则
upnpc-shared.exe -a 192.168.1.98 4444 8888 TCP

其它相关规则,使用-h查看使用

3.3 关于开启upnp功能后无法添加端口

问题背景:
upnpc-shared.exe -l查询,或者upnpc-shared.exe -a
使用上述命令都提示失败,主要看提示是wan口的IP事内网IP,然后看打印也是提示私有IP。

可以看到源代码里(getifaddr.c)会检测私有IP和一些特殊IP,如果是那么就无法成功配置相关规则。

RFC1918规范里规定了3个保留地址段:10.0.0.0-10.255.255.255,172.16.0.0-172.31.255.255,192.168.0.0-192.168.255.255,这三个范围分别处于A、B、C类的地址段,专门用于组织或者企业内部使用,不需要进行申请。和公有IP地址相比,这些私有IP地址只在企业内部使用,不能作为全球路由地址,出了企业或组织的管理范围,这类私有地址就不在有任何意义。注意:任何一个组织都可以在内部使用这些私有地址,因此两个不同网络中存在相同IP地址的情况是很可能出现的,但是同一个网络中不允许两台主机拥有相同IP地址,否则将发生地址冲突。

有两种方法可以暂时解决:
方式一:修改配置文件
(1)修改/etc/config/upnpd:新增下面两行配置

option use_stun '1'
option stun_host 'stun.qq.com' #任意公网地址,会自动转换为公网IP

(2)或者直接配置一个任意公网IP,就可以成功转发。

option external_ip '随意一个公网IP'

方式二:直接修改上级路由器lan口地址
如下,我修改上级lan地址为172.0.0.1,最终能够成功配置下去。

查询miniupnpd的防火墙规则

iptables -t nat -nvL MINIUPNPD

总结:上述问题主要出现在miniupnpd版本2.2及以后版本,2.0和2.1都不会去检测。

#查询版本信息
opkg list-installed | grep miniupnpd

四、其它知识补充

4.1 NAT

4.1.1 NAT概念

NAT全称是Network Address Translation,翻译过来就是网络地址转换
(1) 有了NAT以后,内网的主机不在需要申请公网IP地址,只需要将内网主机地址和端口通过NAT映射到网络出口的公网IP即可,然后通信的两端在无感知的情况下进行通信。这也是为什么前文说NAT挽救了IPV4,因为大量的内网主机有了NAT,只需要很少的公网地址做映射就可以了,如此就可以节约出很多的IPV4地址空间。

(2) 当在私网网络出口处部署了NAT网关以后,只能由内网主机发起到外网主机的连接,外网主机无法主动发起连接到内网。这样虽然对外隔离了内网主机,但同时又限制了P2P的通信,这也是NAT带来的一大弊端。

4.1.2 NAT的分类

(1) 一对一NAT

就是一个内网主机对应一个公有IP。这种类型的NAT对于节省IP地址没什么意义。

(2) 一对多NAT

内网的多个主机都映射到同一个公有IP地址上。但是这里就有前文提到的那个面试问题:当内网有多台主机都请求同一服务器时,如果仅仅是替换地址,从返回信息是无法确认该将响应转发到哪一台主机的。此时还需要NAT根据传输层信息或者上层协议区分不同的会话,把不同的会话映射到公网IP不同的传输层端口上(NAPT)。

按照端口映射的方式分类,1对多的NAT又可以细分为4种:
(1) 全锥型NAT:

假设内网设备192.168.0.1:80向svr1发起请求,内网地址在NAT网关被映射为公网地址和端口:192.169.0.1:8080,在全锥形模式下,一旦连接成功后,外网所有主机发送到192.169.0.1:8080的数据,都将被NAT网关转发到内网192.168.0.1:80设备上。

(2) 限制锥型NAT:

假设内网设备192.168.0.1:80成功连接了svr1,内网设备的地址和端口在NAT网关被映射为192.169.0.1:8080,在限制锥形模式下,只有外网设备向svr1发送过数据,之后从svr1的任意端口发送到192.169.0.1:8080的数据,都会被网关转发给内网设备192.168.0.1:80,但是外网其他设备(图中的svr2)发送到192.169.0.1:8080的数据将不会被转发

(3) 端口限制锥形NAT:

与限制锥形NAT相比,端口限制锥形NAT更加严格:

假设内网设备192.168.0.1:80向外网svr1的80端口建立连接并发送数据,其内网地址和端口在NAT网关被映射为192.169.0.1:8080,在端口限制锥形模式下,只有svr1的80端口发送到网关192.169.0.1:8080的数据才会被转发到内网设备192.168.0.1:80,svr1的其他端口或者外网其他主机发送到192.168.0.1:8080的数据均不会抓发到内网设备。

(4)对称型NAT:

对于来自同一个内部IP地址和端口的所有数据包,只要目标端口相同,NAT网关会将它们映射到同一个外部端口。但是,如果目标端口不同,NAT网关会将它们映射到不同的外部端口。与限制锥型NAT不同的是,当其他主机向这个已经被映射过的外部端口发送数据包时,NAT网关会将其路由到该主机。

4.2 NAT穿透

P2P学习(三)网络传输基本知识—STUN协议(一)

4.2.1 STUN

RFC STUN规范中,实际上有两套STUN规范:

规范一:RFC3489

STUN的全称是Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs)(Simple Tranversal of UDP through NAT),即穿越NAT的简单UDP传输,是一个轻量级的协议,允许应用程序发现自己和公网之间的中间件类型,同时也能允许应用程序发现自己被NAT分配的公网IP。
它就是将STUN定义成简单的通过UDP进行NAT穿越的一套规范,也就是告诉你如何一步一步通过UDP进行穿越,但是这套规范在穿越的过程中还是存在很多问题,尤其是现在的网络路由器对UDP的限制比较多,有的路由器甚至不允许进行UDP传输,所以这就导致了我们通RFC3489这套规范进行NAT穿越的时候它的失败率会非常高。

所以为了解决这个问题,又定义了另一套标准,RFC5389.

规范二:RFC5389

在RFC5389中,STUN的全称为Session Traversal Utilities for NAT,即NAT环境下的会话传输工具,是一种处理NAT传输的协议,但主要作为一个工具来服务于其他协议。
和STUN/RFC3489类似,可以被终端用来发现其公网IP和端口,同时可以检测端点间的连接性,也可以作为一种保活(keep-alive)协议来维持NAT的绑定。
和RFC3489最大的不同点在于,STUN本身不再是一个完整的NAT传输解决方案,而是在NAT传输环境中作为一个辅助的解决方法,同时也增加了TCP的支持。
RFC5389废弃了RFC3489,因此后者通常称为classic STUN,但依旧是后向兼容的。而完整的NAT传输解决方案则使用STUN的工具性质,ICE就是一个基于offer/answer方法的完整NAT传输方案,如SIP。

RFC5389是在RFC3489的基础上又增加了一些功能,但是它对整个STUN的描述就不一样了, 它是把STUN描述成一系列穿越NAT的工具,所以都叫STUN,但是他们的含义完全就不一样了。RFC5389在UDP尝试可能失败的情况下,尝试使用TCP,也就是说RFC5389是包括UDP和TCP的两种协议进行NAT穿越的,这是两套规范最本质的区别。当然在协议的具体内容上,包括协议头还有协议体中的属性都有很多的变化,但是那些都不是最关键的,最关键的是RFC5389里面将TCP纳入进来。你可以通过TCP进行穿越。

4.2.2 TURN

TURN的全称为Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,主要添加了Relay中继功能。
那么在特定的情景下,有可能使得终端无法和其对等端(peer)进行直接的通信,这时就需要公网的服务器作为一个中继,对来往的数据进行转发。
这个转发的协议就被定义为TURN。TURN和其他中继协议的不同之处在于,它允许客户端使用同一个中继地址(relay address)与多个不同的peer进行通信。
使用TURN协议的客户端必须能够通过中继地址和对等端进行通讯,并且能够得知每个peer的的IP地址和端口(确切地说,应该是peer的服务器反射地址)。

4.2.2.1 TURN协议出现的目的(解决对称NAT无法穿越的问题)

在之前我们介绍过,NAT的四种类型(完全锥型NAT (Full Cone NAT)、地址限制锥型NAT(Address Restricted Cone NAT)、端口限制锥型NAT (Port Restricted Cone NAT)、对称型NAT (Symmetric NAT))。
当我们检测到一端是端口受限锥型一端是对称型或者两端都是对称型,那肯定是无法穿越的;

在NAT无法穿越的时候,我们如何才能保证业务的运行呢?
那这个时候就要引入TURN协议,TURN协议实际上就是在服务端架设一个TURN服务,客户端在发送数据的时候无法NAT穿越的时候将这个媒体流数据首先传给TURN服务,通过URN的中介然后转给其他的接收者,或者其他接收者也可以发送数据给这个TURN服务,TURN在转给client端。这就是TURN 出现的目的。

4.2.2.2 TURN协议与STUN/RFC5389协议的关系

其建立在STUN/RFC5389之上,消息格式使用STUN格式消息;
那TURN协议就是建立在STUN协议之上的,它的协议头和body几乎是一样的,只是里面的一些属性和内容不一样,外壳形式什么的都是一样的,所以很多服务器都是将STUN协议和TURN协议放在一起形成了一个服务器,就是既提供STUN的功能又提供TURN的功能 。

TURN Client要求服务端分配一个公共IP和Port用于接收或发送数据
实际上在进行TURN协议的时候我们应该将它分成两类,一类是TURN Client,一类是服务端,这与我们之前介绍的STUN是一样的,就是客户端服务器模式。

那如何在这个TURN服务器上提供这种中继服务呢?
首先要TURN Client向TURN 服务端发送一个请求,发送了请求之后就就在服务端根据这个请求建立一个公共的IP地址和端口用户接收和发送数据 。
那么对端(TURN client想要通讯的对端)其实是不需要是一个TURN Client端的,它只需要正常的发送UDP包就可以,