datetime:2024-04-23 16:49:00
author:nzb

Software Defined Networking

iptables

一、简介

iptables其实只是一个简称,其真正代表的是netfilter/iptables这个IP数据包过滤系统。为了简便,本文也将整套系统用iptables简称。 iptables是3.5版本的Linux内核集成的IP数据包过滤系统。当系统接入网络时,该系统有利于在Linux系统上更好地控制IP信息包和防火墙配置。此外,iptables还可以进行NAT规则的管理。 上面有提到netfilter/iptables这个组合,这个组合中:

  • netfilter位于内核空间,是内核的一部分,由一些数据包过滤表组成,这些表包含内核用来控制数据包过滤处理的规则集;而netfilter又是由内核中若干hook组成的, 程序在执行到内核hook 处时便会执行数据包过滤的相关逻辑。
  • iptables位于用户空间,是一种工具。该工具可以很便捷地对netfilter所维护的表数据进行修改。从而可以很便捷地控制数据包的过滤规则。

二、相关概念

2.1 包过滤防火墙

包过滤防火墙在网络层截取网络数据包的包头(header),针对数据包的包头,根据事先定义好的防火墙过滤规则进行对比,根据对比结果,再执行不同的动作。 包过滤防火墙一般工作在网络层,所以也称为“网络防火墙”,通过检查数据流中每一个数据包的源ip地址,目标ip地址,源端口,目标端口,协议类型(tcp,udp,icmp等),状态等信息来判断是否符合规则。

2.2 NAT

NAT(Network Address Translation) 网络地址转换,常用于局域网主机想与互联网服务通信时做地址转换,因为公网IP有限,且局域网主机访问公网必须要使用公网IP才可以访问到,因此使用NAT方法对地址做转换是一个很高效的方法。 根据NAT使用场景不同可以将NAT分为SNAT(Source Network Address Translation)DNAT(Destination Network Address Translation)

  • SNAT:用于局域网服务访问公网服务的场景。即将局域网发出的请求的原地址转换成NAT主机所拥有的公网IP地址,从而与公网服务进行通信;
  • DNAT:用于公网请求访问局域网服务的场景。即将从公网接收到的请求的目的地址通过NAT规则所配置的局域网网段进行目标服务器局域网地址的转换,从而与局域网内服务通信。

举个例子,本地Web服务器A地址为192.168.1.2,NAT主机地址为192.168.1.1,公网地址为1.1.1.1;另一个局域网主机B地址为172.16.1.2,NAT主机地址为172.16.1.1 ,公网地址为1.1.1.2。 此时B想要访问A的Web服务,B对应的NAT主机会将B发出的请求的源地址转换成其公网地址1.1.1.2从而与A对应的NAT主机进行通信,这里就是SNAT。 而A对应的NAT主机收到该请求后会将该请求的目的地址转换成Web服务器A在局域网内的地址,即192.168.1.2,从而与Web服务器A进行通信,这里就是DNAT

2.3 Netfilter Hooks

在上面的介绍中我们了解到,Netfilter其实是内核中若干个Hook点组成的。数据包经过内核协议栈处理程序时,处理程序会触发内核模块注册在相关Hook点上的数据包处理函数。 至于处理程序会触发哪个Hook 函数,取决于当前数据包的方向(ingress/egress)、数据包的目的地址、数据包在上一个Hook点的状态等等。内核中有关数据过滤的Hook点有如下几个:

  • NF_IP_PRE_ROUTING:接收到的数据包进行协议栈后立即触发此Hook,在进行任何路由判断之前;
  • NF_IP_LOCAL_IN:接收到的数据包经过了路由判断,如果目的地址是本机,将触发此Hook
  • NF_IP_FORWARD:接收到的数据包经过了路由判断,如果目的地址是其他机器,将触发此Hook
  • NF_IP_LOCAL_OUT:本机产生的准备发送的数据包,在进入协议栈之前立即执行该Hook
  • NF_IP_POST_ROUTING:本机产生的准备发送的或者转发的数据包,在经过路由判断之后,将执行该Hook

Netfilter Hook函数工作位置

内核处理模块在往这些Hook上注册处理函数时,必须要提供优先级,以便Hook触发时能按照优先级高低调用处理函数。 这就可以保证多个内核模块(或者同一内核模块的多个实例)可以在同一个Hook 点进行处理函数的注册,并且有确定的调用顺序。内核模块会被依次调用, 并且处理完成后返回一个结果给netfilter框架, 告诉某个数据包应该做什么操作。

2.4 表(tables)、链(chains)、规则(rules)

iptables通过表(tables)、链(chains)和规则(rules)来管理数据包处理函数,结合对netfilter的了解可知,iptables会将这些数据包处理函数注册到内核提供的五个Hook 点上。三者相关定义如下:

  • 表(tables):表将处理同一类型的数据包规则聚合在一起。内核中内置有4张表,分别是rawmanglenatfilter。每一张表都只包含同一类型的数据包规则,比如nat表只包含与网络地址转换相关的规则。
  • 链(chains):每一张表包含若干链,其规定了相关规则在什么时候执行。内核中内置有5条链,分别对应netfilter提供的5个Hook点。链能够让管理员在数据包传输过程中的某一个点通过相关规则控制数据包的走向。
  • 规则(rules):规则存在于中,每一条包含若干规则。当被调用时,数据包处理函数将按照顺序依次匹配对应链中的所有规则。每条规则都由匹配部分+动作部分 组成,如果数据包满足匹配规则,则会执行相关动作对数据包进行处理。

总的来说,规则是最终对数据包进行处理的部分,而表和链则是提供规则在协议栈被触发的前后顺序。三者关系可以用下面的图来表示:

2.5 规则优先级

通过上面几节的介绍,我们应该了解到:数据包在进入协议栈后,触发Hook点注册的相关处理函数实际上对应的是表、链、规则中的链。也就是说, 某一规则的触发优先级首先取决于chain所在的位置。其次通过包含了该chain 类型的table中所对应的实际的chain下的规则进行规则匹配和动作执行。在这段过程中,需要注意:

  • table有优先级:由高到低排列为:raw -> mangle -> nat -> filter;
  • 当有多个table包含同一类型的chain时,所有的table都会按照上面table优先级被遍历,执行table中实际的chain下的规则。

尝试了解一条规则被执行的条件和顺序,这对于后面理解netfilter在协议栈中处理数据包的全过程有很大的帮助,一通百通。

三、表

提到iptables,常常会提到三表五链、四表五链等的词汇。这些词汇中提到的“三表”,“四表”等其实指的就是Linux内核中内置的常见表。Linux内核内置的表其实有五个,分别为:

  • raw
  • mangle
  • nat(最常用)
  • filter(最常用)
  • security

3.1 Raw Table

iptables提供一个有状态的防火墙,基于netfilter上建立了连接跟踪的特性,即connection tracking,简称conntrackiptables在处理数据包时都会依赖之前已经判断过的数据包。 例如一条NAT记录,在第一次处理过后就会被存储在conntrack的哈希表中,下次有相同的数据包,则复用处理结果。 raw表提供的功能很简单:提供且仅提供一个让数据包绕过连接跟踪的框架。

3.2 Mangle Table

mangle表提供修改数据包IP头部的功能,例如,修改数据包的TTL等。此外,mangle表中的规则还可以对数据包打一个仅在内核内有效的标记(mark),后续对于该数据包的处理可以用到这些标记。

3.3 Nat Table

nat表顾名思义是用来做网络地址转换的。当数据包进入协议栈后,nat表中的相关规则将决定是否修改以及如何修改数据包的源/目标地址,从而改变数据包被路由的行为。 nat 表通常用于将数据包路由到外部网络无法直接访问到的局域网络中。

应用场景:

  • 企业路由或者网关主机做SNAT,实现共享上网(通过POSTROUTING链)
  • 做内部网络和外部网络的IP地址一对一映射,常用于dmz区域(通过PREROUTING链)
  • 硬件防火墙映射IP到内部服务器;
  • 可以做单个端口的映射,直接将外部的80相关端口映射到内部Web服务器非80端口上。

3.4 Filter Table

filter表是iptables中最常用的表,用来判断一个数据包是否可以通过。在防火墙领域,filter表提供的功能通常被称为“过滤”包。这个表提供了防火墙的一些常见功能。 Filter表负责的主要是和主机自身相关的数据包处理手段,是真正负责主机防火墙功能的一张表。

应用场景:主机防火墙

3.5 Security Table

security表的作用是给数据包打上SELinux标记。SELinux以及可以解读SELinux安全上下文的系统在处理由security表做了标记的数据包时,行为会相应做出改变。

四、链

内核中内置的链有且仅有5条。不难发现,这与前面提到的NetFilter提供的5个Hook点的数量是一致的。没错,内核中内置的5条链正是对应5个Hook点。即:

  • PREROUTING: 由 NF_IP_PRE_ROUTING hook 触发;
  • INPUT: 由 NF_IP_LOCAL_IN hook 触发;
  • FORWARD: 由 NF_IP_FORWARD hook 触发;
  • OUTPUT: 由 NF_IP_LOCAL_OUT hook 触发;
  • POSTROUTING: 由 NF_IP_POST_ROUTING hook 触发。

前面也提到过,链是位于表中的,内核内置表与内置链之间的包含关系如下表所示:

Tables PREROUTING INPUT FORWARD OUTPUT POSTROUTING
raw
mangle
nat
filter
security

这里我们对最常用的两个表:filternat进行相关链的说明,来看看某条链在某个表中起到什么作用。

4.1 Filter Table

filter表中有三条链:inputforwardoutput

  • input:用来过滤进入主机的数据包;
  • forward:负责转发流经主机的数据包,起到转发的作用,和NAT关系很大。想要主机支持转发需要设置相关内核参数:
net.ipv4.ip_forward=1
  • output:用来处理从主机发出去的数据包。

4.2 Nat Table

nat表中有三条链:preroutingpostroutingoutput

  • prerouting:在数据包到达netfilter系统时,在进行路由判断之前执行该链上的规则,作用是改变数据包的目的地址、目的端口等,起到DNAT的作用;
  • postrouting:数据包发出时,当数据包经过了路由判断后执行该链上的规则,作用是改变数据包的源地址、源端口等,起到SNAT的作用;
  • output:用来处理从主机发出去的数据包。

五、规则

规则是最终影响数据包的地方,一条有效的规则必须由匹配规则+动作目标组成:

  • 匹配规则:提供了需要执行对应动作的目标匹配机制。通常可以匹配协议类型、目的地址、源地址、目的端口、源端口、目的网段、源网段、接收数据包的网卡、发送数据包的网卡、协议头、连接状态等。
  • 动作目标:又称为Target。是数据包满足匹配规则时触发的相应的动作。Target分为两种类型:终止目标和非终止目标。

5.1 终止目标

Linux内核提供如下的终止目标动作:

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

5.2 特殊的非终止目标 —— Jumping Target

我们知道,Linux内核内置的链只有5条,且这5条链是netfilter hooks触发的唯一方式。那如果我想在不影响其他链的情况下使用自己定义的链,该如何操作呢? 这时就可以在内置链上配置一个Jumping Target 。实际上这里指定的就是我自定义的链的名字。例如下面的配置:

[root@localhost ~]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
KUBE-FIREWALL  all  --  anywhere             anywhere

Chain KUBE-FIREWALL (2 references)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere             /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000

上面的配置中,INPUT链的target为一条自定义的名为KUBE-FIREWALL的链,这样,从INPUT入口进入的数据包将会沿着链到达KUBE-FIREWALL链,然后将所有带有0x8000/0x8000 标记的包丢弃。

六、数据包处理流程图

先通过一个简单的图示来了解各个表和链在数据包处理流程上起作用的位置和效果。如下图所示,将最常用的两张表filternat考虑到数据包过滤流程上。

6.1 数据流入

  • 当数据包流入网卡进入netfliter系统中时,首先对数据包进行DNAT,将公网地址转换成局域网地址;
  • 进行路由判断;
  • 如果目的地址为本机地址,则进行包过滤;
  • 如果目的地址不为本机地址,则准备进行包转发,经过filter表中forward链的规则匹配后,如果允许对目的地址进行转发,则进行包转发;
  • 通过Nat表中PostRouting链的规则查看当前数据包的转发是否要做SNAT,处理完成后发出数据包。 值得注意的是,当数据包流入后, 经过路由选择发现不是发给Local的包,则会通过FORWARD 链直接到达POSTROUTING链,而不会再走OUTPUT链。

6.2 数据流出

  • 当数据包从本机准备发出时,会先经过Nat表的output链进行规则检查;
  • 随后,会经过Filter表的output链进行规则检查;
  • 最后根据Nat表中PostRouting链的规则查看当前数据包的发出是否要做SNAT,处理完成后发出数据包。

6.3 完整图示

七、常用iptables命令使用

iptables命令的大致语法如下,详细使用参见manual手册

iptables [-t TABLE] [COMMAND] [OPTIONS]

7.1 基础篇

  • 查看iptables命令使用方式

    # 查看iptables使用手册
    man iptables
    
    # 查看iptables详细参数使用手册
    man iptables-extensions
    
  • 查看Filter表中所有链以及规则

    iptables -nL --line-numbers
    
    • -n:将主机信息(IP地址,端口等)以数字的形式打印出来。默认会以hostname等方式打印出来;
    • -L:显示规则链中已有的条目;
    • --line-numbers:显示条目序号。
  • 只看INPUT表中所有链以及规则

    iptables -nL INPUT
    
  • filter表的INPUT链中新增拒绝所有来自192.168.1.1的数据包并指定其序号为2

    iptables -I INPUT 2 -s 192.168.1.1/32 -j DROP
    
    • -I:表示insert,即向链中插入一条规则,INPUT为链名,2为规则的序号;
    • -s: 代表匹配源地址;
    • -j:规则目标(Target),DROP代表丢弃所有包。
  • 删除filter表的INPUT链中拒绝所有来自192.168.1.1的数据包的规则

    iptables -D INPUT -s 192.168.1.1/32
    
    • -D:表示delete,即从链中删除相关规则。
  • 删除filter表的INPUT链中序号为2的规则

    iptables -D INPUT 2
    
    • -D:表示delete,即从链中删除相关规则,链名后面可以接数字,表示删除某个序号。序号怎么获取可以在查看链规则时使用--line-numbers选项。
  • filter表的INPUT链中追加一条拒绝所有发送到192.168.1.1的数据包

    iptables -A INPUT -d 192.168.1.1/32 -j DROP
    
    • -A:表示append,即向链末尾追加一条规则;
    • -d:代表匹配目的地址。
  • nat表的PREROUTING链中新增一条序号为1LOG规则

    # LOG目标通常放在对数据包过滤和处理前,可以用来分析数据包流向。
    iptables -I PREROUTING -t nat -j LOG --log-prefix "[NAT_PREROUTING_LOG]"
    
    • -I:表示insert,即向链中插入一条规则,PREROUTING为链名,没有指定序号默认为1,即顶部插入;
    • -j:规则目标(Target),LOG代表获取数据包并打印日志;
    • --log-prefix:日志信息的前缀,只能在-j LOG的情况下使用。可以通过man iptables-extensions查看其他针对某个Target的配置使用方式。
  • 保存当前系统iptables规则

    iptables-save > $HOME/iptables-save.bak
    
  • filter表的INPUT链上对所有经过路由选择后判定为发给本机的数据包做跳转至KUBE-NODE-PORT链的操作

    iptables -I INPUT -m addrtype --dst-type LOCAL -j KUBE-NODE-PORT
    
    • -m:表示match,这里涉及到iptables 扩展的用法,即包匹配扩展模块extended packet matching modules)。 这里使用的addrtype 意思是通过选项指定的地址类型进行匹配,结合--dst-type不难得知:当数据包的目的地址类型是本机时,则该包匹配该规则。

7.2 实战篇

  • 禁止源地址192.168.1.1访问服务器的22,53,80端口:

    iptables -I INPUT -s 192.168.1.1/32 -p tcp --dport 22,53,80 -j DROP
    
    • -ssource address,匹配源地址
    • -pprotocol,匹配协议
    • --dportdestination port,匹配目的端口。逗号分隔多个端口。
  • 对于访问量比较大的服务器,例如192.168.1.1,可以通过raw表配置绕过连接跟踪:

    iptables -t raw -A PREROUTING -d 192.168.1.1/32 -p tcp --dport 80 -j NOTRACK
    
  • 将访问192.168.1.1:80的请求转到192.168.1.2:9000

    iptables -t nat -A PREROUTING -d 192.168.1.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.2:9000
    
  • 实现所有192.168.1.0/24的地址通过123.123.123.123公网地址访问公网

    iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 123.123.123.123
    
  • 拒绝一分钟内新建超过4次SSH连接的IP再次连接

    iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name SSH --rsource
    iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j DROP
    
  • 模拟丢包率:

# 模拟80端口10%的丢包率
iptables -A INPUT -p tcp --dport 80 -m statistic --mode random --probability 0.1 -j DROP

# 删除80端口10%的丢包率
iptables -D INPUT -p tcp --dport 80 -m statistic --mode random --probability 0.1 -j DROP

# 模拟50%的丢包率
iptables -I INPUT -p icmp -m statistic --mode random --probability 0.5 -j DROP

# 删除50%的丢包率
iptables -D INPUT -p icmp -m statistic --mode random --probability 0.5 -j DROP

# 模拟精确的33%丢包率:每3个包丢掉1个
iptables -I INPUT  -p icmp -m statistic --mode nth --every 3 --packet 0 -j DROP

# 删除精确的33%丢包率:每3个包丢掉1个
iptables -D INPUT  -p icmp -m statistic --mode nth --every 3 --packet 0 -j DROP

# 模拟精确的66%丢包率:每3个包丢掉2个,在每3个包丢1个的基础上再每2个包丢1个,实现每3个丢2个
iptables -I INPUT  -p icmp -m statistic --mode nth --every 3 --packet 0 -j DROP
iptables -I INPUT  -p icmp -m statistic --mode nth --every 2 --packet 0 -j DROP

# 删除精确的66%丢包率:每3个包丢掉2个,在每3个包丢1个的基础上再每2个包丢1个,实现每3个丢2个
iptables -D INPUT  -p icmp -m statistic --mode nth --every 3 --packet 0 -j DROP
iptables -D INPUT  -p icmp -m statistic --mode nth --every 2 --packet 0 -j DROP

results matching ""

    No results matching ""