WinPcap 中文技术文档(4.1.2) 第二章

1.  WinPcap用户手册

转载者注:出现在文章1.3节中斜体的文字,需要用实际的ip地址,如192.168.1.1替换。

1.1.  详细描述

    这节包含了有关wpcap.dll的用户指南,wpcap.dll是一个包含公共WinPcapAPI的动态链接库。Wpcap.dll导出一组系统独立的包捕获和网络分析的函数。这些函数可以用于:
1) 获取网络适配器列表
2) 获取网络适配器的不同信息,比如网卡描述和地址的列表
3) 使用PC的一个网卡来捕获数据包
4) 向网络上发送数据
5) 有效保存数据包到磁盘,并通过一个接口捕获数据包,就如同从网卡捕获数据一样
6) 使用高级语言创建一个数据包过滤器,并把它们应用到数据捕获中去
wpcap.dll 兼容libpcap库,后者是Unix平台下著名的数据包捕获库。这个兼容性意味着你可以开发可移植的网络工具,这些工具既可以运行在Win32系列的操作系统,也可以运行在与Unix兼容的机器上。
在这一章节中,手册中的几个部分内容直接来自于tcpdump和libpcap的用户手册,它们由tcpdump.org的开发人员维护。因此,如果你想阅读最新的文档,你可以访问www.tcpdump.org网站。

1.2.  注意

有些函数被标注为deprecated 或 discouraged。这些标签的含义是:
1) discouraged: 这个函数的功能已经被另一个函数所代替,不过这个函数仍然可以使用。
2) deprecated: 这些函数只是为了可移植性和向下兼容而存在的,它应该被禁止使用,并且强烈建议你使用另一个等价的函数来代替它。

1.3.  过滤串表达式的语法

 注意:这篇文档取自tcpdump的指南。原始的版本可以在www.tcpdump.org 上找到。
wpcap的过滤器是以已声明的谓词语法为基础的。过滤器是一个包含过滤表达式的ASCII字符串。pcap_compile()把这个表达式编译成内核级的包过滤器。
这个表达式会选择那些数据包将会输出。如果给定表达式,那么网络上所有的包都会被内核级过滤引擎所接收。不然,只有那些表达式为“true”的包才会被接收。
这个表达式包含了一个或多个原语。原语通常包含一个id(名字或序列),后面跟着一个或者多个限定词。以下是三种不同的限定词:
type(类型)
限定词指明id名称或数字所代表是什么东西。可能的类型有host、net和port。比如:“host foo”,“net 128.3”,“port 20”。如果没有类型限定词,就缺省为host。
dir(方向)
限定词指定相对于id的一个特定的传输方向。可能的方向有src、dst、src or dst和src and dst。例如:“src foo”,'dst net 128.3',`src or dst port ftp-data'。如果没有指定方向,那就缺省为src ordst。如果没有链路层(比如,像slip这样的点对点协议),那么限定词可以使用inbound和outbound,来指明一个方向。
Proto(协议)
限定词限制了所匹配的协议。可能的协议有ether,fddi,tr,ip,ip6,arp,rarp,decnet,tcp和udp。比如:`ethersrc foo',`arp net 128.3',`tcp port 21'。如果没有指定协议限定词,那么就假定所有的协议都会被允许。例如:'src foo'等价于'(ip or arp or rarp)src foo'(当然,不能有不符合语法的字母出现),'net bar'等价于'(ip orarp or rarp) net bar','port 53'等价于'(tcp or udp) port 53'。
[ 'fddi'通常是'ether'的别名;解析器会认为它们是在特定网络接口上的数据链路层。FDDI的首部包含了和以太网很相似的源地址和目的地址,并且通常也包含了和以太网很相似的数据包类型。所以,在FDDI网域上使用过滤器和在以太网上使用过滤器基本一致。FDDI的首部还包括了其他的数据,不过你不能在过滤器表达式内表示他们。同样的,'tr'也是'ether'的一个别名,它是较早被应用于FDDI的首部,也应用在令牌环网络首部。] 
除了以上内容,还有一些特殊的限定词和上面的形式不太一样,它们是gateway,broadcast,less,greater和一些算术表达式。这些内容会在下面和大家介绍。
我们可以使用and,or和not逻辑表达式将原语连接起来,来构造一个更复杂的过滤表达式。例如:`host foo and not port ftp and not port ftp-data'。如果要简化输入,我们可以把已列出的id限定词省略。比如:`tcp dst port ftp or ftp-data or domain' 和 `tcp dstport ftp or tcp dst port ftp-data or tcp dst port domain'两者是完全等价的。 
可使用的原语有: 
dst host host:当IPv4/v6数据包的目标域(destinationfield)为host时为true,host既可以是地址,也可以是名字。
src host host:当IPv4/v6数据包的源字段(sourcefield)为host时为true。
host host 当IPv4/v6数据包的源字段(sourcefield)或目标字段(destination field)为host时为true。以上任何一个host表达式可以是ip,arp,rarp或ip6开头,如下所示:
ip host host 等价于: ether proto ip and host host
如果host是一个带有多IP地址的名称,那么每一个地址都会被匹配。
ether dst ehost:当以太网的目的地址为ehost时为true。ehost可以是一个来自/etc/ether的名字,也可以是一个数字代号(参见 ethers(3N)for numeric format)。 
ether src ehost:当以太网的源地址为ehost时为true。 
ether host ehost:当以太网的目的地址,或源地址为ehost时为true。 
gateway host:当host为网关时为true。即,以太网源地址或目的地址是host,但源地址和目的地址不同时为host。host必须能被机器的主机到IP地址(host-name-to-IP-address)机制找到(例如:主机名文件,DNS,NIS等),也能被主机到以太网地址(host-name-to-Ethernet-address)机制找到(如:/etc/ethers等)。
例如: ether host ehost and not host host
host / ehost均可使用名字或数字。这个语法目前在IPv6下不能工作。
dst net net:当IPv4/v6数据包的目的地址的网络号包含net时为true。net可以是一个来自/etc/networks的名字,也可以是一个网络号(更多内容请参见 networks(4))。 src net net当IPv4/v6数据包的源地址的网络号包含了net时为true。
net net:当IPv4/v6数据包的目的地址,或源地址的网络号包含了net时为true 
net net mask netmask:当IP地址是net ,子网掩码匹配netmask 时为true。可能需要 src 或 dst加以限制。注意,这个语法不能应用于IPv6。
net net/len:当IP地址是 net ,子网掩码连续1的个数为 len 时为true。可能需要src或ds加以限制。
dst port port:当数据包是ip/tcp,ip/udp, ip6/tcp 或 ip6/udp,并且目的端口号是port时为true。port可以是数字,或是在/etc/services中被使用的名字。(参见 tcp(4P) and udp(4P))。如果使用名字,那么端口号和协议都将被检测。如果使用数字,或者一个不明确的名字,那么只有端口号会被检测。(比如:dst port 513将打印tcp/login数据流和udp/who数据流。port domain将打印tcp/domain的数据流和udp/domain的数据流)。 
src port port:当源端口号是 port时为true。 
port port:当源端口号或目的端口号为port 时为true。以上任何一个port表达式可以以关键字tcp或udp开头,如下所示:tcp src port port
只匹配源端口是 port 的tcp数据包。 
less length:当数据包的长度小于等于length时为true。即: len <=length.
greater length:当数据包的长度大于等于length时为true。即: len >=length.
ip proto protocol:当数据包是IP数据包,并且它的协议类型为protocol时为true。protocol可以是一个数字,也可以是icmp,icmp6,igmp,igrp,pim,ah,esp,vrrp,udp 或 tcp中的一个。注意,tcp,udp, icmp是关键字,所以,它们要使用反斜杠(\)来转义,就好比C-shell中的\\。注意,这个原语不会去追踪协议首部链。
ip6 proto protocol:当数据包是IPv6数据包,并且它的协议类型为protocol时为true。注意,这个原语不会去追踪协议首部链。 
ip6 protochain protocol当数据包是IPv6数据包,并且,在它的协议首部链中,包含了protocol类型的协议首部时,为true。例如: ip6 protochain 6
能匹配所有的,拥有TCP协议首部的IPv6的数据包。在IPv6首部和TCP首部之间,可能包含认证首部,路由首部和跳数选项首部。由这个原语所生成的BPF(BSD Packet Filter,包过滤机制)码是复杂的,而且不能被BPF优化器优化,所以,在某些程度上,它的速度比较慢。
ip protochain protocol:其功能和 ip6protochain protocol相同,只是这个应用于 IPv4。
ether broadcast:当数据包是以太网广播数据包时为true。关键字ether是可选的。 
ip broadcast:当数据包是IP广播数据包时为true。它会检查所有的广播,包括地址全是0的和地址全是1的,然后,检查子网掩码。
ether multicast:当数据包是以太网多播数据包时为true。关键字ether是可选的。下面是一个常用短语`ether[0]& 1 != 0' 
ip multicast:当数据包是IP多播数据包时为true。 
ip6 multicast:当数据包是IPv6多播数据包时为true。 
ether proto protocol:当数据包是以太类型的protocol时为true。protocol可以是一个数字,也可以是ip,ip6, arp, rarp, atalk, aarp,decnet, sca, lat, mopdl, moprc,iso, stp, ipx,netbeui中的一个。注意,这些符号也都是关键字,所以,他们都需要用反斜杠(\)转义。 [在使用FDDI(比如'fddi protocol arp')和令牌环(比如'tr protocol arp')和其他大多数这种协议时,协议根据802.2逻辑链路控制(LLC)来识别,这些信息通常在FDDI或令牌环首部的开始。当需要识别大多数协议的标识,比如FDDI或令牌环时, Tcpdump只检查LLC报头的ID数据域,它们以SNAP格式存储,并且,组织单位识别码(Organizational Unit Identifier(OUI))为0x000000,以封装以太网。它不会检查这个包是不是SNAP格式的,并在0x000000单元有OUI。然而,iso是个特例,它会检查LLC首部的目的服务存取点DSAP(Destination Service Access Point)和源服务存取点SSAP(SourceService Access Point),stp和netbeui会检查LLC首部的DSAP,atalk会检查数据包是不是SNAP格式的,并且OUI是不是0x080007。Appletalk 同样如此。在以太网的例子中,tcpdump检查大部分协议的以太网类型字段,iso,sap 和 netbeui除外,因为它们会检查802.3帧,然后检查LLC首部,就像它对FDDI和令牌环那样。atalk,它检查以太网帧的Appletalk etype和SNAP格式的以太网帧,arrp,它在以太网帧中检查Appletalk ARP etype,或是在OUI为0x000000的802.2 SNAP帧中查找,还有ipx,他会在以太网帧中检查IPX etype,在LLC首部检查IPX DSAP,没有用802.3封装的LLC首部的IPX,和SNAP帧中的IPX etype。]
decnet src host:当DECNET的源地址为host时为true,它可能是一个格式为'10.123'的地址,也可能是一个DECNET主机名。[DECNET主机名称只有在配置成可运行DECNET的Ultrix系统中才得到支持。] 
decnet dst host :当DECNET的目的地址为host时为true。 
decnet host host:当DECNET的源地址或目的地址为host时为true。 ip, ip6,arp, rarp, atalk, aarp, decnet, iso, stp, ipx, netbeui缩写是: etherproto p
p 是以上协议中的一个。
lat, moprc,mopdl缩写是: ether proto p
p 是以上协议中的一个。注意: tcpdump 目前并不知道,如何解析出这些协议。 
vlan [vlan_id]当数据包是IEEE802.1Q VLAN数据包时为true。若[vlan_id]被指定,则仅当数据包为指定的vlan_id,值才为true。注意,在假设数据包为VLAN数据包的前提下,表达式中的第一个关键字vlan会改变剩余表达式的解码偏移量。
 tcp, udp, icmp缩写是: ip proto p orip6 proto p
p 是以上协议中的一个。
 iso proto protocol:当数据包的协议类型为protocol的OSI数据包时值为true。Protocol可以是一个数字或以下名称中的一个:clnp,esis或isis。
clnp, esis, isis缩写是: isoproto p
p 是以上协议中的一个。注意,tcpdump并不能完成这些协议的全部解析工作。 
expr relop expr:若关系式如下:relop是 >, <,>=, <=, =, != 中的一个,并且expr是一个由正整常数(用标准C语言的语法表示),标准二进制运算符[ +, -, *, /, &, | ],运算符的长度,和指定数据包存取,则值为true。要存取数据包内的数据,可以使用以下的语法: proto [ expr : size ]
Proto 是 ether,fddi, tr, ip, arp, rarp, tcp, udp, icmp or ip6中的一个,它为索引操作指明了协议层。注意,tcp,udp和其他较高层的协议类型只能应用于IPv4,而不能用于IPv6(这个问题可能在将来能得到解决)。被指定的协议层的字节偏移量由expr给出。Size是可选的,它指明了数据域中,我们所感兴趣的字节数。它可以是1,2,或4,默认为1。运算符的长度,由关键字len给出,指明了数据包的长度。
例如,`ether[0] & 1!= 0'会捕捉所有的多播数据流。表达式`ip[0] & 0xf != 5'能捕捉所有带可选域的IP数据包。表达式`ip[6:2] & 0x1fff = 0'仅捕捉未分段的数据报和段偏移量是0的数据报。这个检查隐含在tcp和udp的下标操作中。例如,tcp[0]通常指第一个字节的TCP首部,而不是指第一个字节的分段。 
有些偏移量和域值可以以名字来表示,而不是数值。以下协议首部域的偏移量是正确的:icmptype (ICMP 类型域), icmpcode (ICMP 代码域), and tcpflags (TCP 标志域)。
ICMP 类型域有以下这些:icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo,icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob,icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq,icmp-maskreply. 
TCP 标志域有以下这些:tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg. 
原语可以用以下内容组合:用圆括号括起来的原语和操作符 (圆括号在Shell中是特殊符号,所以必须要转义)。取反操作 (`!' 或 `not'). 连接操作 (`&&' 或 `and'). 选择操作 (`||' 或 `or'). 
取反操作的优先级最高。连接操作和选择操作有相同的优先级,并且它们的结合方向为从左向右。注意:做连接的时候是需要显示的 and 操作符的,而不是把要连接的东西写在一起。
如果给出一个标识符,却没有关键字,那么就会假定用最近使用的关键字。例如: 
not host vs and ace
等价于 
not host vs and host ace
不能和下面的混淆 
not ( host vs orace )
表达式参数即可以作为单个参数,也可以作为多个参数传递给tcpdump,后者更加方便一些。一般的,如果表达式包含一个Shell的元字符,那么用一个参数传递比较容易,最好把它括起来,多个参数在传递前,用空格连接起来。

1.4.  在你程序中使用WinPcap

1.4.1.  创建一个使用 wpcap.dll 的应用程序

    用 Microsoft VisualC++ 创建一个使用 wpcap.dll 的应用程序,需要按一下步骤:
1) 在每一个使用了库的源程序中,将 pcap.h 头文件包含(include)进来。
2) 如果你在程序中使用了WinPcap中提供给Win32平台的特有的函数,记得在预处理中加入WPCAP 的定义。
3) 如果你的程序使用了WinPcap的远程捕获功能,那么在预处理定义中加入HAVE_REMOTE。不要直接把remote-ext.h直接加入到你的源文件中去。
4) 设置VC++的链接器(Linker),把你的目标(x86或x64)指定的wpcap.lib库文件包含进来。X86的wpcap.lib可以在WinPcap开发包中lib目录下找到,x64位的wpcap.lib可以在lib/x64目录中发现。
5) 设置VC++的链接器(Linker),把ws2_32.lib库文件包含进来。这个文件分布于C的编译器,并且包含了Windows的一些socket函数。本教程中的一些范例程序,会需要它。
如果正确的设置MicrosoftVisual Studio:

Visual Studio 6

1) 要添加一个预处理定义,你需要打开Project菜单,选择Settings,然后选择C/C++选项卡,在General类下,你必须在Preprocessor Definitions下的文本框中添加定义。 
2) 要在一个VC++6.0工程中,添加一,个新的库,你必须打开Project菜单,选择Settings,然后选择Link选项卡,然后把新库的名字添加到Object/Library modules下的文本框中
3) 要向VC++6.0中添加一个新的库所在的路径,你必须打开Tool菜单,选择Options,然后选择Directories选项卡,在Show directories下拉框中选择Library files,并且将新的路径添加到Directories中去
4) 要向VC++6.0中添加一个新的包含文件所在的路径,你必须打开Tool菜单,选择Options,然后选择Directories选项卡,在Show directories下拉框中选择Include files,并且将新的路径添加到Directories中去。

Visual Studio2005(需要编译x64位应用程序)

1) 添加预处理器定义,你必须选择“Project”/“Properties”,然后从左边的列表控件中选择C/C++,在Preprocessor目录下,你必须把定义添加到Preprocessor Definitions文本框中。
2) 添加新的库到项目中,你必须选择Project/Properties,然后从坐标的列表控件中选择Linker,在Inpute目录下,把一个新的库添加到Additonal Dependencies文本框中。
3) 把新的路径添加到查找库的路径中,你必须选择Tools/Options,然后从左边的列表控件中选中Project/Solutions,VC++Directories,然后再显示的目录可选框中选择库文件,添加路径到文本框中。
4) 添加新的路径,从改路径中查找Include文件,你必须选择Tools/Options,然后在左边的列表控件中选择Project/Solutions,VC++ Directories,这时选择Include Files,添加路径到文本框中。

1.4.2.  范例程序

    我们提供一些范例程序来显示WinPcapAPI的使用方法。这些程序的源代码,以及编译运行这些代码所需的所有文件,都可以在 Developer's Pack找到。作为教程,在这里我们提供了可浏览形式的代码:这样,在每个函数和变量之间的跳转会比较方便。更多完整的范例程序,请参阅 WinPcap教程。

1.4.2.1.   Packet Dump

    这个程序会依据命令行参数,从网络适配器或是从文件中读取数据包。如果没有提供数据源,那么程序会显示出所有可用的适配器,你可以从中选择一个。当捕获过程开始后,程序会打印数据包的时间戳、长度和原始内容。一旦程序被编译,那么它将能运行于所有的Win32平台,当然,它也可以被编译成Unix平台的程序。
/*
 * Copyright (c) 1999 - 2005 NetGroup,Politecnico di Torino (Italy)
 * Copyright (c) 2005 - 2006 CACE Technologies,Davis (California)
 * All rights reserved.
 *
 * Redistribution and use in source and binaryforms, with or without
 * modification, are permitted provided thatthe following conditions
 * are met:
 *
 * 1. Redistributions of source code mustretain the above copyright
 * notice, this list of conditions and thefollowing disclaimer.
 * 2. Redistributions in binary form mustreproduce the above copyright
 * notice, this list of conditions and thefollowing disclaimer in the
 * documentation and/or other materialsprovided with the distribution.
 * 3. Neither the name of the Politecnico diTorino, CACE Technologies 
 * nor the names of its contributors may beused to endorse or promote 
 * products derived from this software withoutspecific prior written 
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTHOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIEDWARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OFMERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NOEVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSOR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISINGIN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
 *
 */
 
 
#include<stdlib.h>
#include<stdio.h>
 
//
// NOTE:remember to include WPCAP and HAVE_REMOTE among your
// preprocessordefinitions.
//
 
#include<pcap.h>
 
#define LINE_LEN16
 
main(int argc,char **argv)
{   
pcap_if_t *alldevs, *d;
pcap_t *fp;
u_int inum, i=0;
char errbuf[PCAP_ERRBUF_SIZE];
int res;
struct pcap_pkthdr *header;
const u_char *pkt_data;
 
    printf("pktdump_ex: prints the packetsof the network using WinPcap.\n");
    printf("   Usage: pktdump_ex [-s source]\n\n"
      "  Examples:\n"
      "      pktdump_ex -sfile://c:/temp/file.acp\n"
      "      pktdump_ex -srpcap://\\Device\\NPF_{C8736017-F3C3-4373-94AC-9A34B7DAD998}\n\n");
    if(argc < 3)
    {
 
        printf("\nNo adapter selected:printing the device list:\n");
        /* The user didn't provide a packetsource: Retrieve the local device list */
        if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
        {
            fprintf(stderr,"Error inpcap_findalldevs_ex: %s\n", errbuf);
            return -1;
        }
        
        /* Print the list */
        for(d=alldevs; d; d=d->next)
        {
            printf("%d. %s\n    ", ++i, d->name);
 
            if (d->description)
                printf(" (%s)\n",d->description);
            else
                printf(" (No descriptionavailable)\n");
        }
        
        if (i==0)
        {
            fprintf(stderr,"No interfacesfound! Exiting.\n");
            return -1;
        }
        
        printf("Enter the interface number(1-%d):",i);
        scanf("%d", &inum);
        
        if (inum < 1 || inum > i)
        {
            printf("\nInterface number outof range.\n");
 
            /* Free the device list */
            pcap_freealldevs(alldevs);
            return -1;
        }
        
        /* Jump to the selected adapter */
        for (d=alldevs, i=0; i< inum-1;d=d->next, i++);
        
        /* Open the device */
        if ( (fp= pcap_open(d->name,
                            100 /*snaplen*/,
                           PCAP_OPENFLAG_PROMISCUOUS /*flags*/,
                            20 /*readtimeout*/,
                            NULL /* remoteauthentication */,
                            errbuf)
                            ) == NULL)
        {
            fprintf(stderr,"\nErroropening adapter\n");
            return -1;
        }
    }
    else 
    {
        // Do not check for the switch type('-s')
        if ( (fp= pcap_open(argv[2],
                            100 /*snaplen*/,
                           PCAP_OPENFLAG_PROMISCUOUS /*flags*/,
                            20 /*readtimeout*/,
                            NULL /* remoteauthentication */,
                            errbuf)
                            ) == NULL)
        {
            fprintf(stderr,"\nErroropening source: %s\n", errbuf);
            return -1;
        }
    }
 
    /* Read the packets */
    while((res = pcap_next_ex( fp, &header,&pkt_data)) >= 0)
    {
 
        if(res == 0)
            /* Timeout elapsed */
            continue;
 
        /* print pkt timestamp and pkt len */
        printf("%ld:%ld (%ld)\n",header->ts.tv_sec, header->ts.tv_usec, header->len);          
        
        /* Print the packet */
        for (i=1; (i < header->caplen + 1) ; i++)
        {
            printf("%.2x ",pkt_data[i-1]);
            if ( (i % LINE_LEN) == 0)printf("\n");
        }
        
        printf("\n\n");     
    }
 
    if(res == -1)
    {
        fprintf(stderr, "Error reading thepackets: %s\n", pcap_geterr(fp));
        return -1;
    }
 
    return 0;
}

1.4.2.2.  数据包过滤器

    这是一个更加完整的使用libpcap的范例程序,它显示了如何创建和设置过滤器,如何把捕获数据包保存到硬盘上。这个程序在Win32和Unix平台下都能编译。Pcap_filter(pf.exe)是一个通用的数据包过滤程序:它的输入参数有数据包的源(可以是物理接口或是一个文件),过滤器和一个输出文件。它会从源获取数据包,并对它们进行过滤,如果它们符合过滤器的要求,就把它们保存到输出文件,直到按下Ctrl+C,或者整个文件处理完毕。Pcap_filter不但可以根据一个特定的过滤器,处理网络中的数据,而且可以从已经保存过的文件中提取数据包。输入和输出文件的格式都是libpcap兼容的格式,比如,WinDump,tcpdump和其他许多网络工具具有相同的格式。
/*
 * Copyright (c) 1999 - 2005 NetGroup,Politecnico di Torino (Italy)
 * Copyright (c) 2005 - 2006 CACE Technologies,Davis (California)
 * All rights reserved.
 *
 * Redistribution and use in source and binaryforms, with or without
 * modification, are permitted provided thatthe following conditions
 * are met:
 *
 * 1. Redistributions of source code mustretain the above copyright
 * notice, this list of conditions and thefollowing disclaimer.
 * 2. Redistributions in binary form mustreproduce the above copyright
 * notice, this list of conditions and thefollowing disclaimer in the
 * documentation and/or other materialsprovided with the distribution.
 * 3. Neither the name of the Politecnico diTorino, CACE Technologies 
 * nor the names of its contributors may beused to endorse or promote 
 * products derived from this software withoutspecific prior written 
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTHOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIEDWARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OFMERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NOEVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODSOR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISINGIN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF SUCH DAMAGE.
 *
 */
 
 
#include<stdlib.h>
#include<stdio.h>
 
#include<pcap.h>
 
#define MAX_PRINT80
#define MAX_LINE16
 
 
void usage();
 
 
void main(intargc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
char *source=NULL;
char *ofilename=NULL;
char *filter=NULL;
int i;
pcap_dumper_t *dumpfile;
struct bpf_program fcode;
bpf_u_int32 NetMask;
int res;
struct pcap_pkthdr *header;
const u_char *pkt_data;
 
    if (argc == 1)
    {
        usage();
        return;
    }
 
    for(i=1;i < argc; i+= 2)
    {
 
        switch (argv[i] [1])
        {
            case 's':
            {
                source=argv[i+1];
            };
            break;
 
            case 'o':
            {
                ofilename=argv[i+1];
            };
            break;
 
            case 'f':
            {
                filter=argv[i+1];
            };
            break;
        }
    }
 
    // open a capture from the network
    if (source != NULL)
    {
        if ( (fp= pcap_open(source,
                            1514 /*snaplen*/,
                           PCAP_OPENFLAG_PROMISCUOUS /*flags*/,
                            20 /*readtimeout*/,
                            NULL /* remoteauthentication */,
                            errbuf)
                            ) == NULL)
        {
            fprintf(stderr,"\nUnable toopen the adapter.\n");
            return;
        }
    }
 
    else usage();
 
    if (filter != NULL)
    {
        // We should loop through the adaptersreturned by the pcap_findalldevs_ex()
        // in order to locate the correct one.
        //
        // Let's do things simpler: we supposeto be in a C class network ;-)
        NetMask=0xffffff;
 
        //compile the filter
        if(pcap_compile(fp, &fcode, filter,1, NetMask) < 0)
        {
            fprintf(stderr,"\nErrorcompiling filter: wrong syntax.\n");
            return;
        }
 
        //set the filter
        if(pcap_setfilter(fp, &fcode)<0)
        {
            fprintf(stderr,"\nErrorsetting the filter\n");
            return;
        }
 
    }
 
    //open the dump file
    if (ofilename != NULL)
    {
        dumpfile= pcap_dump_open(fp,ofilename);
 
        if (dumpfile == NULL)
        {
            fprintf(stderr,"\nErroropening output file\n");
            return;
        }
    }
    else usage();
 
    //start the capture
    while((res = pcap_next_ex( fp, &header,&pkt_data)) >= 0)
    {
 
        if(res == 0)
        /* Timeout elapsed */
        continue;
 
        //save the packet on the dump file
        pcap_dump((unsigned char *) dumpfile,header, pkt_data);
 
    }
}
 
 
void usage()
{
 
    printf("\npf - Generic PacketFilter.\n");
    printf("\nUsage:\npf -s source -ooutput_file_name [-f filter_string]\n\n");
    exit(0);
}

转自:fan_hai_ping

猜你喜欢

转载自blog.csdn.net/lixiangminghate/article/details/81606098