用ebpf写包过滤程序

时间:2019-07-15 13:49:26

标签: packet bpf ebpf

如果我想编写一个过滤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);

1 个答案:

答案 0 :(得分: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 filterbpftoolbcclibbpf,{{3} },...)。
  4. 将字节码注入内核并将其附加到钩子(例如套接字)(通常由相同的工具或库完成)。

内核中有一堆用C编写的gobpf。您可以看一下其中是否可以适应您的需求。您需要实现的大概是:

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

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