我正在使用https://elixir.bootlin.com/linux/v4.9.137/source/samples/bpf/sockex3_kern.c这个例子,但我使用的是普通的 AF_INET6/SOCK_STREAM 和 BPF_PROG_TYPE_SOCKET_FILTER 而不是 RAW 套接字。
我不明白为什么用 load_half 来读取 proto。前 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 大小 = 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;
}