久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Wincap

 menglei 2010-06-03
循序漸進(jìn)學(xué)WinPcap
風(fēng)兒 發(fā)表于 2006-4-19 10:48:00

WinPcap tutorial: a step by step guide to using WinPcap
詳細(xì)說(shuō)明
 這部分展示了怎樣使用WinPcap API。這個(gè)教程通過(guò)一系列的課程,從基本的函數(shù)(取得網(wǎng)卡列表,開(kāi)始抓包,等等)到最高級(jí)的應(yīng)用(處理數(shù)據(jù)包包發(fā)送隊(duì)列和統(tǒng)計(jì)網(wǎng)絡(luò)流量),一步一步地教會(huì)讀者如何用WinPcap來(lái)編程。
 這里提供了幾個(gè)雖然簡(jiǎn)單但卻完整的程序段作為參考:所有的源代碼都有其余部分的鏈接,,只需要點(diǎn)擊一下函數(shù)和數(shù)據(jù)結(jié)構(gòu)就可以跳轉(zhuǎn)到相應(yīng)的文檔。
 這些例子都是使用c語(yǔ)言寫(xiě)的,所以在讀本教程前要了解一些基本的c語(yǔ)言的知識(shí),。而且,,這是一個(gè)關(guān)于處理原始網(wǎng)絡(luò)包的庫(kù)的教程,所以假定讀者具有良好的網(wǎng)絡(luò)和網(wǎng)絡(luò)協(xié)議方面的知識(shí),。
WinPcap tutorial: a step by step guide to using WinPcap(1)
獲取網(wǎng)絡(luò)設(shè)備列表
 基本上所有基于Winpcap的應(yīng)用程序所做的第一件事情都是獲取一個(gè)已經(jīng)綁定的網(wǎng)卡列表,。為此,libcap和winpcap都提供了pcap_findalldevs_ex()函數(shù):這個(gè)函數(shù)返回一個(gè)指向pcap_if結(jié)構(gòu)的鏈表,,其中的每一項(xiàng)都包含了一個(gè)已經(jīng)綁定的適配器的全部信息,。其中name和description這兩項(xiàng)分別包含了相應(yīng)設(shè)備的名稱(chēng)和描述。
 下面的代碼取得適配器列表并在屏幕上顯示出來(lái),,如果適配器沒(méi)有被發(fā)現(xiàn)就把顯示錯(cuò)誤,。
#i nclude "pcap.h"
main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;
    int i=0;
    char errbuf[PCAP_ERRBUF_SIZE];
   
    /* 取得本機(jī)的網(wǎng)絡(luò)設(shè)備列表 */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* 這個(gè)參數(shù)在這里不需要 */, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf);
        exit(1);
    }
   
    /* 顯示列表 */
    for(d= alldevs; d != NULL; 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;
    }
    /* We don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
}
關(guān)于這段代碼的說(shuō)明。
 首先,,就象其他的libpcap函數(shù),,pcap_findalldevs_ex()有一個(gè)errbuf參數(shù),。如果發(fā)生錯(cuò)誤,,libcap就把一個(gè)錯(cuò)誤說(shuō)明放到這個(gè)參數(shù)指向的字符串中。
 其次,,并不是所有的操作系統(tǒng)都支持libpcap提供的網(wǎng)絡(luò)接口描述,,因此如果我們想寫(xiě)一個(gè)可移植的程序,我們必須考慮description為null的情況:這個(gè)時(shí)候我們就輸出字符串"No description available" ,。
 最后要提醒一下:一旦我們完成了這些動(dòng)作,,就應(yīng)該釋放用pcap_freealldevs()列表。
讓我們編譯并運(yùn)行這段簡(jiǎn)單的代碼,。在unix或者cygwin中編譯的話,,打入下面的命令:
gcc -o testaprog testprog.c -lpcap
 在windows中,你需要?jiǎng)?chuàng)建一個(gè)project,,照著手冊(cè)中的Using WinPcap in your programs 那一章做就可以了,。但是,我們建議你使用the WinPcap developer's pack(可以在http://www. 下載),,因?yàn)檫@個(gè)開(kāi)發(fā)包提供了許多教程中使用的代碼示例,,這些示例都已經(jīng)配置好了,其中包含了編譯執(zhí)行例子所需要的include文件和lib文件,。
 編譯好了程序后,,在我的winxp工作站上運(yùn)行的結(jié)果:
1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
 就象你看到的一樣,在windows系統(tǒng)中網(wǎng)絡(luò)適配器的名稱(chēng)(在打開(kāi)網(wǎng)絡(luò)適配器時(shí)將被傳遞給libcap)根本沒(méi)有辦法理解,,所以附加說(shuō)明可能是非常有幫助的,。
WinPcap tutorial: a step by step guide to using WinPcap(2)
Obtaining advanced information about installed devices
 課程1(Obtaining the device list)說(shuō)明了怎樣得到可用適配器的基本信息(比如設(shè)備名和說(shuō)明)。實(shí)際上,winpcap也提供其他的高級(jí)信息,。每個(gè)由pcap_findalldevs_ex()返回的pcap_if 結(jié)構(gòu)體都包含了一個(gè)pcap_addr結(jié)構(gòu)列表,,里面包含的內(nèi)容有:
一個(gè)接口的地址列表。
一個(gè)子網(wǎng)掩碼列表(每一個(gè)都與地址列表中的條目一一對(duì)應(yīng)),。
一個(gè)廣播地址列表(每一個(gè)都與地址列表中的條目一一對(duì)應(yīng)),。
一個(gè)目的地址列表(每一個(gè)都與地址列表中的條目一一對(duì)應(yīng))。
 除此之外,,pcap_findalldevs_ex() 也能返回遠(yuǎn)程的適配器和任給的本地文件夾的pcap文件列表,。
 下面的例子提供了一個(gè)ifprint() 函數(shù)來(lái)打印出一個(gè)pcap_if 結(jié)構(gòu)中的所有內(nèi)容。程序?qū)γ恳粋€(gè)pcap_findalldevs_ex()返回的條目都調(diào)用一次這個(gè)函數(shù),。
/*
 * Copyright (c) 1999 - 2003
 * NetGroup, Politecnico di Torino (Italy)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Politecnico di Torino nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 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) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#i nclude "pcap.h"
#ifndef WIN32
    #i nclude <sys/socket.h>
    #i nclude <netinet/in.h>
#else
    #i nclude <winsock.h>
#endif

// Function prototypes
void ifprint(pcap_if_t *d);
char *iptos(u_long in);
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen);

int main()
{
  pcap_if_t *alldevs;
  pcap_if_t *d;
  char errbuf[PCAP_ERRBUF_SIZE+1];
  char source[PCAP_ERRBUF_SIZE+1];
  printf("Enter the device you want to list:\n"
            "rpcap://              ==> lists interfaces in the local machine\n"
            "rpcap://hostname:port ==> lists interfaces in a remote machine\n"
            "                          (rpcapd daemon must be up and running\n"
            "                           and it must accept 'null' authentication)\n"
            "file://foldername     ==> lists all pcap files in the give folder\n\n"
            "Enter your choice: ");
  fgets(source, PCAP_ERRBUF_SIZE, stdin);
  source[PCAP_ERRBUF_SIZE] = '\0';
  /* Retrieve the interfaces list */
  if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
  {
    fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
    exit(1);
  }
  /* Scan the list printing every entry */
  for(d=alldevs;d;d=d->next)
  {
    ifprint(d);
  }
  pcap_freealldevs(alldevs);
  return 1;
}
 
/* Print all the available information on the given interface */
void ifprint(pcap_if_t *d)
{
  pcap_addr_t *a;
  char ip6str[128];
  /* Name */
  printf("%s\n",d->name);
  /* Description */
  if (d->description)
    printf("\tDescription: %s\n",d->description);
  /* Loopback Address*/
  printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
  /* IP addresses */
  for(a=d->addresses;a;a=a->next) {
    printf("\tAddress Family: #%d\n",a->addr->sa_family);
 
    switch(a->addr->sa_family)
    {
      case AF_INET:
        printf("\tAddress Family Name: AF_INET\n");
        if (a->addr)
          printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
        if (a->netmask)
          printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
        if (a->broadaddr)
          printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
        if (a->dstaddr)
          printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
        break;
      case AF_INET6:
        printf("\tAddress Family Name: AF_INET6\n");
        if (a->addr)
          printf("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
       break;
      default:
        printf("\tAddress Family Name: Unknown\n");
        break;
    }
  }
  printf("\n");
}
 
/* From tcptraceroute, convert a numeric IP address to a string */
#define IPTOSBUFFERS    12
char *iptos(u_long in)
{
    static char output[IPTOSBUFFERS][3*4+3+1];
    static short which;
    u_char *p;
    p = (u_char *)&in;
    which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
    sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    return output[which];
}
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen)
{
    socklen_t sockaddrlen;
    #ifdef WIN32
    sockaddrlen = sizeof(struct sockaddr_in6);
    #else
    sockaddrlen = sizeof(struct sockaddr_storage);
    #endif

    if(getnameinfo(sockaddr,
        sockaddrlen,
        address,
        addrlen,
        NULL,
        0,
        NI_NUMERICHOST) != 0) address = NULL;
    return address;
}
WinPcap tutorial: a step by step guide to using WinPcap(3)
Opening an adapter and capturing the packets
打開(kāi)一個(gè)適配器開(kāi)始抓取
 現(xiàn)在我們已經(jīng)知道了怎樣去獲取一個(gè)適配器并使用它,,讓我們開(kāi)始真正的工作-----開(kāi)始抓取網(wǎng)絡(luò)數(shù)據(jù)包吧。在這一課中我們將寫(xiě)一個(gè)程序,,這個(gè)程序?qū)⒃谖覀冞x擇的適配器上監(jiān)聽(tīng),,并抓取通過(guò)這個(gè)適配器上的每一個(gè)數(shù)據(jù)包,打印其中的一些信息,。
 我們主要使用的函數(shù)是pcap_open(),,這個(gè)函數(shù)的功能是打開(kāi)一個(gè)抓取設(shè)備。在這里有必要對(duì)其中的幾個(gè)參數(shù)snaplen, flags and to_ms作一下說(shuō)明,。
 snaplen指定了我們所要抓取的包的長(zhǎng)度(譯者:也就是我們想抓多長(zhǎng)就設(shè)置多長(zhǎng)),。在一些操作系統(tǒng)(如xBSD和Win32)中,底層驅(qū)動(dòng)可以通過(guò)配置只抓取數(shù)據(jù)包的開(kāi)始部分:這樣就減少了拷貝給應(yīng)用程序的數(shù)據(jù)量,,因此可以提高抓取效率,。在這個(gè)例子里我們使用65536這個(gè)比我們所能遇到的最大的MTU還大的數(shù)字。這樣我們就能確保我們的程序可以抓到整個(gè)數(shù)據(jù)包,。
 flags:最重要的標(biāo)志是一個(gè)指示適配器是否工作在混雜模式下的,。在正常狀況下,一個(gè)適配器僅僅抓取網(wǎng)絡(luò)中目的地是它自己的數(shù)據(jù)包,;因此其他主機(jī)交換的數(shù)據(jù)包都被忽略,。相反,當(dāng)適配器處在混雜模式下的時(shí)候它就會(huì)抓取所有的數(shù)據(jù)包而不管是不是發(fā)給它的,。這就意味著在共享媒體(如非交換的以太網(wǎng))上,,WinPcap將能夠抓取其他主機(jī)的數(shù)據(jù)包?;祀s模式是大部分抓取程序的默認(rèn)模式,,所以在下面的例子中我們就開(kāi)啟它。
 to_ms以豪秒為單位指定了讀取操作的超時(shí)界限,。在適配器上一個(gè)讀取操作(比如,,pcap_dispatch() 或者 pcap_next_ex())將總是在to_ms豪秒后返回,即使網(wǎng)絡(luò)中沒(méi)有數(shù)據(jù)包可供抓取。如果適配器工作在統(tǒng)計(jì)模式(如果對(duì)此不了解,,請(qǐng)看課程9),,to_ms還定義了統(tǒng)計(jì)報(bào)告之間的間隔。把tm_ms設(shè)置為0意味著沒(méi)有時(shí)間限制,,如果沒(méi)有數(shù)據(jù)包到達(dá)適配器,,讀取操作將永遠(yuǎn)不會(huì)返回。反過(guò)來(lái),,把tm_ms設(shè)置為-1將使讀取操作總是立即返回,。
#i nclude "pcap.h"
/* 數(shù)據(jù)包處理程序,回調(diào)函數(shù) */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
   
    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }
   
    /* Print the list */
    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");
        /* 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 ( (adhandle= pcap_open(d->name,          // name of the device
                              65536,            // portion of the packet to capture
                                                // 65536 guarantees that the whole packet will be captured on all the link layers
                              PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                              1000,             // read timeout
                              NULL,             // authentication on the remote machine
                              errbuf            // error buffer
                              ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    printf("\nlistening on %s...\n", d->description);
   
    /* At this point, we don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
   
    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);
   
    return 0;
}

/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm *ltime;
    char timestr[16];
   
    /* convert the timestamp to readable format */
    ltime=localtime(&header->ts.tv_sec);
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
   
    printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
   
}
 一旦打開(kāi)了適配器,,就由pcap_dispatch() 或者pcap_loop()開(kāi)始抓取,。這兩個(gè)函數(shù)都非常慢,所不同的是pcap_ dispatch()一旦超時(shí)就可以返回(盡管不能保證)而pcap_loop() 會(huì)一直等到cnt包被抓到才會(huì)返回,,所以這個(gè)函數(shù)在沒(méi)有數(shù)據(jù)包的網(wǎng)絡(luò)中會(huì)阻塞任意的時(shí)間,。在這個(gè)例子中pcap_loop()就足夠了,而pcap_dispatch() 則可以在一個(gè)更復(fù)雜的程序中使用,。
 這兩個(gè)函數(shù)都有一個(gè)回調(diào)函數(shù)作為參數(shù),,packet_handler,這個(gè)參數(shù)指定的函數(shù)將收到數(shù)據(jù)包,。這個(gè)函數(shù)在每一個(gè)新的數(shù)據(jù)包從網(wǎng)絡(luò)中到達(dá)時(shí)都會(huì)被libpcap調(diào)用,,并且會(huì)收到一個(gè)反映pcap_loop() 和 pcap_dispatch()函數(shù)的生成狀態(tài),,和一個(gè)結(jié)構(gòu)體header,。這個(gè)header中帶有一些數(shù)據(jù)包中的信息,比如時(shí)間戳和長(zhǎng)度,、包括所有協(xié)議頭的實(shí)際數(shù)據(jù)包,。注意結(jié)構(gòu)體中是沒(méi)有CRC的,因?yàn)樵跀?shù)據(jù)確認(rèn)后已經(jīng)被適配器去掉了,。也要注意大部分適配器丟棄了CRC錯(cuò)誤的數(shù)據(jù)包,,因此Winpcap不能抓取這些包。
 上面的例子從pcap_pkthdr中提取每個(gè)數(shù)據(jù)包的時(shí)間戳和長(zhǎng)度并顯示它們,。
 請(qǐng)注意使用pcap_loop()可能有一個(gè)缺點(diǎn),,就是使用這個(gè)函數(shù)時(shí)包處理函數(shù)要被包抓取驅(qū)動(dòng)程序來(lái)調(diào)用;因此應(yīng)用程序不能直接控制它,。另一種方法(并且更容易理解)是使用函數(shù)pcap_next_ex(),,這個(gè)函數(shù)我們將在下一個(gè)例子中使用。
4.
Capturing the packets without the callback
 這節(jié)課程中的例子程序完成的功能和上節(jié)課的一樣,,但是使用的是pcap_next_ex()而不是pcap_loop().
 基于回調(diào)捕獲機(jī)制的 pcap_loop()是非常優(yōu)雅的,,在很多情況下都是一個(gè)不錯(cuò)的選擇。不過(guò),有時(shí)候處理一個(gè)回調(diào)函數(shù)顯得不太現(xiàn)實(shí) --- 通常這會(huì)使程序更加復(fù)雜,,在使用多線程或者c++類(lèi)的時(shí)候尤其如此,。
 在這種情況下,可以直接調(diào)用 pcap_next_ex() 來(lái)返回一個(gè)數(shù)據(jù)包 -- 這樣程序員可以在僅僅想使用它們的時(shí)候再處理 pcap_next_ex() 返回的數(shù)據(jù)包,。
 這個(gè)函數(shù)的參數(shù)和回調(diào)函數(shù) pcap_loop() 的一樣 -- 由一個(gè)網(wǎng)絡(luò)適配器描述符作為入口參數(shù)和兩個(gè)指針作為出口參數(shù),,這兩個(gè)指針將在函數(shù)中被初始化,然后再返回給用戶(hù)(一個(gè)指向pcap_pkthdr 結(jié)構(gòu),,另一個(gè)指向一個(gè)用作數(shù)據(jù)緩沖區(qū)的內(nèi)存區(qū)域),。
 在下面的程序中,我們繼續(xù)使用上一節(jié)課中的例子的數(shù)據(jù)處理部分的代碼,,把這些代碼拷貝到main()函數(shù)中pcap_next_ex()的后面,。
#i nclude "pcap.h"

main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
int res;
char errbuf[PCAP_ERRBUF_SIZE];
struct tm *ltime;
char timestr[16];
struct pcap_pkthdr *header;
u_char *pkt_data;
   
   
    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }
   
    /* Print the list */
    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");
        /* 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 ( (adhandle= pcap_open(d->name,          // name of the device
                              65536,            // portion of the packet to capture.
                                                // 65536 guarantees that the whole packet will be captured on all the link layers
                              PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                              1000,             // read timeout
                              NULL,             // authentication on the remote machine
                              errbuf            // error buffer
                              ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    printf("\nlistening on %s...\n", d->description);
   
    /* At this point, we don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
   
    /* Retrieve the packets */
    while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){
       
        if(res == 0)
            /* Timeout elapsed */
            continue;
       
        /* convert the timestamp to readable format */
        ltime=localtime(&header->ts.tv_sec);
        strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
       
        printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
    }
   
    if(res == -1){
        printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
        return -1;
    }
   
    return 0;
 為什么我們使用 pcap_next_ex() 而不是 pcap_next()?因?yàn)?pcap_next() 有一些缺陷。首先,,它的效率不高,,因?yàn)樗m然隱藏了回調(diào)模式但是仍然依賴(lài)于 pcap_dispatch()。其次,,它不能檢測(cè)EOF(譯者注:end of file,,意思是文件結(jié)束標(biāo)志),所以當(dāng)我們從一個(gè)文件中收集包的時(shí)候不是很有用(譯者注:winpcap可以把捕獲的數(shù)據(jù)包以很高的效率存在文件中,,留待以后分析,,這一點(diǎn)以后的課程中也會(huì)講到)。
 也要注意 pcap_next_ex() 對(duì)于成功調(diào)用,、超時(shí),、錯(cuò)誤和EOF狀態(tài)會(huì)返回不同的值。
5.Filtering the traffic
 WinPcap提供的最強(qiáng)大的特性之一就是過(guò)濾引擎,。它是被集成到了winpcap的捕獲機(jī)制中的,,提供了一種非常高效的方法來(lái)獲取部分網(wǎng)絡(luò)數(shù)據(jù)。被用來(lái)過(guò)濾數(shù)據(jù)包的函數(shù)是 pcap_compile() 和 pcap_setfilter(),。
 pcap_compile() 接受一個(gè)包含布爾表達(dá)式的字符串,,生成可以被捕獲包驅(qū)動(dòng)中的過(guò)濾引擎解釋的代碼。布爾表達(dá)式的語(yǔ)法在這個(gè)文檔的Filtering expression syntax 那一節(jié)(譯者注:其實(shí)和tcpdump的一樣,,如果了解tcpdump,,可以直接按照tcpdump的語(yǔ)法來(lái)寫(xiě))。
 pcap_setfilter() 綁定一個(gè)過(guò)濾器到一個(gè)在核心驅(qū)動(dòng)中的捕獲進(jìn)程中,。一旦 pcap_setfilter() 被調(diào)用,,這個(gè)過(guò)濾器就會(huì)對(duì)網(wǎng)絡(luò)來(lái)的所有數(shù)據(jù)包進(jìn)行過(guò)濾,所有符合條件的數(shù)據(jù)包(按照布爾表達(dá)式來(lái)計(jì)算出結(jié)果是真的數(shù)據(jù)包)都會(huì)被拷貝給進(jìn)行捕獲的應(yīng)用程序,。
 下面的代碼說(shuō)明了怎樣編譯和設(shè)置一個(gè)過(guò)濾器,。注意我們必須得到說(shuō)明適配器的 pcap_if 結(jié)構(gòu)中的子網(wǎng)掩碼,,因?yàn)橐恍┍?pcap_compile() 生成的過(guò)濾器需要它。這個(gè)過(guò)濾器中傳遞給 pcap_compile() 的字符串是 "ip and tcp",意思是“僅僅把IPv4 and TCP 數(shù)據(jù)包保存下來(lái)并交付給應(yīng)用程序”,。
if (d->addresses != NULL)
        /* Retrieve the mask of the first address of the interface */
        netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* If the interface is without an address we suppose to be in a C class network */
        netmask=0xffffff;

    //compile the filter
    if (pcap_compile(adhandle, &fcode, "ip and tcp", 1, netmask) < 0)
    {
        fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    //set the filter
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
        fprintf(stderr,"\nError setting the filter.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
 如果你想看一些在這節(jié)課中講述的使用過(guò)濾功能的代碼,,請(qǐng)看下節(jié)課中的例子,Interpreting the packets.
6.Interpreting the packets.
 現(xiàn)在我們已經(jīng)能夠捕獲并且過(guò)濾網(wǎng)絡(luò)數(shù)據(jù)包,,下面我們就把我們的知識(shí)運(yùn)用到一個(gè)簡(jiǎn)單的“真實(shí)的”應(yīng)用程序中去,。
 在這節(jié)課中我們將從前面的課程中拷貝代碼并用它們來(lái)構(gòu)造出一個(gè)更有用途的程序。這個(gè)程序主要的目的就是說(shuō)明怎樣分析和解釋我們已經(jīng)捕獲的數(shù)據(jù)包的協(xié)議結(jié)構(gòu),。最終的應(yīng)用程序,,叫做UDPdump,會(huì)打印出一個(gè)在我們的網(wǎng)絡(luò)中的UDP數(shù)據(jù)包的概要。
 在開(kāi)始階段我們選擇分析并顯示UDP協(xié)議,,因?yàn)閁DP協(xié)議比其他的協(xié)議比如TCP協(xié)議更容易理解,,從而非常適合作為初始階段的例子。還是讓我們開(kāi)始看代碼吧:
/*
 * Copyright (c) 1999 - 2003
 * NetGroup, Politecnico di Torino (Italy)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Politecnico di Torino nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 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) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#i nclude "pcap.h"
/* 4 bytes IP address */
typedef struct ip_address{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;
/* IPv4 header */
typedef struct ip_header{
    u_char  ver_ihl;        // Version (4 bits) + Internet header length (4 bits)
    u_char  tos;            // Type of service
    u_short tlen;           // Total length
    u_short identification; // Identification
    u_short flags_fo;       // Flags (3 bits) + Fragment offset (13 bits)
    u_char  ttl;            // Time to live
    u_char  proto;          // Protocol
    u_short crc;            // Header checksum
    ip_address  saddr;      // Source address
    ip_address  daddr;      // Destination address
    u_int   op_pad;         // Option + Padding
}ip_header;
/* UDP header*/
typedef struct udp_header{
    u_short sport;          // Source port
    u_short dport;          // Destination port
    u_short len;            // Datagram length
    u_short crc;            // Checksum
}udp_header;
/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
u_int netmask;
char packet_filter[] = "ip and udp";
struct bpf_program fcode;
    /* Retrieve the device list */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }
   
    /* Print the list */
    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");
        /* 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 adapter */
    if ( (adhandle= pcap_open(d->name,  // name of the device
                             65536,     // portion of the packet to capture.
                                        // 65536 grants that the whole packet will be captured on all the MACs.
                             PCAP_OPENFLAG_PROMISCUOUS,         // promiscuous mode
                             1000,      // read timeout
                             NULL,      // remote authentication
                             errbuf     // error buffer
                             ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    /* Check the link layer. We support only Ethernet for simplicity. */
    if(pcap_datalink(adhandle) != DLT_EN10MB)
    {
        fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    if(d->addresses != NULL)
        /* Retrieve the mask of the first address of the interface */
        netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* If the interface is without addresses we suppose to be in a C class network */
        netmask=0xffffff;

    //compile the filter
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
    {
        fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    //set the filter
    if (pcap_setfilter(adhandle, &fcode)<0)
    {
        fprintf(stderr,"\nError setting the filter.\n");
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
   
    printf("\nlistening on %s...\n", d->description);
   
    /* At this point, we don't need any more the device list. Free it */
    pcap_freealldevs(alldevs);
   
    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, NULL);
   
    return 0;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm *ltime;
    char timestr[16];
    ip_header *ih;
    udp_header *uh;
    u_int ip_len;
    u_short sport,dport;
    /* convert the timestamp to readable format */
    ltime=localtime(&header->ts.tv_sec);
    strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
    /* print timestamp and length of the packet */
    printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
    /* retireve the position of the ip header */
    ih = (ip_header *) (pkt_data +
        14); //length of ethernet header
    /* retireve the position of the udp header */
    ip_len = (ih->ver_ihl & 0xf) * 4;
    uh = (udp_header *) ((u_char*)ih + ip_len);
    /* convert from network byte order to host byte order */
    sport = ntohs( uh->sport );
    dport = ntohs( uh->dport );
    /* print ip addresses and udp ports */
    printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
        ih->saddr.byte1,
        ih->saddr.byte2,
        ih->saddr.byte3,
        ih->saddr.byte4,
        sport,
        ih->daddr.byte1,
        ih->daddr.byte2,
        ih->daddr.byte3,
        ih->daddr.byte4,
        dport);
}
 首先,,我們?cè)O(shè)定過(guò)濾器的過(guò)濾規(guī)則為"ip and udp",。這樣我們就能夠確保 packet_handler() 函數(shù)只返回IPv4的UDP數(shù)據(jù)包:這可以簡(jiǎn)化分析工作,改善程序的效率,。
 在程序開(kāi)始部分,,我們已經(jīng)建立了兩個(gè)結(jié)構(gòu)體,分別用來(lái)描述IP和UDP頭,。這兩個(gè)結(jié)構(gòu)體被 packet_handler() 函數(shù)用來(lái)正確定位IP和UDP頭字段,。
 packet_handler(),雖然被限制為只能解析一個(gè)協(xié)議(IPv4的UDP),,但是仍然可以說(shuō)明那些象 tcpdump/WinDump 一樣復(fù)雜的嗅探器怎樣解析網(wǎng)絡(luò)數(shù)據(jù)包的,。因?yàn)槲覀儗?duì)MAC頭不感興趣,所以我們就忽略它,。為了簡(jiǎn)單起見(jiàn),,在開(kāi)始捕獲之前,我們用 pcap_datalink() 函數(shù)來(lái)檢查MAC層,,以確保我們正在處理的是以太網(wǎng)楨。這樣我們就能夠確保MAC頭正好是14字節(jié),。(譯者注:這里因?yàn)槭侵苯影岩蕴W(wǎng)楨加14來(lái)獲得IP包的,,所以要確保的卻是以太網(wǎng)楨,不然就會(huì)產(chǎn)生錯(cuò)誤,。)
 IP頭就緊跟在MAC頭后面,。我們將從IP頭中取得IP源地址和目的地址。
 到達(dá)UDP頭復(fù)雜了一點(diǎn),,因?yàn)镮P頭的長(zhǎng)度是不固定的,。因此,,我們使用IP頭的長(zhǎng)度字段來(lái)確定它的大小。于是我們就知道了UDP頭的位置,,然后就可以取得源端口和目的端口,。
 我們把獲取的數(shù)據(jù)打印到屏幕上,結(jié)果如下:
1. {A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter)
Enter the interface number (1-2):1

listening on Xircom CardBus Ethernet 10/100 Adapter...
16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53
16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682
16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53
后三行的每一行都代表了一個(gè)不同的數(shù)據(jù)包,。
7.Handling offline dump files
 在這節(jié)課中我們來(lái)學(xué)習(xí)怎樣將數(shù)據(jù)包保存到一個(gè)文件中,。Winpcap提供了一系列保存網(wǎng)絡(luò)數(shù)據(jù)包到一個(gè)文件和從文件中讀取保存內(nèi)容的函數(shù) -- 這節(jié)課就是講述怎樣使用這些函數(shù)的。同時(shí)也會(huì)展示怎樣winpcap核心中的保存特性來(lái)獲得高性能的存儲(chǔ)(注意:現(xiàn)在,,由于新的內(nèi)核緩存的一些問(wèn)題,,這個(gè)特性已經(jīng)不能使用了)。
 dump文件的格式和libpcap的是一樣的,。在這個(gè)格式里捕獲的數(shù)據(jù)包是用二進(jìn)制的形式來(lái)保存的,,現(xiàn)在已經(jīng)作為標(biāo)準(zhǔn)被許多網(wǎng)絡(luò)工具使用,其中就包括WinDump, Ethereal 和 Snort,。
保存數(shù)據(jù)包到一個(gè)dump文件:
 首先,,讓我們看看怎樣用libpcap格式來(lái)寫(xiě)數(shù)據(jù)包。下面的例子從選擇的網(wǎng)絡(luò)接口中捕獲數(shù)據(jù)并保存到一個(gè)由用戶(hù)提供名字的文件中,。
#i nclude "pcap.h"
/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;

   
    /* Check command line */
    if(argc != 2)
    {
        printf("usage: %s filename", argv[0]);
        return -1;
    }
   
    /* Retrieve the device list on the local machine */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }
   
    /* Print the list */
    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");
        /* 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 ( (adhandle= pcap_open(d->name,          // name of the device
                              65536,            // portion of the packet to capture
                                                // 65536 guarantees that the whole packet will be captured on all the link layers
                              PCAP_OPENFLAG_PROMISCUOUS,    // promiscuous mode
                              1000,             // read timeout
                              NULL,             // authentication on the remote machine
                              errbuf            // error buffer
                              ) ) == NULL)
    {
        fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        /* Free the device list */
        pcap_freealldevs(alldevs);
        return -1;
    }
    /* Open the dump file */
    dumpfile = pcap_dump_open(adhandle, argv[1]);
    if(dumpfile==NULL)
    {
        fprintf(stderr,"\nError opening output file\n");
        return -1;
    }
   
    printf("\nlistening on %s... Press Ctrl+C to stop...\n", d->description);
   
    /* At this point, we no longer need the device list. Free it */
    pcap_freealldevs(alldevs);
   
    /* start the capture */
    pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
    return 0;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    /* save the packet on the dump file */
    pcap_dump(dumpfile, header, pkt_data);
}
現(xiàn)在你也看到了,,這個(gè)程序的結(jié)構(gòu)和我們以前學(xué)的程序的結(jié)構(gòu)非常類(lèi)似。只有兩點(diǎn)不同:
 打開(kāi)網(wǎng)絡(luò)接口后跟著就調(diào)用pcap_dump_open() ,,這個(gè)調(diào)用打開(kāi)一個(gè)dump文件并把它和網(wǎng)絡(luò)接口綁定到一起,。
 在 packet_handler() 回調(diào)函數(shù)中數(shù)據(jù)包被 pcap_dump() 函數(shù)寫(xiě)到打開(kāi)的文件中去。pcap_dump() 的參數(shù)與 packet_handler() 中的參數(shù)一一對(duì)應(yīng),。
從一個(gè)dump文件中讀取數(shù)據(jù)包:
 現(xiàn)在我們已經(jīng)有了一個(gè)有效的dump文件,,我們可以嘗試來(lái)讀取它的內(nèi)容。下面的代碼打開(kāi)一個(gè)dump文件并顯示出里面包含的每一個(gè)數(shù)據(jù)包,。文件打開(kāi)是用的 pcap_open_offline() 函數(shù),,然后一般是用 pcap_loop() 來(lái)按照順序來(lái)讀取數(shù)據(jù)包。就象你看到的一樣,,從一個(gè)dump文件中讀取數(shù)據(jù)包和從一個(gè)物理接口來(lái)捕獲數(shù)據(jù)包基本上是一樣的,。
 這個(gè)例子還介紹了另一個(gè)函數(shù):pcap_createsrcsrc()。這個(gè)函數(shù)生成一個(gè)以一個(gè)標(biāo)記開(kāi)始的數(shù)據(jù)源字符串,,這個(gè)標(biāo)記用來(lái)告訴winpcap數(shù)據(jù)源的類(lèi)型,,比如"rpcap://" 代表一個(gè)適配器,"file://" 代表一個(gè)文件,。如果已經(jīng)使用了 pcap_findalldevs_ex() (這個(gè)函數(shù)的返回值已經(jīng)包含了數(shù)據(jù)源字符串),,那么就不需要再使用 pcap_createsrcsrc() 了。不過(guò),,因?yàn)槲募质怯脩?hù)輸入的,,所以在這個(gè)例子里我們還是要使用它的,。
#i nclude <stdio.h>
#i nclude <pcap.h>
#define LINE_LEN 16
void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
char source[PCAP_BUF_SIZE];
    if(argc != 2){
        printf("usage: %s filename", argv[0]);
        return -1;
    }
 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多