Skip to main content
  1. Posts/

eBPF for Linux Admins: Part V

·3 mins· loading · loading ·
Ansil H
ebpf
Author
Ansil H
DevOps Guy
eBPF - This article is part of a series.
Part 5: This Article

In the previous article, we wrote an eBPF program to block all packets via XDP.

This article is a continuation of previous article where we will block a TCP port of an interface instead of all packets.

But before we go forward, let’s expand the diagram we have see in the first article.

The BPF or pseudo VM has been enhanced by Alexei Starovoitov along with Daniel Borkmann and called it eBPF or extended BPF.

  • Registers were increased from 3 to 10 (+1 sp).
  • Changed register to 64bit.
  • Added a stack of 512 bytes
  • Added unlimited arbitrary key/value structure called maps
  • Added helper function support
  • Added a Verifier to verify code
  • Added a JIT compiler to generate native assembly code from object code

A simple firewall using eBPF
#

This eBPF program will will block traffic to port 80 of an interface.

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define BLOCK_PORT 80 
#define TOTSZ (sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr))

SEC("xdp")
int xdp_drop_port(struct xdp_md *ctx)
{
	void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
	
    // Set IP and TCP header structs
    struct iphdr *ip = data + sizeof(struct ethhdr);
	struct tcphdr *tcph = data + sizeof(struct ethhdr) + sizeof(struct iphdr);
    
    //Below check is made mandatoy by eBPF verifier
    if (data + TOTSZ > data_end) {
        return XDP_PASS;
    }
	
    // If its a TCP packet and destined to port 80, then drop iit
    if (ip->protocol == IPPROTO_TCP && tcph->dest == htons(BLOCK_PORT)) {
        // Write debug info to /sys/kernel/debug/tracing/trace_pipe
		bpf_printk("Blocking packet from %pI4 to port %u\n",&ip->saddr, ntohs(tcph->dest));
		return XDP_DROP;
	}
	
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

We are reading the start and end of data using xdp_md.

We have to make sure the headers + data is not greater than the end of the data. If we read anything outside of the end of data by accident, then that may crash the kernel and that is why the verifier enforces this check.

Other details are self explanatory from the program itself.

Let’s compile the program and then load it.

clang -O2 -g -Wall -target bpf -c xdp_drop_port.c -o xdp_drop_port.o
sudo xdp-loader load -m skb -s xdp enp0s8  xdp_drop_port.o

Then you can watch the trace logs with below command

cat /sys/kernel/debug/tracing/trace_pipe

If you try to use curl command to the IP assigned to the interface enp0s8 then you will notice and output like below;

<idle>-0       [003] ..s21 89616.096958: bpf_trace_printk: Blocking packet from 192.168.57.1 to port 80
<idle>-0       [003] ..s21 89617.123247: bpf_trace_printk: Blocking packet from 192.168.57.1 to port 80
<idle>-0       [003] ..s21 89619.139545: bpf_trace_printk: Blocking packet from 192.168.57.1 to port 80

Congratulations for making yourself to this stage!!.🎉
Give a pat on your shoulder 😄

So far we have used eBPF in XDP. In upcoming one, we will use eBPF on kprobes. Brace yourself for the next eBPF chapters.

eBPF - This article is part of a series.
Part 5: This Article

Related

eBPF for Linux Admins: Part IV
·3 mins· loading · loading
Ansil H
ebpf
eBPF for Linux Admins: Part III
·4 mins· loading · loading
Ansil H
ebpf
eBPF for Linux Admins: Part II
·2 mins· loading · loading
Ansil H
ebpf