2023年7月23日发(作者:)
第3章 打开数据截获接口
3.1 LibPcap() 主要库函数简介
LibPcap 是一套最初用于Linux的数据包用户级截获驱动,其Windows版本为WinPcap。
注:在Windows下使用WinPcap,可能存在一些与Snort的兼容性问题,Snort的安装目录doc中,32
文件对此已有比较详细的说明。
Snort使用了这套驱动库做为数据包的截获引擎,这里介绍Snort使用了的LibPcap 的函数。
1、pcap_lookupdev
pcap_lookupdev用来查找系统第一个可以使用的网络适配器,查找成功后,返回该设备的名称;如果系统有多个网卡,也可以使用pcap_findalldevs函数来查找选取;
2、pcap_open_live
函数用于打开指定网络适配器,准备截取数据。其调用形式为:
pd = pcap_open_live(ace,
snaplen,
/*设备名称*/
/*捕获包的长度,通常设置为65536,表示捕获链路层上的所有数据*/
c_flag ? PROMISC : 0, /*网卡是否工作于混杂模式*/
READ_TIMEOUT,
errorbuf);
/*超时时间控制,单位毫秒*/
3、pcap_open_offline
Libpcap使用库函数pcap_open_offline进行脱机方式截获,即先将网络上的数据截获下来,以文件形式储存到磁盘上,等事后方便时再从磁盘上读取数据文件来做进一步分析。
4、pcap_snapshot 函数用于获取数据链路层协议的类型;
5、pcap_compile和pcap_setfilter
我们在进行数据包截获时,常常并不需要捕获所有的包,如只需要捕获ARP协议等,这就需要过滤规则。Pcap_compile用于将设置的过滤字符串编译成一个过滤器程序。而pcap_setfilter则用来设置过滤器的过滤规则;
6、pcap_loop
前面的函数都可以看做捕获数据包的准备工作,pcap_loop用来从网络中捕获数据包。需要注意的是函数的第三个参数,它是一个回调函数,捕获到的数据包,就交由它来处理;
关于更多LibPcap的信息,请参考本书附录的相关章节;
3.2 OpenPcap() 函数
OpenPcap 函数的主要作用是调用上节所介绍的函数,完成了包截获引擎在截获数据包前的所有工作,如查找网卡、打开网卡,设置过滤规则等等,但是并调用pcap_loop来捕获数据包,数据包的捕获,要等到系统初始化完所有的准备工作,再通过InterfaceThread 来调用。函数源码分析如下(有删节):
int OpenPcap()
{
/*系统在ParseCmdLine函数中根据用户命令调用过pcap_lookupdev 了,所以这里再做个判断,如果ace为空,再调用一次*/
if(ace == NULL)
{
if (!de_flag) /*判断是从网络捕获包还是从文件中读取*/
{
ace = pcap_lookupdev(errorbuf);
if(ace == NULL)
{
FatalError("OpenPcap() interface lookup: nt%sn",
errorbuf); }
}
else
{
ace = "[reading from a file]";
}
}
if(!_flag)
{
if (!de_flag)
LogMessage("nInitializing Network Interface %sn",
PRINT_INTERFACE(ace));
else
LogMessage("TCPDUMP file reading mode.n");
}
if (!de_flag)
{
if(_snaplen) /* 设置的数据包捕获长度,对应命令行参数P */
{
/* 这一段主要用来设置捕获数据包长度参数snaplen的值*/
/*如果设置的数据包捕获长度比允许捕获的最小数据包还要小*/
if(_snaplen < MIN_SNAPLEN)
{
snaplen = MIN_SNAPLEN; /*重新调整一个*/
}
else
{
snaplen = _snaplen;
}
}
else
{
snaplen = SNAPLEN; /* otherwise let's put the compiled value in */
}
/* 打开网络设备*/
pd = pcap_open_live(ace, snaplen,
c_flag ? PROMISC : 0, READ_TIMEOUT, errorbuf);
}
else /*如果是从文件读取数据*/
{ if (!_flag)
{
LogMessage("Reading network traffic from "%s" file.n",
le);
}
/* 打开文件*/
pd = pcap_open_offline(le, errorbuf);
if(pd == NULL)
{
FatalError("unable to open file "%s" for readback: %sn",
le, errorbuf);
}
snaplen = pcap_snapshot(pd);
if(!_flag)
LogMessage("snaplen = %dn", snaplen);
}
/* something is wrong with the opened packet socket */
if(pd == NULL)
{
if(strstr(errorbuf, "Permission denied"))
{
FatalError("You don't have permission to"
" doing this as root.n");
}
else
{
FatalError("OpenPcap() device %s open: nt%sn",
PRINT_INTERFACE(ace), errorbuf);
}
}
/* 在设置过滤器的时候,会需要接口对应的掩码信息,这里调用pcap_lookupnet 得到本地网络及掩码地址*/
if(pcap_lookupnet(ace, &localnet, &netmask, errorbuf) < 0)
{
if (!de_flag)
{
ErrorMessage("OpenPcap() device %s network lookup: n"
"t%sn",
PRINT_INTERFACE(ace), errorbuf);
}
/*
*获取失败,因为有时候用于包捕获的网卡并不需要设置IP地址及掩码。这里为其设置一个默认掩码255.255.255.0 */
netmask = htonl(defaultnet);
}
else
{
DefineIfaceVar(PRINT_INTERFACE(ace),
(u_char *) &localnet,
(u_char *) &netmask);
}
/*编译一个过滤设备*/
if(pcap_compile(pd, &fcode, _cmd, 1, netmask) < 0)
{
FatalError("OpenPcap() FSM compilation failed: nt%sn"
"PCAP command: %sn", pcap_geterr(pd), _cmd);
}
/* 设置过滤规则 */
if(pcap_setfilter(pd, &fcode) < 0)
{
FatalError("OpenPcap() setfilter: nt%sn",
pcap_geterr(pd));
}
/* 获取链路层协议类型 */
datalink = pcap_datalink(pd);
if(datalink < 0)
{
FatalError("OpenPcap() datalink grab: nt%sn",
pcap_geterr(pd));
}
return 0;
}
我们对照libpcap各库函数的作用,不难分析这段程序。不过需要留意的地方是pcap_snapshot函数的调用:
snaplen = pcap_snapshot(pd);
函数的作用是获取数据链路层的协议类型,置于全局变量snaplen中。系统在后面指定数据链路层拆包函数的时候,会用到该函数指针,这个指针究意指向哪个数据链路层的函数,就是要依靠snaplen的值来决定,我们后面会再来详细分析这个问题。
3.3 小结
本章的内容其实就是简单的libpcap库函数的调用。Libpcap因为其简单易于,深受开发人员的喜爱。本书附录中,为大家介绍了如何使用WinPcap(Libpcap的Windows版本),翻译自其帮助文件中的《WinPcap user's manual》。
发布者:admin,转转请注明出处:http://www.yc00.com/news/1690105403a306241.html
评论列表(0条)