linux 如何激活BCC eBPF程序来修改传出/出口网络流量?

wfsdck30  于 2023-10-16  发布在  Linux
关注(0)|答案(1)|浏览(114)

我使用BPF加密器集合(BCC)编写了一个eBPF程序来修改传出的UDP数据包。
我使用了BPF_PROG_TYPE_SCHED_ACT类型的程序,我希望这是正确的。(https://ebpf-docs.dylanreimerink.nl/linux/program-type/)。
但是装上之后,我不知道如何“激活”它。将其附加到eth0或其他东西似乎不起作用。我猜我需要tc命令,但我不明白为什么(因为我不知道那到底是什么)。
下面是我的Python脚本:

import sys
import time

from bcc import BPF

def main():
    src = open("my_example.c").read()

    b = BPF(text=src, cflags=["-Wno-macro-redefined"])  # 3

    # fn = b.load_func("my_example", BPF.SK_SKB)
    fn = b.load_func("my_example", BPF.SCHED_CLS)

    b.attach_raw_socket(fn, "eth0") # this doesn't work

if __name__ == "__main__":
    main()

而eBPF计划本身是这样的:

#include <bcc/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/udp.h>

int my_example(struct __sk_buff *skb)
{
    if(skb->protocol != htons(ETH_P_IP)) return TC_ACT_OK;
    if(skb->pkt_type != PACKET_OUTGOING) return TC_ACT_OK;

    if(skb->wire_len<176) return TC_ACT_OK;
    if(skb->len<176) return TC_ACT_OK;

    bpf_skb_pull_data(skb, 176);

    u8* packet = (u8*)(long)skb->data;
    u8* packet_end = (u8*)(long)skb->data_end;
    if(packet_end<packet+176) return TC_ACT_OK;

    if(packet[94] != 0x54) return TC_ACT_OK;

    bpf_skb_change_tail(skb, 30, 0);

    packet=(u8*)(long)skb->data;
    packet_end=(u8*)(long)skb->data_end;
    if (packet_end<packet+206) return TC_ACT_OK;

    packet[205] = packet[205-30];
    packet[94] = 0x56;
    // ...

    // more code for length and checksums ...

    return TC_ACT_RECLASSIFY;
}

如何“激活”这个程序?

polhcujo

polhcujo1#

**TL; DR.**您可以使用Python pyroute 2库将程序附加到接口eth0的tc钩子。请参阅我文章末尾的代码示例。

fn = b.load_func("my_example", BPF.SCHED_CLS)
b.attach_raw_socket(fn, "eth0") # this doesn't work

这不起作用,因为您将程序声明为SCHED_CLS类型,然后试图将其附加到不同的钩子上。
如果你使用bcc,你可以检查示例程序https://github.com/iovisor/bcc/blob/master/examples/networking/xdp/xdp_drop_count.py(该程序同时处理XDP和tc)。特别是,您可以将tc-bpf程序附加到:

import pyroute2

fn = b.load_func("my_example", BPF.SCHED_CLS)

ip = pyroute2.IPRoute()
ipdb = pyroute2.IPDB(nl=ip)
idx = ipdb.interfaces["eth0"].index
ip.tc("add", "clsact", idx)
ip.tc("add-filter", "bpf", idx, ":1", fd=fn.fd, name=fn.name,
      parent="ffff:fff2", classid=1, direct_action=True)

相关问题