(原创)WinpCap的详解(三)
接著WinpCap詳解(二),這篇博客主要來討論一下,堆文件的處理以及簡單發送數據包。
1、處理脫機堆文件
我們將學習如何處理捕獲到文件中的數據包。 WinPcap提供了很多函數來將網絡數據流保存到文件并讀取它們 -- 本講將教你如何使用這些函數。我們還將看到如何使用WinPcap內核堆特性來獲取一個高性能的堆。
堆文件的格式是libpcap的一種。這種格式中,包含了被捕捉到的包的二進制數據,并且,這種格式是許多網絡工具所使用的一種標準,這些工具包括WinDump,Etheral和Snort。
保存數據包到堆文件
首先,讓我們看一下如何將一個數據包寫成libpcap的格式。
接下來的例子講從一個選定的接口捕獲數據包,并且將它們保存到用戶指定的文件中。
這里pcap_dump_t和pcap_dump一樣的東西,表示的是libpcap存儲文件的描述符,對用戶來說也是不透明的。
這里的pcap_findalldevs_ex()函數是pcap_findalldevs()的擴展。這里我列出他的英文解釋吧,翻譯起來還不是很好,看英文比較容易了。
This function is a superset of the old 'pcap_findalldevs()', which is obsolete, and which allows listing only the devices present on the local machine. Vice versa, pcap_findalldevs_ex() allows listing the devices present on a remote machine as well. Additionally, it can list all the pcap files available into a given folder. Moreover, pcap_findalldevs_ex() is platform independent, since it relies on the standard pcap_findalldevs() to get addresses on the local machine.
pcap_dump_open(pcap_t* p,const char* name)打開一個堆文件,第二個參數是文件的名字,第一個參數是已經打開的適配器描述符。
#include "pcap.h"
/* 回調函數原型 */
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;
/* 檢查程序輸入參數 */
if(argc != 2)
{
printf("usage: %s filename", argv[0]);
return -1;
}
/* 獲取本機設備列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* 打印列表 */
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");
/* 釋放列表 */
pcap_freealldevs(alldevs);
return -1;
}
/* 跳轉到選中的適配器 */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
/* 打開適配器 */
if ( (adhandle= pcap_open(d->name, // 設備名
65536, // 要捕捉的數據包的部分
// 65535保證能捕獲到不同數據鏈路層上的每個數據包的全部內容
PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式
1000, // 讀取超時時間
NULL, // 遠程機器驗證
errbuf // 錯誤緩沖池
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* 釋放設備列表 */
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... Press Ctrl+C to stop...\n", d->description);
/* 釋放設備列表 */
pcap_freealldevs(alldevs);
/* 開始捕獲 */
pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
return 0;
}
/* 回調函數,用來處理數據包 */
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
/* 保存數據包到堆文件 */
pcap_dump(dumpfile, header, pkt_data);
}
從堆文件中讀取數據包
既然我們有了可用的堆文件,那我們就能讀取它的內容了。 以下代碼將打開一個WinPcap/libpcap的堆文件,并顯示文件中每一個包的信息。文件通過 pcap_open_offline() 打開,然后,我們通常使用 pcap_loop() 來有序獲取數據包。你可以看到,從脫機文件中讀取數據包和從物理接口中接收它們是很相似的。
這個例子還會介紹另一個函數:pcap_createsrcsrc()。這個函數用于創建一個源字符串,這個源字符串以一個標志開頭,這個標志會告訴WinPcap這個源的類型。比如,使用"rpcap://"標志來打開一個適配器,使用"file://"來打開一個文件。如果 pcap_findalldevs_ex() 已經被使用,那么這部是不需要的,因為其返回值已經包含了這些字符串。然而,在這個例子中,我們需要它。因為文件的名字來自于用戶的輸入。
2、發送數據包
盡管從 WinPcap 的名字上看,這個庫的目標應該是數據捕捉(Packet Capture),然而,它也提供了針對很多其它有用的特性。在其中,我們可以找到一組很完整的用于發送數據包的函數。
請注意:原始的libpcap庫是不支持發送數據包的,因此,這里展示的函數都屬于是WinPcap的擴展,并且它們不能運行于Unix平臺下。
使用 pcap_sendpacket() 發送單個數據包
下面的代碼展示了發送一個數據包的最簡單的方式。打開適配器以后,調用 pcap_sendpacket() 來發送手工制作的數據包。 pcap_sendpacket() 的參數有一個要包涵發送數據的緩沖區,緩沖的長度,以及用來發送數據的適配器。注意,緩沖數據將直接發送到網絡,而不會進行任何加工和處理。這就意味著應用程序需要創建一個正確的協議首部,來使這個數據包更有意義。
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
void main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
u_char packet[100];
int i;
/* 檢查命令行參數的合法性 */
if (argc != 2)
{
printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
return;
}
/* 打開輸出設備 */
if ( (fp= pcap_open(argv[1], // 設備名
100, // 要捕獲的部分 (只捕獲前100個字節)
PCAP_OPENFLAG_PROMISCUOUS, // 混雜模式
1000, // 讀超時時間
NULL, // 遠程機器驗證
errbuf // 錯誤緩沖
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
return;
}
/* 假設在以太網上,設置MAC的目的地址為 1:1:1:1:1:1 */
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
/* 設置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;
/* 填充剩下的內容 */
for(i=12;i<100;i++)
{
packet[i]=i%256;
}
/* 發送數據包 */
if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
{
fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(fp));
return;
}
return;
}
這里面只是簡單的數據發送,還有更復雜的隊列發送,由于現在不需要用到這一塊,所以就不看這一部分了,因為我只需要發送簡單的命令,不需要大量的數據發送,這里就不再講下去啦,如果想更深入的了解WinpCap的功能,推薦一個好的網站,http://www.ferrisxu.com/WinPcap/html/modules.html,這個網站里面有很多關于WinpCap的東西,可能里面有很多更新的東西,還值得大家以后共同學習,本人就學習這么多啦!
總結
以上是生活随笔為你收集整理的(原创)WinpCap的详解(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP 下载图片文件并压缩文件成zip
- 下一篇: 油价有望迎今年第3次下调:加满一箱油或便