iptables和linux内核的联系

iptables 在 Linux 是基本的防火墙工具,同时也是很常见的网络工作,但是 iptables 实际上只是应用层的东西,那么 iptables 是如何和 Linux 的内核网络栈联系起来的,这里我就这个问题进行一个简单的介绍。

# 概述

iptables 在 Linux 是基本的防火墙工具,同时也是很常见的网络工作,但是 iptables 实际上只是应用层的东西,那么 iptables 是如何和 Linux 的内核网络栈联系起来的,这里我就这个问题进行一个简单的介绍。

# NetFilter 框架

Netfilter 框架是 Linux 内核网络为应用提供的注册各种 Handler 的框架,通过 Netfilter 框架,允许用户铜鼓欧 Handler 达到控制 Linux 网络部分功能的效果。

常用的注入点有以下这些:

  • NF_IP_PRE_ROUTING: 数据包进入网络栈时就会被调用,没有任何网络决策被执行;
  • NF_IP_LOCAL_IN: 进来的数据包被确认是发给这个系统后被执行;
  • NF_IP_FORWARD: 进来的数据包被确认是发给其他主机后执行;
  • NF_IP_LOCAL_OUT: 本机创建的出去流量进入网络栈后被执行;
  • NF_IP_POST_ROUTING: 出去流量(包括本地产生的和转发的)路由完成后(放入网卡前)被执行;

# Iptables

iptables 就是 Linux 内核提供给应用层用于设置 NetFliter 的工具之一,iptables 通过 table 来组织规则,所谓的 table 其实就是对应的不同的功能,例如:

  • NAT:网络地址转换
  • Filter:过滤数据包
  • Mangle:修改数据包(主要是修改 IP Header)
  • Raw:修改原始数据包
  • Security:这个是给数据报添加 SELinux 标识的(一般用户都用不到)

在每个表中,iptables 通过链来组织规则,所谓的链其实就是对应到 NetFilter 中的不同 Hook,其实就是定义规则的执行时机时机顺序:

iptables 链 NetFilter Hook
PREROUTING NF_IP_PRE_ROUTING
INPUT NF_IP_LOCAL_IN
FORWARD NF_IP_FORWARD
OUTPUT NF_IP_LOCAL_OUT
POSTROUTING NF_IP_POST_ROUTING

# table 的运行顺序

因为 table 是 iptables 才有的概念,当不同的 table 包含相同链的规则时,最终在 NetFilter 中是需要有一个顺序的,这个顺序用户是不能指定优先级的,但是 iptables 给你定义好了执行顺序,默认的顺序是这么走的:

  • 主链是从左到右:
    • PreRouting -> Input -> Output -> PostRouting
    • PreRouting -> Forward -> PostRouting
  • 对于每个链,执行顺序从上往下走
Tables↓/Chains→ PREROUTING INPUT FORWARD OUTPUT POSTROUTING
(routing decision)
raw
(connection tracking enabled)
mangle
nat (DNAT)
(routing decision)
filter
security
nat (SNAT)

# 用户自定义链

对于 iptables 来说,所谓的规则可以理解为两部分组成,分别是:

  • 匹配部分
  • 动作部分
    • 终结动作:可以马上给出结果的动作,例如默认的 :ACCEPT,REJECT 等;
    • 非终结动作:调用另外一条链的动作,直到另外一条链返回

这里所谓的自定义链条就是非终结动作,那么为什么要引入自定义链呢?

# 引入自定义链

前面说了,默认 iptables 只有 5 条链,虽然 iptables 用表来区分了,但是,还是不够,尤其是在企业级使用中(例如 Istio),往往会创建一大堆的规则,那么当我想查看某一个功能的规则的时候,可能就不好找了,所以这个自定义链就可以起作用了。我们可以将不同的应用 / 功能的规则放入单独的链中,这样我们需要修改或者查看的时候直接看对应的链就可以了,例如

  • INPUT_CHAIN_NGINX:表示针对 nginx 的自定义链
  • INPUT_CHAIN_ENVOY:表示针对 envoy 的自定义链

# 自定义链的执行实际

因为默认情况下,iptables 只会使用 5 条默认的链,所以自定义的链是不会被执行的。如果想要执行自定义链,就需要在默认的链中主动调用自定义链(所谓的非终止动作),这样就和自定义链配合起来了。一个例子:

[[email protected]]# iptables -I INPUT -p tcp --dport 9090 -j INPUT_CHAIN_ENVOY
1

就表示在 INPUT 链中添加一个 INPUT_CHAIN_ENVOY 的引用,当 INPUT 链执行的时候,对应就执行这个自定义的链。和其他链的顺序就按照前面的表格顺序执行,在 INPUT 链中的顺序就和你定义的先后顺序从旧往新执行,先执行旧的定义,再执行新的定义。

# 连接跟踪

iptables 还执行连接追踪的功能,这个也是基于 NetFilter 实现的,这里连接跟踪所谓的连接不单单指我们常见的 TCP 连接,还包括 UDP,甚至 ICMP 也算,这些协议都称为可跟踪协议,跟踪的基础是基于” 连接 “的元组,例如 TCP 的就是四元组 <SrcIP, SrcPORT, DestIP, DestPort>

# 连接跟踪的作用

连接跟踪本质上还是为包的动作服务的,例如一个设置了防火墙的 Web 主机,如果我们打开了 80 端口的入口,那么对于出口是全开还是全闭,可能都不合适。那么能不能做到半开半闭,如何半开半闭这就是连接跟踪的功能了,想象一下我们要对谁开放?我们要对访问了我们 80 端口的客户端开放,那么这里就可以先跟踪成功访问 80 端口的客户端的信息,然后再定义一条针对已经打开的连接的出口规则:

[[email protected]]# iptables -A OUTPUT -m state --state NEW,RELATED -j ALLOW
1

这样就不需要针对特定的客户端来开放出口流量了。

# Ref

全文完

本文由 简悦 SimpRead (opens new window) 优化,用以提升阅读体验

使用了 全新的简悦词法分析引擎 beta,点击查看 (opens new window)详细说明

概述 (opens new window)NetFilter 框架 (opens new window)Iptables (opens new window)table 的运行顺序 (opens new window)用户自定义链 (opens new window)引入自定义链 (opens new window)自定义链的执行实际 (opens new window)连接跟踪 (opens new window)连接跟踪的作用 (opens new window)Ref (opens new window)

Last Updated: 2022/7/8 下午2:41:42