iptables实用知识 ,一文学会配置linux防火墙

iptables实用知识 ,一文学会配置linux防火墙, 以自己实际使用情况来总结了iptables常用知识点

iptables 官方man文档: https://linux.die.net/man/8/iptables

iptables中文指南: https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
(比较详细,讲了一些技术的实现原理, 版本旧,和centos7有点差异,我知道的是NAT时指定IP范围,centos7不再支持自动循环使用指定的IP范围,猜测只会使用第一个IP,没做实验)

说明:

本文测试基于系统环境: centOS 7

本文以实用的角度理解防火墙,不是官方文档的知识点罗列。

1.防火墙的概念

计算机领域中防火墙一般指的是网络(特指TCP/IP网络)防火墙,根据TCP/IP网络模型,防火墙可以处在不同的层,主要两种:普通的网络层防火墙,上层的应用防火墙,如WAF。

linux和windows操作系统中的防火墙,我们叫网络层防火墙,准确的说应该是传输层的,因为会处理TCP, UDP端口号,而不仅仅是IP。

网络层防火墙的作用: 包过滤,根据源IP,端口,目标IP端口,过滤数据包,允许通行或者禁止通行。

2. linux防火墙

linux防火墙由内核netfiter实现,用户不能直接操作内核,提供了防火墙配置工具iptables和现在centos 7版本开始的firewalld工具,这两个工具只是防火墙的配置接口,内核都是netfiter。

iptables配置命令复杂,原始,难度较大,但支持配置全部的功能。

而firewalld做了更高级的封装,配置命令简单,但无法实现复杂的配置,要实现复杂的配置需要用rich-rule(富规则),以及更高级的direct命令(和iptables命令几乎一模一样了)。

iptables的功能:

  1. iptables是网络层防火墙,必然支持基于ip和端口的过滤规则;

  2. 默认包过滤是没有状态的,即每个进出的数据包均视为一个独立的数据包。

  3. 支持扩展模块,通过扩展模块可以实现许多高级的功能 ,常用如下:

    • 支持基于状态的,
    • 连续ip
    • 一条命令匹配多端口
    • 连接数
    • 速率限制
    • 基于时间的规则
    • 应用层数据过滤 ( 只的简单的字符串匹配)
  4. iptables防火墙的功能上还增加了修改数据包的功能,修改数据包最广泛的应用应该是NAT了, iptables支持DNAT, SNAT , 如果同时使用DNAT, SNAT可以实现端口转发的功能(后面有实例说明)。

    iptables 的NAT是有状态的NAT ,只需要配置发起请求时的转换规则,而返回的数据会自动对应转换回来。

  5. 其它更高级的修改数据包的应用没研究过。

3.linux数据包处理流程

任何一个网络主机处理数据必须有以下流程:

​ 1.接收到数据:网卡接收到数据--> 路由判断数据是否是本机->1,本机:转给相应的上层应用 ->2, 目标不是本机, 再路由判断通过哪个网卡转发出去-->发出去

如果不允许数据转发,数据目标不是本机则直接丢弃。

​ 2.本机上层应用要发送数据出去: 应用数据转给内核--> 路由判断从哪个网口发送出去-->发出去

3.1 linux 防火墙将以上流程,固定区分为5个流程节点

  1. prerouting: 网卡收到数据
  2. input : 转发数据给本机上层应用
  3. forward: 目标非本机数据进入转发流程
  4. output: 本机应用发出的数据
  5. postrouting: 数据从网卡流出

3.2 数据流程

  1. 接收到目标为本机的数据: prerouting--> input
  2. 接收到目标不是本机的数据 ,prerouting--> forward --> postrouting
  3. 本机发出的数据:output --> postrouting

4 linux防火墙的实现机制

实现原理:在不同数据流程节点挂勾子函数,过滤数据, 符合的放回数据包流中,不符合条件的数据包从流程移除。

4.1 iptables五链

iptables将数据转发的5个流程节点勾子依次对应为5个链,全部为大写字母:

  1. PREROUTING
  2. INPUT
  3. FORWARD
  4. OUTPUT
  5. POSTROUTING

4.2 iptables四表

iptables将功能分为4类,即为iptables四表 :

实际有5个表,而不是我们常说的4表,还有一个表是security,本文不讨论这个表。

  1. filter : 包过滤防火墙
  2. nat : 地址和端口转换
  3. mangle : 数据包修改
  4. raw : 不带连接状态的nat

4.3 iptables 4表5链的关系

不同的表可以应用到不同的链上,

  1. filter: INPUT 、FORWARD 、OUTPUT

    • 过滤目标或本地为源的数据:接收-INPUT 、发出-OUTPUT

    • 过滤经本机转发的数据: FORWARD

  2. nat : PREROUTING 、INPUT 、OUTPUT 、 POSTROUTING

    • 修改本机上层应用发出去的数据: OUTPUT

    2.1 SNAT: INPUT、 POSTROUTING

    必须先路由, 所以不能在PREROUTING 做,在从本机发出前的最后一步再修改源IP为本机出接口IP,如果在路由前即刚接收到数据就修改源端口为出接口的IP是不合理的:

    1. 主机自己出接口IP的数据,从另一个网口接收到,网络环路才会出现这种情况;
    2. 源IP变为出接口的IP,之后的处理流程看不到真实的源端口IP, 防火墙策略无法设置;
    3. 之后的流程,比如forward 看到源端口是自身的接口 ,按照内核数据转发流程,本机应用发出的数据不应该进入forward流程。

    2.2 DNAT: OUTPUT 、 PREROUTING

    必须在路由前做DNAT, 这个好理解,只有DNAT修改数据报为真实的目标IP ,后面的路由才能正确选择,因为源IP端口没有修改,也不会影响之后流程处理。

    2.3 总结: 一般 SNAT在POSTROUTING做,SNAT在PREROUTING 做 , OUTPUT是本机发出的数据,没怎么见过需要用到NAT的场景。

    2.4 同时进行SNAT和DNAT

  3. mangle : 5链均适用, 没用过,不讨论

  4. raw :PREROUTING 、 OUTPUT,没用过,不讨论

4.4 表的优先级

同一链上,如果有多个表的配置规则,优先处理次序依次为raw --> mangle --> nat --> filter

5. iptables 命令

iptables 【-t 表名 】 操作 链名 【规则编号】 匹配规则 -j 处理动作

5.1 表 名

可选,不配置默认是 filter,

  • filter
  • nat
  • mangle
  • raw

5.2 操作

  • -A 链中末尾添加规则
  • -I 链名【规则编号】 如果没有规则编号,插入到第一条的位置,有规则编号,插入到指定编号位置,原编号及之后的规则依次下移
  • -R 链名 规则编号 必须输入规则编号,替换该编号的规则
  • -D 链名 规则编号 必须输入规则编号,删除该编号的规则

5.3 链名

不同表只能使用允许的链名

  1. PREROUTING
  2. INPUT
  3. FORWARD
  4. OUTPUT
  5. POSTROUTING

5.4 匹配条件

iptables命令最复杂的部分就在匹配条件这部分

一级条件参数形式 -option , 一级参数可能包含二级参数, 二级参数必须紧跟在主参数后写, 形式为 --option 两个 “--”

  1. TCP/IP匹配条件,IP 和端口号

    • -s 源IP IP可以是单个IP , 也加掩码 配置网段 如192.168.1.1/24, 但不能是连续ip, 如 192.168.1.1-192.168.1.20 (连续ip需要扩展模块)

    • -d 目标IP IP可以是单个IP , 也加掩码 配置网段 如192.168.1.1/24, 但不能是连续ip, 如 192.168.1.1-192.168.1.20

  2. -i 网卡名 数据进入的网卡

  3. -0 网卡名 数据流出的网卡

  4. -p [!]协议名 tcp 、udp、icmp 等等, 指定协议名后才能进一步指定端口号,其实-p 会自动加载相应协议的扩展模块,指定端口号是扩展模块的功能。

    • --dport 源端口号 [!]port[:port] ,--source-port 的简写,可以是端口范围

    • --sport 目标端口号 port[:port] --destination-port的简写, 可以是端口范围

    • --tcp-flags [!] mask comp

    • mask comp 例 SYN,ACK,FIN,RST SYN 匹配 SYN标志必须为1, ACK,FIN,RST必须为0, 其它标志不检查的数据包。

  5. -m 扩展模块

    1. state 基于状态的匹配规则, 与特定的协议没有关系,可以是TCP, UDP , 状态也不是指TCP协议连接状态。

      **对于TCP来说,第一个连接请求SYN包状态为 NEW , 之后的全部为 ESTABLISHED 。 这个简单的规则是非常有用的,用于区分连接发起的方向,是从内到外还是从外到内,而其它的匹配规则都无法识别连接的发起方向 **

      这个模块我认为是最有用的,关于内核如何跟踪、标识各个协议的链接状态,这个地址里有详细的介绍:https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html

      • --state 状态
        • NEW 新发起的连接请求,第一次讲求的数据报为NEW状态
        • ESTABLISHED 同一连接第一次请求之后的数据报均是该状态
        • RELATED 第一请求,但是该请求是由已建立的其它连接发起的,典型应用 FTP的数据传输,数据传输连接是由已建立的FTP控制连接发起的新连接,使用这个需要加载
        • INVALID 无效数据包,数据包不合法
    2. connlimit 连接数据限制,可以限制匹配规则的连接数量,比如限制SSH连接数据只能为3

      • --connlimit-upto n 连接数小于等于n
      • --connlimit-above n 连接数大于等于n
    3. multiport 端口使用集合指定 ,最多15个,

      • --sports port,port,port 或者 port:port 连续范围的port
      • --dports port,port,port 或者 port:port 连续范围的port
    4. iprange 指定ip地址范围

      • --src-range ip1-ip2
      • --dst-range ip1-ip2
    5. time 时间匹配

      • --timestart 开始日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和时间中间有个大写T,默认 1970-01-01T00:00:00
      • --timestop 结束日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和时间中间有个大写T,默认 2038-01-19T04:17:07
      • --datestart 结束时间 hh:mm:ss 例 11:30:00, 默认00:00:00
      • --datestop 结束时间 hh:mm:ss 例 11:30:00, 默认23:59:59
      • --monthdays 日期 1-31, 可以是集合,如 1,2,5,9
      • --weekdays 星期,1-7 , 可以是集合,如 1,3,5 1是星期一
    6. limit 速率匹配 ,

      使用令牌桶的算法,每个要转发的数据包要获取一个令牌才能转发,没有获取令牌的包,不匹配该规则,会转由下一条匹配,如果限速,紧跟后面要有一条规则丢弃数据。

      • --limit rate n[/second|/minute/hour/day] 速率限制 , 单位时间允许生成的令牌数据,也即允许转发的数据报数量, 注意: 不是带宽,不是带宽,当然通过限制包的数据也会间接限制了带宽速率,包大小*包数=带宽数。 默认3/hour
      • --limit-burst n 初始令牌数据, 即初始允许不受限制发送的数据量,初始令牌用完,后面要等--limit 指定的单位时间生成的新令牌填充。
    7. string 匹配应用层数据中的字符串, 只是简单以字符串形式匹配应用层数据,不会识别应用协议,如果是加密的也不会解密,只能是应该层协议没有加密时有用,比如http

      --string pattern

5.5 处理动作 -j

​ 处理动作全部用大写字母

5.5.1 filter表动作

  • ACCEPT 允许
  • DROP 直接丢弃
  • REJECT 拒绝 ,丢弃同时返回ICMP消息
  • LOG 日志记录 , 不会终止规则匹配,也就是说该动作只记录日志,至于数据包是否被转发,会继续匹配后续规则

5.5.2 NAT 表动作

  • SNAT 源地址转换

    • --to-source [ipaddr[-ipaddr]][:port[-port]][:port][-port] 可以指定端口范围,如果不指定,默认尽可能不变更端口,但如果端口已经被其它链接占用,会选用另一个端口替换,默认的端口转换遵守以下规则:

      • 1 . 512以内的端口,会转换成512以内的端口,保证不会大于512
      • 2 . 512-1023以内的端口,转换为512-1024 ,保证不会大于1024
      • 3 . 1024以上的端口,转换为1024以上的端口

      TCP/UDP标准将端口分为了0-511, 512-1024,1024以上这三个段,以上规则与之对应,不会出现源端口占用标准服务端口的情况:

      比如,访问外部http服务,把源端口转换成了21 , 占用了FTP的端口,导致端口混乱(虽然技术上说也能通)

  • DNAT 目标地址转换

    • --to-destination [ipaddr[-ipaddr]][:port[-port] 可以指定端口范围,如果不指定,不变更端口,如果不指定IP, IP不会变更
    • --random 端口转换会随机进行

​ Later Kernels (>= 2.6.11-rc1) 不再支持IP范围内的轮训转换,这个功能常做负载均衡用,也就是说centos7 开始不支持这一功能了, 不知道什么原因。

5.6 保存,恢复iptables配置

默认iptables配置规则只能当前生效,重启就没有了,需要用命令把规则放保存到文件,然后设置开机启动脚本加载配置文件

  • 保存 iptables-save > 文件名.rules
  • 恢复 iptables-restore <文件名.rules

5.7 iptables 命令实例

  1. 查看当前规则

    • -vL 详细信息,可以-vvL 更详细的信息
    • --line-number 显示规则编号
    [root@localhost ~]# iptables -vL --line-number
    Chain INPUT (policy ACCEPT 9639 packets, 806K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain FORWARD (policy ACCEPT 5388 packets, 2808K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 8262 packets, 1684K bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    [root@localhost ~]# 
    
    
    • 查看nat表 , 没有指定-t 默认filter表

      [root@localhost ~]# iptables -t nat  -vL --line-number
      Chain PREROUTING (policy ACCEPT 1281 packets, 105K bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      1        6   312 DNAT       tcp  --  any    any     anywhere             localhost.localdomain  tcp dpt:rtsps to:192.168.31.12:22
      
      Chain INPUT (policy ACCEPT 629 packets, 56218 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      
      Chain OUTPUT (policy ACCEPT 296 packets, 22480 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      
      Chain POSTROUTING (policy ACCEPT 296 packets, 22480 bytes)
      num   pkts bytes target     prot opt in     out     source               destination         
      1        1    52 SNAT       tcp  --  any    any     10.100.90.200        192.168.31.12        tcp dpt:ssh to:192.168.31.1:1023
      2      686 50843 SNAT       all  --  any    any     192.168.31.0/24      anywhere             to:10.100.93.202
      
      
  2. 清空规则

    • -F 清空规则
    [root@localhost ~]# iptables -t nat -F
    [root@localhost ~]# iptables -t nat  -vL --line-number
    Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    
    Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    [root@localhost ~]# 
    
    
  3. 开放本地端口80

    没有用 -A 是因为表中已有其它规则,一般最后一条是默认规则,实际中往往是插入到第一条比较常见

    • 插入到第2条

      iptables -t filter -I INPUT  1  -p tcp --dport 80 -j ACCEPT
      
    • 插入到第2条

      iptables -t filter -I INPUT  2 -p tcp --dport 80 -j ACCEPT
      
    • 替换第2条

      iptables -t filter -R INPUT  2 -p tcp --dport 80 -j ACCEPT
      
    • 只允许指定源IP访问

      iptables -t filter -R INPUT  2 -s 192.168.1.1 -p tcp --dport 80 -j ACCEPT
      
  4. 通过状态匹配防火墙

    • 禁止本机主动发起的出站连接 (服务器上可以这么设置,因为服务器是让别人访问自身 ,而自己本身不需要发起对外的连接,可以防止反弹木马)

      iptables -t filter -I OUTPUT  -m multiport -m state --state NEW -j DROP
      
    • 允许(非本机主动发起的)外部主机主动发起的对本机的连接

      iptables -t filter -I OUTPUT  -m multiport -m state --state ESTABLISHED,RELATED -j DROP
      
  5. SNAT 代理上网, 允许源地址192.168.1.0/24 经本机上网 10.100.93.202为连通公网的IP

    iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 10.100.93.202
    
  6. DNAT 将目标为本机IP 10.100.93.202 ,目标端口为 80 的数据转发到后端真实服务器 192.168.1.10的8000端口去

    iptables -t nat -I PREROUTING -d 192.168.1.0/24 -p tcp  --dport 80 -j DNAT --to-destination 192.168.1.0:8000
    
  7. 接合 SNAT和DNAT实现端口转发

SNAT在数据发出时转换IP为本机出接口,DNAT在接收到数据时转换目标IP为后端真实服务器IP ,组合这两个特性,可以实现端口转发的功能。

假如有如下场景:

在外网的用户能访问到防火墙外网IP 10.100.0.20

防火墙内网IP和内网服务器可以互通,同时内网服务器与外网隔离,不能通信

用户要想直接访问内网服务器的一个端口。

解决方法:

  1. 此场景不能只用DNAT, 因为内网服务器与外网不通,返回给user的数据是无法出内网的。

  2. user只能与防火墙能,数据包的源地址必须是防火墙的,所以还需要SNAT, 在从防火墙内网口发出时转换源地址为192.168.0.20 , 内网服务器返回数据,自然目标地址也就是192.168.0.20。

  3. iptables nat是有链接状态的,返回的数据会自动反向转换,返回的数据经由以下过程:

  4. 防火墙内网口192.168.0.20 收到数据时,返向转换目标IP为真实的USER , 经路由后,由公网口

  5. 10.100.0.20发出时,反向转换源端口为防火墙自身端口 10.100.0.20.

  6. 通信完成。

此过程即为端口转发,当然有很多开源软件可以实现端口转发,但linux防火墙全部是在内核完成这些操作的,而使用其它软件自然数据是要经过用户空间,而且需要在公网端口建立tcp/udp监听才可以。

​ 配置:

​ 内网服务器端口22, 防火墙用端口 13322转发:

# DNAT
iptables -t nat -I PREROUTING -d 10.100.0.20 -p tcp  --dport 13222 -j DNAT --to-destination 192.168.0.10:22
# SNAT
iptables -t nat -I POSTROUTING -d 192.168.0.10 --dport 22  -j SNAT --to-source 192.168.0.20

6 iptables防火墙配置最佳实践

  1. 防火墙建议用白名单机制,即默认禁止所有,只明确放行需要放行的流量,

    • 不推荐 使用iptables 的 -P DROP 操作设置为默认禁止,
    • 推荐在链的最后一条规则设置为禁止所有

    原因:使用-P 设置为默认禁止,那么调试规则时不小心清空了防火墙,自己岂不是被关在了门外, 排查连接问题时,有时需要临时清空规则,放行所有流量,来判断是否因为防火墙阻止了连接。

  2. 被流量匹配到的频率和可能性越大,规则越要往前面放,这样能提高效率,防火墙的机制是从上向下顺序匹配,配置到一条规则时,不再继续向下匹配(此处说的是常规流量处理动作,如ACCEPT, DROP, REJECT, SNAT,DNAT, 像LOG还是会继续向下匹配的)

  3. 建议使用扩展模块state设置有状态的防火墙,安全性更高(因为能认识是谁主动发起的连接),配置规则更简化。

    • 默认允许所有ESTABLISHEDRELATED、状态连接,
    • 禁止所有INVALID 无效的数据包
    • 通过状态NEW 控制数据发起的方向和IP,端口等。
posted @ 2020-09-08 16:39  wyf368  阅读(408)  评论(0编辑  收藏  举报