Linux下Libpcap源码分析和包过滤机制[4]

上传人:re****.1 文档编号:561084226 上传时间:2024-02-09 格式:DOC 页数:6 大小:36KB
返回 下载 相关 举报
Linux下Libpcap源码分析和包过滤机制[4]_第1页
第1页 / 共6页
Linux下Libpcap源码分析和包过滤机制[4]_第2页
第2页 / 共6页
Linux下Libpcap源码分析和包过滤机制[4]_第3页
第3页 / 共6页
Linux下Libpcap源码分析和包过滤机制[4]_第4页
第4页 / 共6页
Linux下Libpcap源码分析和包过滤机制[4]_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《Linux下Libpcap源码分析和包过滤机制[4]》由会员分享,可在线阅读,更多相关《Linux下Libpcap源码分析和包过滤机制[4](6页珍藏版)》请在金锄头文库上搜索。

1、 .wd.过滤代码的安装前面我们曾经提到,在内核空间过滤数据包对整个捕获机制的效率是至关重要的。早期使用 SOCK_PACKET 方式的 Linux 不支持内核过滤,因此过滤操作只能在用户空间执行请参阅函数 pcap_read_packet() 代码,在?UNIX 网络编程(第一卷)?参考资料 B的第 26 章中对此有明确的描述。不过现在看起来情况已经发生改变,Linux 在 PF_PACKET 类型的 socket 上支持内核过滤。Linux 内核允许我们把一个名为 LPF(Linux Packet Filter) 的过滤器直接放到 PF_PACKET 类型 socket 的处理过程中,过滤

2、器在网卡接收中断执行后立即执行。LSF 基于BPF机制,但两者在实现上有略微的不同。实际代码如下:/* 在包捕获设备上附加 BPF 代码 pcap-Linux.c*/static intpcap_setfilter_Linux(pcap_t *handle, struct bpf_program *filter)#ifdef SO_ATTACH_FILTERstruct sock_fprogfcode;int can_filter_in_kernel;int err = 0;#endif/* 检查句柄和过滤器构造的正确性 */if (!handle)return -1;if (!filter)

3、 strncpy(handle-errbuf, setfilter: No filter specified,sizeof(handle-errbuf);return -1;/* 具体描述如下 */ if (install_bpf_program(handle, filter) md.use_bpf = 0;/* 尝试在内核安装过滤器 */#ifdef SO_ATTACH_FILTER#ifdef USHRT_MAXif (handle-fcode.bf_len USHRT_MAX) /*过滤器代码太长,内核不支持 */fprintf(stderr, Warning: Filter too c

4、omplex for kerneln);fcode.filter = NULL;can_filter_in_kernel = 0; else#endif /* USHRT_MAX */* Linux 内核设置过滤器时使用的数据构造是 sock_fprog,而不是 BPF 的构造 bpf_program ,因此应做构造之间的转换 */switch (fix_program(handle, &fcode) /* 严重错误,直接退出 */case -1:default: return -1;/* 通过检查,但不能工作在内核中 */case 0: can_filter_in_kernel = 0;br

5、eak;/* BPF 可以在内核中工作 */case 1: can_filter_in_kernel = 1;break;/* 如果可以在内核中过滤,则安装过滤器到内核中 */if (can_filter_in_kernel) if (err = set_kernel_filter(handle, &fcode) = 0)/* 安装成功 ! */handle-md.use_bpf = 1;else if (err = -1)/* 出现非致命性错误 */if (errno != ENOPROTOOPT & errno != EOPNOTSUPP) fprintf(stderr, Warning:

6、 Kernel filter failed: %sn,pcap_strerror(errno);/* 如果不能在内核中使用过滤器,则去掉曾经可能在此 socket上安装的内核过滤器。主要目的是为了防止存在的过滤器对数据包过滤的干扰 */if (!handle-md.use_bpf)reset_kernel_filter(handle);pcap-Linux.c#endif /* 把 BPF 代码拷贝到 pcap_t 数据构造的 fcode 上 */int install_bpf_program(pcap_t *p, struct bpf_program *fp)size_t prog_size

7、;/* 首先释放可能已存在的 BPF 代码 */ pcap_freecode(&p-fcode);/* 计算过滤代码的长度,分配内存空间 */prog_size = sizeof(*fp-bf_insns) * fp-bf_len;p-fcode.bf_len = fp-bf_len;p-fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);if (p-fcode.bf_insns = NULL) snprintf(p-errbuf, sizeof(p-errbuf),malloc: %s, pcap_strerror(errno);ret

8、urn (-1);/* 把过滤代码保存在捕获句柄中 */memcpy(p-fcode.bf_insns, fp-bf_insns, prog_size);return (0);/* 在内核中安装过滤器 */static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode)int total_filter_on = 0;int save_mode;int ret;int save_errno;/*在设置过滤器前,socket 的数据包接收队列中可能已存在假设干数据包。当设置过滤器后,这些数据包极有可能不满足过滤条件,但它们

9、不被过滤器丢弃。这意味着,传递到用户空间的头几个数据包不满足过滤条件。注意到在用户空间过滤这不是问题,因为用户空间的过滤器是在包进入队列后执行的。libpcap 解决这个问题的方法是在设置过滤器之前,首先读完接收队列中所有的数据包。具体步骤如下。*/ /*为了防止无限循环的情况发生反复的读数据包并丢弃,但新的数据包不停的到达,首先设置一个过滤器,阻止所有的包进入 */ setsockopt(handle-fd, SOL_SOCKET, SO_ATTACH_FILTER,&total_fcode, sizeof(total_fcode);/* 保存 socket 当前的属性 */save_mod

10、e = fcntl(handle-fd, F_GETFL, 0);/* 设置 socket 它为非阻塞模式 */fcntl(handle-fd, F_SETFL, save_mode | O_NONBLOCK);/* 反复读队列中的数据包,直到没有数据包可读。这意味着接收队列已被清空 */while (recv(handle-fd, &drain, sizeof drain, MSG_TRUNC) = 0);/* 恢复曾保存的 socket 属性 */fcntl(handle-fd, F_SETFL, save_mode);/* 现在安装新的过滤器 */setsockopt(handle-fd

11、, SOL_SOCKET, SO_ATTACH_FILTER,fcode, sizeof(*fcode);/* 释放 socket 上可能有的内核过滤器 */static int reset_kernel_filter(pcap_t *handle)int dummy;return setsockopt(handle-fd, SOL_SOCKET, SO_DETACH_FILTER,&dummy, sizeof(dummy);Linux 在安装和卸载过滤器时都使用了函数 setsockopt(),其中标志SOL_SOCKET 代表了对 socket 进展设置,而 SO_ATTACH_FILTE

12、R 和 SO_DETACH_FILTER 则分别对应了安装和卸载。下面是 Linux 2.4.29 版本中的相关代码:net/core/sock.c#ifdef CONFIG_FILTERcase SO_ATTACH_FILTER:/* 把过滤条件构造从用户空间拷贝到内核空间 */if (copy_from_user(&fprog, optval, sizeof(fprog)break;/* 在 socket 上安装过滤器 */ret = sk_attach_filter(&fprog, sk);case SO_DETACH_FILTER:/* 使用自旋锁锁住 socket */spin_lo

13、ck_bh(&sk-lock.slock);filter = sk-filter;/* 如果在 socket 上有过滤器,则简单设置为空,并释放过滤器内存 */if (filter) sk-filter = NULL;spin_unlock_bh(&sk-lock.slock);sk_filter_release(sk, filter);break;spin_unlock_bh(&sk-lock.slock);ret = -ENONET;break;#endif上面出现的 sk_attach_filter() 定义在 net/core/filter.c,它把构造sock_fprog 转换为构造

14、 sk_filter, 最后把此构造设置为 socket 的过滤器:sk-filter = fp。其他代码libpcap 还提供了其它假设干函数,但 根本上是提供辅助或扩展功能,重要性相对弱一点。我个人认为,函数 pcap_dump_open() 和 pcap_open_offline() 可能比较有用,使用它们能把在线的数据包写入文件并事后进展分析处理。总结1994 年libpcap 的第一个版本被发布,到现在已有 11 年的历史,如今libpcap 被广泛的应用在各种网络监控软件中。libpcap 最主要的优点在于平台无关性,用户程序几乎不需做任何改动就可移植到其它 unix 平台上;其次,libpcap也能适应各种过滤机制,特别对BPF的支持最好。分析它的源代码,可以学习开发者优秀的设计思想和实现技巧,也能了解到Linux操作系统的网络内核实现,对个人能力的提高有很大帮助。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 国内外标准规范

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号