青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

elva

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

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

的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)境下才行因為它不是原始libpcap API中的一部分,這就意味著依賴于這個函數(shù)的代碼不會在UNIX下工作。那

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

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

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

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

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


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

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

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

下面的代碼展示了如何編譯并社定一個過濾設(shè)備。注意我們必須從pcap_if結(jié)構(gòu)中獲得掩碼,因為一些過濾器的創(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é)的學習能夠進行數(shù)據(jù)報的捕獲和過濾了,我們想用一個簡單的"real world"程序?qū)⑽覀兯鶎W的

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

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

UDP數(shù)據(jù)的信息。
在此我們選擇解析UDP而不用TCP因為他比TCP簡單更加的直觀明了。下面讓我們來看看原代碼。

程序代碼: [ 復(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; // 校驗和
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順序 */
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的位置時有點復(fù)雜,因為IP的長度以

為版本的不同而不同,所以我們用頭長字段來定位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īng)熟悉了從網(wǎng)卡上捕獲數(shù)據(jù)包,現(xiàn)在我門將學習如何處理數(shù)據(jù)包。WINPCAP為我們提供了很多API來將流經(jīng)網(wǎng)絡(luò)的數(shù)據(jù)包

保存到一個堆文件并讀取堆的內(nèi)容。這一節(jié)將講述如何使用所有的這些API。
這種文件的格式很簡單,但包含了所捕獲的數(shù)據(jù)報的二進制內(nèi)容,這種文件格式也是很多網(wǎng)絡(luò)工具的標準如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)讀取脫機的數(shù)據(jù)幾乎和實時的從網(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標志。
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的最新版本提供了一個進一步的方法來將數(shù)據(jù)包存儲到磁盤,就是使用pcap_live_dump()函數(shù)。他需要三個參數(shù):一個文件名,和一個

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

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

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

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

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

上向文件中寫數(shù)據(jù),從而使內(nèi)存拷貝最小化。
顯然,這些特點當前在其他的操作系統(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的擴展功能,所以并不能夠工作在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ā)送隊列:
pcap_sendpacket()只是提供一個簡單的直接的發(fā)送數(shù)據(jù)的方法,而發(fā)送隊列提供一個高級的強大的和最優(yōu)的機

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

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

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

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

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

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

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

因為他的數(shù)據(jù)是在內(nèi)核級上被緩沖。
當不再需要隊列時可以用pcap_sendqueue_destroy()來釋放掉所有的隊列資源。

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

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

程序代碼: [ 復(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);

/* 從文件獲得包來填充隊列 */
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;
}

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

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

來將網(wǎng)卡設(shè)置為統(tǒng)計模式。
在統(tǒng)計模式下編寫一個程序來監(jiān)視TCP流量只是幾行代碼的事情,下面的例子說明了如何來實現(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)計模式 */
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];

/* 從最近一次的采樣以微秒計算延遲時間 */
/* 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的標準格式 */
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)計模式前可以設(shè)置一個過濾器來指定要捕獲的協(xié)議包。如果沒有設(shè)置過濾器那么整個網(wǎng)絡(luò)數(shù)據(jù)都將被監(jiān)視。一旦設(shè)置了 過濾器就可

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

被裝入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位的計數(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)將用來存儲個時間戳以計算兩次采樣的時間間隔。
dispatcher_handler()用該間隔來獲取每秒的比特數(shù)和數(shù)據(jù)包數(shù),并把著兩個數(shù)顯示在顯示器上。
最后指出的是目前這個例子是比任何一個利用傳統(tǒng)方法在用戶層統(tǒng)計的包捕獲程序都高效。因為統(tǒng)計模式需要

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

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


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            牛牛精品成人免费视频| 欧美一级久久| aa亚洲婷婷| 国产在线播放一区二区三区| 欧美国产免费| 国产欧美日本一区视频| 亚洲国产欧美在线| 欧美另类变人与禽xxxxx| 久久久久久亚洲精品中文字幕| 欧美精品久久久久久久久老牛影院| 欧美一区二区久久久| 欧美日韩国产精品专区| 欧美成人一品| 精品电影一区| 欧美一区二区精美| 99re热精品| 99国产精品| 亚洲精品之草原avav久久| 久久精品视频免费播放| 亚洲一二三区在线| 欧美美女bbbb| 亚洲电影一级黄| 在线播放中文字幕一区| 久久国产精品久久久| 一区二区三区免费网站| 欧美区一区二| 亚洲精品乱码久久久久久按摩观| 亚洲高清在线观看一区| 久久九九国产精品| 久久这里只有精品视频首页| 国产日本精品| 久久成人精品电影| 麻豆精品一区二区综合av| 国产欧美日韩亚洲一区二区三区| 亚洲精品无人区| 日韩视频在线播放| 欧美日本一道本| 亚洲美女av网站| 亚洲视频欧洲视频| 老司机精品久久| 亚洲国产乱码最新视频| 亚洲激情一区二区三区| 欧美成人官网二区| 久久综合久色欧美综合狠狠| 国产一区二区三区视频在线观看| 欧美一区二区黄色| 欧美高清在线视频| 亚洲国产精品一区二区三区 | 在线免费观看成人网| 久久久国产91| 亚洲国产美国国产综合一区二区| 99精品国产99久久久久久福利| 久久岛国电影| 亚洲激情在线激情| 亚洲欧洲av一区二区| 国产亚洲毛片| 久久综合影视| 99热这里只有精品8| 欧美一区二区精美| 亚洲成人在线网| 欧美精品日韩综合在线| 亚洲欧美国产日韩天堂区| 久久精品免费| 亚洲一区亚洲二区| 欧美日韩国产123| 中文在线资源观看网站视频免费不卡 | 久久九九精品| 亚洲国产视频直播| 性久久久久久久| 亚洲高清二区| 欧美精品日本| 亚洲精品免费电影| 久久久蜜臀国产一区二区| 亚洲福利在线看| 欧美精品videossex性护士| 国产精品99久久久久久人| 美女被久久久| 一本久道久久久| 国产精品日韩在线播放| 久久久久九九九| 日韩视频亚洲视频| 久久gogo国模啪啪人体图| 亚洲精品无人区| 国产欧美日本在线| 欧美日韩一区二区高清| 久久噜噜噜精品国产亚洲综合| 亚洲精品国精品久久99热| 久久麻豆一区二区| 亚洲欧美韩国| 亚洲国产另类久久久精品极度| 国产精品久久久久免费a∨大胸| 久久五月天婷婷| 亚洲桃花岛网站| 美日韩精品视频免费看| 午夜在线一区二区| 亚洲精品一区二区网址| 国产欧美日韩另类视频免费观看| 欧美激情中文不卡| 久久久久一区二区三区| 午夜日本精品| 亚洲一区二区三区精品动漫| 欧美成人综合| 久久久久青草大香线综合精品| 亚洲在线播放电影| 亚洲欧洲日韩在线| 在线激情影院一区| 激情亚洲一区二区三区四区| 国产精品一区二区你懂的| 亚洲一本视频| 久久综合999| 久久久欧美精品| 久久九九免费| 久久精品国产精品亚洲精品| 亚洲欧美成人在线| 亚洲伊人久久综合| 亚洲无人区一区| 亚洲伦伦在线| 在线视频精品一区| 中文有码久久| 亚洲欧美久久久| 午夜精品理论片| 午夜精品一区二区在线观看| 亚洲一区自拍| 欧美一区成人| 久久精品欧美| 免费欧美视频| 欧美精品日韩| 国产精品久久久一区二区| 国产精品视频网站| 国产一区二区中文字幕免费看| 国产一区高清视频| 在线观看一区二区精品视频| 在线看成人片| 亚洲免费黄色| 亚洲欧美在线免费| 久久久久88色偷偷免费| 麻豆精品91| 亚洲黑丝在线| 中国av一区| 久久精品男女| 欧美日本久久| 国产日产欧美一区| 激情亚洲网站| 在线综合亚洲| 久久久久久夜精品精品免费| 欧美国产另类| 日韩一区二区精品葵司在线| 亚洲尤物在线视频观看| 欧美一区二区三区婷婷月色 | 亚洲精品久久嫩草网站秘色| 亚洲精品字幕| 欧美尤物巨大精品爽| 欧美插天视频在线播放| 国产精品久久久久aaaa九色| 国产欧美精品一区| 亚洲人成免费| 欧美在线网址| 亚洲欧洲日本mm| 欧美在线观看一区二区| 欧美久色视频| 精品va天堂亚洲国产| aⅴ色国产欧美| 久久久亚洲高清| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 久久福利视频导航| 久久综合中文字幕| 99国产精品国产精品久久| 欧美一级视频免费在线观看| 久久久久久欧美| 国产精品网站在线观看| 极品尤物久久久av免费看| 亚洲视频在线观看视频| 美女黄色成人网| 午夜欧美大尺度福利影院在线看| 欧美理论在线播放| 亚洲福利电影| 久久久综合网| 日韩一级片网址| 免费在线播放第一区高清av| 国产午夜精品久久久| 亚洲午夜一区| 亚洲激情中文1区| 免费观看成人鲁鲁鲁鲁鲁视频| 国产九九精品| 亚洲免费影视| 亚洲欧洲在线播放| 欧美a级一区| 怡红院精品视频在线观看极品| 亚洲男人的天堂在线aⅴ视频| 亚洲国产日韩欧美在线图片| 久久阴道视频| 在线观看成人小视频| 久久裸体视频| 欧美伊人久久| 国产一区二区黄| 久久久五月天| 久久电影一区| 在线电影院国产精品| 久久女同互慰一区二区三区| 亚洲永久字幕|