0

I am trying to write a small program that leverages Linux's tracepoints sys_enter_recvfrom and sys_enter_sendto to display the pairs of HTTP requests and responses that occur on the system.

First of all, I defined the following C structure that can hold an HTTP Object, so either a request or a response:

struct http_obj {
        char comm[TASK_COMM_LEN];
        int fd;
        char *buff;
        char *addr_data;
        int size;
};

Following are my tracepoints:

TRACEPOINT_PROBE(syscalls, sys_enter_recvfrom) {
    return do_trace(args, args->fd, args->ubuf, args->addr);
}

TRACEPOINT_PROBE(syscalls, sys_enter_sendto){
    return do_trace(args, args->fd, args->buff, args->addr);
}

Following is the function that gets the args of the sys_enter_<syscall> tracepoint:

static inline int do_trace(void* ctx, int fd, char *ubuf, struct sockaddr *addr)
{
    // Built event for userland
    struct http_obj evt = {};
    bpf_get_current_comm(evt.comm, TASK_COMM_LEN);
    evt.fd = fd;    
    evt.buff = (char *) ubuf;
    evt.size = sizeof(ubuf);
    evt.addr_data = (char *) addr->sa_data;
    // send to userland
    http_obj.perf_submit(ctx, &evt, sizeof(evt));

    return 0;
}

Using the bcc library in python, I am simply printing the values of the fields that are sent to userland. The problem is that the buffer and the address of the event are always empty. Note that the fields exist, if we do a cat on /sys/kernel/debug/tracing/events/syscalls/sys_enter_recvfrom, we get:

field:int __syscall_nr; offset:8;   size:4; signed:1;
    field:int fd;   offset:16;  size:8; signed:0;
    field:void __attribute__((user)) * buff;    offset:24;  size:8; signed:0;
    field:size_t len;   offset:32;  size:8; signed:0;
    field:unsigned int flags;   offset:40;  size:8; signed:0;
    field:struct sockaddr __attribute__((user)) * addr; offset:48;  size:8; signed:0;
    field:int addr_len; offset:56;  size:8; signed:0;

Any recommendations?

Odess4
  • 420
  • 5
  • 17

1 Answers1

1

The problem is that the buffer and the address of the event are always empty.

This is not unexpected, what you are seeing are the arguments from userspace that are passed to the kernel via a syscall. The buffer is empty since the kernel is supposed to write packet contents into it after this tracepoint has been ran. The address is an optional field, and is allowed to be empty according to the man page of recvfrom:

  If  the  caller  is  not  interested in the source address, src_addr and addrlen should be specified as NULL.

I recommend using TC programs to inspect traffic

Dylan Reimerink
  • 5,874
  • 2
  • 15
  • 21