如何使用BPF访问内核变量?

时间:2017-05-29 16:54:16

标签: linux-kernel kernel bpf

例如,要访问函数skb中的ip_rcv变量:

int ip_rcv(struct sk_buff *skb, struct net_device *dev,
           struct packet_type *pt, struct net_device *orig_dev)
{
...
}

我在互联网上搜索但找不到任何例子。

2 个答案:

答案 0 :(得分:0)

使用BPF拦截内核函数的最简单方法可能是使用bcc。它提供了一个更高级别的Python API,用于在内核中加载BPF程序并与之交互:

#!/usr/bin/env python
from bcc import BPF

BPF(text="""
int kprobe__ip_rcv(struct pt_regs *ctx, struct sk_buff *skb) {
    bpf_trace_printk("skb=%p!\\n", skb);
    return 0;
}
""").trace_print()

返回:

      <idle>-0     [007] d.s.  1441.065248: : skb=ffff906b2bd53400!
      <idle>-0     [007] d.s.  1442.267325: : skb=ffff906b76c5b700!
      <idle>-0     [007] d.s.  1442.993894: : skb=ffff906b42b76800!
      <idle>-0     [007] d.s.  1443.194334: : skb=ffff906be925d300!
      <idle>-0     [007] d.s.  1444.616469: : skb=ffff906b67e6a200!

有关详细信息,请参阅密件抄送存储库中的the tutorial

如果您不想使用密件抄送,可以在Linux内核中找到examples of BPF programs。特别是,我邀请您研究tracex1_kern/user.c

答案 1 :(得分:0)

您还可以通过将其附加到原始套接字(例如,下面的程序尝试过滤和解析HTTP数据包)来访问它。 C BPF程序应如下所示:

int http_filter(struct __sk_buff * skb){

u8 *cursor = 0;

struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
//filter IP packets (ethernet type = 0x0800)
if (!(ethernet->type == 0x0800)) {
    goto DROP;
}

struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
//filter TCP packets (ip next protocol = 0x06)
if (ip->nextp != IP_TCP) {
    goto DROP;
}

u32  tcp_header_length = 0;
u32  ip_header_length = 0;
u32  payload_offset = 0;
u32  payload_length = 0;
struct Key  key;
struct Leaf zero = {0};

    //calculate ip header length
    //value to multiply * 4
    //e.g. ip->hlen = 5 ; IP Header Length = 5 x 4 byte = 20 byte
    ip_header_length = ip->hlen << 2;    //SHL 2 -> *4 multiply

    //check ip header length against minimum
    if (ip_header_length < sizeof(*ip)) {
            goto DROP;
    }

    //shift cursor forward for dynamic ip header size
    void *_ = cursor_advance(cursor, (ip_header_length-sizeof(*ip)));

struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));

//retrieve ip src/dest and port src/dest of current packet
//and save it into struct Key
key.dst_ip = ip->dst;
key.src_ip = ip->src;
key.dst_port = tcp->dst_port;
key.src_port = tcp->src_port;

//calculate tcp header length
//value to multiply *4
//e.g. tcp->offset = 5 ; TCP Header Length = 5 x 4 byte = 20 byte
tcp_header_length = tcp->offset << 2; //SHL 2 -> *4 multiply

//calculate payload offset and length
payload_offset = ETH_HLEN + ip_header_length + tcp_header_length;
payload_length = ip->tlen - ip_header_length - tcp_header_length;

//http://stackoverflow.com/questions/25047905/http-request-minimum-size-in-bytes
//minimum length of http request is always geater than 7 bytes
//avoid invalid access memory
//include empty payload
if(payload_length < 7) {
    goto DROP;
}

//load first 7 byte of payload into p (payload_array)
//direct access to skb not allowed
unsigned long p[7];
int i = 0;
for (i = 0; i < 7; i++) {
    p[i] = load_byte(skb , payload_offset + i);
}

}

附加程序的Python脚本应如下所示: 而1:   #从套接字检索原始数据包   packet_str = os.read(socket_fd,4096)