iovisor / bcc

BCC - Tools for BPF-based Linux IO analysis, networking, monitoring, and more
Apache License 2.0
20.51k stars 3.87k forks source link

Routing from one IP to another is not working #3653

Open arayu05 opened 3 years ago

arayu05 commented 3 years ago

Hi, I tried below code for testing the IP routing of data packets.

iplist.py -

`from bcc import BPF, table
import socket
import struct
import ctypes as ct
import utils
import json
import os
# from ctypes import *
from datetime import datetime
import time
import ipaddress

device = "lo"
src_file = './filter.c'

ip_list = []
ip_list.append(utils.ip_to_uint32('127.0.0.1'))

#open eBPF c source code
with open(src_file, 'r') as f:
    file = ''.join(f.readlines())

b = BPF(text=file)
functions = b.load_func('udpfilter', BPF.XDP)
print("eBPF progam loaded")
b.attach_xdp(device, functions, 0)
print("eBPF program attached")

#load blacklist map
blacklist= b.get_table("iplist")
blacklist.clear()

#put the to block ip addreses in map
for item in ip_list:
    blacklist[ct.c_uint32(item)] =  ct.c_uint32(utils.ip_to_uint32('127.0.0.2')) 

while True:
    try:
        b.trace_print()
        time.sleep(5)
    except KeyboardInterrupt:
        print("Removing filter from device")
        break

b.remove_xdp(device, 0)
print('done')`

filter.c -


`#define KBUILD_MODNAME "filter"
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/udp.h>

BPF_TABLE("percpu_hash", uint32_t, uint32_t, iplist, 6524288);

int udpfilter(struct xdp_md *ctx) {
  bpf_trace_printk("got a packet\n");
  void *data = (void *)(long)ctx->data;
  void *data_end = (void *)(long)ctx->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_UDP) {
        struct udphdr *udp = (void*)ip + sizeof(*ip);
        if ((void*)udp + sizeof(*udp) <= data_end) {
                 uint32_t *value;
        value = iplist.lookup(&(ip->daddr));
        // bpf_trace_printk("%d value\n", *value);
        if(value){
        bpf_trace_printk("ip daddr found in the ip blacklist %lu\n",*value);
        // bpf_trace_printk("port of the  %lu\n",*value);

        // *value += 1;
        ip->daddr = *value;
        bpf_trace_printk("ip daddr changed to %lu\n", ip->daddr);

    }
        }
      }
    }
  }
  return XDP_PASS;
}`

But this is not routing the packet coming at 127.0.0.1 to 127.0.0.2 I tested it with nc (netcat) commands. Is there something wrong in the code?

Also, sometimes it prints correct updated address(127.0.0.2) in uint32 format in ip->daddr and sometimes it randomly prints 0 as updated daddr.

chenhengqi commented 3 years ago

Not pretty sure, but you may need to update the checksum accordingly.

See the BPF helper bpf_csum_update.

arayu05 commented 3 years ago

we tried updating checksum as below, Also tried updating eth header but still the same issue:

if(value){
            //uint32_t new_daddr = *value;
            bpf_trace_printk("old address is: %lu\n", old_daddr);
            bpf_trace_printk("ip daddr found in the ip my_list %lu\n", *value);

            //ethr hdr update
            // eth->h_dest[0] = ;
            // eth->h_dest[1] = ;
            // eth->h_dest[2] = ;
            // eth->h_dest[3] = ;
            // eth->h_dest[4] = ;
            // eth->h_dest[5] = ;

            //ip->tos = 7 << 2;
            ip->daddr = *value;
            ip->check = 0;
            ip->check = checksum((unsigned short *)ip, sizeof(struct iphdr));
            bpf_trace_printk("ip daddr changed to %lu\n", ip->daddr);

            unsigned long sum;
            // Update checksum
            sum = old_daddr + (~ntohs(*(unsigned short *)&ip->daddr) & 0xffff);
            sum += ntohs(udp->check);
            sum = (sum & 0xffff) + (sum>>16);
            udp->check = htons(sum + (sum>>16) - 1);

            }`

Couldn't use bpf_csum_update() and it needs skb buff in the param which is not used in xdp code right? we are using ctx pointer.

chenhengqi commented 3 years ago

@Ayushri-wipro Do you solve this problem ? Or I may spend some time working on it.

arayu05 commented 3 years ago

Hi @chenhengqi I couldn't solve the issue till now. can you please suggest a proper way of doing it?

arayu05 commented 2 years ago

@chenhengqi Can you please suggest if I am doing right. Or else what is the correct way to reroute the packet.