最近对网络编程来了兴趣,开始研究libpcap把自己的一些学习历程写下来,绝对是由浅入深希望对大家有帮助
本文版权所有:doggy(chaujy@x263.net) 欢迎非盈利性转载
任何其他形式的使用请与作者联系
1.入门使用篇
本篇讲述如何抓包
最简单的libpcap抓包程序只要有以下几句就可以了
char ebuf[PCAP_ERRBUF_SIZE];
pcap_t *pd = pcap_open_live("eth0", 68, 0, 1000, ebuf);
建立libpcap捕捉句柄,若出错,ebuf返回错误字串.ebuf可以为NULL(以后同)
struct bpf_program fcode;
pcap_compile(pd, &fcode, NULL, 1, 0);
添写过滤规则串fcode,可以为空(即第三个参数,格式在后面讲到)
pcap_setfilter(pd, &fcode);
给 pd 设置上过滤规则
pcap_loop(pd, 10, eth_printer, NULL);
主循环,开始抓包,共抓10个(由第二个参数指定),抓到包后就进入函数 eth_printer
pcap_close(pd);
结束
这个就是最简单的程序了,其中还有个不明,
在pcap_loop参数 eth_printer的类型是pcap_handler,pcap_handler定义如下:
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
const u_char *);
当然要包含
#include "pcap.h"
编译要加上 -lpcap
至于怎么得到libpcap,还有安装,我就不费话了
本文版权所有:doggy(chaujy@x263.net) 欢迎转载
2.使用进阶篇
刚才我们对程序的要求是能编译通过,能运行成功,现在我们让这个程序实用点吧
2.1 其它几个函数介绍
这几个函数的特点是简单但无关紧要
现在我们隆重退出
char * pcap_lookupdev ( char * errbuf );
这个函数就是查找本机上的网络接口设备,我机器上就返回"eth0",在pcap_open_live之前用,没什么意思吧,反正我是不爱用它
int pcap_lookupnet(char *, bpf_u_int32 *, bpf_u_int32 *, char *);
第一个参数就是pcap_lookupdev返回的接口名,二三参数都是32位无符号数,分别是IP网段和掩码,最后那个参数还是ebuf
int pcap_datalink(pcap_t *);
它返回你的网络类型,如 DLT_EN10MB 就是10M以太网,让人ft的是这些常量定义不在pcap.h中,在哪?自己找找吧;-)
int pcap_snapshot(pcap_t *);
返回最长抓多少字节,就是我们在pcap_open_live中第二个参数设置的
int pcap_stats(pcap_t *, struct pcap_stat *);
计数,共抓了多少过滤掉了多少,看看struct pcap_stat的定义就明白了
struct pcap_stat {
u_int ps_recv; /* number of packets received */
u_int ps_drop; /* number of packets dropped */
u_int ps_ifdrop; /* drops by interface XXX not yet supported */
};
int pcap_major_version(pcap_t *);
int pcap_minor_version(pcap_t *);
版本号,你有用么?
我的eth_printer如下
void eth_printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p)
{
printf("I get one packet! ");
}
简单吧 :*)
2.2 现在的程序(C++)
文件名p.cxx
#ifdef __cplusplus
extern “C” {
#endif
#include
#ifdef __cplusplus
}
#endif
void printer(u_char * user, const struct pcap_pkthdr * h, const u_char * p)
{
printf(”I get one packet! “);
/* 哈哈,我都想喝一杯庆祝一下了! */
}
#define DEFAULT_SNAPLEN 68
/* 别问我为什么是68,我从tcpdump看来的 */
int main()
{
char ebuf[PCAP_ERRBUF_SIZE];
char *device = pcap_lookupdev(ebuf);
bpf_u_int32 localnet, netmask;
pcap_lookupnet(device, &localnet, &netmask, ebuf);
printf(”%u.%u.%u.%u”, localnet&0xff, localnet>>8&0xff,
localnet>>16&0xff, localnet>>24&0xff);
printf(”:%d.%d.%d.%d “, netmask&0xff, netmask>>8&0xff,
netmask>>16&0xff, netmask>>24&0xff);
struct pcap_t *pd = pcap_open_live(device, DEFAULT_SNAPLEN, 0, 1000, ebuf);
if(pcap_datalink(pd) == DLT_EN10MB)
printf(”10Mb以太网 “);
struct bpf_program fcode;
pcap_compile(pd, &fcode, NULL, 1, 0);
pcap_setfilter(pd, &fcode);
pcap_loop(pd, 10, printer, NULL);
struct pcap_stat stat;
pcap_stats(pd, &stat);
printf(”recv %d, drop %d. “, stat.ps_recv, stat.ps_drop);
pcap_close(pd);
}
#gcc p.cxx -lpcap
#./a.out
166.111.168.0:255.255.252.0
10Mb以太网
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
I get one packet!
recv 10, drop 0.
#
重要提示: libpcap 程序需要root权限
费了半天劲显示网段和掩码,抓了10个包,值得吗?
2.3 出错处理
象其它库一样,libpcap 也有自己的错误处理机制,基本上每个函数都有返回值,出错时返回值<0,另外有如下函数
void pcap_perror(pcap_t *, char *);
char *pcap_strerror(int);
char *pcap_geterr(pcap_t *);
前两个和 perror() strerror() 用法相同,最后一个也很简单,在 pcap_t 中有一个成员存了错误字串
struct pcap {
...
char errbuf[PCAP_ERRBUF_SIZE];
};
所以......
于是我们在刚才的程序中加上错误处理
先加一个函数
#include
int err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(-1);
}
之后处理每个函数的异常,在成功建立捕捉句柄pcap_t *pd前,使用ebuf参数
char *device = pcap_lookupdev(ebuf);
if(device == NULL)
err_quit("%s", ebuf);
有了句柄pd后
if(pcap_compile(pd, &fcode, NULL, 1, 0) < 0)
err_quit("%s", pcap_geterr(pd));
注意不是每个函数都是出错返回<0
pcap_datalink(pd)和pcap_snapshot(pd)等可不要这么处理
2.4 参数初步研究
前面使用各函数时,并没有具体说明每个函数的意义,现在来探讨一下
pcap_t * pcap_open_live(char *device, int snaplen, int promisc,
int to_ms, char *ebuf)
device指定设备,snaplen指定最长抓多少字节,ebuf出错信息,前面都说过
promisc指出是否设置为混杂模式(不懂?我也不懂,整个网都听还有什么安全性可言)
to_ms设置超时时间,单位milliseconds
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
cnt为要抓的包数,pcap_loop在正常时抓cnt个包后返回,异常时返回值<0
user是要传入callback()的数据,例如我们把上面的程序修改几行
file://pcap_loop(pd, 10, printer, NULL);
pcap_loop(pd, 10, printer, (u_char*)pd);
再在printer()内加
pcap_stat stat;
pcap_stats((pcap_t*)user, &stat);
printf("recv %d, drop %d. ", stat.ps_recv, stat.ps_drop);
再编译运行后输出为
166.111.168.0:255.255.252.0
10Mb以太网
recv 1, drop 0.
recv 2, drop 0.
recv 3, drop 0.
recv 4, drop 0.
recv 5, drop 0.
recv 6, drop 0.
recv 7, drop 0.
recv 8, drop 0.
recv 9, drop 0.
recv 10, drop 0.
recv 10, drop 0.
int pcap_compile(pcap_t *p, struct bpf_program *program,
char *buf, int optimize, bpf_u_int32 mask)
该函数用于解析过滤规则串buf,填写bpf_program结构.
optimize为1表示对过滤规则进行优化处理
netmask指定子网掩码
buf的格式比较复杂
int pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
把pcap_compile()构造的filter设置到handle上
今天到这里吧,改天有时间再继续
大家早上好,我晚安 :,)
分享到:
相关推荐
struts2简单例子,struts2实例开发
java web 学习简单实例
canvas简单实例详解
springmvc4简单例子,springmvc例子,适合学习。。。。。。
AJAX简单实例,AJAX简单实例,AJAX简单实例
spring的aop简单例子spring的aop简单例子spring的aop简单例子spring的aop简单例子
html5 简单实例源代码
struts2的简单实例struts2的简单实例struts2的简单实例struts2的简单实例struts2的简单实例
java中使用session购物车的简单例子,本代码是基于servlet的简单实例,帮助理解session原理。
Ajax最简单例子,一个例子让你明白Ajax原理,XMLHttpRequest原理 var http_request = false; function createRequest(url) { http_request = false; if (window.XMLHttpRequest) { // Mozilla浏览器 ...
delphi7操作SQL数据库简单实例.pdf
通过实例,讲解JavaBean入门的概念和简单例子。入门专用。希望喜欢。
css 简单例子 div css 简单例子 div css 简单例子 div
这是关于delphi应用的简单实例(包含多个例子)。
ARM学习简单例子,初学者适用 ARM学习简单例子,初学者适用,引导部分简单有注释
Java简单实例 Java简单实例 Java简单实例 Java简单实例 Java简单实例 Java简单实例
springmvc注解简单实例,本例子从dao层service层controller层,层层采用注解形式,层层调用,紧密相连,通过这个简单的例子我相信大家会对springmvc又一个整体大概的了解
jquery简单实例代码,适合初学者入门。
spring-Security简单例子,实现了对登录,访问权限的一些简单认证