天天看點

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教程。      
這個程式會依據指令行參數,從網絡擴充卡或是從檔案中讀取資料包。如果沒有提供資料源,那麼程式會顯示出所有可用的擴充卡,你可以從中選擇一個。當捕獲過程開始後,程式會列印資料包的時間戳、長度和原始内容。一旦程式被編譯,那麼它将能運作于所有的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;
}      
這是一個更加完整的使用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);
}