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钩子回调函数。

相关推荐
三坛海会大神5553 分钟前
计算机网络参考模型与子网划分
网络·计算机网络
云卓SKYDROID20 分钟前
无人机激光测距技术应用与挑战
网络·无人机·吊舱·高科技·云卓科技
Lovyk1 小时前
Linux 正则表达式
linux·运维
Fireworkitte2 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9002 小时前
ubuntu常见问题汇总
linux·ubuntu
ac.char3 小时前
在CentOS系统中查询已删除但仍占用磁盘空间的文件
linux·运维·centos
淮北也生橘124 小时前
Linux的ALSA音频框架学习笔记
linux·笔记·学习
iナナ6 小时前
传输层协议——UDP和TCP
网络·网络协议·tcp/ip·udp
华强笔记7 小时前
Linux内存管理系统性总结
linux·运维·网络
十五年专注C++开发8 小时前
CMake进阶: CMake Modules---简化CMake配置的利器
linux·c++·windows·cmake·自动化构建