• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            elva

            wincap中文版翻譯2<轉(zhuǎn)>

            不用loopback捕獲數(shù)據(jù)報
            這節(jié)的例子很象先前的一章(獲得網(wǎng)卡的高級信息)但是這一節(jié)中是用pcap_next_ex()來代替pcap_loop()來捕獲數(shù)據(jù)包。基于回調(diào)包捕獲機(jī)制

            的pcap_loop()在某些情況下是不錯的選擇。但是在一些情況下處理回調(diào)并不特別好:這會使程序變的復(fù)雜并且在象多線程或C++類這些情況下

            它看起來到象一塊絆腳石。

            在這些情況下pcap_next_ex()允許直接調(diào)用來接收包,它的參數(shù)和pcap_loop()相同:有一個網(wǎng)卡描述副,和兩個指針,這兩個指針會被初始化

            并返回給用戶,一個是pcap_pkthdr結(jié)構(gòu),另一個是接收數(shù)據(jù)的緩沖區(qū)。下面的程序我門將循環(huán)調(diào)用前一節(jié)的例子中的回掉部分,只是把它移到

            了main里面了。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            #include "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 */
            if (pcap_findalldevs(&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_live(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.
            1, // promiscuous mode
            1000, // read timeout
            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;
            }

            printf("\nlistening on %s...\n", d->description);

            /* At this point, we don‘t need any more the device list. Free it */
            pcap_freealldevs(alldevs);

            /* 此處循環(huán)調(diào)用 pcap_next_ex來接受數(shù)據(jù)報*/
            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()只在Win32環(huán)境下才行因?yàn)樗皇窃糽ibpcap API中的一部分,這就意味著依賴于這個函數(shù)的代碼不會在UNIX下工作。那

            么為什么我們用pcap_next_ex()而不用pcap_next()?因?yàn)閜cap_next()有許多限制在很多情況下并不鼓勵用它。首先它的效率很低因?yàn)樗[藏

            了回掉方法并且還依賴于pcap_dispatch()這個函數(shù)。再次它不能夠識別文件結(jié)束標(biāo)志EOF所以對來自文件的數(shù)據(jù)流它幾乎無能為力。
            注意當(dāng)pcap_next_ex()在成功,超時,出錯和文件結(jié)束的情況下會返回不同的值

            五)數(shù)據(jù)流的過濾

            WinPcap或libpca最強(qiáng)大的特點(diǎn)之一就是數(shù)據(jù)流的過濾引擎。它提供一種高效的方法來只捕獲網(wǎng)絡(luò)數(shù)據(jù)流的某些數(shù)據(jù)而且常常和系統(tǒng)的捕獲機(jī)制

            相集成。過濾數(shù)據(jù)的函數(shù)是pcap_compile() 和 pcap_setfilter()來實(shí)現(xiàn)的。


            pcap_compile()來編譯一個過濾設(shè)備,它通過一個高層的boolean型變量和字串產(chǎn)生一系列的能夠被底層驅(qū)動所解釋的二進(jìn)制編碼。boolean表

            示語法能夠在這個文件的過濾表示語法中找到。

            pcap_setfilter() 用來聯(lián)系一個在內(nèi)核驅(qū)動上過濾的過濾器,這時所有網(wǎng)絡(luò)數(shù)據(jù)包都將流經(jīng)過濾器,并拷貝到應(yīng)用程序中。

            下面的代碼展示了如何編譯并社定一個過濾設(shè)備。注意我們必須從pcap_if結(jié)構(gòu)中獲得掩碼,因?yàn)橐恍┻^濾器的創(chuàng)建需要這個參數(shù)。

            下面的代碼段中的pcap_compile()的"ip and tcp"參數(shù)說明只有IPV4和TCP數(shù)據(jù)才會被內(nèi)核保存并被傳遞到應(yīng)用程序。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            if(d->addresses != NULL)
            /* 獲得第一個接口地址的掩碼 */
            netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
            else
            /* 如果這個接口沒有地址那么我們假設(shè)他為C類地址 */
            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;
            }

               
            六)解析數(shù)據(jù)包
            現(xiàn)在經(jīng)過上幾節(jié)的學(xué)習(xí)能夠進(jìn)行數(shù)據(jù)報的捕獲和過濾了,我們想用一個簡單的"real world"程序?qū)⑽覀兯鶎W(xué)的

            知識應(yīng)用于實(shí)際。
            這一節(jié)里我們將利用以前的代碼并將其引申從而建立一個更實(shí)用的程序。該程序的主要目的是如何顯示出所捕

            獲的數(shù)據(jù)報的內(nèi)容,尤其是對它的協(xié)議頭的分析和說明。這個程序名叫UDPdump它將在屏幕上顯示出我們網(wǎng)絡(luò)上

            UDP數(shù)據(jù)的信息。
            在此我們選擇解析UDP而不用TCP因?yàn)樗萒CP簡單更加的直觀明了。下面讓我們來看看原代碼。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            /*
            * Copyright (c) 1999 - 2002
            * Politecnico di Torino. All rights reserved.
            *
            * Redistribution and use in source and binary forms, with or without
            * modification, are permitted provided that: (1) source code distributions
            * retain the above copyright notice and this paragraph in its entirety, (2)
            * distributions including binary code include the above copyright notice and
            * this paragraph in its entirety in the documentation or other materials
            * provided with the distribution, and (3) all advertising materials mentioning
            * features or use of this software display the following acknowledgement:
            * ``This product includes software developed by the Politecnico
            * di Torino, and its contributors.‘‘ Neither the name of
            * the University 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 ``AS IS‘‘ AND WITHOUT ANY EXPRESS OR IMPLIED
            * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
            * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
            */

            #include "pcap.h"

            /* 4 BIT的IP頭定義 */
            typedef struct ip_address{
            u_char byte1;
            u_char byte2;
            u_char byte3;
            u_char byte4;
            }ip_address;

            /* IPv4 頭的定義 */
            typedef struct ip_header{
            u_char ver_ihl; // 4 bit的版本信息 + 4 bits的頭長
            u_char tos; // TOS類型
            u_short tlen; // 總長度
            u_short identification; // Identification
            u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
            u_char ttl; // 生存期
            u_char proto; // 后面的協(xié)議信息
            u_short crc; // 校驗(yàn)和
            ip_address saddr; // 源IP
            ip_address daddr; // 目的IP
            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;

            /* 定義處理包的函數(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];
            u_int netmask;
            char packet_filter[] = "ip and udp";
            struct bpf_program fcode;

            /* Retrieve the device list */
            if (pcap_findalldevs(&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_live(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.
            1, // promiscuous mode
            1000, // read timeout
            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);

            /* 找到IP頭的位置 */
            ih = (ip_header *) (pkt_data +
            14); //14為以太頭的長度

            /* 找到UDP的位置 */
            ip_len = (ih->ver_ihl & 0xf) * 4;
            uh = (udp_header *) ((u_char*)ih + ip_len);

            /* 將端口信息從網(wǎng)絡(luò)型轉(zhuǎn)變?yōu)橹鳈C(jī)順序 */
            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);
            }

             

            首先我門設(shè)置UDP過濾,用這種方法我們確保packet_handler()只接受到基于IPV4的UDP數(shù)據(jù)。我們同樣定義了

            兩個數(shù)據(jù)結(jié)構(gòu)來描述IP 和UDP的頭部信息,packet_handler()用這兩個結(jié)構(gòu)來定位頭部的各種字段。
            packet_handler()雖然只是限于處理一些UDP數(shù)據(jù)但卻顯示了復(fù)雜的嗅探器如tcpdump/WinDump的工作原理。
            首先我們對MAC地址的頭部并不感興趣所以我們跳過它。不過在開始捕獲之前我們用pcap_datalink()來檢查MAC

            層,所以以上的程序只能夠工作在Ethernet networks上,再次我們確保MAC頭為14 bytes。
            MAC頭之后是IP頭,我們從中提取出了目的地址。IP之后是UDP,在確定UDP的位置時有點(diǎn)復(fù)雜,因?yàn)镮P的長度以

            為版本的不同而不同,所以我們用頭長字段來定位UDP,一旦 我們確定了UDP的起始位置,我們就可以解析出原

            和目的端口。
            下面是我們打印出來的一些結(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

            上面每一行都顯示出不同的數(shù)據(jù)包的內(nèi)容.

              
            (七)處理脫機(jī)的堆文件

            通過以前的學(xué)習(xí)我門已經(jīng)熟悉了從網(wǎng)卡上捕獲數(shù)據(jù)包,現(xiàn)在我門將學(xué)習(xí)如何處理數(shù)據(jù)包。WINPCAP為我們提供了很多API來將流經(jīng)網(wǎng)絡(luò)的數(shù)據(jù)包

            保存到一個堆文件并讀取堆的內(nèi)容。這一節(jié)將講述如何使用所有的這些API。
            這種文件的格式很簡單,但包含了所捕獲的數(shù)據(jù)報的二進(jìn)制內(nèi)容,這種文件格式也是很多網(wǎng)絡(luò)工具的標(biāo)準(zhǔn)如WinDump, Ethereal 還有 Snort等.


            關(guān)于如何將數(shù)據(jù)包保存到文件:

            首先我們看看如何以LIBPCAP的格式寫數(shù)據(jù)包。
            下面的例子演示了如何從指定的接口上捕獲數(shù)據(jù)包并將它們存儲到一個指定的文件。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            #include "pcap.h"

            /* 定義處理數(shù)據(jù)的函數(shù)原形 */
            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;

             

            /* 檢查命令行參數(shù) 是否帶有文件名*/
            if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

            }

            /* 獲得驅(qū)動列表 */
            if (pcap_findalldevs(&alldevs, errbuf) == -1)
            {
            fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
            exit(1);
            }

            /* 打印 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;
            }

            /* 跳轉(zhuǎn)到指定的網(wǎng)卡 */
            for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);

            /* Open the adapter */
            if ( (adhandle = pcap_open_live(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.
            1, // promiscuous mode
            1000, // read timeout
            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;
            }

            /* 打開文件 */
            dumpfile = pcap_dump_open(adhandle, argv[1]);
            if(dumpfile==NULL){
            fprintf(stderr,"\nError opening output file\n");
            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);

            /* 循環(huán)捕獲數(shù)據(jù)并調(diào)用packet_handler函數(shù)把數(shù)據(jù)存儲到堆文件 */
            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)
            {
            /* 此函數(shù)功能將數(shù)據(jù)報存儲到堆文件 */
            pcap_dump(dumpfile, header, pkt_data);
            }

             

            正如你看到的那樣該程序的結(jié)構(gòu)非常類似與以前的例子,區(qū)別是:
            一旦打開網(wǎng)卡就調(diào)用pcap_dump_open()來打開一個文件,該調(diào)用將文件和某個網(wǎng)卡相關(guān)聯(lián)。
            packet_handler()內(nèi)部通過調(diào)用pcap_dump()來將捕獲的數(shù)據(jù)報存儲到文件。pcap_dump()的參數(shù)和 packet_handler()一樣,所以用起來比較方

            便。

            從文件讀數(shù)據(jù)包:

            下面我們來看如何從文件讀取數(shù)據(jù)內(nèi)容。下面的代碼打開了 一個堆文件并打印了其中的每個包內(nèi)容。
            pcap_open_offline()用來打開一個堆文件,之后用pcap_loop()來循環(huán)從文件中讀取數(shù)據(jù)。你能發(fā)現(xiàn)讀取脫機(jī)的數(shù)據(jù)幾乎和實(shí)時的從網(wǎng)卡上讀

            取一摸一樣。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            #include <stdio.h>
            #include <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];


            if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

            }

            /* 打開一個存儲有數(shù)據(jù)的堆文件 */
            if ( (fp = pcap_open_offline(argv[1], errbuf) ) == NULL)
            {
            fprintf(stderr,"\nError opening dump file\n");
            return -1;
            }

            // 讀取數(shù)據(jù)直到遇到 EOF標(biāo)志。
            pcap_loop(fp, 0, dispatcher_handler, NULL);

            return 0;
            }

             

            void dispatcher_handler(u_char *temp1,
            const struct pcap_pkthdr *header, const u_char *pkt_data)
            {
            u_int i=0;

            /* 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");

            }

             

            下面的代碼具有一樣的作用,只不過是用pcap_next_ex()來代替pcap_loop()循環(huán)讀取數(shù)據(jù)而已。


            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            #include <stdio.h>
            #include <pcap.h>

            #define LINE_LEN 16

            main(int argc, char **argv) {

            pcap_t *fp;
            char errbuf[PCAP_ERRBUF_SIZE];
            struct pcap_pkthdr *header;
            u_char *pkt_data;
            u_int i=0;
            int res;

            if(argc != 2){

            printf("usage: %s filename", argv[0]);
            return -1;

            }

            /* Open a capture file */
            if ( (fp = pcap_open_offline(argv[1], errbuf) ) == NULL)
            {
            fprintf(stderr,"\nError opening dump file\n");
            return -1;
            }

            /* Retrieve the packets from the file */
            while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0){
            /* 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){
            printf("Error reading the packets: %s\n", pcap_geterr(fp));
            }

            return 0;
            }


            用pcap_live_dump將數(shù)據(jù)寫到文件:
            WinPcap的最新版本提供了一個進(jìn)一步的方法來將數(shù)據(jù)包存儲到磁盤,就是使用pcap_live_dump()函數(shù)。他需要三個參數(shù):一個文件名,和一個

            該文件允許的最大長度還有一個參數(shù)是該文件所允許的最大包的數(shù)量。對這些參數(shù)來說 0 意味著沒有最大限制。注:我們可以在調(diào)用

            pcap_live_dump()前設(shè)置一個過濾器來定義哪些數(shù)據(jù)報需要存儲。

            pcap_live_dump() 是非阻塞的,所以他會立刻返回:數(shù)據(jù)的存儲過程將會異步的進(jìn)行,直到文件到達(dá)了指定的最大長度或最大數(shù)據(jù)報的數(shù)目為

            止。
            應(yīng)用程序能夠用pcap_live_dump_ended()來等檢查是否數(shù)據(jù)存儲完畢,如果你指定的最大長度參數(shù)和數(shù)據(jù)報數(shù)量為0,那么該操作將永遠(yuǎn)阻塞。

            pcap_live_dump() 和 pcap_dump()的不同從設(shè)置的最大極限來說就是性能的問題。pcap_live_dump()采用WinPcap NPF驅(qū)動來從內(nèi)核級的層次

            上向文件中寫數(shù)據(jù),從而使內(nèi)存拷貝最小化。
            顯然,這些特點(diǎn)當(dāng)前在其他的操作系統(tǒng)下是不能夠?qū)崿F(xiàn)的,pcap_live_dump()是WinPcap所特有的,而且只能夠應(yīng)用于Win32環(huán)境.

               
            八)發(fā)送數(shù)據(jù)包

            盡管WinPcap從名字上來看表明他的主要目的是捕獲數(shù)據(jù)包,但是他還為原始網(wǎng)絡(luò)提供了一些其他的功能,其中

            之一就是用戶可以發(fā)送數(shù)據(jù)包,這也就是本節(jié)的主要內(nèi)容。需要指出的是原來的libpcap并不提供數(shù)據(jù)包 的發(fā)

            送功能,這里所說的功能都是WinPcap的擴(kuò)展功能,所以并不能夠工作在UNIX下。

            用pcap_sendpacket來發(fā)送一個數(shù)據(jù)包:

            下面的代碼是一個最簡單的發(fā)送數(shù)據(jù)的方法。打開一個適配器后就可以用 pcap_sendpacket()來手工發(fā)送一

            個數(shù)據(jù)包了。這個函數(shù)需要的參數(shù):一個裝有要發(fā)送數(shù)據(jù)的緩沖區(qū),要發(fā)送的長度,和一個適配器。注意緩沖

            區(qū)中的數(shù)據(jù)將不被內(nèi)核協(xié)議處理,只是作為最原始的數(shù)據(jù)流被發(fā)送,所以我門必須填充好正確的協(xié)議頭以便正

            確的將數(shù)據(jù)發(fā)送。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            #include <stdlib.h>
            #include <stdio.h>

            #include <pcap.h>

            void usage();

            void main(int argc, char **argv) {
            pcap_t *fp;
            char error[PCAP_ERRBUF_SIZE];
            u_char packet[100];
            int i;

            /* Check the validity of the command line */
            if (argc != 2)
            {
            printf("usage: %s inerface", argv[0]);
            return;
            }

            /* 打開指定網(wǎng)卡 */
            if((fp = pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL)
            {
            fprintf(stderr,"\nError opening adapter: %s\n", error);
            return;
            }

            /* 假設(shè)網(wǎng)絡(luò)環(huán)境為ethernet,我門把目的MAC設(shè)為1:1:1:1:1:1*/
            packet[0]=1;
            packet[1]=1;
            packet[2]=1;
            packet[3]=1;
            packet[4]=1;
            packet[5]=1;

            /* 假設(shè)源MAC為 2:2:2:2:2:2 */
            packet[6]=2;
            packet[7]=2;
            packet[8]=2;
            packet[9]=2;
            packet[10]=2;
            packet[11]=2;

            /* 填充發(fā)送包的剩余部分 */
            for(i=12;i<100;i++){
            packet[i]=i%256;
            }

            /* 發(fā)送包 */
            pcap_sendpacket(fp,
            packet,
            100);

            return;
            }

             

            發(fā)送隊(duì)列:
            pcap_sendpacket()只是提供一個簡單的直接的發(fā)送數(shù)據(jù)的方法,而發(fā)送隊(duì)列提供一個高級的強(qiáng)大的和最優(yōu)的機(jī)

            制來發(fā)送一組數(shù)據(jù)包,隊(duì)列實(shí)際上是一個裝有要發(fā)送數(shù)據(jù)的一個容器,他有一個最大值來表明他所能夠 容納的

            最大比特數(shù)。
            pcap_sendqueue_alloc()用來創(chuàng)建一個隊(duì)列,并指定該隊(duì)列的大小。
            一旦隊(duì)列被創(chuàng)建就可以調(diào)用pcap_sendqueue_queue()來將數(shù)據(jù)存儲到隊(duì)列中,這個函數(shù)接受一個帶有時間戳和

            長度的pcap_pkthdr結(jié)構(gòu)和一個裝有數(shù)據(jù)報的緩沖區(qū)。這些參數(shù)同樣也應(yīng)用于pcap_next_ex() 和

            pcap_handler()中,所以給要捕獲的數(shù)據(jù)包或要從文件讀取的數(shù)據(jù)包排隊(duì)就是pcap_sendqueue_queue()的事情

            了。
            WinPcap調(diào)用pcap_sendqueue_transmit()來發(fā)送數(shù)據(jù)包,注意,第三個參數(shù)如果非零,那么發(fā)送將是同步的,

            這將站用很大的CPU資源,因?yàn)榘l(fā)生在內(nèi)核驅(qū)動的同步發(fā)送是通過"brute force"loops的,但是一般情況下能夠

            精確到微秒。
            需要指出的是用pcap_sendqueue_transmit()來發(fā)送比用pcap_sendpacket()來發(fā)送一系列的數(shù)據(jù)要高效的多,

            因?yàn)樗臄?shù)據(jù)是在內(nèi)核級上被緩沖。
            當(dāng)不再需要隊(duì)列時可以用pcap_sendqueue_destroy()來釋放掉所有的隊(duì)列資源。

            下面的代碼演示了如何用發(fā)送隊(duì)列來發(fā)送數(shù)據(jù),該示例用pcap_open_offline()打開了一個文件,然后將數(shù)據(jù)

            從文件移動到已分配的隊(duì)列,這時就同步地傳送隊(duì)列(如果用戶指定為同步的話)。

            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            /*
            * Copyright (c) 1999 - 2002
            * Politecnico di Torino. All rights reserved.
            *
            * Redistribution and use in source and binary forms, with or without
            * modification, are permitted provided that: (1) source code distributions
            * retain the above copyright notice and this paragraph in its entirety, (2)
            * distributions including binary code include the above copyright notice and
            * this paragraph in its entirety in the documentation or other materials
            * provided with the distribution, and (3) all advertising materials mentioning
            * features or use of this software display the following acknowledgement:
            * ``This product includes software developed by the Politecnico
            * di Torino, and its contributors.‘‘ Neither the name of
            * the University 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 ``AS IS‘‘ AND WITHOUT ANY EXPRESS OR IMPLIED
            * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
            * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
            */

            #include <stdlib.h>
            #include <stdio.h>

            #include <pcap.h>

            void usage();

            void main(int argc, char **argv) {
            pcap_t *indesc,*outdesc;
            char error[PCAP_ERRBUF_SIZE];
            FILE *capfile;
            int caplen,
            sync;
            u_int res;
            pcap_send_queue *squeue;
            struct pcap_pkthdr *pktheader;
            u_char *pktdata;

            /* Check the validity of the command line */
            if (argc <= 2 || argc >= 5)
            {
            usage();
            return;
            }

            /* 得到文件長度 */
            capfile=fopen(argv[1],"rb");
            if(!capfile){
            printf("Capture file not found!\n");
            return;
            }

            fseek(capfile , 0, SEEK_END);
            caplen= ftell(capfile)- sizeof(struct pcap_file_header);
            fclose(capfile);

            /* 檢查確保時間戳被忽略 */
            if(argc == 4 && argv[3][0] == ‘s‘)
            sync = TRUE;
            else
            sync = FALSE;

            /* Open the capture */
            if((indesc = pcap_open_offline(argv[1], error)) == NULL){
            fprintf(stderr,"\nError opening the input file: %s\n", error);
            return;
            }

            /* Open the output adapter */
            if((outdesc = pcap_open_live(argv[2], 100, 1, 1000, error) ) == NULL)
            {
            fprintf(stderr,"\nError opening adapter: %s\n", error);
            return;
            }

            /* 檢測MAC類型 */
            if(pcap_datalink(indesc) != pcap_datalink(outdesc)){
            printf("Warning: the datalink of the capture differs from the one of the selected

            interface.\n");
            printf("Press a key to continue, or CTRL+C to stop.\n");
            getchar();
            }

            /* 給對列分配空間 */
            squeue = pcap_sendqueue_alloc(caplen);

            /* 從文件獲得包來填充隊(duì)列 */
            while((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1){
            if(pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1){
            printf("Warning: packet buffer too small, not all the packets will be sent.\n");
            break;
            }
            }

            if(res == -1){
            printf("Corrupted input file.\n");
            pcap_sendqueue_destroy(squeue);
            return;
            }

            /* 傳送隊(duì)列數(shù)據(jù) */

            if((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
            {
            printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", error,

            res);
            }

            /* free the send queue */
            pcap_sendqueue_destroy(squeue);

            return;
            }


            void usage()
            {

            printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris

            Degioanni.\n");
            printf("\nUsage:\n");
            printf("\t sendcap file_name adapter [s]\n");
            printf("\nParameters:\n");
            printf("\nfile_name: the name of the dump file that will be sent to the network\n");
            printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
            printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the

            timestamps in the dump file. This option will work only under Windows NTx.\n\n");

            exit(0);
            }

               
            九)收集并統(tǒng)計(jì)網(wǎng)絡(luò)流量
            這一節(jié)將展示W(wǎng)inPcap的另一高級功能:收集網(wǎng)絡(luò)流量的統(tǒng)計(jì)信息。WinPcap的統(tǒng)計(jì)引擎在內(nèi)核層次上對到來的數(shù)據(jù)進(jìn)行分類。如果你想了解更

            多的細(xì)節(jié)請查看NPF驅(qū)動指南。
            為了利用這個功能來監(jiān)視網(wǎng)絡(luò),我門的程序必須打開一個網(wǎng)卡并用pcap_setmode()將其設(shè)置為統(tǒng)計(jì)模式。注意pcap_setmode()要用 MODE_STAT

            來將網(wǎng)卡設(shè)置為統(tǒng)計(jì)模式。
            在統(tǒng)計(jì)模式下編寫一個程序來監(jiān)視TCP流量只是幾行代碼的事情,下面的例子說明了如何來實(shí)現(xiàn)該功能的。
            程序代碼: [ 復(fù)制代碼到剪貼板 ]
            /*
            * Copyright (c) 1999 - 2002
            * Politecnico di Torino. All rights reserved.
            *
            * Redistribution and use in source and binary forms, with or without
            * modification, are permitted provided that: (1) source code distributions
            * retain the above copyright notice and this paragraph in its entirety, (2)
            * distributions including binary code include the above copyright notice and
            * this paragraph in its entirety in the documentation or other materials
            * provided with the distribution, and (3) all advertising materials mentioning
            * features or use of this software display the following acknowledgement:
            * ``This product includes software developed by the Politecnico
            * di Torino, and its contributors.‘‘ Neither the name of
            * the University 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 ``AS IS‘‘ AND WITHOUT ANY EXPRESS OR IMPLIED
            * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
            * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
            */

            #include <stdlib.h>
            #include <stdio.h>

            #include <pcap.h>

            void usage();

            void dispatcher_handler(u_char *,
            const struct pcap_pkthdr *, const u_char *);


            void main(int argc, char **argv) {
            pcap_t *fp;
            char error[PCAP_ERRBUF_SIZE];
            struct timeval st_ts;
            u_int netmask;
            struct bpf_program fcode;

            /* Check the validity of the command line */
            if (argc != 2)
            {
            usage();
            return;
            }

            /* Open the output adapter */
            if((fp = pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL)
            {
            fprintf(stderr,"\nError opening adapter: %s\n", error);
            return;
            }

            /* Don‘t care about netmask, it won‘t be used for this filter */
            netmask=0xffffff;

            //compile the filter
            if(pcap_compile(fp, &fcode, "tcp", 1, netmask) <0 ){
            fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
            /* Free the device list */
            return;
            }

            //set the filter
            if(pcap_setfilter(fp, &fcode)<0){
            fprintf(stderr,"\nError setting the filter.\n");
            /* Free the device list */
            return;
            }

            /* 將網(wǎng)卡設(shè)置為統(tǒng)計(jì)模式 */
            pcap_setmode(fp, MODE_STAT);

            printf("TCP traffic summary:\n");

            /* Start the main loop */
            pcap_loop(fp, 0, dispatcher_handler, (PUCHAR)&st_ts);

            return;
            }

            void dispatcher_handler(u_char *state, const struct pcap_pkthdr *header, const u_char *pkt_data)
            {
            struct timeval *old_ts = (struct timeval *)state;
            u_int delay;
            LARGE_INTEGER Bps,Pps;
            struct tm *ltime;
            char timestr[16];

            /* 從最近一次的采樣以微秒計(jì)算延遲時間 */
            /* This value is obtained from the timestamp that the associated with the sample. */
            delay=(header->ts.tv_sec - old_ts->tv_sec) * 1000000 - old_ts->tv_usec + header->ts.tv_usec;
            /* 獲得每秒的比特數(shù) */
            Bps.QuadPart=(((*(LONGLONG*)(pkt_data + 8)) * 8 * 1000000) / (delay));
            /* ^ ^
            | |
            | |
            | |
            converts bytes in bits -- |
            |
            delay is expressed in microseconds --
            */

            /* 獲得每秒的數(shù)據(jù)包數(shù) */
            Pps.QuadPart=(((*(LONGLONG*)(pkt_data)) * 1000000) / (delay));

            /* 將時間戳轉(zhuǎn)變?yōu)榭勺x的標(biāo)準(zhǔn)格式 */
            ltime=localtime(&header->ts.tv_sec);
            strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);

            /* Print timestamp*/
            printf("%s ", timestr);

            /* Print the samples */
            printf("BPS=%I64u ", Bps.QuadPart);
            printf("PPS=%I64u\n", Pps.QuadPart);

            //store current timestamp
            old_ts->tv_sec=header->ts.tv_sec;
            old_ts->tv_usec=header->ts.tv_usec;
            }


            void usage()
            {

            printf("\nShows the TCP traffic load, in bits per second and packets per second.\nCopyright (C) 2002 Loris Degioanni.\n");
            printf("\nUsage:\n");
            printf("\t tcptop adapter\n");
            printf("\t You can use \"WinDump -D\" if you don‘t know the name of your adapters.\n");

            exit(0);
            }

             

            在設(shè)置為統(tǒng)計(jì)模式前可以設(shè)置一個過濾器來指定要捕獲的協(xié)議包。如果沒有設(shè)置過濾器那么整個網(wǎng)絡(luò)數(shù)據(jù)都將被監(jiān)視。一旦設(shè)置了 過濾器就可

            以調(diào)用pcap_setmode()來設(shè)置為統(tǒng)計(jì)模式,之后網(wǎng)卡開始工作在統(tǒng)計(jì)模式下。
            需要指出的是pcap_open_live()的第四個參數(shù)(to_ms)定義了采樣的間隔,回調(diào)函數(shù)pcap_loop()每隔一定間隔就獲取一次采樣統(tǒng)計(jì),這個采樣

            被裝入pcap_loop()的第二和第三個參數(shù),過程如下圖所示:
            ______________
            |struct timeval ts |
            |_____________|
            |bpf_u_int32 |
            |caplen=16 | struct pcap_pkthdr*
            |_____________| (參數(shù)2)
            | bpf_u_int32 |
            | len=16 |
            |_____________|

            __________________________
            |large_integer Accepted packet |
            |_________________________| uchar *
            | large_integer Accepted bits | (參數(shù)3)
            |_________________________|

             

            用兩個64位的計(jì)數(shù)器分別記錄最近一次間隔數(shù)據(jù)包數(shù)量和比特數(shù)量。
            本例子中,網(wǎng)卡打開時設(shè)置超時為1000毫秒,也就是說dispatcher_handler()每隔1秒就被調(diào)用一次。過濾器也

            設(shè)置為只監(jiān)視TCP包,然后pcap_setmode() and pcap_loop()被調(diào)用,注意一個指向timeval的指針 作為參數(shù)傳

            送到pcap_loop()。這個timeval結(jié)構(gòu)將用來存儲個時間戳以計(jì)算兩次采樣的時間間隔。
            dispatcher_handler()用該間隔來獲取每秒的比特數(shù)和數(shù)據(jù)包數(shù),并把著兩個數(shù)顯示在顯示器上。
            最后指出的是目前這個例子是比任何一個利用傳統(tǒng)方法在用戶層統(tǒng)計(jì)的包捕獲程序都高效。因?yàn)榻y(tǒng)計(jì)模式需要

            最小數(shù)量的數(shù)據(jù)拷貝和上下環(huán)境交換,同時還有最小的內(nèi)存需求,所以CPU是最優(yōu)的。

            posted on 2008-10-07 10:11 葉子 閱讀(1092) 評論(0)  編輯 收藏 引用 所屬分類: 網(wǎng)絡(luò)編程

            7777久久亚洲中文字幕| 久久这里只有精品首页| 久久青青草视频| 欧美久久久久久| 无码任你躁久久久久久久| 99久久精品日本一区二区免费| 久久精品国产男包| 青草影院天堂男人久久| 国产一久久香蕉国产线看观看| 国产婷婷成人久久Av免费高清| 久久久久中文字幕| 久久国产欧美日韩精品| 精品伊人久久久| 国产精品99久久久久久猫咪| 伊人久久综合精品无码AV专区| 91精品观看91久久久久久| 无码久久精品国产亚洲Av影片| 久久精品无码一区二区app| 久久久久久人妻无码| 国产欧美久久久精品影院| 丁香五月综合久久激情| 国产Av激情久久无码天堂| 无码人妻久久一区二区三区蜜桃| 欧美亚洲另类久久综合| 99久久777色| 丰满少妇人妻久久久久久| 亚洲精品乱码久久久久久按摩 | 天天久久狠狠色综合| 乱亲女H秽乱长久久久| 久久精品国产99久久久古代| 久久免费视频一区| 久久精品国产精品亚洲人人| 99久久精品免费| 国产成人99久久亚洲综合精品| 久久91精品久久91综合| 久久久国产精品网站| 欧美亚洲国产精品久久蜜芽| 51久久夜色精品国产| 国产高清国内精品福利99久久| 热久久这里只有精品| 国产精品久久久99|