您现在的位置是:首页 >学无止境 >Linux 操作系统原理 — netfilter/iptables 流量处理框架网站首页学无止境

Linux 操作系统原理 — netfilter/iptables 流量处理框架

范桂飓 2024-06-26 14:23:36
简介Linux 操作系统原理 — netfilter/iptables 流量处理框架

目录

Netfilter 流量处理框架

Netfilter 自 1998 年开发,2000 年合并到 Kernel v2.4 版本,是 Kernel 提供的一个流量处理框架,用于实现对 IP 数据包的控制和过滤(Manipulation and Filtering)等功能,包括:

  • 无状态数据包过滤(IPv4、IPv6)。
  • 有状态的数据包过滤(IPv4、IPv6)。
  • 基于协议类型的连接跟踪(CT)。
  • NAT、NAPT(IPv4、IPv6)。
  • 灵活可扩展的基础架构。
  • 第三方扩展的 API,例如:被 iptables 调用。

在这里插入图片描述

Netfilter 的实现原理

在这里插入图片描述

Netfilter 在 Kernel 的 L3-subsystem 中设置多个 Hooks(钩子)点。通过在 IP 流量的必经之路上设置多个 Hooks 点,来实现对所有的 IP 数据包进行检测、过滤、拦截或其他处理,包括:

  • 通过:不对数据包进行任何修改,退出检测逻辑,继续后面正常的数据包处理流程。
  • 修改:例如进行 NAT 编辑,然后继续后面正常的数据包处理流程。
  • 丢弃:例如 iptables 安全策略和防火墙功能。

如下图所示,Netfilter 具有 5 个 Hooks 点,每个 Hook 点都注册了一些 Handler 处理函数,当有数据包经过 Hook 点时, 就会调用相应的 Handler。

#define NF_IP_PRE_ROUTING    0 /* After promisc drops, checksum checks. */
#define NF_IP_LOCAL_IN       1 /* If the packet is destined for this box. */
#define NF_IP_FORWARD        2 /* If the packet is destined for another interface. */
#define NF_IP_LOCAL_OUT      3 /* Packets coming from a local process. */
#define NF_IP_POST_ROUTING   4 /* Packets about to hit the wire. */
#define NF_IP_NUMHOOKS       5

在这里插入图片描述

5 个 Hooks 点分别对应下述 5 条 Chaim(链):

  1. PREROUTING:数据包进入路由表之前。
  2. INPUT:通过路由表后目的地为本机。
  3. FORWARD:通过路由表后,目的地不为本机。
  4. OUTPUT:由本机产生,向外发送。
  5. POSTROUTIONG:发送到网卡接口之前。

在这里插入图片描述

Hook Handler 对 IP 数据包进行判断或处理之后,需要返回一个判断结果,指导接下来要对这个包做什么。可能的结果有:

// include/uapi/linux/netfilter.h

#define NF_DROP   0  // 已丢弃这个包。
#define NF_ACCEPT 1  // 接受这个包,继续下一步处理。
#define NF_STOLEN 2  // 当前处理函数已经消费了这个包,后面的处理函数不用处理了。
#define NF_QUEUE  3  // 应当将包放到队列。
#define NF_REPEAT 4  // 当前处理函数应当被再次调用。

Netfilter 的工作原理

Netfilter 为实现数据包控制和过滤功能而设计了 3 个核心概念:

  1. 规则(Rules):用于定义 IP 数据包的识别和处理规则,每条 Rule 都包含了 “匹配" 和 “动作" 这 2 个元素。其中,动作包括有:修改或跳转。跳转可以用于处理接受该数据包、拒绝该数据包,也可以跳转到其他 Chain 中继续进行匹配,或者从当前 Chain 中返回到调用者 Chain。

  2. 链(Chains):每条 Chain 由多条 Rules 组成,这些 Rules 会用于与 IP 数据包进行逐一匹配。一旦匹配上,则执行 Rule 对应的动作。如果当 Chain 中的所有 Rules 都执行完后,但仍然没有跳转时,将根据该 Chain 的默认策略执行对应动作。如果 Chain 也没有默认动作,那么就会返回到调用者 Chain。

  3. 表(Tables):每张 Table 由多条 Chains 组成,是一种 Chains 和 Rules 的业务场景分类管理手段。不同的 Tables 通常会具有特定的应用场景,例如:filter table 用于进行数据包过滤,nat table 用于进行 NAT 操作等。

规则(Rules)

规则(Rules)是用户预定义的,例如:我们常说的防火墙规则。配置防火墙的主要工作就是添加、修改和删除这些规则。

每条 Rule 都由下列 2 个元素组成:

  1. 若干个匹配条件(Xmatch):与 IP 数据包进行匹配,具有以下匹配条件类型:

    • Interface(接口,e.g. eth0、eth1)
    • Protocol(协议类型,e.g. ICMP、TCP、UDP)
    • Source IP / Destination IP
    • Source Port / Destination Port
  2. 一个执行动作(Action):数据包匹配所有条件后所需要执行的动作。具有以下动作类型:

    • ACCEPT:运行通过。
    • DEOP:直接丢弃。
    • REJECT:拒绝通过。
    • SNAT:源地址转换。
    • DNAT:目标地址转换。
    • MASQUERADE:特殊的 SNAT,适用于动态变更的 IP。
    • LOG:记录日志信息。
    • QUEUE:将数据包移交到用户空间。
    • RETURN:防火墙停止执行当前链中的后续规则,并返回到调用链。
    • REDIRECT:端口重定向。
    • MARK:做防火墙标记。

链(Chains)

链(Chains)的本质是一个有序的 Rules 列表。在复杂的网络环境中,用户可以通过配置 Rules 在 Chain 中的顺序来灵活实现多种效果。

也因为 Chain 中 Rules 的次序非常关键,执行 Rules 时,会按照从上往下的顺序进行。所以越严格的 Rule,就越应该放在越靠前,而 Default Rule 则总是在最后生效。

此外,Netfilter 提供了 5 条内建的 Chains,用户也可以新建自定义的 Chains。

  1. INPUT(输入链):发往本机的数据包通过此链,并执行此链上关于 INPUT 的 Rules,例如:DDoS 攻击防御规则。
  2. OUTPUT(输出链):从本机发出的数据包通过此链,并执行此链上关于 OUTPUT 的 Rules。
  3. PORWARD(转发链):由本机转发的数据包通过此链,并执行此链上关于 PORWARD 的 Rules。例如:作为 IP 路由器。
  4. PREROUTING(路由前链):在处理 IP 路由规则前(Pre-Routing)通过此链,并执行此链上关于 Pre-Routing 的 Rules。例如:DNAT。
  5. POSTOUTING(路由后链):在处理 IP 路由规则后(Post-Routing)通过此链,并执行此链上关于 Post-Routing 的 Rules。例如:SNAT。

在这里插入图片描述

表(Tables)

表(Table)是面向应用场景的管理方式,每张表被赋予了不同的应用场景,所以也内含了不同的 Chains 和 Rules。

用户在实际使用 Netfilter 时,往往是通过 Table 作为操作入口,然后对 Chains 和 Rules 进行定义。

Netfilter 内建了以下五张表:

  1. filter 表(默认):提供数据包的过滤功能,例如:用于防火墙规则。
  2. nat 表:提供了 NAT、NAPT 功能,例如:用于网关路由器。
  3. mangle 表:提供了数据包修改功能,例如:更改 IP Header 的 TOS、DSCP、ECN 位。
  4. raw 表:用来提前标记报文不需要执行一些流程,例如:不需要建立会话。
  5. conntrack 表:连接跟踪表,跟踪连接会话,用来实现状态防火墙,是 NAT 功能的基础,也可以扩展更多功能。

每张表所挂载的链如下图所示:
在这里插入图片描述

在不同的 Hooks 点上会执行不同的表:
在这里插入图片描述

数据包处理流程图

在这里插入图片描述
在这里插入图片描述

iptables CLI

iptables 是运行在 Userspace 的 Netfilter 配置工具,iptables 用于 IPv4,ip6tables 用于 IPv6。更新的 nftables 已经包含在 Linux kernel v3.13 版本中,以后会取代 iptables 成为主要的 Linux 防火墙配置工具。

iptables-service

大多 Linux 发型版将 iptables 被做成了一个服务,启动,则将防火规则生效。反之,则将防火规则撤销。

# 停止 firewalld 服务
$ systemctl stop firewalld

# 禁用 firewalld 服务
$ systemctl mask firewalld

$ yum install -y iptables
$ yum install iptables-services

$ systemctl enable iptables.service
$ systemctl start iptables.service

配置文件为:

  • /etc/sysconfig/iptables
  • /etc/iptables/iptables.rules

指令应用

制定 iptables 表规则思路

  1. 选择一张表(此表决定了数据包的处理方式,e.g. filter、nat);
  2. 选择一条链(此链决定了数据包的流经位置,e.g. INPUT、OUTPUT);
  3. 选择合适的规则匹配条件(此条件决定了对数据包做何种条件匹配,e.g. Source IP、ICMP);
  4. 选择处理数据包的动作(e.g. ACCEPT、DEOP)。

iptables 语法格式

$ iptables [ -t 表名 ] 管理选项 [ 链名 ] [ 条件匹配 ] [ -j 目标动作或转发 ]

不指定表名时,默认为 filter 表,不指定链名时,默认表示该表的所有链。除非设置了链的缺省策略,否则需要指定条件匹配。

在这里插入图片描述

查看规则

默认查看的是 filter 表的规则,可以指定表名或链名,也可以显示规则编号。

$ iptables -nvL [--line-numbers] [-t 表名] [链名] 
  • –line-numbers:列出规则的编号。
  • 五表:raw,nat,filter,mangle,conntrack
  • 五链:INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING

添加规则

添加规则有两种方式,一种是在链最后追加(-A)规则,另一种是将规则插入(-I)到链上的某个特定位置。

# 添加规则到指定的链中
$ iptables -A INPUT -s 192.168.1.5 -j DROP

# 插入规则到指定的链中,默认为插入到链首
$ iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"

删除规则

# 通过编号删除链中的规则
$ iptables -D INPUT 8

修改规则

# 用新规则代替已存在的旧规则
$ iptables -R INPUT 2 -s 127.0.0.1 -d 127.0.0.1 -i lo -j ACCEPT

保存和加载规则

通过命令行添加规则,配置文件不会自动改变,所以必须手动保存:

# 备份与保存规则至指定文件
$ cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak
$ iptables-save > /etc/sysconfig/iptables

修改配置文件后,需要重新加载服务生效:

$ systemctl reload iptables

或者通过指定配置文件由 iptables 直接加载:

# 从指定文件加载规则
$ iptabls-restore < /PATH/FROM/SOME_RULE_FILE
  • -n, --noflush:不清除原有规则。
  • -t, --test:仅分析生成规则集,但不提交。

常规初始化配置

# 查看 iptables 现有规则
$ iptables -L -n

# 备份现有的规则
$ cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak

# 先允许所有
$ iptables -P INPUT ACCEPT

# 清空所有默认规则
$ iptables -F
# 清空所有自定义规则
$ iptables -X
# 所有计数器归 0
$ iptables -Z

# 开放本地回环
$ iptables -A INPUT -i lo -j ACCEPT
# 开放已建立的或相关的连接的
$ iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 开放 22 端口(SSH)
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 开放 21 端口(FTP)
$ iptables -A INPUT -p tcp --dport 21 -j ACCEPT
# 开放 80 端口(HTTP)
$ iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 开放 443 端口(HTTPS)
$ iptables -A INPUT -p tcp --dport 443 -j ACCEPT
#开放 ping
$ iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
# 允许接受本机请求之后的返回数据 RELATED,是为 FTP 设置的
$ iptables -A INPUT -m state --state  RELATED,ESTABLISHED -j ACCEPT

# 其他入站一律丢弃
$ iptables -P INPUT DROP
# 所有出站一律绿灯
$ iptables -P OUTPUT ACCEPT
# 所有转发一律丢弃
$ iptables -P FORWARD DROP

指令选项解析

管理选项

  • 规则显示
-L, --list [chain]:列出规则;
-v, --verbose:详细信息; 
-vv 更详细的信息
-n, --numeric:数字格式显示主机地址和端口号;
-x, --exact:显示计数器的精确值,而非圆整后的数据;
--line-numbers:列出规则时,显示其在链上的相应的编号;
-S, --list-rules [chain]:显示指定链的所有规则;
  • 规则管理
-A, --append chain rule-specification:追加新规则于指定链的尾部; 
-I, --insert chain [rulenum] rule-specification:插入新规则于指定链的指定位置,默认为首部;
-R, --replace chain rulenum rule-specification:使用新的规则替换指定的旧规则;
-D, --delete chain rulenum:根据规则编号删除规则;
-D, --delete chain rule-specification:根据规则本身删除规则;
  • 链管理
-N, --new-chain chain:新建一个自定义链;
-X, --delete-chain [chain]:删除自定义的引用计数为 0 的空链;
-F, --flush [chain]:清空指定链上的规则;
-E, --rename-chain old-chain new-chain:重命名链;
-Z, --zero [chain [rulenum]]:置零计数器;
      NOTE:每条规则都有两个计数器
          1. packets:被本规则匹配到的数据包个数;
          2. bytes:被本规则匹配到的数据包大小之和;
-P, --policy chain target:制定链表的策略(ACCEPT | DROP | REJECT);

条件匹配(Xmatch)

条件匹配分为基本匹配和扩展匹配,扩展匹配又分为显示匹配和隐式匹配。

基本匹配:无需加载扩展模块,匹配规则生效。

-p:指定规则协议,e.g. tcp/udp/icmp/all
-s:指定数据包的源地址,IP or Hostname
-d:指定数据包的目的地址
-i:输入接口,网卡设备
-o:输出接口                                              
!:取反

扩展匹配:需要加载扩展模块,匹配规则方可生效。

隐式匹配:使用 -p 选项指明协议时,无需同时使用 -m 选项指明扩展模块以及不需要手动加载扩展模块。

-p tcp
  --sport:匹配报文段的源端口;可以给出多个端口,但只能是连续的端口范围 
  --dport:匹配报文段的目标端口;可以给出多个端口,但只能是连续的端口范围
  --tcp-flags mask comp:匹配报文段的 tcp 标志位
-p udp
  --sport:匹配数据报端口;可以给出多个端口,但只能是连续的端口范围
  --dport:匹配数据报目标端口;可以给出多个端口,但只能是连续的端口范围
--icmp-type
  8:echo request,Ping 请求
  0:echo reply,接收 Ping 请求之后响应的 Ping 应答

显示匹配:必须使用 -m 选项指明要调用的扩展模块的扩展机制以及需要手动加载扩展模块。

  • multiport(多端口):以离散或连续的方式定义多端口匹配条件,最多 15 个。
iptables -I INPUT -d 172.16.100.7 -p tcp -m multiport --dports 22,80 -j ACCEPT
iptables -I OUTPUT -s 172.16.100.7 -p tcp -m multiport --sports 22,80 -j ACCEPT
  • iprange(IP 范围):以连续地址块的方式来指明多个 IP 地址匹配条件。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 23 -m iprange --src-range 172.16.100.1-172.16.100.100 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 23 -m iprange --dst-range 172.16.100.1-172.16.100.100 -j ACCEPT
  • time:指定时间范围。
iptables -A INPUT -d 172.16.100.7 -p tcp --dport 901 -m time --weekdays Mon,Tus,Wed,Thu,Fri --timestart 08:00:00 --time-stop 18:00:00 -j ACCEPT
iptables -A OUTPUT -s 172.16.100.7 -p tcp --sport 901 -j ACCEPT
  • string:对应用层的报文做字符串模式匹配检测。
--algo {bm|kmp}:字符匹配查找时使用算法
--string "STRING":要查找的字符串
--hex-string "HEX-STRING":要查找的字符,先编码成16进制格式
  • connlimit:根据每个客户端 IP 作并发连接数量限制。
--connlimit-upto n:连接数小于或等于 n 时匹配
--connlimit-above n:连接数大于 n 时匹配
  • limit:报文速率控制。

  • state:追踪本机上的请求和响应之间的数据报文的状态。

    • INVALID:无法识别的连接
    • ESTABLISHED:已建立的连接
    • NEW:新建立的连接
    • RELATED:相关联的连接,当前连接是一个新连接,但依附于某个已存在的连接
    • UNTRACKED:未追踪的连接

NOTE

  1. 对于进入的状态为 ESTABLISHED 都应该放行。
  2. 对于出去的状态为 ESTABLISHED 都应该放行。
  3. 严格检查进入的状态为 NEW 的连接。
  4. 所有状态为 INVALIED 都应该拒绝。

NAT/NAPT

IP 网络有公网与私网的区分,企业内网使用私网 IP,Internet 使用公网 IP。当使用私网 IP 地址访问公网 IP 时就需要使用到 NAT(Network Address Translation,网络地址转换)技术,包括:

  1. SNAT(源地址转换):私网访问公网时使用。
  2. DNAT(目标地址转换):公网访问私网时使用。
  3. PAT(端口转换):通常配合 DNAT 使用。

在这里插入图片描述

SNAT

SNAT(Source Network Transform,源地址转换),实现私网内主机使用同一个公网 IP 进行上网。即:内网 IP 地址向外访问 Internet 时,发起访问的内网 IP 地址转换为指定的对外 IP 地址(可指定具体的服务以及相应的端口或端口范围),这使内网的多部主机可以通过同一个有效的公网 IP 地址访问外部网络。

数据包出站路径为:APP => TCP/IP stack 路由子系统 => filter:OUTPUT => nat:POSTROUTING => 出站。

# SNAT:由内到外的源地址转换 
$ iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -o eth1 -j SNAT --to 198.51.100.3 

在外网地址非固定时的共享动态 IP 地址上网场景中,需要使用 IP 地址伪装模式。MASQUERADE 是一种动态 SNAT 技术,通常用于连接到动态 IP 地址的网络,例如:家庭网络或移动网络。

MASQUERADE 会将数据包的 srcIP 地址替换为外部网络接口的 IP 地址,而不需要提前指定固定的某一个公共 IP 地址。这样,无论外部网络的 IP 地址如何变化,MASQUERADE 都能够确保数据包可以正确地返回到内部网络。

$ iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

在这里插入图片描述

DNAT

DNAT(Destination Network Transform,目的地址转换)与 SNAT 相对,当外部网络访问内部网络时,进来的 IP 数据包会被改变 dstIP 地址。

# DNAT:由外到内的目的地址转换
$ iptables -t nat -I PREROUTING -p tcp -d 198.51.100.3 --dport 80 -j DNAT --to 192.168.0.2

NAT 转发操作需要在 filter 表中 FORWARD 链中允许,并且打开系统的 ip_forwarding 转发功能。

在这里插入图片描述

PAT

PAT(端口映射)通常和 DNAT 一起使用,例如:将本机公网 IP 的 2222 端口映射到虚拟机内网 IP 的 22 端口。

$ iptables -t nat -A PREROUTING -d 210.14.67.127 -p tcp --dport 2222  -j DNAT --to-dest 192.168.188.115:22

# 测试。
$ ssh root@210.14.67.127 -p 2222

应用示例

  • 放行所有网段的主机访问本机的 httpd 服务
# 入向规则
$ iptables -t filter -A INPUT -p tcp –dport 80 -m state –state NEW,ESTABLISHED -j ACCEPT
# 出向规则
$ iptables -t filter -A OUTPUT -p tcp –sport 80 -m state –state ESTABLISHED -j ACCEPT
  • 端口重定向
$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

如果你在你的计算机上面运行了这个指令,它只会对连到你的机器上的外部 IP 产生效果。从本地端发起的连线不会遵循 nat 表上 PREROUTING 链的设置。如果你想让本地端也遵循规则,你需要将 lo 接口上的数据包输出由 80 端口转向到 8080 端口上面:

$ iptables -t nat -A OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080
  • 指定数据包出去的网络接口:该操作只对 OUTPUT,FORWARD,POSTROUTING 三个链起作用。
$ iptables -A FORWARD -o eth0
  • 阻止 Windows 蠕虫的攻击
$ iptables -I INPUT -j DROP -p tcp -s 0.0.0.0/0 -m string --algo kmp --string "cmd.exe"
  • 防止 SYN 洪水攻击
$ iptables -A INPUT -p tcp --syn -m limit --limit 5/second -j ACCEPT
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。