著作權資訊:
本文來自internet,轉載這裡供網路編程愛好者學習和研究使用,請尊重作者的勞動成果。未經授權而在商業上使用原作者的文章屬侵權行為,後果由使用者自負,本人不承擔任何法律責任。
今天在閱讀Winpcap Manual的時候發現一句話:
“This means that on shared media (like non-switched Ethernet), WinPcap will be able to capture the packets of other hosts.”
我理解為:如果在通過沒有交換功能的集線器串連的網路上,只要把網卡設定為混雜(promiscuous)模式,winpcap能夠捕獲到其他主機通訊的資料包。如果是具有交換功能的集線器串連的網路winpcap還能管用嗎?這個在後邊的實習中將會進行實驗。
實驗程式2:
/*
* 截獲資料包的實驗。先列印出所有網路介面卡的列表,然後選擇
* 想在哪個適配器上截獲資料包。然後通過pcap_loop()函數將截獲
* 的資料包傳給回呼函數packet_handler()處理。
* 通過該程式初步瞭解了使用winpcap截獲資料包的步驟以及一些在
* 截獲資料包時非常重要的函數和結構體。
* 2006-1-26
*/
#include <pcap.h>
#include <remote-ext.h>
/* Prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i = 0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
/* Retrieve the devices 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)
{
/* Print name */
printf("%d. %s", ++ i, d->name);
/* Print description */
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;
}
/* Select an adapter */
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 */
/* 65535 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, "/nnable to open the adapter. %s is not supported by Winpcap/n", d->name);
/* Free the devices 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 1;
}
/* 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);
}
函數1:
pcap_t *pcap_open(const char * source,
int snaplen,
int flags, [Page]
int read_timeout,
struct pcap_rmtauth * auth,
char * errbuf
)
為捕獲/發送資料開啟一個普通的源。pcap_open()能夠替代所有的pcap_open_xxx()函數,它隱藏了不同的pcap_open_xxx()之間的差異,所以程式員不必使用不同的open函數。
source:的是包含要開啟的源名稱的以’/0’結尾的字串。源名稱得包含新的源規範文法(Source Specification Syntax),並且它不能為NULL。為了方便的使用源文法,請記住:(1)pcap_findalldevs_ex()返回的適配器(網卡)可以直接被pcap_open()使用;(2)萬一使用者想傳遞他自己的源字串給pcap_open(),pcap_createsrcstr()可以建立正確的源標識。
snaplen:需要保留的資料包的長度。對每一個過濾器接收到的資料包,第一個‘snaplen’位元組的內容將被儲存到緩衝區,並且傳遞給使用者程式。例如,snaplen等於100,那麼僅僅每一個資料包的第一個100位元組的內容被儲存。簡言之就是從每一個包的開頭到snaplen的那段內容將被儲存。
flags:儲存一些由於抓包需要的標誌。Winpcap定義了三種標誌:
l PCAP_OPENFLAG_PROMISCUOUS:1,它定義了適配器(網卡)是否進入混雜模式(promiscuous mode)。
l PCAP_OPENFLAG_DATATX_UDP:2,它定義了資料轉送(假如是遠程抓包)是否用UDP協議來處理。
l PCAP_OPENFLAG_NOCAPTURE_RPCAP:4,它定義了遠程探測器是否捕獲它自己產生的資料包。
read_timeout:以毫秒為單位。read timeout被用來設定在遇到一個資料包的時候讀操作不必立即返回,而是等待一段時間,讓更多的資料包到來後從OS核心一次讀多個資料包。並非所有的平台都支援read timeout;在不支援read timeout的平台上它將被忽略。
auth:一個指向’struct pcap_rmtauth’的指標,儲存當一個使用者登入到某個遠程機器上時的必要資訊。假如不是遠程抓包,該指標被設定為NULL。
errbuf:一個指向使用者申請的緩衝區的指標,存放當該函數出錯時的錯誤資訊。
傳回值是一個’pcap_t’指標,它可以作為下一步調用(例如pcap_compile()等)的參數,並且指定了一個已經開啟的Winpcap會話。在遇到問題的情況下,它返回NULL並且’errbuf’變數儲存了錯誤資訊。
函數2:
int pcap_loop( pcap_t* p,
int cnt,
pcap_hander callback,
u_char* user
)
收集一群資料包。pcap_loop()與pcap_dispatch()類似,但是它會一直保持讀資料包的操作直到cnt包被處理或者發生了錯誤。當有活動的讀逾時(read timeout)時它並不返回。然而,對pcap_open_live()指定一個非0的讀逾時(read timeout),當發生逾時的時候調用pcap_dispatch()來接收並處理到來的所有資料包更好。Cnt指明了返回之前要處理資料包的最大數目。如果cnt為負值,pcap_loop()將一直迴圈(直到發生錯誤才停止)。如果出錯時返回-1;如果cnt用完時返回0;如果在任何包被處理前調用pcap_breakloop()來中止迴圈將返回-2。所以,如果程式中使用了pcap_breakloop(),必須準確的來判斷傳回值是-1還是-2,而不能簡單的判斷<0。
函數3:
hypedef void (* pcap_handler)(u_char* user,
const struct pcap_pkthdr* pkt_header,
const u_char* pkt_data)
接收資料包的回呼函數原型。當使用者程式使用pcap_dispatch()或者pcap_loop(),資料包以這種回調的方法傳給應用程式。使用者參數是使用者自己定義的包含捕獲工作階段狀態的參數,它必須跟pcap_dispatch()和pcap_loop()的參數相一致。pkt_hader是與抓包驅動有關的頭。pkt_data指向包裡的資料,包括協議頭。
結構體1:
struct pcap_pkthdr {
struct timeval ts;
bpf_u_int32 caplen;
bpf_u_int32 len;
}
ts:時間戳記
cpalen:當前分組的長度
len:資料包的長度
本篇文章來源於 中國協議分析網|www.cnpaf.net 原文連結:http://www.cnpaf.net/Class/winpcap/200610/16293.html