You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在BPF_CGROUP_INET_INGRESS钩子获取入站数据包数据及eBPF程序推荐

针对CGroup入站数据包/套接字数据获取的eBPF方案推荐

你当前使用的BPF_PROG_TYPE_CGROUP_SKB配合BPF_CGROUP_INET_INGRESS钩子,仅能访问skb线性缓冲区的数据(通常对应网络协议头部),若数据包存在非线性分片(比如TCP载荷存储在skb frags中),bpf_skb_load_bytes无法直接读取这部分内容。以下是几种更适合获取完整数据包/套接字数据的eBPF程序类型:


1. BPF_PROG_TYPE_SOCKET_FILTER(套接字过滤器)

  • 挂载方式:可绑定到单个套接字,或通过BPF_CGROUP_INET_SOCK挂载到CGroup,对CGroup内所有新建套接字生效
  • 核心优势:能访问完整的套接字数据(包括TCP/UDP载荷),内核5.1及以上版本支持通过bpf_skb_load_bytes读取线性区和分片数据
  • 适用场景:需要针对CGroup内特定套接字或全量套接字的流量做内容分析的场景

2. BPF_PROG_TYPE_XDP(eXpress Data Path)

  • 挂载方式:绑定到指定网络接口(支持XDP_ATTACH_MODE_SKB或XDP_ATTACH_MODE_DRV两种模式)
  • 核心优势:在网络栈最早期处理数据包,可获取完整原始数据包(包含所有分片),性能远高于传统网络钩子
  • CGroup适配:若需限定CGroup范围,可在XDP程序中通过bpf_get_current_cgroup_id()获取当前进程所属CGroup,再做流量筛选

3. BPF_PROG_TYPE_SOCK_OPS(套接字操作钩子)

  • 触发时机:内核5.8及以上版本支持BPF_SOCK_OPS_TCP_DATA_READ/BPF_SOCK_OPS_TCP_DATA_WRITE事件,对应TCP数据的读写操作
  • 核心优势:直接关联到套接字的CGroup上下文,可精准捕获套接字层面的数据收发事件,配合bpf_skb_load_bytes读取数据包内容

4. BPF_PROG_TYPE_TRACEPOINT(跟踪点)

  • 可用跟踪点:net/netif_receive_skb(数据包进入网络栈时触发)、tcp/tcp_revmsg(TCP接收消息完成时触发)等
  • 核心优势:可在网络栈任意阶段捕获数据包,通过bpf_get_current_cgroup_id()过滤目标CGroup的流量,能访问完整的skb结构体及数据

优化后的CGroup SKB程序示例(读取TCP载荷)

如果希望继续使用BPF_PROG_TYPE_CGROUP_SKB,可通过解析协议头部定位载荷位置,读取线性区内的载荷数据(非线性分片仍无法读取):

#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/if_ether.h>
#include <linux/bpf.h>
#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>

char LICENSE[] SEC("license") = "GPL";

SEC("cgroup_skb/ingress")
int bpf_extract_tcp_payload(struct __sk_buff *skb) {
    long err;
    char payload_buf[100] = {0};
    struct ethhdr eth;
    struct iphdr ip;
    struct tcphdr tcp;
    int ip_hdr_len, tcp_hdr_len, payload_offset;

    // 读取以太网头部
    err = bpf_skb_load_bytes(skb, 0, &eth, sizeof(eth));
    if (err < 0) {
        bpf_printk("Failed to read eth header: %ld\n", err);
        return SK_PASS;
    }
    if (bpf_ntohs(eth.h_proto) != ETH_P_IP) {
        return SK_PASS; // 仅处理IPv4流量
    }

    // 读取IP头部
    err = bpf_skb_load_bytes(skb, sizeof(eth), &ip, sizeof(ip));
    if (err < 0) {
        bpf_printk("Failed to read ip header: %ld\n", err);
        return SK_PASS;
    }
    ip_hdr_len = ip.ihl * 4;

    // 读取TCP头部
    err = bpf_skb_load_bytes(skb, sizeof(eth) + ip_hdr_len, &tcp, sizeof(tcp));
    if (err < 0) {
        bpf_printk("Failed to read tcp header: %ld\n", err);
        return SK_PASS;
    }
    tcp_hdr_len = tcp.doff * 4;
    payload_offset = sizeof(eth) + ip_hdr_len + tcp_hdr_len;

    // 读取TCP载荷(仅线性区部分)
    if (skb->len > payload_offset + sizeof(payload_buf)) {
        err = bpf_skb_load_bytes(skb, payload_offset, payload_buf, sizeof(payload_buf));
        if (err >= 0) {
            bpf_printk("TCP Payload (partial): %s\n", payload_buf);
        } else {
            bpf_printk("Failed to read payload: %ld\n", err);
        }
    }

    return SK_PASS;
}

内容的提问来源于stack exchange,提问作者diviquery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:57:02