Linux下Libpcap源码分析及包过滤机制Word格式.docx
- 文档编号:18414689
- 上传时间:2022-12-16
- 格式:DOCX
- 页数:7
- 大小:17.79KB
Linux下Libpcap源码分析及包过滤机制Word格式.docx
《Linux下Libpcap源码分析及包过滤机制Word格式.docx》由会员分享,可在线阅读,更多相关《Linux下Libpcap源码分析及包过滤机制Word格式.docx(7页珍藏版)》请在冰豆网上搜索。
handle)
return-1;
filter){
strncpy(handle->
errbuf,"
setfilter:
Nofilterspecified"
sizeof(handle->
errbuf));
}
/*具体描述如下*/
if(install_bpf_program(handle,filter)<
0)
/*缺省情况下在用户空间运行过滤器,但如果
在内核安装成功,则值为1*/
handle->
md.use_bpf=0;
/*尝试在内核安装过滤器*/
#ifdefUSHRT_MAX
if(handle->
fcode.bf_len>
USHRT_MAX){
/*过滤器代码太长,内核不支持*/
fprintf(stderr,"
Warning:
Filtertoocomplexforkerneln"
);
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:
/*通过检查,但不能工作在内核中*/
case0:
break;
/*BPF可以在内核中工作*/
case1:
can_filter_in_kernel=1;
/*如果可以在内核中过滤,则安装过滤器到内核中*/
if(can_filter_in_kernel){
if((err=set_kernel_filter(handle,&
fcode))==0)
/*安装成功!
!
*/
md.use_bpf=1;
elseif(err==-1)/*出现非致命性错误*/
if(errno!
=ENOPROTOOPT&
&
errno!
=EOPNOTSUPP){
Kernelfilterfailed:
%sn"
pcap_strerror(errno));
/*如果不能在内核中使用过滤器,则去掉曾经可能在此socket
上安装的内核过滤器。
主要目的是为了避免存在的过滤器对数据包过滤的干扰*/
md.use_bpf)
reset_kernel_filter(handle);
[pcap-Linux.c]
#endif
/*把BPF代码拷贝到pcap_t数据结构的fcode上*/
intinstall_bpf_program(pcap_t*p,structbpf_program*fp)
size_tprog_size;
/*首先释放可能已存在的BPF代码*/
pcap_freecode(&
p->
fcode);
/*计算过滤代码的长度,分配内存空间*/
prog_size=sizeof(*fp->
bf_insns)*fp->
bf_len;
fcode.bf_len=fp->
fcode.bf_insns=(structbpf_insn*)malloc(prog_size);
if(p->
fcode.bf_insns==NULL){
snprintf(p->
errbuf,sizeof(p->
errbuf),
"
malloc:
%s"
pcap_strerror(errno));
return(-1);
/*把过滤代码保存在捕获句柄中*/
memcpy(p->
fcode.bf_insns,fp->
bf_insns,prog_size);
return(0);
/*在内核中安装过滤器*/
staticintset_kernel_filter(pcap_t*handle,structsock_fprog*fcode)
inttotal_filter_on=0;
intsave_mode;
intret;
intsave_errno;
/*在设置过滤器前,socket的数据包接收队列中可能已存在若干数据包。
当设置过滤器后,
这些数据包极有可能不满足过滤条件,但它们不被过滤器丢弃。
这意味着,传递到用户空间的头几个数据包不满足过滤条件。
注意到在用户空间过滤这不是问题,因为用户空间的过滤器是在包进入队列后执行的。
libpcap解决这个问题的方法是在设置过滤器之前,
首先读完接收队列中所有的数据包。
具体步骤如下。
*/
/*为了避免无限循环的情况发生(反复的读数据包并丢弃,
但新的数据包不停的到达),首先设置一个过滤器,阻止所有的包进入*/
setsockopt(handle->
fd,SOL_SOCKET,SO_ATTACH_FILTER,
total_fcode,sizeof(total_fcode);
/*保存socket当前的属性*/
save_mode=fcntl(handle->
fd,F_GETFL,0);
/*设置socket它为非阻塞模式*/
fcntl(handle->
fd,F_SETFL,save_mode|O_NONBLOCK);
/*反复读队列中的数据包,直到没有数据包可读。
这意味着接收队列已被清空*/
while(recv(handle->
fd,&
drain,sizeofdrain,MSG_TRUNC)>
=0);
/*恢复曾保存的socket属性*/
fd,F_SETFL,save_mode);
/*现在安装新的过滤器*/
fcode,sizeof(*fcode));
/*释放socket上可能有的内核过滤器*/
staticintreset_kernel_filter(pcap_t*handle)
intdummy;
returnsetsockopt(handle->
fd,SOL_SOCKET,SO_DETACH_FILTER,
dummy,sizeof(dummy));
Linux在安装和卸载过滤器时都使用了函数setsockopt(),其中标志SOL_SOCKET代表了对socket进行设置,而SO_ATTACH_FILTER和SO_DETACH_FILTER则分别对应了安装和卸载。
下面是Linux2.4.29版本中的相关代码:
[net/core/sock.c]
#ifdefCONFIG_FILTER
caseSO_ATTACH_FILTER:
……
/*把过滤条件结构从用户空间拷贝到内核空间*/
if(copy_from_user(&
fprog,optval,sizeof(fprog)))
/*在socket上安装过滤器*/
ret=sk_attach_filter(&
fprog,sk);
……
caseSO_DETACH_FILTER:
/*使用自旋锁锁住socket*/
spin_lock_bh(&
sk->
lock.slock);
filter=sk->
filter;
/*如果在socket上有过滤器,则简单设置为空,并释放过滤器内存*/
if(filter){
filter=NULL;
spin_unlock_bh(&
sk_filter_release(sk,filter);
ret=-ENONET;
上面出现的sk_attach_filter()定义在net/core/filter.c,它把结构sock_fprog转换为结构sk_filter,最后把此结构设置为socket的过滤器:
filter=fp。
其他代码
libpcap还提供了其它若干函数,但基本上是提供辅助或扩展功能,重要性相对弱一点。
我个人认为,函数pcap_dump_open()和pcap_open_offline()可能比较有用,使用它们能把在线的数据包写入文件并事后进行分析处理。
总结
1994年libpcap的第一个版本被发布,到现在已有11年的历史,如今libpcap被广泛的应用在各种网络监控软件中。
libpcap最主要的优点在于平台无关性,用户程序几乎不需做任何改动就可移植到其它unix平台上;
其次,libpcap也能适应各种过滤机制,特别对BPF的支持最好。
分析它的源代码,可以学习开发者优秀的设计思想和实现技巧,也能了解到(Linux)操作系统的网络内核实现,对个人能力的提高有很大帮助。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux Libpcap 源码 分析 过滤 机制