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

在BPF_PROG_TYPE_SK_LOOKUP中获取连接所属进程的PID

如何在eBPF sk_msg上下文获取客户端连接的进程PID

你遇到的核心问题有两个:

  1. bpf_get_current_pid_tgid()在sk_msg钩子中拿到的是当前处理消息的进程(比如代理进程)的PID,而非发起该连接的客户端进程PID;
  2. 即便该函数可用,也无法满足你过滤客户端PID的需求。

正确的思路是在连接建立阶段记录客户端PID与socket的关联,再在sk_msg阶段通过socket标识查询对应的PID。具体实现步骤如下:

1. 定义eBPF映射存储PID与socket的关联

首先创建一个哈希映射,用socket的cookie作为键,客户端PID作为值:

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 10240);
    __type(key, u64);  // socket cookie
    __type(value, u32); // 客户端PID(内核态tgid,对应用户态PID)
} sock_pid_map SEC(".maps");

2. 在连接建立钩子中记录关联

使用sockops钩子或者tracepoint钩子捕获连接建立事件,记录socket的cookie和对应的PID:

方法一:使用sockops钩子(内核4.17+支持)

SEC("sockops")
int sockops_handler(struct bpf_sock_ops *ctx) {
    u32 op = ctx->op;
    // 捕获TCP连接建立完成事件
    if (op == BPF_SOCK_OPS_TCP_CONNECT_CB) {
        u64 sock_cookie = bpf_get_socket_cookie(ctx->sk);
        u32 pid = bpf_get_current_pid_tgid() >> 32;
        bpf_map_update_elem(&sock_pid_map, &sock_cookie, &pid, BPF_ANY);
    }
    // 连接关闭时清理映射,避免内存泄漏
    else if (op == BPF_SOCK_OPS_TCP_CLOSE_CB) {
        u64 sock_cookie = bpf_get_socket_cookie(ctx->sk);
        bpf_map_delete_elem(&sock_pid_map, &sock_cookie);
    }
    return 0;
}

方法二:使用tracepoint钩子(更直观,内核4.15+支持)

SEC("tracepoint/syscalls/sys_enter_connect")
int trace_connect(struct trace_event_raw_sys_enter *ctx) {
    struct socket *sock = (struct socket *)ctx->args[0];
    if (!sock) return 0;
    u64 sock_cookie = bpf_get_socket_cookie(sock->sk);
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    bpf_map_update_elem(&sock_pid_map, &sock_cookie, &pid, BPF_ANY);
    return 0;
}

// 可选:添加sys_exit_close钩子清理已关闭连接的映射条目

3. 在sk_msg钩子中查询PID并过滤

回到你的echo_dispatch程序,获取当前socket的cookie,从映射中查询客户端PID,再执行过滤逻辑:

SEC("sk_msg")
int echo_dispatch(struct sk_msg_md *msg) {
    struct sock *sk = msg->sk;
    if (!sk) return SK_PASS;

    u64 sock_cookie = bpf_get_socket_cookie(sk);
    u32 *client_pid = bpf_map_lookup_elem(&sock_pid_map, &sock_cookie);
    if (!client_pid) return SK_PASS;

    // 替换为你需要过滤的目标PID
    if (*client_pid == YOUR_TARGET_PID) {
        // 执行代理逻辑,比如转发或丢弃
        return SK_PASS; // 或SK_DROP,根据需求调整
    }

    return SK_PASS;
}

注意事项

  • 内核版本兼容性:确保内核支持所需的eBPF辅助函数(bpf_get_socket_cookie需4.15+,sockops钩子需4.17+);
  • 映射清理:必须在连接关闭时清理映射条目,避免内存泄漏;
  • 权限要求:加载eBPF程序时需要CAP_BPF、CAP_PERFMON等权限;
  • 连接复用场景:如果同一个socket被多进程复用,会记录最后操作该socket的进程PID,需根据业务场景调整逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:57:43