The Beginner's Guide to eBPF Programming for Networking

Overview

The Beginner's Guide to eBPF Programming for Networking

As seen at Cloud Native eBPF Day 2021.

Setup

Create a container that we can issue curl requests to.

docker run -d --rm --name backend-A -h backend-A --env TERM=xterm-color nginxdemos/hello:plain-text

# Get the IP address of this target 
docker exec -it backend-A ip a 

Create a privileged container from which we can run eBPF programs. We will attach most of our programs to its eth0 virtual interface.

docker run --rm -it -v /usr:/usr -v /home:/home -v /sys:/sys --privileged --env TERM=xterm-color -h container ubuntu

Assuming you cloned this repo into your home directory, the mount of /home means you can cd /home/<user name>/ebpf-networking within this container to find this example code.

In a separate terminal window, observe the debug trace output:

sudo cat /sys/kernel/debug/tracing/trace_pipe

Prerequisites

These examples use BCC

Examples

See the slides and video (coming soon) for more info on the different examples included here, and how to use them.

Examples include

  • Kprobe on tcp_v4_connect() kernel function
  • Attaching a socket filter to a raw socket
  • XDP
  • Traffic control - adding a filter on ingress
Issues
  • IP routing using tc

    IP routing using tc

    Hi, I am trying to perform IP routing using tc. I am taking guidance from two repos : lb-from-scratch and ebpf-networking. The client and backend are running in containers on my system and the load balancer(LB) is receiving packets on the docker0 interface. However, when connection is initiated from client to LB, the client continuously retries sending the first SYN packet. Below is the bpf kernel code:

    #include <bcc/proto.h>
    #include <linux/bpf.h>
    #include <uapi/linux/bpf.h>
    #include <linux/if_ether.h>
    #include <linux/ip.h>
    #include <linux/tcp.h>
    #include <linux/pkt_cls.h>
    #include <linux/icmp.h>
    
    
    #define IP_ADDRESS(x,y,z,w) (uint32_t)(x + (y << 8) + (z << 16) + (w << 24))
    #define IS_PSEUDO 0x10
    
    struct address{
        unsigned char mac[6];
        uint32_t ip;
        u16 port;
    };
    
    
    #define IP_CSUM_OFF (offsetof(struct iphdr, check))
    #define TCP_CSUM_OFF offsetof(struct tcphdr, check)
    
    static __always_inline void change_address_and_update_crc(
        struct __sk_buff * skb, 
        struct address * addr,
        struct ethhdr * eth,
        struct iphdr * ip,
        struct tcphdr * tcp){
        
        int flags = IS_PSEUDO;
        uint32_t orig_src_ip;
        uint64_t orig_src_mac;
        u16 orig_src_port;
        
        orig_src_mac = (unsigned char)(eth->h_source);
        orig_src_ip = ip->saddr;
        orig_src_port = tcp->source;
    
        eth->h_source[0] = eth->h_dest[0];
        eth->h_source[1] = eth->h_dest[1];
        eth->h_source[2] = eth->h_dest[2];
        eth->h_source[3] = eth->h_dest[3];
        eth->h_source[4] = eth->h_dest[4];
        eth->h_source[5] = eth->h_dest[5];
        ip->saddr = ip->daddr;
        //tcp->source = tcp->dest;
    
        uint32_t dst_ip = (*addr).ip;
        u16 dst_port = (*addr).port;
        eth->h_dest[0] = (*addr).mac[0];
        eth->h_dest[1] = (*addr).mac[1];
        eth->h_dest[2] = (*addr).mac[2];
        eth->h_dest[3] = (*addr).mac[3];
        eth->h_dest[4] = (*addr).mac[4];
        eth->h_dest[5] = (*addr).mac[5];
        ip->daddr = (*addr).ip;
        //tcp->dest = (*addr).port;
    
        bpf_trace_printk("AFTER CHANGING\n");
        bpf_trace_printk("src mac address [0-2] : %u %u %u\n", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
        bpf_trace_printk("src mac address [3-5] : %u %u %u\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);
        bpf_trace_printk("dst mac address [0-2] : %u %u %u\n", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
        bpf_trace_printk("dst mac address [3-5] : %u %u %u\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);
        bpf_trace_printk("ip addresses : %u %u\n", ip->saddr, ip->daddr);
        bpf_trace_printk("ports : %u %u\n", tcp->source, tcp->dest);
    
        bpf_l4_csum_replace(skb, TCP_CSUM_OFF, orig_src_ip, dst_ip, flags | sizeof(dst_ip));
        //ip->check = iph_csum(ip);
        bpf_l3_csum_replace(skb, IP_CSUM_OFF, htons(orig_src_ip), htons(dst_ip), 4);
        //bpf_l4_csum_replace(skb, TCP_CSUM_OFF, orig_src_port, dst_port, 2);   
    }
    
    int tc(struct __sk_buff * skb){
        int key=0;
        struct address client_addr, server_addr;
    
        server_addr.ip = IP_ADDRESS(172,17,0,2);
        server_addr.port = 8000;
        
        server_addr.mac[5] = 0x02;
        server_addr.mac[4] = 0x00;
        server_addr.mac[3] = 0x11;
        server_addr.mac[2] = 0xac;
        server_addr.mac[1] = 0x42;
        server_addr.mac[0] = 0x02;
    
        client_addr.ip = IP_ADDRESS(172,17,0,3);
        client_addr.port = 8000;
    
        client_addr.mac[5] = 0x03;
        client_addr.mac[4] = 0x00;
        client_addr.mac[3] = 0x11;
        client_addr.mac[2] = 0xac;
        client_addr.mac[1] = 0x42;
        client_addr.mac[0] = 0x02;
    
        bpf_trace_printk("pckt rcvd\n");
        void *data = (void *)(long)skb->data;
        void *data_end = (void *)(long)skb->data_end;
        struct ethhdr *eth = data;
        if ((void *)eth + sizeof(*eth) <= data_end)
        {
            struct iphdr *ip = data + sizeof(*eth);
            if ((void *)ip + sizeof(*ip) <= data_end)
            {
                if (ip->protocol == IPPROTO_TCP)
                {
                    struct tcphdr *tcp = (void *)ip + sizeof(*ip);
                    if ((void *)tcp + sizeof(*tcp) <= data_end)
                    {
                        if(tcp->dest==ntohs(8000)){
                            uint64_t src_mac, dst_mac;
                            uint32_t src_ip, dst_ip;
                            u16 src_port, dst_port;
                            bpf_trace_printk("BEFORE CHANGING\n");
                            bpf_trace_printk("src mac address [0-2] : %u %u %u\n", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
                            bpf_trace_printk("src mac address [3-5] : %u %u %u\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);
                            bpf_trace_printk("dst mac address [0-2] : %u %u %u\n", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
                            bpf_trace_printk("dst mac address [3-5] : %u %u %u\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);
                            bpf_trace_printk("ip addresses : %u %u\n", ip->saddr, ip->daddr);
                            bpf_trace_printk("ports : %u %u\n", tcp->source, tcp->dest);
    
                            if(eth->h_source[5]==0x03){ //packet from client to server
                                bpf_trace_printk("CLIENT TO LB TO BACKEND\n");
                                change_address_and_update_crc(skb, &server_addr, eth, ip, tcp);
                                //bpf_redirect(6, 0);
                                return TC_ACT_REDIRECT;
                            }
                            else{
                                bpf_trace_printk("BACKEND TO LB TO CLIENT\n");
                                change_address_and_update_crc(skb, &client_addr, eth, ip, tcp);
                               // bpf_redirect(8, 0);
                               return TC_ACT_REDIRECT;
                            }
                        }   
                    }
                }
            }
        }
        return TC_ACT_OK;
    }
    

    I'm not sure what I'm missing. For the checksum, I feel using the bpf helper functions bpf_l4_csum_replace and bpf_l3_csum_replace should be sufficient. In some other articles, I have read not to change the checksum at all.

    opened by RuchiSaluja8 1
  • network.py actually contains C source

    network.py actually contains C source

    Hi! I just stumbled on this awesome repo after watching the eBPF Day presentation! It looks like the network.py file may have been mistakenly added to the repo with the same contents as the network.c file:

    ┌─╼[~/ebpf-networking] [main] 
    └────╼ diff network.c network.py | wc
          0       0       0
    

    Just figured I'd bring this to your attention in case there are other folks who want to follow along with the example here.

    Thanks!

    opened by taspelund 3
Owner
Liz Rice
Open Source @isovalent @cilium | @cncf Technical Oversight Committee chair | O'Reilly Container Security author
Liz Rice
Linux Application Level Firewall based on eBPF and NFQUEUE.

eBPFSnitch eBPFSnitch is a Linux Application Level Firewall based on eBPF and NFQUEUE. It is inspired by OpenSnitch, and Douane, but utilizing modern

Harpo Roeder 641 Jun 17, 2022
eBPF bytecode assembler and compiler

An eBPF bytecode assembler and compiler that * Assembles the bytecode to object code. * Compiles the bytecode to C macro preprocessors. Symbolic

Emil Masoumi 6 Jan 23, 2022
Example how to run eBPF probes without a usermode process using fentry

Pinning eBPF Probes Simple example to demonstrate how to pin kernel function and syscall probes. Overview From my reading of the kernel code, KProbe a

pat_h/to/file 3 Jun 7, 2021
A Rust crate that simplifies the integration of Rust and eBPF programs written in C.

This crate simplifies the compilation of eBPF programs written in C integrating clang with Rust and the cargo build system with functions that can be

Simone Margaritelli 19 Mar 16, 2022
eBPF implementation that runs on top of Windows

eBPF for Windows eBPF is a well-known technology for providing programmability and agility, especially for extending an OS kernel, for use cases such

Microsoft 1.4k Jun 27, 2022
ebpfkit-monitor is a tool that detects and protects against eBPF powered rootkits

ebpfkit-monitor ebpfkit-monitor is an utility that you can use to statically analyse eBPF bytecode or monitor suspicious eBPF activity at runtime. It

Guillaume Fournier 57 Jun 27, 2022
A very basic eBPF Load Balancer in a few lines of C

An eBPF Load Balancer from scratch As seen at eBPF Summit 2021. This is not production ready :-) This uses libbpf as a git submodule. If you clone thi

Liz Rice 137 Jul 2, 2022
skbtracer on ebpf

skbtracer skbtracer 基于 ebpf 技术的 skb 网络包路径追踪利器, 实现代码基于 BCC (required Linux Kernel 4.15+) 使用样例 skbtracer.py # trace

DavadDi 45 Jun 18, 2022
some experiments with ebpf

Learning eBPF and some kernel tracing, probe DNS + TCP connection with portable bpf prog. DevEnv Ubuntu 20.04 Install go Install make, clang, llvm Ins

null 9 Jun 19, 2022
Small utility that leverages eBPF to dump the traffic of a unix domain socket

UnixDump UnixDump is a small eBPF powered utility that can be used to dump unix socket traffic. System requirements This project was developed on a Ub

Guillaume Fournier 5 Dec 1, 2021
Tool for Preventing Data Exfiltration with eBPF

bouheki: Tool for Preventing Data Exfiltration with eBPF bouheki is a KSRI implementation using LSM Hook by eBPF. Flexibility to apply restricted netw

mrtc0 44 Jun 13, 2022
pwru is an eBPF-based tool for tracing network packets in the Linux kernel with advanced filtering capabilities.

pwru (packet, where are you?) pwru is an eBPF-based tool for tracing network packets in the Linux kernel with advanced filtering capabilities. It allo

Cilium 788 Jun 28, 2022
Dectect syscall hooking using eBPF

BPF-HookDetect Detect Kernel Rootkits hooking syscalls Overview Details To Build To Run Example Test Resources Overview Kernel Rootkits such as Diamor

pat_h/to/file 22 May 28, 2022
A collection of eBPF programs demonstrating bad behavior

Bad BPF A collection of malicious eBPF programs that make use of eBPF's ability to read and write user data in between the usermode program and the ke

pat_h/to/file 207 Jun 20, 2022
bpflock - eBPF driven security for locking and auditing Linux machines

bpflock - Lock Linux machines bpflock - eBPF driven security for locking and auditing Linux machines. This is a Work In Progress: bpflock is currently

The Linux lock machine projects 64 Jun 7, 2022
A list of network measurement sketch algorithms implemented in eBPF

eBPF Sketches This repository contains a list of the most famous sketches implemented within the eBPF/XDP subsystem. In particular, we have: Count Ske

null 11 May 22, 2022
A Linux Host-based Intrusion Detection System based on eBPF.

eHIDS 介绍 eBPF内核技术实现的HIDS demo. 功能实现: TCP网络数据捕获 UDP网络数据捕获 uprobe方式的DNS信息捕获 进程数据捕获 uprobe方式实现JAVA的RASP命令执行场景事件捕获 eBPF的go框架实现,针对kprobe\uprobe挂载方式,多类型even

CFC4N 233 Jun 19, 2022
eBPF-based EDR for Linux

ebpf-edr A proof-of-concept eBPF-based EDR for Linux Seems to be working fine with the 20 basic rules implemented. Logs the alerts to stdout at the mo

null 16 May 6, 2022
Parca-agent - eBPF based always-on profiler auto-discovering targets in Kubernetes and systemd, zero code changes or restarts needed!

Parca Agent Parca Agent is an always-on sampling profiler that uses eBPF to capture raw profiling data with very low overhead. It observes user-space

Parca 155 Jun 30, 2022