Linux内核下包过滤框架——iptables&netfilter

iptables & netfilter

1、简介

netfilter/iptables(下文中简称为iptables)组成Linux内核下的包过滤防火墙,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。

iptabels其实不是真正的防火墙,netfilter才是防火墙真正的安全框架(framework),netfilter位于内核空间。iptables其实是一个命令行工具,位于用户空间,我们用这个工具操作真正的框架。

Netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有如下功能:

  • 网络地址转换(Network Address Translate)
  • 数据包内容修改
  • 数据包过滤的防火墙功能

2、iptables基础

iptatble是按规则来办事的,当数据包与规则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则。

netfilter才是真正的防火墙,它是内核的一部分,所以,如果我们想要防火墙能够达到”防火”的目的,则需要在内核中设置关卡,所有进出的报文都要通过这些关卡,经过检查后,符合放行条件的才能放行,符合阻拦条件的则需要被阻止,于是,就出现了input关卡和output关卡,而这些关卡在iptables中不被称为”关卡”,而被称为”链”。

image-20210628104032315

iptatbles中不仅有inputoutput关卡,还有preroutingforwardpostrouting,当我们启用了防火墙功能时,报文需要经过如下关卡,也就是说,根据实际情况的不同,报文经过”链”可能不同。如果报文需要转发,那么报文则不会经过input链发往用户空间,而是直接在内核空间中经过forward链和postrouting链转发出去的。

image-20210628104401907

2.1、链

防火墙的作用就在于对经过的报文匹配”规则”,然后执行对应的”动作”,所以,当报文经过这些关卡的时候,则必须匹配这个关卡上的规则,但是,这个关卡上可能不止有一条规则,而是有很多条规则,当我们把这些规则串到一个链条上的时候,就形成了”链”。

这样来说,把他们称为”链”更为合适,每个经过这个”关卡”的报文,都要将这条”链”上的所有规则匹配一遍,如果有符合条件的规则,则执行规则对应的动作。

image-20210628104747790

2.2、表

具有相同功能规则的集合叫做“表”,iptables定义来4种表,每种表对应了不同的功能,即我们定义的规则都逃脱不了这4种功能的范围。

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

需要注意的是,某些“链”注定 不会包含“某类规则”,表链的对应关系如下:

iptables 表和链的对应关系- 御用闲人- 博客园

综合上面描述,数据包经过防火墙的流程总结为下:

image-20210628112502976

如果想要linux主机支持转发,则需要开启内核的IP_FORWARD功能,可以临时修改对应文件/proc/sys/net/ipv4/ip_forward。

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

2.3、规则

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

匹配条件分为

基本匹配条件:源IP、目的IP等

扩展匹配条件:源端口、目的端口等

处理动作(在iptatbles中被称为target):

  • ACCEPT:允许数据包通过
  • DROP:丢弃数据包,不给任何回应信息
  • REJECT:拒绝数据包通过,必要时发送一个响应信息
  • SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题
  • MASOUERADE:SNAT的一种特殊形式,适用于动态的、临时会变的ip上
  • DNAT:目的地址转换
  • REDIRECT:在本机做端口映射
  • LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则。

3、使用

3.1、规则查询

#查看对应表所有规则,省略表名默认为filter表
iptables -t 表名 -L

#指定链的规则,-v:详细信息 -n:直接显示IP地址 --line-numbers:显示规则序号 -x:显示计数器的精确值 
iptables --line-numbers -t 表名 -nvxL 链名 

3.2、规则管理

添加规则

命令语法:iptables -t 表名 -A 链名 匹配条件 -j 动作
示例:iptables -t filter -A INPUT -s 192.168.1.146 -j DROP

-I:在对应链开头添加规则
-A:在末尾添加规则


规则是按照顺序执行的,添加时候可以指定规则序号,这样就可以在任意位置插入规则了.

命令语法:iptables -t 表名 -I 链名 规则序号 匹配条件 -j 动作
示例:iptables -t filter -I INPUT 5 -s 192.168.1.146 -j REJECT

---设置默认动作---
命令语法:iptables -t 表名 -P 链名 动作
示例:iptables -t filter -P FORWARD ACCEPT

删除规则

命令语法:iptables -t 表名 -D 链名 规则序号
示例:iptables -t filter -D INPUT 3

---按照具体匹配条件与动作删除规则--
命令语法:iptables -t 表名 -D 链名 匹配条件 -j 动作
示例:iptables -t filter -D INPUT -s 192.168.1.146 -j DROP
-F:清空对应链的规则,如果省略链名表示删除表中所有规则

修改规则

---规则原本的匹配条件不可省略!如果省略,源地址会变成0.0.0.0/0,此时如果是拒绝动作,那么ssh就断掉了---
命令语法:iptables -t 表名 -R 链名 规则序号 规则原本的匹配条件 -j 动作
示例:iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT

保存规则

---保存在/etc/sysconfig/iptables文件中
service iptables save 或
iptables-save > /etc/sysconfig/iptables

---从文件中重新载入规则
iptatbles-restore < /etc/sysconfig/iptables

3.3、基本匹配条件

当规则中同时存在多个匹配条件时,多个条件之间默认存在“与”的关系.

  • -s: 指定源ip,多个ip用逗号隔开,也可以指定一个网段

    iptables -t filter -I INPUT -s 192.168.1.111,192.168.1.118 -j DROP
    iptables -t filter -I INPUT -s 192.168.1.0/24 -j ACCEPT
    iptables -t filter -I INPUT ! -s 192.168.1.0/24 -j ACCEPT
    
  • -d: 匹配目标地址,用法和-s一样

  • -p: 匹配报文协议类型,可以匹配的协议类型tcp、udp、udplite、icmp、esp、ah、sctp等

  • -i: 匹配报文从哪个网卡接口流入本机,由于匹配条件只是用于匹配报文流入的网卡,所以在OUTPUT链与POSTROUTING链中不能使用此选项

  • -o: 匹配报文从哪个网卡接口流出本机

3.3、扩展匹配条件

  • tcp扩展模块

    常用的扩展匹配条件如下:

    -p tcp -m tcp –-sport 用于匹配tcp协议报文的源端口,可以使用冒号指定一个连续的端口范围

    -p tcp -m tcp –-dport 用于匹配tcp协议报文的目标端口,可以使用冒号指定一个连续的端口范围

    --tc-flages 用于匹配tcp头部字段标志位,第一部分为需要匹配哪些标志位,第二部分为哪些标志位为1

    iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
    iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
    

    --syn 相当于使用”–tcp-flags SYN,RST,ACK,FIN SYN

  • udp模块

    当使用扩展匹配条件时,如果未指定扩展模块,iptables会默认调用与”-p”对应的协议名称相同的模块,所以,当使用”-p udp”时,可以省略”-m udp”.udp只有sport和dport两个匹配条件

  • mutiport扩展模块

    常用的扩展匹配条件如下:

    -p tcp -m multiport –-sports 用于匹配报文的源端口,可以指定离散的多个端口号,端口之间用”逗号”隔开

    -p udp -m multiport –-dports 用于匹配报文的目标端口,可以指定离散的多个端口号,端口之间用”逗号”隔开

  • iprange模块

    包含的扩展匹配条件如下

    -m iprange –-src-range:指定连续的源地址范围,用-指定一个连续的范围

    -m iprange -–dst-range:指定连续的目标地址范围

  • string模块

    使用string扩展模块,可以指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件,常用扩展匹配条件如下

    –-algo:指定对应的匹配算法,可用算法为bm、kmp,此选项为必需选项。

    –-string:指定需要匹配的字符串

  • time模块

    常用扩展匹配条件如下

    –-timestart:用于指定时间范围的开始时间,不可取反

    –-timestop:用于指定时间范围的结束时间,不可取反

    –-weekdays:用于指定”星期几”,可取反

    –-monthdays:用于指定”几号”,可取反

    –-datestart:用于指定日期范围的开始日期,不可取反

    –-datestop:用于指定日期范围的结束时间,不可取反

    iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 6,7 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --monthdays 22,23 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 5 --monthdays 22,23,24,25,26,27,28 -j REJECT
    iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --datestart 2017-12-24 --datestop 2017-12-27 -j REJECT
    
  • connlimit模块

    使用connlimit扩展模块,可以限制每个IP地址同时链接到server端的链接数量,注意:我们不用指定IP,其默认就是针对”每个客户端IP”,即对单IP的并发连接数限制

    –-connlimit-above:单独使用此选项时,表示限制每个IP的链接数量。

    –-connlimit-mask:此选项不能单独使用,在使用–connlimit-above选项时,配合此选项,则可以针对”某类IP段内的一定数量的IP”进行连接数量的限制

    iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
    
  • limit模块

    如果我想要限制单位时间内流入的包的数量,就能用limit模块,我们可以以秒为单位进行限制,也可以以分钟、小时、天作为单位进行限制

    常用的扩展匹配条件如下

    –-limit-burst:类比”令牌桶”算法,此选项用于指定令牌桶中令牌的最大数量

    –-limit:类比”令牌桶”算法,此选项用于指定令牌桶中生成新令牌的频率,可用时间单位有second、minute 、hour、day。

    iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT
    
  • icmp模块

    –-icmp-type:匹配icmp报文的具体类型,可以使用type/code和description两种方式表示

    image-20210914165506130

  • state模块

    问题: 怎样判断这些报文是为了回应我们之前发出的报文,还是主动向我们发送的报文呢?

    state模块可以让iptables实现”连接追踪”机制,”连接”其中的报文可以分为5种状态,报文状态可以为NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED.

    --state

3.4、黑白名单机制

前文中一直在强调一个概念:报文在经过iptables的链时,会匹配链中的规则,遇到匹配的规则时,就执行对应的动作,如果链中的规则都无法匹配到当前报文,则使用链的默认策略(默认动作),链的默认策略通常设置为ACCEPT或者DROP。

所以,当链的默认策略为ACCEPT时,链中的规则对应的动作应该为DROP或者REJECT,表示只有匹配到规则的报文才会被拒绝,没有被规则匹配到的报文都会被默认接受,这就是”黑名单”机制。

同理,当链的默认策略为DROP时,链中的规则对应的动作应该为ACCEPT,表示只有匹配到规则的报文才会被放行,没有被规则匹配到的报文都会被默认拒绝,这就是”白名单”机制。

在对应的链中没有设置任何规则时,这样使用默认策略为DROP是非常不明智的,因为管理员也会把自己拒之门外,即使对应的链中存在放行规则,当我们不小心使用”iptables -F”清空规则时,放行规则被删除,则所有数据包都无法进入,这个时候就相当于给管理员挖了个坑,所以,我们如果想要使用”白名单”的机制,最好将链的默认策略保持为”ACCEPT”,然后将”拒绝所有请求”这条规则放在链的尾部,将”放行规则”放在前面,这样做,既能实现”白名单”机制,又能保证在规则被清空时,管理员还有机会连接到主机

iptables -P INPUT ACCEPT
iptabels -I INPUT -p tcp --dport 22 -j ACCEPT
iptabels -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j ACCEPT

3.5、自定义链

当默认链中的规则非常多时,不方便我们管理。

想象一下,如果INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,假如,我们突然想要修改针对httpd服务的相关规则,难道我们还要从头看一遍这200条规则,找出哪些规则是针对httpd的吗?这显然不合理。

但是需要注意的是,自定义链并不能直接使用,而是需要被默认链引用才能够使用.

--创建自定义链
iptables -t filter -N IN_WEB

--引用自定义链
iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB

--重命名自定义链
iptables -E IN_WEB WEB

--删除自定义链
删除自定义链需要满足两个条件
1、自定义链没有被引用
2、自定义链中没有任何规则

iptables -D INPUT 1
iptables -F WEB
iptables -X WEB

3.6、网络防火墙

防火墙从逻辑上讲,可以分为主机防火墙与网络防火墙。

主机防火墙:针对于单个主机进行防护。

网络防火墙:往往处于网络入口或边缘,针对于网络入口进行防护,服务于防火墙背后的本地局域网。

iptables都是作为主机防火墙的角色出现的,如果想要使用iptables充当网络防火墙,iptables所在的主机则需要处于网络入口处,网络防火墙主要职责就是“过滤并转发”,所以规则只能定义在FORWARD链中.

image-20210914192714657

上图中把C主机的网关指向B主机网卡1的IP,A主机网关设为B网卡2的地址.

A ping 10.1.0.1 是ping不通的,A主机通过路由表得知,发往10.1.0.0/16网段的报文的网关为B主机,当报文达到B主机时,B主机发现A的目标为10.1.0.1,而自己的IP是10.1.0.3,这时,B主机则需要将这个报文转发给10.1.0.1(也就是C主机),但是,Linux主机在默认情况下,并不会转发报文,如果想要让Linux主机能够转发报文,需要额外的设置,这就是为什么10.1.0.1没有回应的原因.

A ping 10.1.0.3可以ping通: 当报文到达B时,B主机发现自己既是192.168.1.146又是10.1.0.3,所以,B主机就直接回应了A主机,并没有将报文转发给谁,所以A主机得到了10.1.0.3的回应。

临时生效:把/proc/sys/net/ipv4/ip_forward文件内容设置为1表示支持转发报文.

永久生效:/etc/sysctl.conf添加net.ipv4.ip_forward=1

此时就可以ping通了

#如果想要iptables作为网络防火墙,iptables所在主机开启核心转发功能,以便能够转发报文。
#使用如下命令查看当前主机是否已经开启了核心转发,0表示为开启,1表示已开启
cat /proc/sys/net/ipv4/ip_forward
#使用如下两种方法均可临时开启核心转发,立即生效,但是重启网络配置后会失效。
方法一:echo 1 > /proc/sys/net/ipv4/ip_forward
方法二:sysctl -w net.ipv4.ip_forward=1
#使用如下方法开启核心转发功能,重启网络服务后永久生效。
配置/etc/sysctl.conf文件(centos7中配置/usr/lib/sysctl.d/00-system.conf文件),在配置文件中将 net.ipv4.ip_forward设置为1
 
#由于iptables此时的角色为"网络防火墙",所以需要在filter表中的FORWARD链中设置规则。
#可以使用"白名单机制",先添加一条默认拒绝的规则,然后再为需要放行的报文设置规则。
#配置规则时需要考虑"方向问题",针对请求报文与回应报文,考虑报文的源地址与目标地址,源端口与目标端口等。
#示例为允许网络内主机访问网络外主机的web服务与sshd服务。
iptables -A FORWARD -j REJECT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -d 10.1.0.0/16 -p tcp --sport 80 -j ACCEPT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -d 10.1.0.0/16 -p tcp --sport 22 -j ACCEPT
 
#可以使用state扩展模块,对上述规则进行优化,使用如下配置可以省略许多"回应报文放行规则"。
iptables -A FORWARD -j REJECT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -s 10.1.0.0/16 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

3.7、动作总结

网关配置和上面一样.

image-20210915145304608

  • SNAT(服务在外网,内网主动访问外网)

    #主机B
    iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 192.168.1.146
    

    此时内网主机ping A主机就能ping通, iptables会自动维护NAT表,并将响应报文的目标地址转换回来.

  • DNAT(服务在内网,外网主动访问内网)

    #主机B
    iptables -t nat -F
    iptables -t nat -I PREROUTING -d 192.168.1.146 -p tcp --dport 3389 -j DNAT --to-destination 10.1.0.6:3389
    iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 192.168.1.146
    

    表示报文目标地址为B公网IP,目标端口为3389的报文符合匹配条件,做DNAT转换映射到10.1.0.6:3389上.

    注:理论上只配置DNAT规则即可,但是如果在测试时无法正常DNAT,可以尝试配置对应的SNAT,此处按照配置SNAT的流程进行。

  • MASQUERADE

    MASQUERADE会动态的将源地址转换为可用的IP地址,其实与SNAT实现的功能完全一致,都是修改源地址,只不过SNAT需要指明将报文的源地址改为哪个IP,而MASQUERADE则不用指定明确的IP,会动态的将报文的源地址修改为指定网卡上可用的IP地址.

    iptables -t nat -I POSTROUTING -s 10.1.0.0/16 -o eth0 -j MASQUERADE
    

    表示通过外网网卡出去的报文在经过POSTROUTING链时,会自动将报文的源地址修改为外网网卡上可用的IP地址,这时,即使外网网卡中的公网IP地址发生了改变,也能够正常的、动态的将内部主机的报文的源IP映射为对应的公网IP,可以把MASQUERADE理解为动态的、自动化的SNAT,如果没有动态SNAT的需求,没有必要使用MASQUERADE,因为SNAT更加高效。

  • REDIRECT

    使用REDIRECT动作可以在本机上进行端口映射

    #将本机80端口映射到本机8080端口
    iptables -i nat -A PREROUTING -o tcp --dport 80 -j REDIRECT --to-ports 8080
    

4、iptables实现负载均衡

在Linux中使用iptables完成tcp的负载均衡有两种模式

  • 随机(random)

    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode random --probability 0.33 -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode random --probability 0.5 -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode random -j DNAT --to-destination 10.0.0.2:1234
    

    rules说明:
    第一条规则有0.33概率被命中

    第二条也为0.33,命中概率为(1-0.33)*0.5 = 0.33

    第三条为1-0.33-0.33约等于0.33

    假设有n个server,想要将流量平均分到n个server,概率为p=1/(n-i+1)。

    注意:因为iptables中,规则是按顺序匹配的,由上至下依次匹配,因此设计iptables规则时,要严格对规则进行排序。因此上述三条规则的顺序也不可以调换,不然就无法实现LB均分了。

  • 轮询(nth)

    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode nth --every 3 --packet 0 -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode nth --every 2 --packet 0 -j DNAT --to-destination 10.0.0.2:1234
    iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 80 -m statistic --mode nth -j DNAT --to-destination 10.0.0.2:1234
    

    轮询算法中有两个参数:

    --every:每n个包匹配一次规则

    --packet:从第p个包开始

5、总结

  1. 规则顺序很重要

    如果报文已经被前面的规则匹配到,IPTABLES则会对报文执行对应的动作,通常是ACCEPT或者REJECT,报文被放行或拒绝以后,即使后面的规则也能匹配到刚才放行或拒绝的报文,也没有机会再对报文执行相应的动作了(前面规则的动作为LOG时除外),所以,针对相同服务的规则,更严格的规则应该放在前面。

  2. 当规则中有多个匹配条件时,条件之间是“与”的关系

  3. 在不考虑1的情况下,应该将更容易被匹配的规则放在前面

    比如,你写了两条规则,一条针对sshd服务,一条针对web服务。假设,一天之内,有20000个请求访问web服务,有200个请求访问sshd服务,那么,应该将针对web服务的规则放在前面,针对sshd的规则放在后面,因为访问web服务的请求频率更高。如果将sshd的规则放在前面,当报文是访问web服务时,sshd的规则也要白白的验证一遍,由于访问web服务的频率更高,白白耗费的资源就更多。

  4. 当IPTABLES所在主机作为网络防火墙时,在配置规则时,应着重考虑方向性,双向都要考虑,从外到内,从内到外。

  5. 在配置IPTABLES白名单时,往往会将链的默认策略设置为ACCEPT,通过在链的最后设置REJECT规则实现白名单机制,而不是将链的默认策略设置为DROP,如果将链的默认策略设置为DROP,当链中的规则被清空时,管理员的请求也将会被DROP掉。

posted @ 2021-09-15 16:00  尹瑞星  阅读(2067)  评论(1编辑  收藏  举报