【ACCESS精品源码栏目提醒】:网学会员为需要ACCESS精品源码的朋友们搜集整理了基于 linux 平台的 libpcap 源代码分析(转)-libpcap入门fgffff - 计算机教材相关资料,希望对各位网友有所帮助!
过滤代码的安装 前面我们曾经提到在内核空间过滤数据包对整个捕获机制的效率是至关重要的。
早期使用 SOCK_PACKET 方式的 Linux 不支持内核过滤因此过滤操作只能在用户空间执行请参阅函数 pcap_read_packet 代码在《UNIX 网络编程第一卷》参考资料 B的第 26 章中对此有明确的描述。
不过现在看起来情况已经发生改变linux 在 PF_PACKET 类型的 socket 上支持内核过滤。
Linux 内核允许我们把一个名为 LPFLinux Packet Filter 的过滤器直接放到 PF_PACKET 类型 socket 的处理过程中过滤器在网卡接收中断执行后立即执行。
LSF 基于BPF机制但两者在实现上有略微的不同。
实际代码如下 / 在包捕获设备上附加 BPF 代码 pcap-linux.c/ static int pcap_setfilter_linuxpcap_t handle struct bpf_program filter ifdef SO_ATTACH_FILTER struct sock_fprog fcode int can_filter_in_kernel int err 0 endif / 检查句柄和过滤器结构的正确性 / if handle return -1 if filter strncpyhandle-errbuf setfilter: No filter specified sizeofhandle-errbuf return -1 / 具体描述如下 / if install_bpf_programhandle filter 0 return -1 / 缺省情况下在用户空间运行过滤器但如果 在内核安装成功则值为 1 / handle-md.use_bpf 0 / 尝试在内核安装过滤器 / ifdef SO_ATTACH_FILTER ifdef USHRT_MAX if handle-fcode.bf_len USHRT_MAX /过滤器代码太长内核不支持 / fprintfstderr Warning: Filter too complex for kerneln fcode.filter NULL can_filter_in_kernel 0 else endif / USHRT_MAX / / linux 内核设置过滤器时使用的数据结构是 sock_fprog 而不是 BPF 的结构 bpf_program 因此应做结构之间的转换 / switch fix_programhandle fcode / 严重错误直接退出 / case -1: default: return -1 / 通过检查但不能工作在内核中 / case 0: can_filter_in_kernel 0 break / BPF 可以在内核中工作 / case 1: can_filter_in_kernel 1 break / 如果可以在内核中过滤则安装过滤器到内核中 / if can_filter_in_kernel if err set_kernel_filterhandle fcode 0 / 安装成功 / handle-md.use_bpf 1 else if err -1 / 出现非致命性错误 / if errno ENOPROTOOPT errno EOPNOTSUPP fprintfstderr Warning: Kernel filter failed: snpcap_strerrorerrno / 如果不能在内核中使用过滤器则去掉曾经可能在此 socket 上安装的内核过滤器。
主要目的是为了避免存在的过滤器对数据包过滤的干扰 / if handle-md.use_bpf reset_kernel_filterhandlepcap-linux.c endif / 把 BPF 代码拷贝到 pcap_t 数据结构的 fcode 上 / int install_bpf_programpcap_t p struct bpf_program fp size_t prog_size / 首先释放可能已存在的 BPF 代码 / pcap_freecodep-fcode / 计算过滤代码的长度分配内存空间 / prog_size sizeoffp-bf_insns fp-bf_len p-fcode.bf_len fp-bf_len p-fcode.bf_insns struct bpf_insn mallocprog_size if p-fcode.bf_insns NULL snprintfp-errbuf sizeofp-errbuf malloc: s pcap_strerrorerrno return -1 / 把过滤代码保存在捕获句柄中 / memcpyp-fcode.bf_insns fp-bf_insns prog_size return 0 / 在内核中安装过滤器 / static int set_kernel_filterpcap_t handle struct sock_fprog fcode int total_filter_on 0 int save_mode int ret int save_errno /在设置过滤器前socket 的数据包接收队列中可能已存在若干数据包。
当设置过滤器后 这些数据包极有可能不满足过滤条件但它们不被过滤器丢弃。
这意味着传递到用户空间的头几个数据包不满足过滤条件。
注意到在用户空间过滤这不是问题因为用户空间的过滤器是在包进入队列后执行的。
Libpcap 解决这个问题的方法是在设置过滤器之前 首先读完接收队列中所有的数据包。
具体步