从外网访问内网的时候,经常会遇到端口被封杀的情况,因为运营商不希望家庭用户架设服务器;两个局域网(通过外网)互相访问的时候则更要命,比如Windows自带的SMB协议只能使用默认的445端口,这个时候端口转发也失效了。挨踢君借助OpenWrt的iptables,使用DNAT巧妙解决了端口问题。
NAT 网络地址转换
先来说说网络地址转换,Network Address Translation。在复用 - 精品教程中,我留了一个问题:路由器是如何复用ip让多个设备共用同一个公网ip上网的?
是通过端口的“时分复用”。
路由器会分配端口给内网应用,应用使用完成后便收回端口,供下次分配给其他应用。这样只让端口被占用一小段时间,便实现了对ip的复用。受篇幅限制,不便展开,大家只要这样理解:
假设
- 路由器内网ip为192.168.1.1,路由器公网ip为110.110.110.110
- 来源地址是局域网内部机器,形如192.168.1.2
- 目的地址是百度服务器,形如39.156.69.79。
这时,数据包发给外网
- ip包上的来源地址(source)会被修改成路由器的公网ip,因为只有公网ip才能上网
- (由于只有一个公网ip,所以在端口已经被使用的情况下,可能还会修改来源端口号)
- 也就是来源地址被转换成:192.168.1.2:2333 - > 110.110.110.110:23333
- 路由器会记住ip包的来源地址、端口号以及目的地址(destination)、端口号
在接受外网返回的数据包时
服务器成为来源,内网机器成为目的地
- 路由器通过来源地址、端口号、目的地址以及目的端口号,确定了这个ip包的身份,也就是这个包所归属的应用
- 路由器把目的地址(此时为公网地址)修改成内网对应地址(192.168.1.2)
- 在数据包发给外网时,如果修改过端口号,则在此处进行相反过程
- 也就是目的地址被转换成: 110.110.110.110:23333 - > 192.168.1.2:2333
这就是NAT,网络地址转换。
端口转发
由于网络地址转换涉及端口号的修改,而这种修改往往是随机的,所以NAT保证了内网设备的安全。也就是说,无法从外网访问内网机器。
我们之前的教程windows 共享教程、复用 - 精品教程,之前主要实现了内网服务。
使用端口转发,可以实现外网访问内网的服务。
SMB端口转发案例:44500 -> 445
我们可以设置路由器,把来自外网的对44500端口的访问,转发到内网的服务器的445端口。
当我们访问路由器的公网ip:对外端口
时,就好像访问内网机器:服务端口
。也就是110.110.110.110:44500
自动被端口转发成192.168.1.2:445
。
市面上的路由器都支持端口转发,大家根据自己的品牌,可以搜索端口转发教程,我这里以OpenWrt的命令行配置为例。
进OpenWrt路由器,输入以下代码:
cat >>/etc/config/firewall<<EOF
config redirect
option target 'DNAT'
option src 'wan'
option dest 'lan'
option proto 'tcp udp'
option src_dport '44500'
option dest_ip '192.168.1.2'
option dest_port '445'
option name 'Forwarding44500'
EOF
/etc/init.d/firewall restart
确认
即可实现端口转发。现在,当你从外网访问110.110.110.110:44500
时,会自动被端口转发到192.168.1.2:445
。也就是:访问路由器的公网ip:对外端口
时,就好像访问内网机器:服务端口
。
你使用iPhone,安卓甚至是Mac 都可以开开心心的从外网访问内网的Windows服务器里面的服务了。
记得把Windows的防火墙打开(详见:复用 - 精品教程):
然而在远在宿舍的你,使用Windows却不能访问家里的SMB服务。
你还需要DNAT
当你使用iPhone连接SMB服务时,可以使用除了445端口外的其他端口。但是Windows是不支持445之外的端口的。
幸亏OpenWrt的iptables可以解君愁。
这里假定你在宿舍访问家里的文件
- 你(在家里的)服务器使用44500端口提供服务
- 你(在宿舍)使用OpenWrt类路由器(许多路由固件都是基于OpenWrt源码),支持iptables
- 你访问了非常规端口
44500
的服务,但你的应用只支持常规端口445
此时,进路由器,输入如下命令:
iptables -t nat -I PREROUTING -p tcp -d 6.1.1.1 --dport 445 -j DNAT --to 110.110.110.110:44500
解释一下这段代码,当路由器发现局域网内的请求满足以下条件时,自动进行DNAT(目的网络地址转换):
- 当局域网内请求目的ip 为
6.1.1.1
,且目的端口为445(你也可以改成任意有效的ip地址)时 - 把目的ip改成
110.110.110.110
,端口改成44500 - 反过来。当收到来自
110.110.110.110:44500
的包时,自动修改成6.1.1.1:445
▲映射网络驱动器
这里假定宿舍的Windows局域网地址为192.168.1.5(你可以改成自己的);在宿舍的Windows映射网络驱动器
窗口中输入地址\\6.1.1.1
,即可以访问家里110.110.110.110:44500
的服务。
当你的服务只能使用特定端口时,都可以利用OpenWrt的iptables来解决这个问题。iptables提供的功能是相当强大的,有时间和大家一起交流这个相对复杂的网络、防火墙工具。
总结
NAT 让我们实现了公网ip 的复用;而端口转发可以让我们从外网方便地访问内网服务,再也不怕运营商屏蔽端口;有些客户端访问服务只能使用常规端口,在这种情况下,我们使用iptables的DNAT巧妙化解问题。