Write packet filtering program in ebpf

0

If I want to write a cBPF program which filter icmp packet I can do it by execute tcpdump with -dd option which

Dump packet-matching code as a C program fragment.

..see the example below

How can I write the same program with eBPF instructions ?

#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
asked on Stack Overflow Jul 15, 2019 by Maicake

1 Answer

1

You can pass eBPF instructions in a way very similar to what you do for your cBPF program: you can have something like

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

(Note the length of the instructions is not the same as for cBPF.)

But there is no tool, at this time, that will dump the instructions for you just like tcpdump -dd does. This means you have to build your program another way.

One solution is to write the eBPF instructions yourself. This is pretty much like programming in assembly. You have some documentation for BPF in the kernel, or a list of the existing instructions and their syntax here.

Because writing manually the individual eBPF instructions is not fun[citation needed], the typical workflow for eBPF is somewhat different. clang/LLVM has a back-end for eBPF, and most eBPF programs built today rely on it. The workflow looks like this:

  1. Write your BPF program in C.
  2. Compile it with clang/LLVM into an object file (ELF).
  3. Load the bytecode from your object file with a tool or library (ip link, tc filter, bpftool, bcc, libbpf, gobpf, ...).
  4. Inject the bytecode into the kernel and attach it to a hook (e.g. a socket) (this is generally done by the same tools or libraries).

The kernel has a bunch of sample BPF programs written in C. You can have a look and see if one of them can be adapted to your needs. What you need to implement is probably something along:

  1. Check your packet is long enough to have a full Ethernet header.
  2. Check that ethertype is IPv4.
  3. Check that following the Ethernet header, your packet is long enough to have a full IPv4 header.
  4. Check that IP protocol number is ICMP.

Then return the action related to what you want to do with that packet (the value depends on what hook, socket/TC/XDP, you attach your program to).

answered on Stack Overflow Jul 15, 2019 by Qeole • edited Jul 19, 2019 by Qeole

User contributions licensed under CC BY-SA 3.0