linux 下的 包过滤器 BPF

来源:互联网 发布:mysql python.tar.gz 编辑:程序博客网 时间:2024/05/29 18:39

一, 导论

    BPF(Berkeley Packet Filter)伯克利包过滤器。 是在linux 平台下的一个包过滤器。使用此过滤器可以在socket编程时非常方便的实现各种过滤规则。

    首先,要确保从socket中读取的是packet,也就是说是 MAC头+IP头+TCP/UDP头。

    关于BPF的相关介绍可以查看英文文档:http://www.gsp.com/cgi-bin/man.cgi?section=4&topic=bpf#1

二, BPF的使用

    首先来看一段实际应用中的代码:

int init_packet_capture(struct lib_cap *p){int sock = -1;struct sock_fprog Filter;struct sockaddr_ll sll;// tcpdump -dd ether proto 0x8033struct sock_filter bpf_code [] = {{0x20, 0, 0, 0x0000000c},{0x15, 0, 1, 0x00000033},{0x6, 0, 0, 0x00000200},{0x6, 0, 0, 0x00000000}};if (NULL == p) {return -1;}// init filter settings Filter.len =4;Filter.filter = bpf_code;//set default valuep->ifindex = -1;p->fd = -1;p->buffer = NULL;p->buf_len = 0;if ( (sock = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_SADP))) < 0){return -1;}if ( setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)) < 0); ....}

以上代码首先定义并初始化了一个bpf过滤器 Filter, 然后将其 SO_ATTACH_FILTER 到了socket 上。

这里用到了两个结构体:sock_fprog和sock_filter:

sock_fprog

struct sock_fprog{        unsigned short      len;        struct sock_filter    *filter;}
sock_filter

struct sock_filter{__u16code;/* actual filter code */__8jt;/* jump true */__8jf;/* jump false*/__u32k;/* Generic multiuse field */}

知道以上两个结构体后,整段代码就比较清晰了, 唯一比较费解的是那一串数字!!!

struct sock_filter bpf_code [] = {{0x20, 0, 0, 0x0000000c},{0x15, 0, 1, 0x00000033},{0x6, 0, 0, 0x00000200},{0x6, 0, 0, 0x00000000}};
下面将分析这一串数字是如何产生的,以及它的意义。

三, BPFcode 生成方法

    在注释中有一段提示 tcpdump -dd ether proto 0x8033。 

tcpdump 是linux 中调试网络的一个工具, 实际上tcpdump 就是用利用BPF原理编写的一个工具,所以tcpdump 提供了一个生成bpf code 的一个命令行:


这段数字的意义就是过滤以太网协议中类型是 0x8033的数据包(某某IT公司的产品自定义的一个数据包)。这段数字到底实现了什么功能呢? tcpdump 提供了 -d 选项来阐述这段数字的意义:


分析这段代码可知,

 ldh 是高位加载, 即从帧的第12位开始加载进内存,第12位就是去除6位src mac 与 6位 dst mac 的数据报类型字段。

jeq: 如果类型字段是 0x8033 的话就返回 96个字节,如果类型字段不是 0x8033的话就返回 0个字节。

至此就已达到过滤类型为0x8033数据包的目的。

小结:

        细心的朋友可能会发现,bpf_code 数组的第三行最后一列 0x00000060 与源代码中的 0x00000020 并不一样!这是因为tcpdump 的默认返回字节是96个字节, 而实际需要抓取512(0x00000200, 16*16*2)个字节的数据。关于这点给tcpdump 指定长度字段-s就可以了:


      linux 下的 BPF 是包过滤的利器, 结合tcpdump 工具,能非常快速的实现各种个性化的包过滤需求! 



1 0
原创粉丝点击