bpftrace对udp及内核函数dev_queue_xmit及sk_buff的解析
#!/usr/bin/bpftrace
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/socket.h>
kprobe:ip_finish_output2
{
// 获取ip_finish_output2函数的调用次数
@ip_finish_output2[tid]=count();
}
kprobe:udp_sendmsg
{
// 保存tid
@udp_tid[tid]=tid
}
kprobe:__dev_queue_xmit
{
//获取调用次数
@dev_queue_xmit[tid]=count();
@skb[tid]=(struct sk_buff *)arg0;
}
kr:__dev_queue_xmit
/@skb[tid]/
{
// 过滤udp的进程
if (tid == @udp_tid[tid]){
$skb = @skb[tid];
// get IPv4 header; see skb_network_header():
$iph = (struct iphdr *)($skb->head + $skb->network_header);
$sip = ntop(AF_INET, $iph->saddr);
$dip = ntop(AF_INET, $iph->daddr);
//id 为ip数据包标识
$id = (($iph->id & 0x00ff) << 8) | (($iph->id & 0xff00) >> 8);
$tot_len = (($iph->tot_len & 0x00ff) << 8) | (( $iph->tot_len & 0xff00) >> 8);
$frag_off = (($iph->frag_off & 0x001f) << 8) | (($iph->frag_off & 0xff00) >> 8) ;
$udphdr = (struct udphdr *)($skb->head + $skb->transport_header);
// 以下两行不可使用,因为经过一个变量后就取不到想要的端口号,原因未知
$sport = (($udphdr->source & 0x00ff) << 8) | (($udphdr->source & 0xff00) >> 8);
$dport = (($udphdr->dest & 0x00ff) << 8) | (($udphdr->dest & 0xff00) >> 8);
// 过滤目标地址为172.20.101.63的地址
if ($iph->daddr == 0x3f6514ac){
printf("tot_len = %d, $skb->truesize=%d \t", $tot_len, $skb->truesize);
printf("sip %s(%d) \t ---> dip %s(%d), id= %d, frag_off = %d\n", $sip, $sport, $dip, $dport, $id, $frag_off * 8);
}
}
}