将eBPF字节码附加到SOCK_STREAM套接字

时间:2018-11-19 21:39:15

标签: linux sockets kernel bpf

在此示例中,我使用https://elixir.bootlin.com/linux/v4.9.137/source/samples/bpf/sockex3_kern.c,但不是使用RAW套接字,而是使用普通的AF_INET6 / SOCK_STREAM和BPF_PROG_TYPE_SOCKET_FILTER。

我不明白为什么使用load_half读取原型。前32位是长度字段:

SEC("socket/0")
int bpf_prog(struct __sk_buff *skb)
{
    __u32 proto = load_half(skb, 12);

    char fmt[] = "PROTO %x\n";
    bpf_trace_printk(fmt, sizeof(fmt), proto);
}

或者,如果我尝试这样做:

SEC("socket/0")
int bpf_prog(struct __sk_buff *skb)
{
    u64 proto = load_half(skb, 12);
    char fmt[] = "PROTO %x %u\n";
    void *data = (void *)(long)skb->data;
    struct ethhdr *eth = data;
    void *data_end = (void *)(long)skb->data_end;
    ...
}

我收到“无效的bpf_context访问关闭= 80 size = 4”错误。据我了解,我应该从此处的“数据”字段中读取所有数据。

那么,也许有人可以告诉我当前sk_buff的前34个字节(eth + ip标头)在哪里修剪?在tcp_v4_rcv中的某个地方?

是否可以通过SOCK_STREAM套接字访问IP标头字段?

UPD : 看起来无法直接从过滤器访问数据:

https://elixir.bootlin.com/linux/v4.9.137/source/net/core/filter.c#L2647

switch (off) {
case offsetof(struct __sk_buff, tc_classid):
case offsetof(struct __sk_buff, data):
case offsetof(struct __sk_buff, data_end):
    return false;
}

1 个答案:

答案 0 :(得分:-1)

根据最新的内核资源,协议为16字节偏移量,而不是12字节!

https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/bpf.h#L2305