【问题标题】:Write packet filtering program in ebpf在ebpf中编写包过滤程序
【发布时间】:2019-07-15 13:49:26
【问题描述】:

如果我想编写一个过滤 icmp 数据包的 cBPF 程序,我可以通过执行 tcpdump-dd 选项来实现

将数据包匹配代码转储为 C 程序片段。

..见下面的例子

如何使用 eBPF 指令编写相同的程序?

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
/* ... */

/* From the example above: tcpdump -i lo icmp -dd */
struct sock_filter code[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 1, 0x00000001 },
{ 0x6, 0, 0, 0x00040000 },
{ 0x6, 0, 0, 0x00000000 },
};

struct sock_fprog bpf = {
    .len = ARRAY_SIZE(code),
    .filter = code,
};

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0)
    /* ... bail out ... */

ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
if (ret < 0)
    /* ... bail out ... */

/* ... */
close(sock);

【问题讨论】:

    标签: packet bpf ebpf


    【解决方案1】:

    您可以通过与您的 cBPF 程序非常相似的方式传递 eBPF 指令:您可以有类似的东西

    struct bpf_insn ebpf_code[] = {
    { 0xb7, 0, 0, 0, 0 },
    { 0x95, 0, 0, 0, 0 },
    };
    

    (注意指令的长度与 cBPF 不同。)

    但目前没有工具可以像tcpdump -dd 那样为您转储指令。这意味着您必须以另一种方式构建您的程序。

    一种解决方案是自己编写 eBPF 指令。这很像汇编中的编程。你有一些 BPF in the kernel 的文档,或者现有指令列表及其语法 here

    因为手动编写单独的 eBPF 指令并不有趣[需要引用],eBPF 的典型工作流程有些不同。 clang/LLVM 有一个 eBPF 的后端,现在构建的大多数 eBPF 程序都依赖它。工作流程如下所示:

    1. 用 C 语言编写 BPF 程序。
    2. 使用 clang/LLVM 将其编译为目标文件 (ELF)。
    3. 使用工具或库(ip linktc filterbpftoolbcclibbpfgobpf,...)从目标文件中加载字节码。
    4. 将字节码注入内核并将其附加到挂钩(例如套接字)(这通常由相同的工具或库完成)。

    内核有一堆用C写的sample BPF programs。你可以看看,看看其中一个是否能适应你的需要。您需要实现的可能是:

    1. 检查您的数据包是否足够长以包含完整的以太网标头。
    2. 检查以太网类型是否为 IPv4。
    3. 检查以太网标头之后的数据包是否足够长以包含完整的 IPv4 标头。
    4. 检查 IP 协议号是否为 ICMP。

    然后返回与您想对该数据包执行的操作相关的操作(该值取决于您将程序附加到的挂钩、套接字/TC/XDP)。

    【讨论】:

    • 感谢您的回答,我想再问您 10000 件事,我可以在下午给您写信吗?你有一些链接可以让我学习如何用 C 编写 ebpf 程序吗?我的意思是,我找不到“友好”的指南。 XD
    • 当然,请随时发送您的问题!但是请记住,在这里也可以询问通用问题,这样其他人也可以从答案中受益:)。有一堆 BPF 资源的链接on this page,一些更完整(特别是 Cilium 指南),一些更易于访问。要开始使用网络处理,我建议查看 Jesper 的 tutorials on XDP(其中大部分也适用于其他网络挂钩)。
    • 再次感谢。如果你能看到这个,那就太好了stackoverflow.com/questions/57053518/… 我正在尝试编写一个简单的 bpf 程序。但它不起作用。
    • 我有一个疑问,为什么我可以使用相同的 struct sock_filter 传递比 cbpf 更长的 ebpf 指令?
    • 是的,我的错,我在那里做了一些过度简化。它根本不是struct sock_filter,而是/usr/include/linux/bpf.h 中定义的struct bpf_insn 数组(我将编辑答案),您最终需要加载它通过bpf() 系统调用(libbpf 围绕它提供了有用的帮助器,作为记录)。如果你想看看,你在kernel repository 中有例子。但老实说,典型的 eBPF 工作流程是从 C 编译的,这种方式要容易得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    相关资源
    最近更新 更多