使用 eBPF Kprobe 附件 tcp_sendmsg 进行 TCP 数据包有效负载嗅探

问题描述 投票:0回答:1

我正在尝试读取 redis-cli 实用程序通过 eBPF 发送到远程 Redis 数据库的传出 TCP 数据包的有效负载,以测试 eBPF 的功能。我的计划是按目标端口(已完成)过滤所有传出的 TCP 数据包,如 tcp_sendmsg() 的第一个参数 sock* sk 访问的那样,然后通过 &(msghdr->msg_iter. iov)->iov_base,其中 msghdr 是第二个参数。

但是,复制的数据似乎已损坏,并且与任何 TCP 数据包的任何有效负载都没有关系(我正在通过 Wireshark 跟踪真实的有效负载)。这是代码:

struct redis_sys_packet {
    u16 lport;
    u16 dport;
    u32 nr_segments;
    u32 packet_length;
    char packet[128];
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, struct redis_sys_packet);
    __type(value, u64);
} redis_sys_write_calls SEC(".maps");

//... other code

// kprobe handler for tcp_sendmsg 
SEC("kprobe/tcp_sendmsg")
int kprobe__tcp_sendmsg(struct pt_regs *ctx) {
    if (!ctx || ctx == NULL) return 0;
    struct sock *sk = (struct sock *)(ctx->di);
    if (!sk || sk == NULL) return 0;
    u16 lport = 0;
    u16 dport = 0;


    bpf_probe_read_kernel(&lport, sizeof(lport), &sk->__sk_common.skc_num);
    bpf_probe_read_kernel(&dport, sizeof(dport), &sk->__sk_common.skc_dport);

    struct redis_sys_packet pack = {};
    pack.lport = lport;
    pack.dport = bpf_ntohs(dport);
    if (pack.dport != 19795) return 0; // filter by port

    // second parameter
    struct msghdr* msg = (struct msghdr *)(ctx->si);
    if (!msg || msg == NULL) return 0;
    // Get the pointer to the iov (IO vector) array that holds the payload
    struct iov_iter *iter = &(msg->msg_iter);
    if (!iter || iter == NULL) return 0;
    bpf_probe_read(&pack.nr_segments, sizeof(unsigned long), &(iter->nr_segs));
    const struct iovec *iov = (const struct iovec *)&(iter->iov);

    // Check if we can access the first iovec
    if (!iov)
        return 0;


    // Get the base address of the payload
    void *iovbase;
    bpf_probe_read(&iovbase, sizeof(void *), &iov[0].iov_base);
    unsigned long iov_len;
    // read from count instead of iov->iov_len - for some reason this always returns 1, not the true length
    bpf_probe_read(&iov_len, sizeof(size_t), &(iter->count));
    pack.packet_length = (u32)iov_len;
    u32 copy_length = (u32)iov_len;
    if (copy_length > 128) {
        copy_length = 128;
    } else if (copy_length <= 0) {
        return 0;
    }


    bpf_probe_read_kernel(pack.packet, copy_length, iovbase);
    increment_map(&redis_sys_write_calls, &pack, 1); // returns irrelevant data

    return 0;
}

如果有任何其他跟踪点/函数可以附加 kprobe/uprobe 来跟踪传出的 TCP 数据包并嗅探有效负载,我也会非常感激。我已经尝试附加到 xdp,但由于不相关的错误而无法工作。

我在 WSL2 之上的 Ubuntu 22.04 上执行所有这些操作,内核为 5.15.153.1-microsoft-standard-WSL2。

tcp trace ebpf kprobe
1个回答
0
投票

您可以使用套接字过滤器、TC(流量控制)或 XDP(eXpress 数据路径)来捕获 TCP、UDP 和 ICMP 有效负载,而无需求助于 kprobe、uprobe 或跟踪点。

以下是您可以探索的一些示例实现:

© www.soinside.com 2019 - 2024. All rights reserved.