Linux配置SNAT上网

前言

一个局域网中,主机之间互联,其中只有一台主机可以上网,其他主机想要上网怎么办?答:使用SNAT。

情景模拟

有主机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也可以上网。

数据包流向

发送数据包

B发送数据包时,A也就是NAT主机,分析数据包表头,将此数据包转到可以连接公网的IP上去。由于私有IP与公有IP不能互通,A会通过iptables的NAT table内的Postrounting链将数据包表头伪装成A的公网IP,并且将这两个不同来源的数据包对应关系写入暂存内存中,然后将数据包传送出去。此时传到互联网的这个数据包,已经表现为来自公网IP,而非来自局域网。

接收响应包

当互联网把数据响应给B时,会首先进入NAT主机A,A分析数据包的序号,对比刚刚记录到内存中的数据,由于发现该数据包为后端主机之前传送出去的,因此在NAT Prerouting链中,会将目标IP修改成为后端主机,即B的IP,然后发现目标已经不是A的公网IP,开始通过路由分析,将数据包传送到A的局域网接口,再传送到最终目标192.168.56.102上去。

iptables小班

snat的配置,主要用到iptables命令,之前在《CentOS7中firewall的使用》简单提过iptables,今天再认真学习一下。

主要参考文档:
Basic iptables howto
iptables详解
ipatebles详解(1):iptales概念
iptables命令
25个iptables常用示例
Linux防火墙iptables学习笔记(三)iptables命令详解和举例

历史

防火墙,其实说白了讲,就是用于实现Linux下访问控制的功能的,它分为硬件的或者软件的防火墙两种。无论是在哪个网络中,防火墙工作的地方一定是在网络的边缘。而我们的任务就是需要去定义到底防火墙如何工作,这就是防火墙的策略,规则,以达到让它对出入网络的IP、数据进行检测。

iptables的前身叫ipfirewall (内核1.x时代),这是一个作者从freeBSD上移植过来的,能够工作在内核当中的,对数据包进行检测的一款简易访问控制工具。但是ipfirewall工作功能极其有限(它需要将所有的规则都放进内核当中,这样规则才能够运行起来,而放进内核,这个做法一般是极其困难的)。当内核发展到2.x系列的时候,软件更名为ipchains,它可以定义多条规则,将他们串起来,共同发挥作用,而现在,它叫做iptables,可以将规则组成一个列表,实现绝对详细的访问控制功能

原理

五个关卡

iptables工作在用户空间中,是定义规则的工具,本身并不算是防火墙。它定义的规则,可以让内核空间中的netfilter来读取,并且实现让防火墙工作。netfilter的架构就是在整个网络流程的若干位置设置一些关卡(HOOK),而在每个关卡上登记了一些规则,所以这些关卡的术语规则链。

在内核空间中,netfilter选择了5个位置,来作为控制的关卡,专业点叫做规则链。朱双印大神的博客中给出了直观的图像:

根据上图,我们能够想象出某些常用场景中,报文的流向:
到本机某进程的报文:PREROUTING –> INPUT
由本机转发的报文:PREROUTING –> FORWARD –> POSTROUTING
由本机的某进程发出报文(通常为响应报文):OUTPUT –> POSTROUTING

五个规则链的作用如下:
INPUT链:处理输入数据包。
OUTPUT链:处理输出数据包。
PORWARD链:处理转发数据包。
PREROUTING链:用于目标地址转换(DNAT)。
POSTOUTING链:用于源地址转换(SNAT)。

表的概念

我们再想想另外一个问题,我们对每个”链”上都放置了一串规则,但是这些规则有些很相似,比如,A类规则都是对IP或者端口的过滤,B类规则是修改报文,那么这个时候,我们是不是能把实现相同功能的规则放在一起呢,必须能的。

我们把具有相同功能的规则的集合叫做”表”,所以说,不同功能的规则,我们可以放置在不同的表中进行管理,而iptables已经为我们定义了4种表,每种表对应了不同的功能,而我们定义的规则也都逃脱不了这4种功能的范围,所以,学习iptables之前,我们必须先搞明白每种表的作用。
iptables为我们提供了如下规则的分类,或者说,iptables为我们提供了如下”表”:

  • filter表:负责过滤功能,防火墙;内核模块:iptables_filter
  • nat表:network address translation,网络地址转换功能;内核模块:iptable_nat
  • mangle表:拆解报文,做出修改,并重新封装的功能;iptable_mangle
  • raw表:关闭nat表上启用的连接追踪机制;iptable_raw

也就是说,我们自定义的所有规则,都是这四种分类中的规则,或者说,所有规则都存在于这4张”表”中。

数据包流向

可以将数据包通过防火墙的流程总结为下图:

我们在写iptables规则的时候,要时刻牢记这张路由次序图,灵活配置规则。

规则

规则:根据指定的匹配条件来尝试匹配每个流经此处的报文,一旦匹配成功,则由规则后面指定的处理动作进行处理。规则由匹配条件和处理动作组成。

匹配条件分为基本匹配条件与扩展匹配条件:
基本匹配条件包括源地址Source IP和目标地址 Destination IP。

扩展匹配条件包括源端口Source Port,目标端口Destination Port等等。

动作也可以分为基本动作和扩展动作,此处列出一些常用动作:
ACCEPT:允许数据包通过。
DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。
REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。
SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。
MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。
DNAT:目标地址转换,解决外网用户访问内网的问题。
REDIRECT:在本机做端口映射。
LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。

命令详解

命令格式:
iptables [选项] [参数]

选项包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-t:指定要操纵的表;
-A:向规则链中添加条目;
-D:从规则链中删除条目;
-I:向规则链中插入条目;
-R:替换规则链中的条目;
-L:显示规则链中已有的条目;
-F:清楚规则链中已有的条目;
-Z:清空规则链中的数据包计算器和字节计数器;
-N:创建新的用户自定义规则链;
-P:定义规则链中的默认目标;
-h:显示帮助信息;
-p:指定要匹配的数据包协议类型;
-s:指定要匹配的数据包源ip地址;
-d:指定要匹配的数据包目标ip地址;
-j:指定要跳转的目标;
-i:指定数据包进入本机的网络接口(网卡);
-o:指定数据包离开本机的网络接口(网卡);
--sport:匹配来源端口号;
--dport:匹配目标端口号。

命令选项输入顺序:
iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

实例

1、清除已有iptables规则

1
2
3
iptables -F
iptables -X
iptables -Z

2、开放指定的端口

1
2
3
4
5
6
7
8
9
iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT               #允许本地回环接口(即允许本机访问本机)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #允许已建立的或相关连的通行
iptables -A OUTPUT -j ACCEPT #允许所有本机向外的访问
iptables -A INPUT -p tcp --dport 22 -j ACCEPT #允许访问22端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT #允许访问80端口
iptables -A INPUT -p tcp --dport 21 -j ACCEPT #允许ftp服务的21端口
iptables -A INPUT -p tcp --dport 20 -j ACCEPT #允许FTP服务的20端口
iptables -A INPUT -j REJECT #禁止其他未允许的规则访问
iptables -A FORWARD -j REJECT #禁止其他未允许的规则访问

3、屏蔽IP

1
2
3
4
iptables -I INPUT -s 123.45.6.7 -j DROP       #屏蔽单个IP的命令
iptables -I INPUT -s 123.0.0.0/8 -j DROP #封整个段即从123.0.0.1123.255.255.254的命令
iptables -I INPUT -s 124.45.0.0/16 -j DROP #封IP段即从123.45.0.1123.45.255.254的命令
iptables -I INPUT -s 123.45.6.0/24 -j DROP #封IP段即从123.45.6.1123.45.6.254的命令是

4、查看已添加的iptables规则
iptables -L -n -v

5、删除已添加的iptables规则
将所有iptables以序号标记显示,执行:
iptables -L -n --line-numbers

比如要删除INPUT里序号为8的规则,执行:
iptables -D INPUT 8

snat具体配置

主机A

接收数据包

允许接收局域网网卡的数据包
sudo iptables -I INPUT -i eth0 -j ACCEPT

或者
sudo iptables -P INPUT ACCEPT

开启路由功能

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。

伪装数据包

sudo iptables -t nat -A POSTROUTING -s 192.168.56.102 -o eth1 -j MASQUERADE

或者用SNAT直接修改IP数据包的表头来源IP
sudo 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

查看与删除

查看NAT表链规则
sudo iptables -t nat -nL --line-number

删除POSTROUTING第一条规则
sudo iptables -t nat -D POSTROUTING 1

重启后依旧生效

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

主机B

centos

如果是centos,那么配置ifcfg文件
sudo vim /etc/sysconfig/network-scripts/ifcfg-eth0

1
2
3
4
5
6
DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.56.102
NETMASK=255.255.255.0
GATEWAY=192.168.56.101

然后service network restart

ubuntu

如果是ubuntu,那么配置interfaces文件
sudo vim /etc/network/interfaces

1
2
3
4
5
6
7
8
auto lo
iface lo inet loopback

auto em1
iface em1 inet static
address 192.168.56.102
netmask 255.255.255.0
gateway 192.168.56.101

然后sudo /etc/init.d/networking restart

总之,B主机配置的关键在于网关,网关要设置成主机A的内网IP。

请问,网关不设置成主机A的内网IP可以吗?可以,那就是另外一种稍微复杂的设置方法了。

此时,使用主机B,已经可以ping通外网的IP了。但是ping域名会提示“ping: unknown host”。

DNS配置

方法一

1、编辑resolv.conf
sudo vim /etc/resolv.conf,添加nameserver的配置

1
2
nameserver 180.76.76.76
nameserver 223.6.6.6

上面的两个IP地址,分别是百度和阿里的公共DNS。

2、测试
ping www.baidu.com

3、不过,这种方法在重启之后会失效。想要永久生效,还需要编辑base文件。
sudo vim /etc/resolvconf/resolv.conf.d/base,添加:

1
2
nameserver 180.76.76.76
nameserver 223.6.6.6

方法二

1、编辑interfaces
sudo 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

结语

至此,snat完美配置成功!在这个过程中,顺带学习了一下iptables,收获满满。感觉iptables和route有很大关系,但是在配置过程中没有用到route。书签中有关于route的文档,用到的时候再深入学习。

书签

Linux下配置SNAT上网

利用iptables的SNAT功能实现局域网共享上网

linux 路由表设置之 route 指令详解

ubuntu配置静态路由及重启生效

0%