1.4 wpcap.dll中相应函数接口的实现
下面对各函数在
wpcap.dll
中的实现进行详细分析。
1.4.1 pcap_open函数
函数首先确认参数source的长度不超过PCAP_BUF_SIZE,然后调用pcap_parsesrcstr()函数分析源的种类,是文件,本地主机接口还是远程主机接口,并依据不同的源类型作不同的处理。
如果是文件类型,直接调用pcap_open_offline函数处理。
如果是远程主机接口类型,调用pcap_create()创建一个pcap_t结构体,然后调用函数pcap_opensource_remote()通过打开一个远程主机的适配器,最后给pcap_t结构体几个重要成员设置合适的值,包括捕获数据包长度、读取超时,与pcap_startcapture()需要使用的标识。
如果是本地主机接口类型,直接调用pcap_open_live()函数,然后给NPF驱动设置几个标识。根据需要,可设置禁止回环数据包捕获,还可设置一次读操作所需获得的最小数据长度(字节为单位)。
最后函数返回一个pcap_t结构体指针,供后面的调用使用。
函数主要代码如下:
pcap_t *pcap_open(const char *source,
int
snaplen, int flags, int read_timeout,
struct
pcap_rmtauth *auth, char *errbuf)
{
char
host[PCAP_BUF_SIZE], port[PCAP_BUF_SIZE], name[PCAP_BUF_SIZE];
int
type;
pcap_t *fp;
int
result;
/*
确认source的长度不超过PCAP_BUF_SIZE*/
if (strlen(source) > PCAP_BUF_SIZE)
{//
错误,函数返回
…
}
/*
分析源的种类,文件,本地主机接口还是远程主机接口)*/
if (pcap_parsesrcstr(source, &type, host, port, name, errbuf) == -1)
return NULL;
/*
依据不同的源类型作不同的处理*/
switch (type)
{
//
文件类型,直接调用pcap_open_offline函数处理
case PCAP_SRC_FILE:
fp = pcap_open_offline(name, errbuf);
break;
//
远程主机接口类型,打开远程主机的适配器,设置几个重要标识的值。
case PCAP_SRC_IFREMOTE:
//
创建pcap_t结构体
fp= pcap_create(source, errbuf);
if (fp == NULL)
{
return NULL;
}
//
打开一个远程主机的适配器
result= pcap_opensource_remote(fp, auth);
if (result != 0)
{
pcap_close(fp);
return NULL;
}
//
设置捕获数据包长度、读取超时,
//
与pcap_startcapture()需要使用的标识。
fp->snapshot= snaplen;
fp->md.timeout= read_timeout;
fp->rmt_flags= flags;
break;
//
本地主机接口类型,直接调用pcap_open_live()函数,
//
然后给NPF驱动设置几个标识。
case PCAP_SRC_IFLOCAL:
fp = pcap_open_live(name, snaplen, (flags &
PCAP_OPENFLAG_PROMISCUOUS), read_timeout, errbuf);
#ifdef
WIN32
//
这些标识仅被Windows支持
if (fp != NULL && fp->adapter != NULL)
{
/*
如果需要,禁止回环数据包捕获*/
if(flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
{
if(!PacketSetLoopbackBehavior(fp->adapter,
NPF_DISABLE_LOOPBACK))
{ //
设置失败,函数返回
…
}
}
/*
如果需要,设置一次读操作所需获得的最小数据长度(字节为单位)*/
if(flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
{
if(!PacketSetMinToCopy(fp->adapter, 0))
{//
设置失败,函数返回
…
}
}
}
#endif
//WIN32
break;
default:
//
不支持的源类型
strcpy(errbuf, "Source type not supported");
return NULL;
}
return fp;
其中函数pcap_parsesrcstr()通过解析一个源字符串,来分析源的种类,是文件,本地主机接口还是远程主机接口)并返回分离出来的内容(type,host,port,name)。函数原型如下:
int
pcap_parsesrcstr(const char *source, int *type,
char
*host, char *port, char *name, char *errbuf)
参数
source
为要分析的源名称。
。参数host、port与name分别返回源的主机、端口与名称,针对不同的源类型,该三个参数可能为空值。参数
errbuf
保存函数的错误信息。
其中
参数
type
返回源的类型,WinPcap
内部用来表示源的类型的各标识如下:
PCAP_SRC_FILE
指明为一个文件,用户希望从一个本地文件获得数据包。
PCAP_SRC_IFLOCAL
指明为一个本机接口,比如用户希望从一个本地主机接口获得数据包。不采用RPCAP协议。
PCAP_SRC_IFREMOTE
指明为一个远程接口,比如用户希望从一个远程主机接口获得数据包。需要采用RPCAP协议。
其中函数pcap_opensource_remote()通过打开一个RPCAP连接等方式,打开一个远程主机的适配器。函数原型如下:
int
pcap_opensource_remote(pcap_t *fp, struct pcap_rmtauth *auth)
参数fp是一个指向pcap_t结构体的指针,该结构体在前面由pcap_create()函数所创建。参数auth是认证权限。
如果函数成功,返回0值,fp指针能够被用来作为后续调用的参数(如pcap_compile()等等)。如果函数失败,返回-1值,fp->errbuf中存储错误信息。
该函数为一个远程接口完成与pcap_open_live()基本类似的功能。不同的是,此处,在调用pcap_startcapture_remote()之前,捕获线程并不启动。因为,在远程捕获时,我们不能在“open adapter”命令一发送出去就开始捕获数据。考虑远程适配器已经负载很重的时候,如果我们开始一个捕获(其默认情况下,具有一个NULL过滤器),新的网络流量将使网络饱和。
作为替代方案,我们想先"open"适配器,接着仅当在我们准备好开始捕获时发送一个"start capture"的命令。该函数作了这样的工作:它发送一个“open adapter”命令(根据RPCAP协议),但是它不开始捕获。
既然其它的libpcap函数并不一定共享该工作方式,我们不得不做一些并不优雅的事情,使得每件事情都能妥善的解决。
注意:万一在捕获还没有开始时,就调用了pcap_compile()函数,过滤器将被存储到pcap_t结构体中,稍后它将被发送到另一个主机(当pcap_startcapture_remote()被调用时)。