1.2 关键数据结构pcap结构体
结构体pcap是
一个已打开捕捉实例的描述符。该结构体对用户来说是不透明的,它通过
wpcap.dll
提供的函数,维护它的内容。此处只说明
WIN32
平台下使用的成员。
typedef
struct pcap pcap_t;
struct
pcap {
ADAPTER *adapter;
LPPACKET Packet;
int nonblock;
int snapshot;
int linktype; /*
网络链路的类型 */
int linktype_ext; /*linktype
成员的扩展信息*/
int tzoff; /*
时区偏移*/
int offset; /*
正确对齐的偏移*/
int activated; /*
如果捕获已经准备好开始,为true*/
int oldstyle; /*
如果使用pcap_open_live()*/
int break_loop; /*
用来强制从数据包循环读取中退出的标志*/
struct pcap_sf sf;
struct pcap_md md;
struct pcap_opt opt;
/*
读缓冲区*/
int bufsize;
u_char *buffer;
u_char *bp;
int cc;
/*pcap_next()
的位置持有者*/
u_char *pkt;
/*
只接收这方向/这些方向的数据包*/
pcap_direction_t direction;
/*
*
各种方法,具体定义参见后续内容
*/
activate_op_t activate_op;
can_set_rfmon_op_t can_set_rfmon_op;
read_op_t read_op;
inject_op_t inject_op;
setfilter_op_t setfilter_op;
setdirection_op_t setdirection_op;
set_datalink_op_t set_datalink_op;
getnonblock_op_t getnonblock_op;
setnonblock_op_t setnonblock_op;
stats_op_t stats_op;
setbuff_op_t setbuff_op;
setmode_op_t setmode_op;
setmintocopy_op_t setmintocopy_op;
cleanup_op_t cleanup_op;
/*
如果过数据包过滤不在内核空间,在此放置过滤器代码*/
struct bpf_program fcode;
char errbuf[PCAP_ERRBUF_SIZE + 1];
int dlt_count;
u_int *dlt_list;
struct pcap_pkthdr pcap_header; /* pcap_next_ex()
工作所需的链表*/
所定义的一些函数指针
typedef
int (*activate_op_t)(pcap_t *);
typedef
int (*can_set_rfmon_op_t)(pcap_t *);
typedef
int (*read_op_t)(pcap_t *, int cnt, pcap_handler, u_char *);
typedef
int (*inject_op_t)(pcap_t *, const void *, size_t);
typedef
int (*setfilter_op_t)(pcap_t *, struct bpf_program *);
typedef
int (*setdirection_op_t)(pcap_t *, pcap_direction_t);
typedef
int (*set_datalink_op_t)(pcap_t *, int);
typedef
int (*getnonblock_op_t)(pcap_t *, char *);
typedef
int (*setnonblock_op_t)(pcap_t *, int, char *);
typedef
int (*stats_op_t)(pcap_t *, struct pcap_stat *);
#ifdef
WIN32
typedef
int (*setbuff_op_t)(pcap_t *, int);
typedef
int (*setmode_op_t)(pcap_t *, int);
typedef
int (*setmintocopy_op_t)(pcap_t *, int);
#endif
typedef
void (*cleanup_op_t)(pcap_t *);
1.3 打开与关闭适配器的实例
我们在下面的示例程序中打开一个适配器并捕获数据包,该程序将每个通过该适配器的数据包长度打印出来,同时打印每个数据包的捕获时间。程序源代码如下:[openadapter]
#define
HAVE_REMOTE
#include
<stdio.h>
#include
"pcap.h"
#include
<winsock.h>
/*
捕获数据包(packet handler)回调函数的原型*/
void
packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
int
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
/*
获取本机网络设备列表*/
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/*
打印网络设备列表*/
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
/*
选择网络设备接口*/
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/*
释放设备列表*/
pcap_freealldevs(alldevs);
return -1;
}
/*
跳转到选中的适配器*/
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/*
打开设备*/
if ( (adhandle= pcap_open(d->name, //
设备名
65536, // 65535
保证能捕获到不同数据链路层上的每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS, //
混杂模式
1000, //
读取超时时间
NULL, //
远程机器验证
errbuf //
错误缓冲池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/*
释放设备列表*/
pcap_freealldevs(alldevs);
return -1;
}
/*
在选中的设备接口上监听数据*/
printf("\nlistening on %s...\n", d->description);
/*
释放设备列表*/
pcap_freealldevs(alldevs);
/*
开始捕获*/
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
/*
每次捕获到数据包时,libpcap都会自动调用该回调函数*/
void
packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm *ltime;
char timestr[16];
time_t local_tv_sec;
/*
将时间戳转换成可识别的格式*/
local_tv_sec = header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
/*
打印数据包的捕获时间与数据包的长度*/
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
本例中,我们将
pcap_open
的snaplen参数
值设定为65535,它比我们能遇到的最大的MTU还要大,同时使用混杂模式,因此可确信我们总能收到完整的数据包。
示例程序的运行结果如图8-2与图8-3所示:
图8-2 选择网络设备接口(此处选择2)
图8-3 打印捕获的时间与数据包的长度