2
votes

I'm using https://elixir.bootlin.com/linux/v4.9.137/source/samples/bpf/sockex3_kern.c this example, but instead of the RAW socket, I'm using ordinary AF_INET6/SOCK_STREAM and BPF_PROG_TYPE_SOCKET_FILTER.

I can't understand why load_half is used to read proto. First 32 bits is the length field:

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);
}

Or if I try to do this:

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;
    ...
}

I got "invalid bpf_context access off=80 size=4" error. As I understand I should read all the data from "data" field here.

So, maybe someone can tell me where the first 34 bytes(eth + ip header) was trimmed for current sk_buff? Somewhere in tcp_v4_rcv?

Is it possible to access IP header fields with SOCK_STREAM socket?

UPD: Looks like there is no way to directly access data from the filter:

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

1 Answers

-1
votes

According to latest kernel sources, protocol is 16-byte offset, not 12!

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