1. iptables

1.1. iptables的工作流程

iptables 从广义上来说是 netfilter + iptables,其中netfilter是工作在内核态的一组处理数据流量的钩子函数,该钩子函数埋点在网络层。无论从虚拟网卡还是物理网卡收到一个包,对内核来说都是收包,都是prerouting链开始。无论一个包去往物理网卡还是虚拟网卡,对内核来说都是发出,都是从postrouting结束。本机进程收到就是input链,本机进程发出就是output链。
iptables.png

1.2. iptables语法规则

1.2.1. 基本概念

防火墙的基本语法是,在一个表(table)的一条链(chain)上定义一个规则(rule),该规则由目标动作(target)和匹配规则(match) 组成,表和链的对应关系,以及表之间的优先级,在上一章节的图中可以查看。

  1. 表:
  2. raw表:关闭nat表上连接追踪机制
  3. mangle表:解析并修饰报文
  4. nat表:网络地址转换,通常用于DNATSNAT
  5. filter: 负责数据包过滤,通常用于防火墙功能
  6. 链:
  7. PREROUTING:所有到达本机网络层的数据包都会经过这个链
  8. INPUT:经过PREROUTING后,进行路由解析,如果是发给本地网卡的数据包则进入该链
  9. FORWARD:经过PREROUTING后,进行路由解析,如果不是本机的数据包,则转发到路由的下一跳
  10. OUTPUT:由传输层封装到达网络层,经过路由匹配后,进入OUTPUT
  11. POSTROUTING:所有从本机流出的数据包都会经过这个链
  12. 匹配对象:
  13. 网络接口:eth0, ens33
  14. IP地址:源IP地址,目标IP地址
  15. 端口:源端口,目标端口
  16. ......
  17. 目标动作:
  18. ACCEPT:允许通过
  19. DROP:丢弃数据包
  20. REJECT:拒绝数据包
  21. SNAT:修改源地址
  22. DNAT:修改目标地址
  23. MASQUERADE:一种特殊的SNAT,将源地址改为出口网卡地址
  24. LOG:仅记录日志,日志输出到系统日志文件,如 message
  25. QUEUE:将数据包交到用户空间
  26. RETURN:停止当前链的匹配,返回上层调用链
  27. REDIRECT:端口重定向
  28. MARK:防火墙标记
  29. CHAIN_NAME: 跳转到指定的链

1.2.2. 查看规则

1.2.2.1. 查看指定表的规则

  1. Usage: iptables -t [table] -nvL [chain] --line-numbers
  2. -t 指定表名称,默认为filter
  3. -n 以数字形式显示地址和端口
  4. -v 显示详细信息
  5. -L 列出规则
  6. --line-numbers 显示序号
  1. [root@duduniao ~]# iptables -nvL FORWARD
  2. Chain FORWARD (policy DROP 0 packets, 0 bytes)
  3. pkts bytes target prot opt in out source destination
  4. 0 0 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0
  5. 0 0 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0
  6. 0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
  7. 0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
  1. [root@duduniao ~]# iptables -t nat -nvL POSTROUTING --line-numbers
  2. Chain POSTROUTING (policy ACCEPT 96 packets, 5785 bytes)
  3. num pkts bytes target prot opt in out source destination
  4. 1 0 0 MASQUERADE all -- * !docker0 172.24.20.0/24 0.0.0.0/0
  5. 2 0 0 MASQUERADE all -- * !br-7060c846c032 172.16.0.0/16 0.0.0.0/0
  6. 3 0 0 MASQUERADE tcp -- * * 172.16.142.189 172.16.142.189 tcp dpt:15672
  7. 4 0 0 MASQUERADE tcp -- * * 172.16.142.189 172.16.142.189 tcp dpt:5672
  8. 5 0 0 MASQUERADE tcp -- * * 172.16.142.189 172.16.142.189 tcp dpt:3306
  9. +++++++++++++++++++++++
  10. policy: 默认规则,针对所有当前链未被匹配到的数据包
  11. num:当前规则的序号。
  12. pkts:对应规则匹配到的报文的个数。
  13. bytes:对应匹配到的报文包的大小总和。
  14. target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施。
  15. prot:表示规则对应的协议,是否只针对某些协议应用此规则。
  16. opt:表示规则对应的选项。
  17. in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
  18. out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
  19. source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
  20. destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。

1.2.2.2. 查看所有规则

上述的命令,可以查看很多有用信息,但是需要你指定表名称,无法一次性查看所有的规则信息。

  1. [root@duduniao ~]# iptables-save
  2. ......
  3. *nat
  4. :PREROUTING ACCEPT [2205:389010]
  5. :INPUT ACCEPT [11:912]
  6. :OUTPUT ACCEPT [96:5785]
  7. :POSTROUTING ACCEPT [96:5785]
  8. :DOCKER - [0:0]
  9. -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
  10. -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
  11. -A POSTROUTING -s 172.24.20.0/24 ! -o docker0 -j MASQUERADE
  12. -A POSTROUTING -s 172.16.0.0/16 ! -o br-7060c846c032 -j MASQUERADE
  13. -A POSTROUTING -s 172.16.142.189/32 -d 172.16.142.189/32 -p tcp -m tcp --dport 15672 -j MASQUERADE
  14. -A POSTROUTING -s 172.16.142.189/32 -d 172.16.142.189/32 -p tcp -m tcp --dport 5672 -j MASQUERADE
  15. -A POSTROUTING -s 172.16.142.189/32 -d 172.16.142.189/32 -p tcp -m tcp --dport 3306 -j MASQUERADE

1.2.3. 简单使用

为了方便测试,写了两个小工具,server, client,下载地址:iptables-test-tools.zip

1.2.3.1. 添加规则

需要格外注意的是,链规则会从上到下匹配,匹配到后会结束当前链的匹配,因此规则顺序很重要

  1. Usage: iptables [-t table] -A|-I chain match_expression -j target
  2. -t 指定表名称,默认为 filter
  3. -I insert,在规则中插入一条规则,可以在链名称后面使用数字指定为第几条规则,默认插入为第一条规则
  4. -A append,在规则的默认添加新的规则
  5. chain 链名称
  6. match_expression 匹配数据包的表达式,如地址、端口等
  7. target 指定动作,如ACCEPTDROP。或者指定自定义链,表示进入自定义链
  • 简单规则案例 ```

    插入一条规则,丢弃从 10.4.7.30 来的tcp连接

    [root@filebeat-41 ~]# iptables -t filter -I INPUT -s 10.4.7.30 -p tcp -j DROP [root@filebeat-41 ~]# iptables -nvL INPUT Chain INPUT (policy ACCEPT 47 packets, 3272 bytes) pkts bytes target prot opt in out source destination 0 0 DROP tcp — 10.4.7.30 0.0.0.0/0

[root@filebeat-41 ~]# ./server -t tcp -h 10.4.7.41 -p 3000 [root@centos-7-30 ~]# ./client -t tcp -h 10.4.7.41 -p 3000 connect to server failed, err:dial tcp 10.4.7.41:3000: i/o timeout

[root@filebeat-41 ~]# iptables -nvL INPUT # 可以查看到被拒绝的报文 Chain INPUT (policy ACCEPT 173 packets, 13187 bytes) pkts bytes target prot opt in out source destination 9 540 DROP tcp — 10.4.7.30 0.0.0.0/0

  1. ```
  2. # 插入一条规则,拒绝 ping 请求
  3. [root@filebeat-41 ~]# iptables -t filter -I INPUT -p icmp -j REJECT
  4. [root@filebeat-41 ~]# iptables -nvL INPUT
  5. Chain INPUT (policy ACCEPT 9 packets, 636 bytes)
  6. pkts bytes target prot opt in out source destination
  7. 0 0 REJECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
  8. 9 540 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  9. [root@centos-7-30 ~]# ping 10.4.7.41
  10. PING 10.4.7.41 (10.4.7.41) 56(84) bytes of data.
  11. From 10.4.7.41 icmp_seq=1 Destination Port Unreachable
  12. From 10.4.7.41 icmp_seq=2 Destination Port Unreachable
  13. From 10.4.7.41 icmp_seq=3 Destination Port Unreachable
  1. [root@filebeat-41 ~]# iptables -t filter -I INPUT -s 10.4.7.30 -p tcp -j ACCEPT # 添加一条与第一条规则相反的规则
  2. [root@filebeat-41 ~]# iptables -nvL INPUT
  3. Chain INPUT (policy ACCEPT 8 packets, 564 bytes)
  4. pkts bytes target prot opt in out source destination
  5. 0 0 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0
  6. 8 672 REJECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
  7. 9 540 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  8. [root@filebeat-41 ~]# ./server -t tcp -h 10.4.7.41 -p 3000
  9. [root@centos-7-30 ~]# ./client -t tcp -h 10.4.7.41 -p 3000 # 此时可以联通到10.4.7.41的TCP端口
  10. [client]:sf
  11. [server]:SF
  • 复杂规则案例
    1. # 多个规则默认使用AND匹配,可以使用 ! 取反
    2. -s 匹配源地址,支持单个IP地址,网段,多个用逗号连接的IP地址或者网段
    3. -d 匹配源地址,支持单个IP地址,网段,多个用逗号连接的IP地址或者网段
    4. -p 匹配协议类型,tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh
    5. -i 指定流入的网卡名称
    6. -o 指定流出的网卡名称
    1. [root@filebeat-41 ~]# iptables -t filter -I INPUT -s 10.4.7.30 ! -p tcp -j DROP
    2. [root@filebeat-41 ~]# iptables -nvL INPUT
    3. pkts bytes target prot opt in out source destination
    4. 0 0 DROP !tcp -- * * 10.4.7.30 0.0.0.0/0

    1.2.3.2. 删除规则

    ``` usage: iptables [-t table] -D chain num|match -D 删除规则 num 指定规则的序号,按照序号删除,可以通过 —line-numbers 显示 match 指定规则的匹配字符串,删除匹配的结果

usage: iptables [-t table] -F [chain] -F 刷新规则,删除指定链下所有规则

  1. ```
  2. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  3. Chain INPUT (policy ACCEPT 176 packets, 12898 bytes)
  4. num pkts bytes target prot opt in out source destination
  5. 1 54 2818 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0
  6. 2 12 1064 REJECT icmp -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
  7. 3 9 540 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  8. [root@filebeat-41 ~]# iptables -D INPUT 2
  9. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  10. Chain INPUT (policy ACCEPT 7 packets, 488 bytes)
  11. num pkts bytes target prot opt in out source destination
  12. 1 100 5210 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0
  13. 2 9 540 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  1. [root@filebeat-41 ~]# iptables -D INPUT -s 10.4.7.30 -p tcp -j ACCEPT
  2. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  3. Chain INPUT (policy ACCEPT 11 packets, 784 bytes)
  4. num pkts bytes target prot opt in out source destination
  5. 1 11 644 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  1. [root@filebeat-41 ~]# iptables -F INPUT
  2. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  3. Chain INPUT (policy ACCEPT 7 packets, 488 bytes)
  4. num pkts bytes target prot opt in out source destination

1.2.3.3. 更新规则

  1. Uage: iptables [-t table] -R chain num match_expression -j target_action
  2. -R 替换规则,替换指定行号的规则
  1. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  2. Chain INPUT (policy ACCEPT 63 packets, 4917 bytes)
  3. num pkts bytes target prot opt in out source destination
  4. 1 18 936 DROP tcp -- * * 10.4.7.30 0.0.0.0/0
  5. 2 0 0 DROP udp -- * * 10.4.7.30 0.0.0.0/0
  6. 3 0 0 DROP icmp -- * * 10.4.7.30 0.0.0.0/0
  7. [root@filebeat-41 ~]# iptables -t filter -R INPUT 1 -s 10.4.7.30 -p tcp -j ACCEPT
  8. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  9. Chain INPUT (policy ACCEPT 7 packets, 488 bytes)
  10. num pkts bytes target prot opt in out source destination
  11. 1 0 0 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0
  12. 2 0 0 DROP udp -- * * 10.4.7.30 0.0.0.0/0
  13. 3 0 0 DROP icmp -- * * 10.4.7.30 0.0.0.0/0

1.2.3.4. 默认规则

  1. Usage: iptables [-t table] -P chain target_action
  1. [root@filebeat-41 ~]# iptables -t filter -I INPUT -p tcp -m tcp --dport 22 -j ACCEPT # 先放开22端口,否则SSH连接将被中断
  2. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  3. Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
  4. num pkts bytes target prot opt in out source destination
  5. 1 9 636 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
  6. 2 18 946 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0
  7. [root@filebeat-41 ~]# iptables -t filter -P INPUT DROP
  8. [root@filebeat-41 ~]# iptables -nvL INPUT --line-numbers
  9. Chain INPUT (policy DROP 0 packets, 0 bytes)
  10. num pkts bytes target prot opt in out source destination
  11. 1 112 7824 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
  12. 2 18 946 ACCEPT tcp -- * * 10.4.7.30 0.0.0.0/0

1.2.3.5. 保存和载入规则

以上所有编辑的规则只是存在于内存中,没有进行持久化存储,重启后会丢失,因此对于传统虚拟机管理员而言,自定义的iptables规则需要持久化,并在开机后载入。
目前市面上的服务,如果用到iptables规则,如docker或者kubernetes,他们会在服务启动后自动载入需要的规则,无需人为干预。
在老版本中,如centos 6,已经安装了 iptables-service,可以使用 service iptables save 保存规则,其他系统如果可以安装 iptables-service,或者将规则保存到文件中,开机时再读取。

持久化规则:
    service iptables save
    iptables-save > backup.iptables

从文件中恢复
    iptables-restore < backup.iptables
[root@filebeat-41 ~]# iptables -nvL INPUT
Chain INPUT (policy DROP 2 packets, 211 bytes)
 pkts bytes target     prot opt in     out     source               destination
   79  6576 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
    4   208 ACCEPT     tcp  --  *      *       10.4.7.30            0.0.0.0/0
[root@filebeat-41 ~]# iptables-save > /tmp/backup.iptables  # 保存规则

[root@filebeat-41 ~]# iptables -t filter -P INPUT ACCEPT    # 在清空规则之前,一定要确认好默认规则,避免SSH断开
[root@filebeat-41 ~]# iptables -F
[root@filebeat-41 ~]# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 18 packets, 1367 bytes)
 pkts bytes target     prot opt in     out     source               destination

[root@filebeat-41 ~]# iptables-restore < /tmp/backup.iptables # 恢复规则
[root@filebeat-41 ~]# iptables -nvL INPUT
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    7   488 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
    0     0 ACCEPT     tcp  --  *      *       10.4.7.30            0.0.0.0/0

1.2.4. 扩展模块

上述的添加规则案例中,使用了 -s-p 参数,用于指定源地址和协议类型,但是还有很多无法表示,如端口,此时需要使用扩展模块,每个扩展模块支持不同的条件。使用 -m 指定需要使用的模块,没有指定的模块,默认使用与协议相同 -p 名称的模块。

1.2.4.1. tcp和udp模块

tcp和udp都支持端口指定,用法相同。其中tcp还支持flag标志位的匹配,因为使用较少,此处不做介绍
--dport      指定目标端口,需要指定协议
--sport      指定源端口,需要指定协议


支持的端口可以是某个具体的端口,也可以是一段连续的端口:
--dport  8080         # 指定8080端口
--dport  8080:8088    # 指定8080到8088之间所有端口
--dport  8080:        # 大于等于 8080 的所有端口
--dport  :8080        # 小于等于 8080 的所有端口
# 此处省略了 -m 参数,因此与使用的模块与 -p 参数相同,即 tcp
[root@filebeat-41 ~]# iptables -t filter -A INPUT -s 10.4.7.30 -p tcp --dport 2333 -j DROP
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 81 packets, 5827 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1       12   648 DROP       tcp  --  *      *       10.4.7.30            0.0.0.0/0            tcp dpt:2333

[root@filebeat-41 ~]# ./server -t tcp -p 2333
[root@centos-7-30 ~]# ./client -t tcp -p 2333 -h 10.4.7.41 # 无法连接
connect to server failed, err:dial tcp 10.4.7.41:2333: i/o timeout
[root@filebeat-41 ~]# iptables -t filter -A INPUT -s 10.4.7.30 -p tcp -m tcp --dport 10080:10088 -j REJECT
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 8 packets, 564 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1       13   700 DROP       tcp  --  *      *       10.4.7.30            0.0.0.0/0            tcp dpt:2333
2        0     0 REJECT     tcp  --  *      *       10.4.7.30            0.0.0.0/0            tcp dpts:10080:10088 reject-with icmp-port-unreachable

[root@centos-7-30 ~]# ./client -t tcp -p 10082 -h 10.4.7.41
connect to server failed, err:dial tcp 10.4.7.41:10082: connect: connection refused
[root@filebeat-41 ~]# iptables -t filter -A INPUT -s 10.4.7.30 -p udp -m udp --dport 10080:10088 -j REJECT
[root@filebeat-41 ~]# iptables -t filter -A INPUT -s 10.4.7.30 -p udp --dport 2333 -j DROP
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 229 packets, 17455 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        2    58 REJECT     udp  --  *      *       10.4.7.30            0.0.0.0/0            udp dpts:10080:10088 reject-with icmp-port-unreachable
2        1    29 DROP       udp  --  *      *       10.4.7.30            0.0.0.0/0            udp dpt:2333

1.2.4.2. multiport模块

tcp 和 udp 指定指定一个端口,或者一段连续的端口。multiport 支持多个离散的端口

--dports  指定目标端口,多个离散端口使用逗号连接,支持冒号指定端口范围
--sports  指定目标端口,多个离散端口使用逗号连接,支持冒号指定端口范围

支持的形式如下:
--dports  10080,10082,10088
--dports  10080,20011:20099
[root@filebeat-41 ~]# iptables -t filter -I INPUT -p tcp -m multiport --dports 10080,10082,10084 -j REJECT
[root@filebeat-41 ~]# iptables -t filter -I INPUT -p udp -m multiport --dports 20081,20088,30010:30012 -j REJECT
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 29 packets, 2329 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     udp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 20081,20088,30010:30012 reject-with icmp-port-unreachable
2        1    60 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 10080,10082,10084 reject-with icmp-port-unreachable

1.2.4.3. iprange模块

使用 -s 和 -d 可以指定源IP和目标IP,但是只能指定网段或者具体IP地址。指定一段连续的ip地址需要使用iprange模块

--src-range   指定源地址范围。如 192.168.0.100-192.168.0.150
--dst-range   指定目标地址范围。如 192.168.0.100-192.168.0.150
[root@filebeat-41 ~]# iptables -t filter -I INPUT -m iprange --src-range 10.4.7.10-10.4.7.30 -j REJECT
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 15 packets, 1080 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            source IP range 10.4.7.10-10.4.7.30 reject-with icmp-port-unreachable

[root@centos-7-30 ~]# ping 10.4.7.41
PING 10.4.7.41 (10.4.7.41) 56(84) bytes of data.
From 10.4.7.41 icmp_seq=1 Destination Port Unreachable
From 10.4.7.41 icmp_seq=2 Destination Port Unreachable

1.2.4.4. comment模块

该模块用于添加注释
--commennt  注释内容
[root@filebeat-41 ~]# iptables -t filter -I INPUT -m iprange --src-range 10.4.7.10-10.4.7.30 -m comment --comment "iprange example" -j REJECT
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 37 packets, 2708 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            source IP range 10.4.7.10-10.4.7.30 /* iprange example */ reject-with icmp-port-unreachable

1.2.4.5. icmp模块

icmp(Internet Control Message Protocol),互联网消息控制协议,常常用于检测网络连通性,最常用的 ping 命令使用的就是icmp协议。
unnamed (1).png
unnamed.png
当A主机ping B主机地址时,A 项B主机发送的报文为 8 类型的 icmp 协议请求,B主机回复的是 0 类型的 icmp 协议的响应

--icmp-type   icmp的协议类型。支持指定类型名称,类型编号,类型编号/状态码。8类型名称为 echo-request, 0类型为 echo-reply

--icmp-type echo-request
--icmp-type 8
--icmp-type 3/2
[root@filebeat-41 ~]# iptables -t filter -I INPUT -p icmp -m icmp --icmp-type 8 -j DROP  # 禁止被其他机器ping
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 31 packets, 2335 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        2   168 DROP       icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 8

[root@filebeat-41 ~]# iptables -t filter -I INPUT -p icmp -m icmp --icmp-type 0 -j REJECT # 禁止ping其他机器
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 65 packets, 4520 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        2   168 REJECT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 0 reject-with icmp-port-unreachable
2        2   168 DROP       icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 8

1.2.4.6. state 模块

举个栗子,假设有一个服务器,需要配置防火墙规则,该服务器对外开放的服务端口有 22 端口和 8080 端口,其他的端口不对外开放,那么我们可能会按照以下策略配置iptables规则:

[root@filebeat-41 ~]# iptables -t filter -I INPUT -p tcp -m tcp --dport 22 -j ACCEPT
[root@filebeat-41 ~]# iptables -t filter -I INPUT -p tcp -m tcp --dport 8080 -j ACCEPT
[root@filebeat-41 ~]# iptables -t filter -P INPUT DROP
[root@filebeat-41 ~]# iptables -t filter -nvL INPUT --line-numbers
Chain INPUT (policy DROP 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080
2      177 12592 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22

此时其他服务器连接 filebeat-41 的 22 和 8080 端口确实没有问题,但是如果 filebeat-41 访问其他服务就会出去,因为 filebeat-41 访问其他服务时,会在本地开放一个随机端口,其他服务器返回的报文目标端口就是这个随机端口,然后这个随机端口却被默认的DROP规则拒绝。

[root@filebeat-41 ~]# curl -I www.baidu.com # 当我们开始访问百度时, 会先访问 dns 服务器,dns响应报文无法被本机接收到
[root@filebeat-41 ~]# netstat -anput        
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
udp        0      0 10.4.7.41:58713         114.114.114.114:53      ESTABLISHED 1930/curl

为了解决上述的问题,引入的连接状态的模块 state ,该模块将状态分为以下几种类型:

  • NEW:发起通信的第一个请求的数据包。即该连接表示客户端发起一个新的连接
  • ESTABLISH:NEW状态之后,通过该连接的客户端与服务端之间所有的数据包交换中,都是为 ESTABLISH 状态
  • RELATED:部分服务的数据传输可能分为多个阶段,比如FTP服务主动模式,客户端通过21端口与服务端建立连接,并开放高位端口等待服务端传输数据,这个过程中,数据传输连接是21端口连接关联连接,状态为RELATED
  • INVALID:包的状态无法被识别
  • UNTRACKED:报文没有被跟踪 ``` [root@filebeat-41 ~]# iptables -t filter -A INPUT -m state —state ESTABLISH,RELATED -j ACCEPT [root@filebeat-41 ~]# iptables -t filter -nvL INPUT —line-numbers Chain INPUT (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 26 1381 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 2 891 65405 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 3 0 0 ACCEPT all — 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED

此时该服务器就可以作为客户端与其他服务发起请求

[root@filebeat-41 ~]# curl -I www.baidu.com HTTP/1.1 200 OK

<a name="yqJli"></a>
#### 1.2.4.9. conntrack模块
conntrack 模块用于连接追踪,应用于NAT技术和L4的负载均衡,更多相关资料请参考: [http://arthurchiao.art/blog/conntrack-design-and-implementation-zh/](http://arthurchiao.art/blog/conntrack-design-and-implementation-zh/)<br />conntrack 的 `--ctstate ` 功能和 `state --state` 功能一致,conntrack 模块的还支持更多的匹配条件,不过其他条件使用的不多,主要用的是 `--ctstate`
<a name="ZCh86"></a>
#### 1.2.4.8. **addrtype模块**

该模块用于指定地址的类型 —src-type 指定源地址类型,使用逗号可以拼接多个类型 —dst-type 指定目标地址类型,使用逗号可以拼接多个类型 —limit-iface-in 指定来源的网卡 —limit-iface-out 指定出去的网卡

支持的地址类型有: LOCAL 本地的地址,常用 UNSPEC 未指定的IP地址,0.0.0.0 UNICAST 单播地址 BROADCAST 广播地址 MULTICAST 组播地址 ANYCAST
BLACKHOLE UNREACHABLE PROHIBIT THROW NAT XRESOLVE

<a name="NE5RB"></a>
### 1.2.5. 自定义链
为了避免大量的规则在默认的几条链上导致管理难度增加,引入了自定义链的概念,用户通过功能将自定义的规则分组,用不同的自定义链名称命名,并且通过调用这些自定义链完成规则的匹配。

iptables -t table -N chain_name # 创建自定义链 iptabels -t table -E chain_name # 重命名自定义链 iptables -t table -X chain_name # 删除自定义链(前提是没有被引用且没有规则) iptables -t table -A|-I chain match_expression -j chain_name # 引用自定义链

```
[root@filebeat-41 ~]# iptables -t filter -N VM_FIREWARD
[root@filebeat-41 ~]# iptables -t filter -I VM_FIREWARD -p tcp -m multiport --dports 22,80,8080 -j ACCEPT
[root@filebeat-41 ~]# iptables -t filter -I VM_FIREWARD -m conntrack --ctstate ESTABLISH,RELATED -j ACCEPT
[root@filebeat-41 ~]# iptables -t filter -A VM_FIREWARD -p icmp -j ACCEPT
[root@filebeat-41 ~]# iptables -t filter -I INPUT -j VM_FIREWARD  # 引用VM_FIREWARD链
[root@filebeat-41 ~]# iptables -t filter -P INPUT DROP

[root@filebeat-41 ~]# iptables -nvL # 注意下 VM_FIREWARD 后面 1 references,表示一次引用
Chain INPUT (policy DROP 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
  448 33107 VM_FIREWARD  all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain VM_FIREWARD (1 references)
 pkts bytes target     prot opt in     out     source               destination
  446 32939 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 22,80,8080
    1    84 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0

1.2.6. 动作

Usage: iptables [-t table] -A|-I chain match_expression -j target

其中target 规则有以下几种:
ACCEPT         放行
DROP           丢弃报文,不做任何响应
REJECT         拒绝,会返回具体响应
SNAT           SNAT规则
DNAT           DNAT规则
MASQUERADE     SNAT动态的自动化NAT
REDIRECT       实现端口的流量转发,从本机的A端口转到B端口
LOG            记录日志,一般不用

1.2.6.1. NAT

NAT(network address Translation),网络地址转换,源地址转换为SNAT,目标地址转换为DNAT,源地址和目标地址都转换为Full NAT。NAT技术其实是内核维护了一张NAT映射表,并跟踪这些进行NAT的连接,此处不多做展开。
如下图所示,内网机器访问互联网就是一个典型的,同时具备SNAT和DNAT过程。VM-1访问百度网站,源地址是10.4.7.41(局域网),但是如果用这个地址直接访问百度,响应报文是回不来的,必须要用公网地址接收百度的服务器响应,因此增加了路由设备,对请求报文中的源地址替换为当前路由上的公网地址,这个过程为SNAT。百度响应给路由的报文中,目标地址为路由器的公网地址,路由器为了将报文正确的送到到VM-1,将目标地址修改为VM-1的地址:10.4.7.41,这个过程为DNAT。这里面存在三个注意点:

  • SNAT和DNAT一般成对出现的,如果一个连接建立中,前半段使用SNAT,则称这个过程为SNAT。前半段使用DNAT,则称这个过程为DNAT
  • 路由器通过连接追踪(conntrack)技术,维护NAT连接映射关系。才能知晓响应报文的目标地址修改为10.4.7.41而不是其他的地址
  • 这个案例中,如果SNAT源地址114.106.181.41经常变化,那么就使用MASQUERADE,将请求报文中的src动态改为路由器出口网卡的地址

未命名绘图.png

# SNAT过程,修改源地址为特定地址。内核会跟踪这个连接,对响应的报文自动进行DNAT操作
-j SNAT --to-source ipaddress  

# DNAT过程,修改目标地址为特定地址。内核会跟踪这个连接,对响应的报文自动进行SNAT操作
-j DNAT --to-destination address

# MASQUERADE,修改源地址为出口网卡地址。内核会跟踪这个连接,对响应的报文自动进行DNAT操作
-j MASQUERADE

NAT操作案例,可以参考 k8s 的iptables 分析案例


01-1-防火墙 - 图5