Linux配置SNAT上网

文章目录
  1. 1. 前言
  2. 2. 情景模拟
  3. 3. 数据包流向
    1. 3.1. 发送数据包
    2. 3.2. 接收响应包
  4. 4. iptables小班
    1. 4.1. 历史
    2. 4.2. 原理
      1. 4.2.1. 五个关卡
    3. 4.3. 表的概念
    4. 4.4. 数据包流向
    5. 4.5. 规则
    6. 4.6. 命令详解
    7. 4.7. 实例
  5. 5. snat具体配置
    1. 5.1. 主机A
      1. 5.1.1. 接收数据包
      2. 5.1.2. 开启路由功能
      3. 5.1.3. 伪装数据包
      4. 5.1.4. 查看与删除
    2. 5.2. 重启后依旧生效
    3. 5.3. 主机B
      1. 5.3.1. centos
      2. 5.3.2. ubuntu
  6. 6. DNS配置
    1. 6.1. 方法一
    2. 6.2. 方法二
  7. 7. 结语
  8. 8. 书签

前言

一个局域网中,主机之间互联,其中只有一台主机可以上网,其他主机想要上网怎么办?答:使用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,今天再认真学习一下。

主要参考文档:
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

删除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

2、添加nameserver的配置

1
2
nameserver 180.76.76.76
nameserver 223.6.6.6

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

3、测试
ping www.baidu.com

方法二

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配置静态路由及重启生效