I've hooked tcp_cleanup_rbuf() and I'm trying to get the IP and port information out of the skb queue. But it seems to be empty. Is that correct? Has it already been free'd at that point?
Here is a shell script that I'm testing with. Fix the path to your own kernel source directory, run it and also run an ncat --keep-open --listen 0.0.0.0 5555
and a ncat <server IP> 5555
.
clear && bpftrace -e '
#include "/usr/src/kernels/3.10.0-957.el7.x86_64/include/net/sock.h"
#include "/usr/src/kernels/3.10.0-957.el7.x86_64/include/net/tcp.h"
#include "/usr/src/kernels/3.10.0-957.el7.x86_64/include/net/ip.h"
#include "/usr/src/kernels/3.10.0-957.el7.x86_64/include/linux/skbuff.h"
// static void tcp_cleanup_rbuf(struct sock *sk, int copied)
// https://elixir.bootlin.com/linux/v4.9/source/net/ipv4/tcp.c#L1416
//
kprobe:tcp_cleanup_rbuf / comm == "ncat" /
{
$sock = (struct sock *) arg0;
$skb = (struct sk_buff *) $sock->sk_receive_queue.next;
$queue = (struct sk_buff_head *)$sock->sk_receive_queue;
printf("%p \t", $queue);
printf("%p \n", (struct sk_buff *) $sock->sk_receive_queue);
printf("%p \n", $queue->next);
printf("%p \n", $queue->prev);
printf("%u %u\n", $queue->qlen, arg1);
if(1)
{
$iph = (struct iphdr *)($skb->head + $skb->network_header); // https://elixir.bootlin.com/linux/v4.9/source/include/uapi/linux/ip.h#L85
$th = (struct tcphdr *)($skb->head + $skb->transport_header); // https://elixir.bootlin.com/linux/v4.9/source/include/uapi/linux/tcp.h#L24
$proto = $iph->protocol; // 6 - TCP 17 - UDP https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
$ipv = $iph->version; // 4 - IPv4 6 - IPv6
$size = (($iph->tot_len >> 8) | (($iph->tot_len & 0xff) << 8)) - ($th->doff * 4) - ($iph->ihl * 4);
printf("%s\t%u\t",
comm,
pid
);
printf("%s:%u\t>\t%s:%u\t%u\n",
ntop($iph->saddr),
(uint16)($th->source << 8) | ($th->source >> 8),
ntop($iph->daddr),
(uint16)($th->dest << 8) | ($th->dest >> 8),
$size
);
}
}'
If anybody knows if I did anything wrong or a better function to hook, I'd be very appreciative.