1. 需求描述
有主机A,eth0的IP为内网IP:192.168.56.101,eth1为公网IP:120.77.36.222。
有主机B,eth0的IP为内网IP:192.168.56.102。
主机A可以访问外网,主机B和主机A在同一个局域网。现在我们想让主机B也可以上网,该怎么办?
最简单的方法有两个:1)SNAT;2)代理
本文中,我们学习使用配置SNAT的方式,实现局域网中的所有主机可以上网。
参考文档:
2. SNAT数据包流向
2.1. 发送数据包
B发送数据包时,A也就是NAT主机,分析数据包表头,将此数据包转到可以连接公网的IP上去。由于私有IP与公有IP不能互通,A会通过iptables的NAT table内的Postrounting链将数据包表头伪装成A的公网IP,并且将这两个不同来源的数据包对应关系写入暂存内存中,然后将数据包传送出去。此时传到互联网的这个数据包,已经表现为来自公网IP,而非来自局域网。
2.2. 接收响应包
当互联网把数据响应给B时,会首先进入NAT主机A,A分析数据包的序号,对比刚刚记录到内存中的数据,由于发现该数据包为后端主机之前传送出去的,因此在NAT Prerouting链中,会将目标IP修改成为后端主机,即B的IP,然后发现目标已经不是A的公网IP,开始通过路由分析,将数据包传送到A的局域网接口,再传送到最终目标192.168.56.102上去。
3. snat具体配置
3.1. 主机A
3.1.1. 接收数据包
允许接收局域网网卡的数据包sudo iptables -I INPUT -i eth0 -j ACCEPT
或者sudo iptables -P INPUT ACCEPT
3.1.2. 开启路由功能
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
如果报错:-bash: /proc/sys/net/ipv4/ip_forward: Permission denied
那就切换到root用户:sudo -i
echo 1 > /proc/sys/net/ipv4/ip_forward
要想永久有效,还要把/etc/sysctl.conf文件里边的net.ipv4.ip_forward的值改为1。
3.1.3. 伪装数据包
sudo iptables -t nat -A POSTROUTING -s 192.168.56.102 -o eth1 -j MASQUERADE
或者用SNAT直接修改IP数据包的表头来源IPsudo iptables -t nat -A POSTROUTING -s 192.168.56.102 -o eth1 -j SNAT --to 192.168.56.101
如果需要支持整个网段:sudo iptables -t nat -A POSTROUTING -s 192.168.56.0/24 -o eth1 -j SNAT --to 192.168.56.101
如果需要支持连续IP:sudo iptables -t nat -A POSTROUTING -m iprange --src-range 192.168.56.102-192.168.56.104 -o eth1 -j SNAT --to 192.168.56.101
注意:
- 亲测以上所有命令中的
-o eth1
可以省略,所以,在分不清哪个网卡是内网哪个网卡是外网的情况下,直接省略即可。 - 如果想要允许所有IP,
-s 192.168.56.0/24
也可以省略。 -j SNAT --to 192.168.56.101
可以换成-j SNAT --to 120.77.36.222
。-j SNAT --to 120.77.36.222
建议换成-j MASQUERADE
,尤其在外网IP非固定的情况下。- 综上,最简单的万能SNAT命令为
sudo iptables -t nat -A POSTROUTING -j MASQUERADE
3.1.4. 查看与删除
查看NAT表链规则sudo iptables -t nat -nL --line-number
删除POSTROUTING第一条规则sudo iptables -t nat -D POSTROUTING 1
3.2. 重启后依旧生效
1、保存规则sudo chmod a+w -R /opt
sudo iptables-save > /opt/iptables.rules
2、手动导入规则sudo iptables-restore < /opt/iptables.rules
3、开机自动导入规则
在ubuntu下要把一个程序加入开机启动,一般可以通过修改rc.local来完成,但ubuntu下有两个rc.local文件,分别是/etc/rc.local和/etc/init.d/rc.local。因为/etc/init.d/rc.local调用了/etc/rc.local,所以我们的开机脚本最好直接写入/etc/rc.local,写在exit 0之前即可。
sudo vim /etc/rc.local
在exit 0之前添加:
1 | /sbin/iptables-restore < /opt/iptables.rules |
3.3. 主机B
3.3.1. centos
如果是centos,那么配置ifcfg文件sudo vim /etc/sysconfig/network-scripts/ifcfg-eth0
1 | DEVICE=eth0 |
然后service network restart
3.3.2. ubuntu
如果是ubuntu,那么配置interfaces文件sudo vim /etc/network/interfaces
1 | auto lo |
然后sudo /etc/init.d/networking restart
总之,B主机配置的关键在于网关,网关要设置成主机A的内网IP。
请问,网关不设置成主机A的内网IP可以吗?可以,那就是另外一种稍微复杂的设置方法了。
此时,使用主机B,已经可以ping通外网的IP了。但是ping域名会提示“ping: unknown host”。
4. DNS配置
4.1. 方法一
1、编辑resolv.confsudo vim /etc/resolv.conf
,添加nameserver的配置
1 | nameserver 180.76.76.76 |
上面的两个IP地址,分别是百度和阿里的公共DNS。
2、测试ping www.baidu.com
3、不过,这种方法在重启之后会失效。想要永久生效,还需要编辑base文件。sudo vim /etc/resolvconf/resolv.conf.d/base
,添加:
1 | nameserver 180.76.76.76 |
4.2. 方法二
1、编辑interfacessudo vim /etc/network/interfaces
2、添加nameserver的配置
1 | dns-nameserver 180.76.76.76 223.5.5.5 |
3、重启服务器sudo reboot
实际上,重启后的dns配置会写入到resolv.conf中。
4、测试ping www.baidu.com
5. 结语
至此,snat完美配置成功!在这个过程中,顺带复习了一下iptables,收获满满。感觉iptables和route有很大关系,但是在配置过程中没有用到route。书签中有关于route的文档,用到的时候再深入学习。