0

I want to somehow redirect packets using ebpf. Took an example from the Cilium documentation: Implementation: proxy via bpf

here is an example of my macro in bpf_helpers:

...
static int (*bpf_csum_diff)(void *from, __u64 from_size, void *to, __u64 to_size, __u64 seed) = (void*) // NOLINT
     BPF_FUNC_csum_diff;
...

here is the code of the proxy script itself:

#include <linux/bpf.h>
#include "../main/bpf_helpers.h"
#include "../main/bpf_endian.h"
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/types.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <stdlib.h>
#include "../main/utils_helpers.h"
#include <stddef.h>
#include <linux/pkt_cls.h>

SEC("socket_filter")
int proxy(struct __sk_buff *skb)
{
    const __be32 cluster_ip = 0x846F070A; // 10.7.111.132
    const __be32 pod_ip = 0x0529050A;     // 10.5.41.5

    const int l3_off = ETH_HLEN;    // IP header offset
    const int l4_off = l3_off + 20; // TCP header offset: l3_off + sizeof(struct iphdr)
    __be32 sum;                     // IP checksum

    void *data = (void *)(long)skb->data;
    void *data_end = (void *)(long)skb->data_end;
    if (data_end < data + l4_off) { // not our packet
        return TC_ACT_OK;
    }

    struct iphdr *ip4 = (struct iphdr *)(data + l3_off);
    if (ip4->daddr != cluster_ip || ip4->protocol != IPPROTO_TCP /* || tcp->dport == 80 */) {
        return TC_ACT_OK;
    }

    // DNAT: cluster_ip -> pod_ip, then update L3 and L4 checksum
    sum = bpf_csum_diff((void *)&ip4->daddr, 4, (void *)&pod_ip, 4, 0);
    bpf_csum_diff((void *)&ip4->daddr, 4, (void *)&pod_ip, 4, 0);
    bpf_skb_store_bytes(skb, l3_off + offsetof(struct iphdr, daddr), (void *)&pod_ip, 4, 0);
    bpf_l3_csum_replace(skb, l3_off + offsetof(struct iphdr, check), 0, sum, 0);
    bpf_l4_csum_replace(skb, l4_off + offsetof(struct tcphdr, check), 0, sum, BPF_F_PSEUDO_HDR);

    return TC_ACT_OK;
}

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

Here is the code of the proxy script itself:

...
2020/06/02 21:58:17 sf.Load(): %vebpf_prog_load() failed: 0: (b7) r2 = 86574346
1: (63) *(u32 *)(r10 -4) = r2
2: (61) r2 = *(u32 *)(r1 +80)
invalid bpf_context access off=80 size=4
processed 3 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
...

Tell me how to correctly proxy packets to another port and another ip in docker?

Qeole
  • 8,284
  • 1
  • 24
  • 52
  • That's weird. The verifier seems to be complaining about `skb->data_end` which is correct as far as I can see. How did you load and attach that program? – pchaigno Jun 02 '20 at 20:09
  • You are loading your program as a `socket_filter`, which does not have _direct packet access_. Please refer to [this question](https://stackoverflow.com/questions/61702223/bpf-verifier-rejects-code-invalid-bpf-context-access) and its answer. – Qeole Jun 02 '20 at 20:36
  • it is possible to recalculate the checksum of the package bpf_csum_diff ((void *) & ip4-> daddr, 4, (void *) & pod_ip, 4, 0); using __sk_buff without access to the package? I download the program using goebpf, so I can not load the program into another section. – Alexandr Ershov Jun 03 '20 at 05:12
  • I'm not sure I understood your question. Why not attach your program as a TC filter instead of a socket filter? It would probably be more flexible and possibly better suited to what you are trying to achieve? – Qeole Jun 03 '20 at 09:03

0 Answers0