вот мой код // filter_xdp_antispam.c
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#ifndef IPPROTO_TCP
#define IPPROTO_TCP 6
#endif
#define SPAM "SPAM"
#define SPAM_LEN 4
#define MAX_CHECK 64

SEC("xdp")
int xdp_filter_spam(struct xdp_md *ctx) {
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;

    struct ethhdr *eth = data;
    if ((void*)eth + sizeof(*eth) > data_end)
        return XDP_PASS;

    __u16 eth_proto = eth->h_proto;
    void *cursor = eth + 1;  // после Ethernet

    // Обработка VLAN
    if (eth_proto == __constant_htons(ETH_P_8021Q) || eth_proto == __constant_htons(ETH_P_8021AD)) {
        if ((void*)cursor + 4 > data_end)
            return XDP_PASS;
        eth_proto = *(__u16 *)(((__u8*)cursor) + 2);
        cursor += 4;
    }

    if (eth_proto != __constant_htons(ETH_P_IP))
        return XDP_PASS;

    struct iphdr *ip = cursor;
    if ((void*)ip + sizeof(struct iphdr) > data_end)
        return XDP_PASS;

    if (ip->ihl < 5) // минимальный размер IP-заголовка
        return XDP_PASS;

    if ((void*)ip + ip->ihl * 4 > data_end)
        return XDP_PASS;

    if (ip->protocol != IPPROTO_TCP)
        return XDP_PASS;

    struct tcphdr *tcp = (void*)ip + ip->ihl * 4;

    if ((void*)tcp + sizeof(struct tcphdr) > data_end)
        return XDP_PASS;

    if (tcp->doff < 5) // минимальный размер TCP-заголовка
        return XDP_PASS;

    if ((void*)tcp + tcp->doff * 4 > data_end)
        return XDP_PASS;

    char *payload = (char *)tcp + tcp->doff * 4;
    if (payload > (char *)data_end)
        return XDP_PASS;

    int payload_len = (char *)data_end - payload;
    if (payload_len < SPAM_LEN)
        return XDP_PASS;

    #pragma unroll
    for (int i = 0; i < MAX_CHECK; i++) {
        int can_check = (i + SPAM_LEN <= payload_len);
        int match = 1;

        #pragma unroll
        for (int j = 0; j < SPAM_LEN; j++) {
            if (!can_check || payload[i + j] != SPAM[j]) {
                match = 0;
                break;
            }
        }
        if (match)
            return XDP_DROP;
    }

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";
и ошибка libbpf: prog 'xdp_filter_spam': BPF program load failed: Permission denied
libbpf: prog 'xdp_filter_spam': -- BEGIN PROG LOAD LOG --
0: R1=ctx() R10=fp0
0: (b7) r0 = 2                        ; R0_w=2
1: (61) r2 = *(u32 *)(r1 +4)          ; R1=ctx() R2_w=pkt_end()
2: (61) r1 = *(u32 *)(r1 +0)          ; R1_w=pkt(r=0)
3: (bf) r3 = r1                       ; R1_w=pkt(r=0) R3_w=pkt(r=0)
4: (07) r3 += 14                      ; R3_w=pkt(off=14,r=0)
5: (2d) if r3 > r2 goto pc+900        ; R2_w=pkt_end() R3_w=pkt(off=14,r=14)
6: (71) r5 = *(u8 *)(r1 +12)          ; R1_w=pkt(r=14) R5_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
7: (71) r4 = *(u8 *)(r1 +13)          ; R1_w=pkt(r=14) R4_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
8: (67) r4 <<= 8                      ; R4_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=0xff00,var_off=(0x0; 0xff00))
9: (4f) r4 |= r5                      ; R4_w=scalar() R5_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
10: (15) if r4 == 0x81 goto pc+1      ; R4_w=scalar()
11: (55) if r4 != 0xa888 goto pc+4    ; R4=0xa888
12: (bf) r3 = r1                      ; R1=pkt(r=14) R3_w=pkt(r=14)
13: (07) r3 += 18                     ; R3_w=pkt(off=18,r=14)
14: (2d) if r3 > r2 goto pc+891       ; R2=pkt_end() R3_w=pkt(off=18,r=18)
15: (69) r4 = *(u16 *)(r1 +16)        ; R1=pkt(r=18) R4_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=0xffff,var_off=(0x0; 0xffff))
16: (55) if r4 != 0x8 goto pc+889     ; R4_w=8
17: (bf) r1 = r3                      ; R1_w=pkt(off=18,r=18) R3_w=pkt(off=18,r=18)
18: (07) r1 += 20                     ; R1=pkt(off=38,r=18)
19: (2d) if r1 > r2 goto pc+886       ; R1=pkt(off=38,r=38) R2=pkt_end()
20: (71) r4 = *(u8 *)(r3 +0)          ; R3=pkt(off=18,r=38) R4_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
21: (57) r4 &= 15                     ; R4_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf))
22: (b7) r1 = 5                       ; R1_w=5
23: (2d) if r1 > r4 goto pc+882       ; R1_w=5 R4_w=scalar(smin=umin=smin32=umin32=5,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf))
24: (67) r4 <<= 2                     ; R4_w=scalar(smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
25: (bf) r1 = r3                      ; R1_w=pkt(off=18,r=38) R3=pkt(off=18,r=38)
26: (0f) r1 += r4                     ; R1=pkt(id=1,off=18,r=0,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c)) R4=scalar(smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
27: (2d) if r1 > r2 goto pc+878       ; R1=pkt(id=1,off=18,r=18,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c)) R2=pkt_end()
28: (71) r3 = *(u8 *)(r3 +9)          ; R3_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=255,var_off=(0x0; 0xff))
29: (55) if r3 != 0x6 goto pc+876     ; R3_w=6
30: (bf) r3 = r1                      ; R1=pkt(id=1,off=18,r=18,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c)) R3_w=pkt(id=1,off=18,r=18,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
31: (07) r3 += 20                     ; R3_w=pkt(id=1,off=38,r=18,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
32: (2d) if r3 > r2 goto pc+873       ; R2=pkt_end() R3_w=pkt(id=1,off=38,r=38,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
33: (69) r3 = *(u16 *)(r1 +12)        ; R1=pkt(id=1,off=18,r=38,smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c)) R3_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=0xffff,var_off=(0x0; 0xffff))
34: (77) r3 >>= 4                     ; R3_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=4095,var_off=(0x0; 0xfff))
35: (57) r3 &= 15                     ; R3_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf))
36: (b7) r4 = 5                       ; R4=5
37: (2d) if r4 > r3 goto pc+868       ; R3=scalar(smin=umin=smin32=umin32=5,smax=umax=smax32=umax32=15,var_off=(0x0; 0xf)) R4=5
38: (67) r3 <<= 2                     ; R3_w=scalar(smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
39: (0f) r1 += r3                     ; R1_w=pkt(id=2,off=18,r=0,smin=umin=smin32=umin32=40,smax=umax=smax32=umax32=120,var_off=(0x0; 0x7c)) R3_w=scalar(smin=umin=smin32=umin32=20,smax=umax=smax32=umax32=60,var_off=(0x0; 0x3c))
40: (2d) if r1 > r2 goto pc+865       ; R1_w=pkt(id=2,off=18,r=18,smin=umin=smin32=umin32=40,smax=umax=smax32=umax32=120,var_off=(0x0; 0x7c)) R2=pkt_end()
41: (1f) r2 -= r1                     ; R1_w=pkt(id=2,off=18,r=18,smin=umin=smin32=umin32=40,smax=umax=smax32=umax32=120,var_off=(0x0; 0x7c)) R2_w=scalar()
42: (bf) r3 = r2                      ; R2_w=scalar(id=3) R3_w=scalar(id=3)
43: (67) r3 <<= 32                    ; R3_w=scalar(smax=0x7fffffff00000000,umax=0xffffffff00000000,smin32=0,smax32=umax32=0,var_off=(0x0; 0xffffffff00000000))
44: (c7) r3 s>>= 32                   ; R3_w=scalar(smin=0xffffffff80000000,smax=0x7fffffff)
45: (b7) r4 = 4                       ; R4=4
46: (6d) if r4 s> r3 goto pc+859      ; R3=scalar(smin=umin=smin32=umin32=4,smax=umax=umax32=0x7fffffff,var_off=(0x0; 0x7fffffff)) R4=4
47: (71) r3 = *(u8 *)(r1 +0)
invalid access to packet, off=18 size=1, R1(id=2,off=18,r=18)
R1 offset is outside of the packet
processed 48 insns (limit 1000000) max_states_per_insn 0 total_states 5 peak_states 5 mark_read 1
-- END PROG LOAD LOG --
libbpf: prog 'xdp_filter_spam': failed to load: -13
libbpf: failed to load object 'filter_xdp_antispam.o'