`
isiqi
  • 浏览: 16031040 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

对网络库libpcap的一点心得

阅读更多

作 者: 网络骑士
来 源: 红客中国


libpcap是一个与实现无关的访问操作系统所提供的分组捕获机制的分组捕获函数库,用于访问数据链路层。用它来写嗅探程序真是方便到爽!象在局域网里嗅探其他机器上的qq号码啊什么的……绝对方便!而且还不受平台的限制。

这个库为不同的平台提供了一致的编程接口,在安装了 libpcap 的平台上,以 libpcap 为接口写的程序、应用,能够自由的跨平台使用。操作系统所提供的分组捕获机制主要有三种:BPF(Berkeley Packet Filter),DLPI(Data Link Provider Interface),及Linux下的SOCK_PACKET类型套接口。基于 BSD 的系统使用 BPF,基于 SVR4 的系统一般使用DLPI。从文献上看BPF比DLPI性能好很多,而SOCK_PACKET更弱。SCO OpenServer 虽然本身没有内核过滤模块 BPF,但有作为可压入内核的 STREAMS 模块 BPF,采用与伯克利 BPF 相一致的概念。但在 ioctl 操作上,SCO 的 BPF 并不完全提供伯克利 BPF 的所有功能。

3.2 libpcap 函数库源码基本架构 libpcap 的结构是简单的。但对于初学者来说,分析其结构能使我们对稍大的程序的编写基本思路有一定了解。首先,为了提供跨平台兼容性,源码中并没有 Makefile ,而是要运行一个 configure 脚本来自动生成 Makefile,congfigure 脚本一方面检测系统特征,以确定当前系统及一些相关配置;另一方面读取已写好的 Makefile.in 文件,以此为蓝本,生成一个适用于当前平台的 Makefile 。


libpcap 共有二十多个 C 程序文件。我们将其按功能分组,来看看他们是如何紧密合作的。


1、打开、读取设备,设置过滤器部分。这一部分集中了所有与具体系统监听方式密切相关的函数,也就是最底层直接与具体设备打交道的部分。设计者将其独立出来,因此要在加入对新的系统的支

持,仅需要修改这一部分即可,这是非常漂亮的想法。我亲自体会了给这一个库加入对 SCO OpenServer 的支持的体验,深深感觉到了这一结构安排的好处。这一部分主要提供三个函数:pcap_read(), pcap_open_live(), pcap_setfilter()。文件形式为 pcap-*.c ,比如 pcap-bpf.c, pcap-dlpi.c, pcap-linux.c, pcap-nit.c及我写的 pcap-sco.c 等等。在 Makefile 里实际只包含了这其中的一个文件,而具体选择哪个文件到 Makefile 里去,就是 configure 脚本的功能。我写完 pcap-sco.c 后,修改 configure 脚本,使之能够检测到 SCO 系统,生成相应的 Makefile ,再 make ,安装,一个功能复杂强大的函数库,被略加改动就顺利的能够运行在自己的平台上。这一思想真是太绝妙了!

2、编译、优化、调试过滤规则表达式部分。这一部分又是 libpcap 的一个设计精彩的地方。简直就是一个计算机系统的微缩翻版,让人赞叹设计者对计算机系统的深入理解及灵活应用。


过滤机制采用了伪机器的方式,参看前面对 BPF 过滤器的基本介绍。正如前面介绍的,BPF 过滤器程序和实际机器语言有很多相似之处。一条指令(即结构 bpf_insn) 具有操作码(code),操作数(jt,jf),等等。设计者还提供了一系列的宏来书写代码,这正是 BPF 编码的“汇编语言”。正因如此,BPF 程序的编写也具有所有低级语言的弱点:编程太复杂。甚至跳转语句都要让你去一条一条的数需要跳过多少条语句。我以前从没有写过机器代码,但写了一点 BPF 的代码,对机器代码编写的难度也可见一二了。让使用者学习使用这些代码的编写方法会分散他们的精力,使用者当然需要更为简单易用,好理解的接口。因此,正如高级语言的产生一样,有了过滤规则表达式,使用这种表达式就直观、易理解多了。完成编译及优化的程序文件为:gencode.c, grammar.c, scanner.c, optimize.c ,这一部分将输入的过滤规则表达式编译为 BPF 代码,存入 bpf_program 结构,再用 pcap_setfilter() 来加载程序。


Libpcap

甚至还提供了“反汇编”的函数 bpf_image() ,定义在 bpf_image.c 中。Pcap_compile() 函数编译完后的代码以二进制的形式存放在 struct bpf_program 中,如果需要修正过滤规则表达式,可以调用 bpf_image() 将二进制代码“反汇编”成“汇编语言”的形式,下面是一段“反汇编”结果:( 对应的过滤规则表达式为:src host 192.168.0.1 and tcp[13:1] & 2 != 0 )

(000) ldh [12]

(001) jeq #0x800 jt 2 jf 12

(002) ld [26]

(003) jeq #0xc0a80001 jt 4 jf 12

(004) ldb [23]

(005) jeq #0x6 jt 6 jf 12

(006) ldh [20]

(007) jset #0x1fff

jt 12 jf 8
(008) ldxb 4*([14]&0xf)

(009) ldb [x + 27]

(010) jset #0x2 jt 11 jf 12

(011) ret #1000

(012) ret #0


非常有趣!如果懂得 BPF 程序的编码规则,还能直接修改这段代码,以获得你想要的结果。


3、脱机方式监听部分。Libpcap 支持脱机监听。即先将网络上的数据截获下来,存到磁盘上,再以后方便时从磁盘上获取数据来做分析。主要函数为 pcap_open_offline(), pcap_offline_read (),定义在文件 savefile.c 中。


4、本地网络设置检测部分。包括检测网络用的 pcap_lookupdev(), pcap_lookupnet() 等函数,包含在文件 inet.c 中。主要实现方式是打开套接口(socket),然后调用一系列的 SIO* ioctl 来获取套接口状态,以达到检测 TCP/IP 一层网络设置的目的。以各种系统的 socket 接口已有统一的规范,所以是跨平台兼容的。而不必象对数据链路层的访问一样为不同的平台编写不同的代码。


也包括名字地址相互转换部分的函数。实现的程序文件为:etherent.c, nametoaddr.c 。


5、主控程序及版本部分。主控程序所在文件为 pcap.c 。这一文件定义了读数据的对外统一接口 pcap_next(),获取当前错误消息的 pcap_geterr() 等函数。用户无论是用实时

还是脱机方式打开设备,都调用 pcap_next() 获取下一个包的数据。

版本声明部分为 version.c。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics