Linux内核Netfilter框架分析

一、Netfilter框架以及挂接点

1.Netfilter子系统的主要功能

数据包选择(iptables)

数据包过滤

网络地址转换(NAT)

数据包操控

连接跟踪

网络统计信息

1. 数据包选择(iptables 规则匹配)

  • 功能:根据预设规则(如源 / 目标 IP、端口、协议等)精准识别和选择特定数据包,为后续操作(如过滤、NAT 等)提供条件。

  • 例子
    使用 iptables 规则选择来自 192.168.1.100 且目标端口为 80 的 HTTP 数据包:

    复制代码
    iptables -A INPUT -s 192.168.1.100 -p tcp --dport 80 -j ACCEPT

    该规则仅匹配符合条件的数据包,并执行允许(ACCEPT)操作。


2. 数据包过滤

  • 功能:基于数据包选择结果,决定允许或拒绝数据包通过,实现网络访问控制。
  • 例子
    禁止来自 203.0.113.5 的所有流量:
复制代码
  iptables -A INPUT -s 203.0.113.5 -j DROP

该规则会直接丢弃来自该 IP 的数据包,阻止其访问本地系统。


3. 网络地址转换(NAT)

  • 功能:修改数据包的源或目标 IP 和端口,实现多设备共享公网 IP(SNAT)或将公网流量转发到内网(DNAT)。

  • 例子

    • SNAT(源地址转换)
      局域网内设备通过路由器访问互联网时,路由器将数据包的源 IP 转换为自己的公网 IP:
    复制代码
      iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    • DNAT(目标地址转换)
      将公网对路由器 8080 端口的访问转发到内网服务器 192.168.1.200 的 80 端口:

      bash

      复制代码
      iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.200:80

4. 数据包操控

  • 功能:修改数据包的字段(如 TTL、TOS、DSCP 等),以实现流量标记、QoS 优先级调整等高级功能。
  • 例子
    使用 mangle 表为特定数据包设置 DSCP 值(用于 QoS):
复制代码
  iptables -t mangle -A PREROUTING -p tcp --dport 80 -j DSCP --set-dscp 0x20

该规则将目标端口为 80 的 HTTP 数据包的 DSCP 值设置为 0x20,以便网络设备优先处理。


5. 连接跟踪

  • 功能:跟踪网络连接的状态(如新建、已建立、相关),确保返回流量能正确匹配原有连接,简化规则配置。

  • 例子
    允许已建立的连接返回流量:

    复制代码
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    该规则自动允许与现有连接相关的响应数据包通过,无需为每个响应单独设置规则。


6. 网络统计信息

  • 功能:统计匹配特定规则的数据包数量和流量大小,用于监控和分析网络行为。
  • 例子
    统计访问 22 端口(SSH)的数据包数量:
复制代码
  iptables -A INPUT -p tcp --dport 22 -m statistic --mode count --probability 1 -j LOG --log-prefix "SSH Access: "
  • 该规则会记录所有匹配的 SSH 连接尝试次数,并写入系统日志,便于后续分析。

2.Linux内核子系统常用框架

1. IPVS(IP Virtual Server,IP 虚拟服务器)

  • 功能与原理
    IPVS 是 Linux 内核实现的传输层负载均衡框架,工作在网络层(L4),支持多种负载均衡模式(如 NAT 模式、DR 模式、TUN 模式),通过调度算法将客户端请求分发到后端多个真实服务器,实现高可用、高性能的服务集群。内核 2.6.28 起支持 IPv6。
  • 示例(DR 模式配置)
    • 安装工具

      复制代码
      yum install ipvsadm  # 或 apt install ipvsadm  
    • 配置负载均衡规则 (假设后端服务器 IP 为 192.168.1.10192.168.1.11,服务端口 80,调度算法为轮询):

    • 说明:客户端访问虚拟 IP(VIP_IP)的 80 端口时,IPVS 会通过轮询算法将请求分发到后端真实服务器。

2. ip sets

  • 功能与原理
    ip sets 是用户空间工具 ipset 和内核模块组成的框架,用于管理 IP 集合(如 IP 地址、端口范围、MAC 地址等)。通过预定义集合,可在 iptables 规则中快速匹配大量 IP,提升规则效率,避免逐条编写规则。
  • 示例(封禁多个恶意 IP)
    • 创建 IP 集合

      复制代码
      ipset create bad_ips hash:ip  # 创建名为 bad_ips 的 IP 集合  
    • 添加恶意 IP 到集合

      复制代码
      ipset add bad_ips 203.0.113.10  
      ipset add bad_ips 203.0.113.11  
    • 结合 iptables 过滤

      复制代码
      iptables -A INPUT -m set --match-set bad_ips src -j DROP  # 丢弃来自集合中 IP 的流量  
    • 说明 :通过 ipset 管理恶意 IP,iptables 规则直接匹配集合,简化大量 IP 过滤场景。

3. iptables

  • 功能与原理
    iptables 是 Netfilter 的前端管理工具,通过定义规则链(如 INPUT、OUTPUT、FORWARD)和规则,实现数据包过滤、NAT、流量操控等功能。规则基于匹配条件(如协议、端口、IP)执行动作(ACCEPT、DROP、MASQUERADE 等)。
  • 示例(基础防火墙规则)
    • 允许本地回环流量

      复制代码
      iptables -A INPUT -i lo -j ACCEPT  
    • 允许已建立的连接返回流量

      复制代码
      iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT  
    • 禁止外部访问本地 22 端口(SSH)

      复制代码
      iptables -A INPUT -p tcp --dport 22 -j DROP  
    • 说明:通过 iptables 逐条定义规则,控制不同场景下的网络流量,是构建 Linux 防火墙的核心工具。

3.Netfilter挂接点

在网络栈有5个地方设置Netfilter挂接点,但要注意ipv4和ipv6中挂接点名称相同。

1. NF_INET_PRE_ROUTING

  • 位置与作用
    所有入站数据包(无论是发往本地还是需转发的)进入内核后遇到的第一个挂接点,位于路由选择(判断数据包是本地接收还是转发)之前。主要用于修改数据包的目标地址(如 DNAT)、过滤非法入站流量等。
  • 典型场景
    • 实现网络地址转换(NAT)中的目标地址转换。例如,将公网用户对路由器 8080 端口的访问,通过该挂接点修改目标地址,转发到内网 Web 服务器的 80 端口。
    • 临时地址修改:在测试场景中,可临时修改数据包的目标地址(类似简易 DNAT),将外部对特定端口的访问重定向到本地其他服务端口,用于调试网络服务映射逻辑。
    • 流量过滤:例如,在数据包进入路由判断前,通过规则丢弃来源不可信的数据包(如恶意 IP 扫描流量)。

2. NF_INET_LOCAL_IN

  • 位置与作用
    处理发往本地主机的数据包(经路由选择判定为本地接收)。数据包到达此挂接点后,会进入上层协议(如 TCP、UDP)进一步处理,最终交付给本地应用程序(如 Web 服务器、SSH 服务)。
  • 典型场景
    本地防火墙规则在此挂接点过滤非法访问本地服务的流量。例如,禁止外部主机访问本地的 SSH 服务(端口 22),可在此挂接点添加规则丢弃相关数据包。

3. NF_INET_FORWARD

  • 位置与作用
    处理需转发的数据包(经路由选择判定不发往本地,需转发到其他网络)。只有开启内核转发功能(net.ipv4.ip_forward=1),且数据包符合转发规则时,才会经过此挂接点。
  • 典型场景
    在路由器或网关设备中,对转发的流量进行过滤或策略控制。例如,限制转发的数据包带宽,或丢弃恶意 IP 的转发流量。

4. NF_INET_LOCAL_OUT

  • 位置与作用
    处理本地主机生成的出站数据包(如本地发起的 HTTP 请求、SSH 连接)。数据包在此挂接点完成本地协议栈处理(如封装 IP 头),随后进入 NF_INET_POST_ROUTING 挂接点。
  • 典型场景
    对本地生成的数据包进行标记或策略调整。例如,为本地发送的视频流数据包设置 QoS 优先级,确保实时传输质量。

5. NF_INET_POST_ROUTING

  • 位置与作用
    所有出站数据包(包括本地生成的数据包和转发的数据包)离开内核前的最后一个挂接点。常用于修改数据包的源地址(如 SNAT),确保出站流量的源 IP 符合网络规划。
  • 典型场景
    局域网共享公网 IP 上网时,路由器通过此挂接点将内网设备的源 IP 转换为公网 IP(SNAT),使内网设备能访问互联网。

总结:挂接点处理流程

  1. 入站数据包先经过 NF_INET_PRE_ROUTING ,路由选择后:
    • 若发往本地,进入 NF_INET_LOCAL_IN,交付本地应用;
    • 若需转发,进入 NF_INET_FORWARD ,再经 NF_INET_POST_ROUTING 发送。
  2. 本地生成的出站数据包先经过 NF_INET_LOCAL_OUT ,再通过 NF_INET_POST_ROUTING 发送。
    这些挂接点为 Netfilter 实现数据包过滤、NAT、流量控制等功能提供了核心支撑。

NF_HOOK

数据包在内核网络栈中传输时,会在某些地方调用NF_HOOK宏使用挂接函数。

  • pf :协议簇,对于 IPv4 用 NFPROTO_IPV4;对于 IPv6 用 NFPROTO_IPV6
  • hook :表示 5 个 Netfilter 挂接点之一,如 NF_INET_PRE_ROUTING
  • skb:要处理的数据包的 SKB(Socket Buffer,套接字缓冲区)对象。
  • indev:输入网络设备(接收数据包的接口)。
  • outdev:输出网络设备(发送数据包的接口)。
  • okfn :函数指针,指向钩子回调函数执行完毕后需调用的默认处理函数,该函数接收 skb 作为参数。

4.注册Netfilter钩子回调函数结构体

要在前面5个挂接点注册Netfilter钩子回调函数,首先需要定义一个nf_hook_ops对象,然后进行注册:

netfilter回调函数返回值如下:

1. #define NF_DROP 0

  • 含义:表示直接丢弃当前数据包,阻止其继续在网络协议栈中传输。

  • 示例
    在内核模块中,若检测到数据包源 IP 属于恶意攻击源(如扫描本地端口的 IP),可通过返回 NF_DROP 丢弃该数据包。

    cpp 复制代码
    static unsigned int drop_malicious_pkt(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {  
        struct iphdr *iph = ip_hdr(skb);  
        if (is_malicious_ip(iph->saddr)) {  // 假设存在检测恶意 IP 的函数  
            printk(KERN_INFO "Dropping malicious packet\n");  
            return NF_DROP;  
        }  
        return NF_ACCEPT;  
    }  

2. #define NF_ACCEPT 1

  • 含义:允许数据包像正常流程一样继续在内核网络协议栈中传输,不进行阻断。

  • 示例
    对合法的 Web 访问流量,钩子函数不做干预,返回 NF_ACCEPT 让数据包继续到达传输层。

    cpp 复制代码
    static unsigned int allow_web_traffic(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {  
        struct iphdr *iph = ip_hdr(skb);  
        if (iph->dport == htons(80)) {  // 目标端口为 80(HTTP)  
            return NF_ACCEPT;  // 允许访问 Web 服务的数据包通过  
        }  
        return NF_DROP;  
    }  

3. #define NF_STOLEN 2

  • 含义:表示数据包不再继续沿协议栈传输,由钩子函数完全接管处理(如复制、保存数据包用于其他用途)。

  • 示例
    网络监控场景中,钩子函数复制数据包到自定义缓冲区分析,不再让原数据包继续传输。

    cpp 复制代码
    static unsigned int steal_pkt_for_monitor(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {  
        struct sk_buff *new_skb;  
        new_skb = skb_clone(skb, GFP_ATOMIC);  // 克隆数据包  
        if (new_skb) {  
            // 对 new_skb 进行分析(如解析协议内容)  
            monitor_packet(new_skb);  
            return NF_STOLEN;  // 原数据包不再继续传输  
        }  
        return NF_ACCEPT;  
    }  

4. #define NF_QUEUE 3

  • 含义 :将数据包送入用户空间队列,由用户空间程序(如 iptables 配合 libnetfilter_queue 库)进一步处理。

  • 示例
    用户空间程序需定义回调函数处理入队数据包,实现灵活的策略(如动态过滤)。

    cpp 复制代码
    // 内核模块钩子函数  
    static unsigned int queue_pkt(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {  
        return NF_QUEUE;  // 数据包入队,交用户空间处理  
    }  
    
    // 用户空间程序(简化逻辑)  
    int main() {  
        struct nfq_handle *h;  
        struct nfq_q_handle *qh;  
        // 初始化队列连接...  
        nfq_callback *cb = &process_packet;  
        nfq_set_callback(qh, cb);  
        // 循环处理入队数据包...  
        return 0;  
    }  
    static int process_packet(struct nfq_q_handle *qh, struct nfgenmsg *msg, struct nfq_data *data, void *user) {  
        // 分析数据包,决定放行或丢弃(如用户空间判断后返回 ACCEPT 或 DROP)  
        return nfq_verdict(qh, NF_ACCEPT, 0, NULL);  
    }  

5. #define NF_REPEAT 4

  • 含义:要求内核重新调用当前挂接点的钩子函数链,通常用于特殊场景(如钩子函数修改了数据包关键信息,需重新检查)。

  • 示例
    钩子函数修改了数据包的目标 IP 后,希望重新执行路由判断,可返回 NF_REPEAT

    cpp 复制代码
    static unsigned int modify_dst_ip_and_repeat(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {  
        struct iphdr *iph = ip_hdr(skb);  
        iph->daddr = new_dst_ip;  // 修改目标 IP  
        return NF_REPEAT;  // 重新执行当前挂接点的钩子函数链(如重新路由判断)  
    }  

具体案例参考:Linux内核Netfilter使用实战案例分析-CSDN博客

二、连接跟踪

链接跟踪能够让内核跟踪会话,主要目标为NAT打基础。

1.连接跟踪的初始化

名为ipv4_conntrack_ops的nf_hook_ops对象数组如下:

在 Linux 内核的网络子系统中,ipv4_conntrack_ops 结构体数组是用于配置 IPv4 连接跟踪功能的 Netfilter 钩子操作的。下面详细讲解相关内容。

1. Netfilter 框架与钩子机制概述

Netfilter 是 Linux 内核中一个强大的网络数据包处理框架,它允许内核在网络数据包处理的不同阶段(钩子点)插入自定义的处理函数(钩子函数),以实现诸如数据包过滤、地址转换、连接跟踪等功能。

2. nf_hook_ops 结构体

ipv4_conntrack_ops 数组中的元素类型是 nf_hook_ops,这是一个用于描述 Netfilter 钩子操作的结构体,其定义大致如下(不同内核版本可能略有差异):

cpp 复制代码
struct nf_hook_ops {
    struct list_head list;
    nf_hookfn *hook;
    struct module *owner;
    int pf;
    int hooknum;
    int priority;
};

下面详细解释其主要成员:

  • nf_hookfn *hook:指向实际的钩子函数的指针。当数据包到达对应的钩子点时,内核会调用这个函数来处理数据包。
  • int pf :指定该钩子操作适用的协议族,例如 NFPROTO_IPV4 表示 IPv4 协议族。
  • int hooknum :指定钩子点的编号,例如 NF_INET_PRE_ROUTINGNF_INET_LOCAL_IN 等。不同的编号代表不同的网络数据包处理阶段。
  • int priority:指定钩子函数的优先级。当多个钩子函数注册到同一个钩子点时,内核会按照优先级顺序依次调用这些函数。

3. ipv4_conntrack_ops 数组示例

以下是一个简化的 ipv4_conntrack_ops 数组示例:

cpp 复制代码
static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
    {
        .hook       = ipv4_conntrack_in,
        .pf         = NFPROTO_IPV4,
        .hooknum    = NF_INET_PRE_ROUTING,
        .priority   = NF_IP_PRI_CONNTRACK,
    },
    {
        .hook       = ipv4_conntrack_local,
        .pf         = NFPROTO_IPV4,
        .hooknum    = NF_INET_LOCAL_OUT,
        .priority   = NF_IP_PRI_CONNTRACK,
    },
};

4. 数组元素详细解释

第一个元素
  • .hook = ipv4_conntrack_in :指定了钩子函数为 ipv4_conntrack_in。这个函数的主要作用是在数据包进入内核且还未进行路由决策之前,对 IPv4 数据包进行连接跟踪处理。它会检查数据包是否属于一个已经存在的连接,如果是,则更新连接状态;如果不是,则尝试创建一个新的连接记录。
  • .pf = NFPROTO_IPV4:明确该钩子操作只处理 IPv4 协议的数据包。
  • .hooknum = NF_INET_PRE_ROUTING :指定钩子点为 NF_INET_PRE_ROUTING,即路由前阶段。这意味着该钩子函数会在数据包进入内核后,在进行路由决策之前被调用。
  • .priority = NF_IP_PRI_CONNTRACK :设置钩子函数的优先级为 NF_IP_PRI_CONNTRACK。这个优先级确保连接跟踪操作在其他可能依赖连接状态的操作(如防火墙规则匹配)之前执行。
第二个元素
  • .hook = ipv4_conntrack_local :指定钩子函数为 ipv4_conntrack_local。该函数用于处理从本地系统发出的 IPv4 数据包的连接跟踪。
  • .pf = NFPROTO_IPV4:同样表示只处理 IPv4 协议的数据包。
  • .hooknum = NF_INET_LOCAL_OUT :指定钩子点为 NF_INET_LOCAL_OUT,即本地输出阶段。这意味着该钩子函数会在本地系统发出数据包时被调用。
  • .priority = NF_IP_PRI_CONNTRACK :设置优先级为 NF_IP_PRI_CONNTRACK,确保连接跟踪操作优先执行。

5. 作用总结

ipv4_conntrack_ops 数组的主要作用是初始化 IPv4 连接跟踪的 Netfilter 钩子,使得内核能够在网络数据包处理的关键阶段(如路由前和本地输出阶段)对 IPv4 数据包进行连接状态的跟踪和管理。通过这种方式,内核可以为后续的网络功能(如防火墙规则匹配、NAT 转换等)提供准确的连接状态信息。

2.连接跟踪的基本元素是nf_conntrack_tuple结构

一个 nf_conntrack_tuple 是 Linux 内核中用于唯一标识一个网络连接的元组结构体,它包含了连接的源和目的地址、端口、协议等关键信息,为网络连接跟踪、防火墙规则匹配和 NAT 转换等操作提供基础依据。

它是一个相对轻量级的结构体,主要用来描述网络连接的基本元组信息。这些信息包含源地址、目的地址、源端口、目的端口以及所使用的协议(如 TCP、UDP、ICMP 等),就像是网络连接的一个 "标识标签",能唯一确定一条网络连接。

nf_conntrack_tuple 是 Linux 内核中用于 连接跟踪(Connection Tracking) 的核心结构体,用于描述网络连接的 "流" 特征(如地址、端口、协议等),帮助内核识别网络连接的属性,为防火墙、NAT 等功能提供连接状态匹配依据。以下是关键字段解析:

核心字段讲解

  1. struct nf_conntrack_man src

    • 用于标识连接的 源端信息,包含源地址、端口等核心标识数据。在连接跟踪中,通过解析该字段可确定数据包的源端特征,是识别网络流的重要依据。
  2. 联合体内的 u3all

    • u3:存储 IPv4/IPv6 地址相关信息,适配不同协议的地址格式。
    • all:以 __be16 类型存储通用地址数据,支持扩展其他协议的地址处理,确保结构体兼容多网络协议(如 IPv4、IPv6)的地址解析需求。
  3. struct { __be16 port; } tcp

    • 专门用于 TCP 协议,存储 TCP 连接的端口号。在 TCP 连接跟踪中,端口是识别连接的关键要素之一,结合源 / 目的地址,可唯一标识一条 TCP 连接。
  4. union nf_conntrack_proto proto

    • 存放 不同协议的特定数据(如端口、ICMP 类型 / 代码等)。例如,处理 TCP/UDP 时存储端口,处理 ICMP 时存储类型和代码,使结构体能够适配多种协议的连接跟踪需求,是协议无关性设计的核心体现。

使用场景

  • 连接跟踪 :内核运用 nf_conntrack_tuple 来跟踪网络连接的状态,记录连接的建立、传输和关闭过程。
  • 防火墙规则匹配 :防火墙规则可以依据 nf_conntrack_tuple 里的信息进行匹配,从而决定是否允许数据包通过。
  • NAT(网络地址转换) :NAT 设备在进行地址转换时,会根据 nf_conntrack_tuple 来修改数据包的源或目的地址。

3.连接跟踪的条目结构

一个 nf_conn 是 Linux 内核连接跟踪系统中,代表一条网络连接的综合管理结构体,它整合了连接的标识信息、状态、生命周期管理等关键内容,是实现防火墙、NAT 等网络功能的底层连接状态数据载体。

该结构体则更为复杂和全面,它代表了一个完整的网络连接对象。nf_conn 会包含 nf_conntrack_tuple 类型的成员,借助 nf_conntrack_tuple 来记录连接的基本标识信息。同时,nf_conn 还会记录连接的其他状态信息,像连接的当前状态(新建、已建立、关闭等)、超时时间、引用计数等。可以把 nf_conn 看作是对 nf_conntrack_tuple 的进一步扩展和封装,它不仅包含了连接的标识,还涵盖了连接的整个生命周期管理和状态信息。

重要字段

  • struct nf_conntrack ct_general

    作为 nf_conn 的核心成员,ct_general 整合了连接跟踪的通用信息,包括:

    • 连接元组信息 :通过 nf_conntrack_tuple 描述连接的源 / 目的地址、端口、协议等标识信息,用于唯一识别网络连接。
    • 连接状态 :记录连接当前所处状态(如新建 CT_NEW、已建立 CT_ESTABLISHED、断开 CT_CLOSE 等)。
    • 超时管理:维护连接的超时时间,用于自动清理长时间无活动的连接,释放系统资源。
  • 引用计数机制

    虽然代码片段未完全展示,但 nf_conn 依赖引用计数(如通过 nf_conntrack_get()nf_conntrack_put() 接口)管理结构体的生命周期。例如,哈希表引用、数据包关联引用等场景都会增减计数,确保连接资源在无引用时正确释放。

4.函数nf_contrack_in

函数概述

nf_conntrack_in 是 Linux 内核中用于 IPv4 连接跟踪的关键函数,它作为 Netfilter 钩子函数,在数据包进入内核网络栈且尚未进行路由决策时被调用。其主要功能是对输入的数据包进行连接跟踪处理,判断数据包是否属于已存在的连接,若不属于则尝试创建新的连接记录,同时更新连接状态,为后续的防火墙规则匹配、NAT 转换等网络功能提供基础。

参数说明

  • struct sk_buff *skb:指向 sk_buff 结构体的指针,sk_buff 是 Linux 内核中用于表示网络数据包的结构体,包含了数据包的所有信息,如网络层头部、传输层头部、数据部分等。
  • const struct nf_hook_state *state:指向 nf_hook_state 结构体的指针,该结构体包含了当前钩子点的状态信息,如协议族、钩子点编号等。

内部重要流程讲解

1. 检查数据包是否已被跟踪
cpp 复制代码
tmpl = nf_ct_get(skb, &ctinfo);
if (tmpl || ctinfo == IP_CT_UNTRACKED) {
    /* Previously seen (loopback or untracked)?  Ignore. */
    if ((tmpl && !nf_ct_is_template(tmpl)) ||
         ctinfo == IP_CT_UNTRACKED) {
        NF_CT_STAT_INC_ATOMIC(state->net, ignore);
        return NF_ACCEPT;
    }
    skb->_nfct = 0;
}
  • 功能 :通过 nf_ct_get 函数尝试获取数据包对应的连接跟踪信息。如果已经存在连接跟踪信息(tmpl 不为空)或者该数据包被标记为无需跟踪(ctinfo == IP_CT_UNTRACKED),则根据情况进行处理。若满足特定条件,则增加 ignore 统计计数器,并直接接受该数据包(返回 NF_ACCEPT)。若不满足条件,则将 skb 中的连接跟踪指针置为 0。
  • 意义:避免对已经处理过或者无需跟踪的数据包进行重复处理,提高处理效率。
2. 获取传输层协议信息
cpp 复制代码
dataoff = get_l4proto(skb, skb_network_offset(skb), state->pf, &protonum);
if (dataoff <= 0) {
    pr_debug("not prepared to track yet or error occurred\n");
    NF_CT_STAT_INC_ATOMIC(state->net, error);
    NF_CT_STAT_INC_ATOMIC(state->net, invalid);
    ret = NF_ACCEPT;
    goto out;
}
  • 功能 :调用 get_l4proto 函数从数据包中提取传输层协议信息,包括协议号(存储在 protonum 中)和传输层头部相对于数据包起始位置的偏移量(存储在 dataoff 中)。如果获取失败(dataoff <= 0),则记录错误信息,增加 errorinvalid 统计计数器,将返回值设为 NF_ACCEPT 并跳转到 out 标签处结束处理。
  • 意义:为后续根据不同的传输层协议进行相应的连接跟踪处理做准备。
3. 处理 ICMP 数据包
cpp 复制代码
if (protonum == IPPROTO_ICMP || protonum == IPPROTO_ICMPV6) {
    ret = nf_conntrack_handle_icmp(tmpl, skb, dataoff,
                                   protonum, state);
    if (ret <= 0) {
        ret = -ret;
        goto out;
    }
    /* ICMP[v6] protocol trackers may assign one conntrack. */
    if (skb->_nfct)
        goto out;
}
  • 功能 :如果数据包的协议号是 ICMP(IPPROTO_ICMP)或 ICMPv6(IPPROTO_ICMPV6),则调用 nf_conntrack_handle_icmp 函数对 ICMP 数据包进行特殊处理。根据该函数的返回值进行相应操作,如果返回值小于等于 0,则取其相反数作为最终返回值并跳转到 out 标签处;如果 skb 中已经有连接跟踪信息,则直接跳转到 out 标签处。
  • 意义:ICMP 协议有其特殊的工作机制,需要专门的处理函数来进行连接跟踪,确保 ICMP 数据包的连接状态能被正确跟踪。
4. 解析并处理正常连接
cpp 复制代码
repeat:
ret = resolve_normal_ct(tmpl, skb, dataoff,
                        protonum, state);
if (ret < 0) {
    /* Too stressed to deal. */
    NF_CT_STAT_INC_ATOMIC(state->net, drop);
    ret = NF_DROP;
    goto out;
}

ct = nf_ct_get(skb, &ctinfo);
if (!ct) {
    /* Not valid part of a connection */
    NF_CT_STAT_INC_ATOMIC(state->net, invalid);
    ret = NF_ACCEPT;
    goto out;
}

ret = nf_conntrack_handle_packet(ct, skb, dataoff, ctinfo, state);
if (ret <= 0) {
    /* Invalid: inverse of the return code tells
     * the netfilter core what to do */
    pr_debug("nf_conntrack_in: Can't track with proto module\n");
    nf_conntrack_put(&ct->ct_general);
    skb->_nfct = 0;
    NF_CT_STAT_INC_ATOMIC(state->net, invalid);
    if (ret == -NF_DROP)
        NF_CT_STAT_INC_ATOMIC(state->net, drop);
    /* Special case: TCP tracker reports an attempt to reopen a
     * closed/aborted connection. We have to go back and create a
     * fresh conntrack.
     */
    if (ret == -NF_REPEAT)
        goto repeat;
    ret = -ret;
    goto out;
}
  • 功能
    • 调用 resolve_normal_ct 函数尝试解析并创建正常的连接跟踪信息。如果返回值小于 0,表示系统压力过大无法处理,增加 drop 统计计数器,将返回值设为 NF_DROP 并跳转到 out 标签处。
    • 通过 nf_ct_get 函数获取数据包对应的连接跟踪结构体 ct。如果获取失败,说明该数据包不属于一个有效的连接,增加 invalid 统计计数器,将返回值设为 NF_ACCEPT 并跳转到 out 标签处。
    • 调用 nf_conntrack_handle_packet 函数对数据包进行进一步处理。如果返回值小于等于 0,表示处理失败,记录错误信息,释放连接跟踪资源,增加 invaliddrop 统计计数器。如果返回值为 -NF_REPEAT,则跳转到 repeat 标签处重新尝试创建连接跟踪信息。
  • 意义:这是处理非 ICMP 数据包的核心流程,负责解析、创建和处理正常的连接跟踪信息,确保数据包所属的连接能被正确跟踪和管理。

5.网络地址转换NAT

网络地址转换(NAT)模块主要要用于处理IP地址转换或端口操纵。NAT最常见的用途之一是:让局域网中的一组使用私有ip地址的主机能够通过内部网关访问Internet,为此可以设置NAT规则。

一、NAT 基础概念讲解

1. NAT 类型
  • 静态 NAT:建立私有 IP 与公共 IP 的固定映射关系,一对一永久绑定。常用于需要外部主动访问内部固定服务的场景(如内部服务器对外提供服务)。
  • 动态地址 NAT:维护一个公共 IP 地址池,当内部主机访问外部网络时,从地址池中动态分配公共 IP 进行转换,释放后可重新分配给其他主机。
  • 网络地址端口转换(NAPT) :将内部多个私有 IP 映射到外部网络的 同一个公共 IP 的不同端口,通过端口区分不同连接,解决公共 IP 稀缺问题,是家庭路由器最常用的 NAT 方式。
2. NAT 主要功能
  • 数据伪装:修改 IP 包的源 / 目的地址,隐藏内部网络结构,实现私有网络与公共网络的通信。
  • 负载均衡:通过 NAT 网关将流量分配到多个内部服务器,提升服务处理能力。
  • 端口转发:将外部对网关某端口的访问转发到内部特定主机的指定端口,实现内部服务对外暴露。
  • 透明代理:对用户透明,自动处理地址转换,无需终端用户配置。
3. NAT 工作原理

当私有网络主机与公共网络主机通信时,IP 包经过 NAT 网关,网关修改 IP 包的源 IP(出网时,私有 IP → 公共 IP)或目的 IP(入网时,公共 IP → 私有 IP),使内部网络借助少量公共 IP 实现与外部通信,同时隐藏内部网络拓扑。


二、nf_nat_ipv4_ops 结构体数组解析

nf_nat_ipv4_ops 是 Linux 内核中用于 IPv4 NAT 功能的 Netfilter 钩子操作数组,通过在不同网络处理阶段挂载钩子函数,实现 NAT 地址转换。以下是数组元素详解:

1. 过滤数据包前修改目标地址(NF_INET_PRE_ROUTING
cpp 复制代码
{
   .hook       = iptable_nat_ipv4_in,
   .pf         = NFPROTO_IPV4,
   .hooknum    = NF_INET_PRE_ROUTING,
   .priority   = NF_IP_PRI_NAT_DST,
},
  • 作用 :在数据包进入内核且未路由前,处理 目的地址转换(DNAT)。例如,外部访问网关某端口时,通过此钩子将目的 IP 转换为内部服务器 IP。
  • 关键字段
    • hook:绑定钩子函数 iptable_nat_ipv4_in,执行 DNAT 逻辑。
    • hooknumNF_INET_PRE_ROUTING 钩子点,确保在路由决策前修改目的地址。
2. 过滤数据包后修改源地址(NF_INET_POST_ROUTING
复制代码
{
   .hook       = iptable_nat_ipv4_out,
   .pf         = NFPROTO_IPV4,
   .hooknum    = NF_INET_POST_ROUTING,
   .priority   = NF_IP_PRI_NAT_SRC,
},
  • 作用 :在数据包即将离开内核网络栈时,处理 源地址转换(SNAT)。例如,内部主机访问外部网络,通过此钩子将源 IP 替换为网关公共 IP。
  • 关键字段
    • hook:钩子函数 iptable_nat_ipv4_out 负责 SNAT 操作。
    • hooknumNF_INET_POST_ROUTING 钩子点,保证在数据包路由后、发送前修改源地址。
3. 本地输出前修改目标地址(NF_INET_LOCAL_OUT
复制代码
{
   .hook       = iptable_nat_ipv4_local_fn,
   .pf         = NFPROTO_IPV4,
   .hooknum    = NF_INET_LOCAL_OUT,
   .priority   = NF_IP_PRI_NAT_DST,
},
  • 作用:处理本地生成的数据包(如本地程序发起的网络请求)的目的地址转换,确保本地流量按 NAT 规则正确转换目标地址。
4. 本地输入后修改源地址(NF_INET_LOCAL_IN
复制代码
{
   .hook       = iptable_nat_ipv4_fn,
   .pf         = NFPROTO_IPV4,
   .hooknum    = NF_INET_LOCAL_IN,
   .priority   = NF_IP_PRI_NAT_SRC,
},
  • 作用:对进入本地的数据包(如外部响应本地请求的数据包)进行源地址转换,确保 NAT 转换的双向一致性。

注册数组nf_nat_ipv4_ops的工作有iptable_nat_init()来完成。

NAT钩子回调函数。

相关推荐
小麦嵌入式4 小时前
Linux驱动开发实战(六):设备树升级!插件设备树点灯!
linux·c语言·驱动开发·单片机·嵌入式硬件·mcu·ubuntu
tpoog5 小时前
MySQL:数据库基础
linux·c语言·开发语言·数据库·redis·mysql
阿正的梦工坊5 小时前
Linux top 命令详解:从入门到高级用法
linux·服务器·网络
单车少年ing5 小时前
stressapptest交叉编译(ARM64)
linux·arm64
遇见火星5 小时前
docker-compose 快速搭建日志平台
linux·运维·centos
她的双马尾5 小时前
WebSocket:开启实时通信的新篇章
网络·websocket·网络协议
四口鲸鱼爱吃盐5 小时前
CVPR2025 | TAPT:用于视觉语言模型鲁棒推理的测试时对抗提示调整
网络·人工智能·深度学习·机器学习·语言模型·自然语言处理·对抗样本
.m5 小时前
Linux怎样源码安装Nginx
linux·运维·nginx
weixin_433431445 小时前
centos【rockylinux】安装【supervisor】的注意事项【完整版】
linux·运维·centos
若汝棋茗6 小时前
TouchSocket TcpService:构建高性能Tcp服务的终极利器
网络·网络协议·tcp/ip·touchsocket