Winpcap網路編程十之Winpcap實戰,兩台主機通過中間主機通訊,winpcap網路編程
註:本篇部落格同樣不針對於伸手黨,原始碼等等的我不會完全公開的,此篇文章寫出來為大家的網路編程或者課程設計提供一定的思路..
好,本次我們需要完成的任務是:
完成兩台主機通過中間主機的資料通訊(網路層)
其實最主要的就是基於IP地址的轉寄功能,網路層的封裝其實我們在初級功能中就已經做好了。
首先,實驗的思路是A通過中間主機B向C發送資料。那麼B則作為一個路由器,B要監聽兩個網卡,一個網卡發來的資料通過另一個網卡發出去。
如下:
A--------->B1===B2------------>C
從圖上可以看出,B主機的兩個網卡資料互連,A和B1則處於一個區域網路內,B2和C處於另一個區域網路內。
就比如這樣,現在室友A在用有線上網,我的電腦B也在用有線上網,我們的有線處在同一區域網路,我的電腦B同時散著一個無線網,My PhoneC又串連到了這個無線上。
那麼要實現A到C的資料傳送,即類比室友A要發送資料到My PhoneC,那麼流程則是這樣的:
室友A在有線區域網路發送資料到我的網卡B1,B1將資料通過網卡B2轉寄到無線區域網路,通過無線區域網路到達My PhoneC。
A的發送要構建一個幀,目的MAC地址為B1,目的IP為C。B則要開啟兩個網卡,B1監聽接收資料,B2網卡則要用ARP協議掃描所在無線區域網路內的IP和MAC,B擷取到了A發來的幀之後,解析它的IP地址和MAC地址,匹配剛才掃描得到的IP和MAC對應表,將源MAC換成B2網卡MAC,目的MAC換成C的MAC,IP不變,資料data不變。構建新幀之後發送出去。
好啦,思路大體就是這樣。
需要三個程式,一個是發送,一個路由,一個接收。所以一共三個程式要同時運行起來執行。
以上是我的大體思路,如有錯誤,還請指正。現已用代碼實現完畢。
代碼暫不公開,只提供部分重點代碼解析:
一、發送端
其實發送端和初級功能的發送差不多
個人編寫的互動流程如下:
IP地址:121.250.216.221 MAC地址:3c970e4b56d6con:127-------------------------------------------IP地址:121.250.216.227 MAC地址:089e01b948f4con:128-------------------------------------------IP地址:121.250.216.228 MAC地址:10bf48705aeecon:129擷取MAC地址完畢,請輸入你要發送對方的IP地址:192.168.1.3請輸入你要發送的內容:im cqc要發送的內容:im cqc
具體代碼不再解析,同上一篇初級功能。
二、路由端
首先要開啟兩個網卡,聲明兩個網卡對象和處理器
pcap_if_t *d,*d2;//選中的網路介面卡pcap_t *adhandle,*adhandle2; //捕捉執行個體,是pcap_open返回的對象,adhandle是用來發送資料,adhandle2是用來接收資料
一個用來接收一個用來發送,這裡定義了adhandle是用來發送,adhandle2是用來接收資料。
那麼開啟適配器就在main方法中,提前開啟兩個網卡
int num;printf("請輸入你要轉寄資料的網卡代號:\n");//讓使用者選擇選擇哪個適配器進行轉寄scanf_s("%d",&num);//跳轉到選中的適配器for(d=alldevs, i=0; i< num-1 ; d=d->next, i++);//運行到此處說明使用者的輸入是合法的,找到發送資料網卡if((adhandle = pcap_open(d->name,//裝置名稱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;}int num2;printf("請輸入你要接收資料的網卡代號:");//讓使用者選擇用哪個網卡來收資料scanf_s("%d",&num2);//使用者輸入的數字超出合理範圍//跳轉到選中的適配器for(d2=alldevs, i=0; i< num2-1 ; d2=d2->next, i++);//運行到此處說明使用者的輸入是合法的if((adhandle2 = pcap_open(d2->name,//裝置名稱65535, //存放資料包的內容長度PCAP_OPENFLAG_PROMISCUOUS, //混雜模式1000, //逾時時間NULL, //遠程驗證errbuf //錯誤緩衝)) == NULL){ //開啟適配器失敗,列印錯誤並釋放適配器列表fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d2->name);
接下來用用於發送的handle處理器來掃描它的區域網路IP,獲得區域網路內的MAC地址,記錄在一個表中,存放IP和MAC的對應關係。
這個表可以用結構體數組來儲存,比如可以這樣:
struct ip_mac_list{IpAddress ip;unsigned char mac[6];};
ip_mac_list list[256]; //儲存IP和MAC地址的對應表
那麼以上便是準備工作,我們完成了兩個網卡的開啟,發送網卡掃描擷取區域網路MAC,接下來便是最重要的監聽加轉寄。
那麼這個怎辦?那就開一個新線程。
讓我們聲明一個新的路由線程。
DWORD WINAPI RouteThread(LPVOID lpParameter);
那麼線程要接收進來什麼參數呢?
首先必須要的是兩個網卡處理器,在main方法中已經做好初始化的adhandle和adhandle2,另外還有alldevs,可以持有這個指標來釋放裝置列表,出現錯誤時釋放資源並退出。
初級功能中聲明過了
struct sparam sp;
struct gparam gp;
這兩個就是發送ARP線程和接收ARP線程中的兩個參數,那麼仿照這個功能,我們定義一個新的結構體
struct rparam{pcap_t *adhandle_rec;pcap_t *adhandle_send;pcap_if_t * alldevs; //所有網路介面卡};
在main方法中把它來初始化賦值
rp.adhandle_send = adhandle;rp.adhandle_rec = adhandle2;rp.alldevs = alldevs;
當做參數傳入這個線程
routethread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) RouteThread, &rp,0, NULL);
其中第四個參數就是傳遞了這個結構體進去。注意這個語句最好不要直接放在main方法中直接調用,可以在全部擷取完MAC地址之後再開啟這個線程。
那麼接下來就說一下這個線程都幹了些什麼,只簡略說一下核心部分。
首先開啟了這個線程之後會一直都在執行,那麼就可以加入
while((res = pcap_next_ex(adhandle2,&header,&pkt_data))>=0)
這樣的while判斷語句來一直監聽資料包的接收,然後解析資料。
ethernet = (EthernetHeader *)(pkt_data);for(int i=0;i<6;i++){sou_mac[i] = ethernet->SourMAC[i];}for(int i=0;i<6;i++){des_mac[i] = ethernet->DestMAC[i];}// 獲得IP資料包頭部的位置ip = (IpHeader *) (pkt_data +14); //14為乙太網路幀頭部長度//獲得TCP頭部的位置ip_len = (ip->Version_HLen & 0xf) *4;tcp = (TcpHeader *)((u_char *)ip+ip_len);data = (char *)((u_char *)tcp+20);printf("data:%s\n",data);printf("ip:");printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",ip->SourceAddr.byte1,ip->SourceAddr.byte2,ip->SourceAddr.byte3,ip->SourceAddr.byte4, ip->DestinationAddr.byte1, ip->DestinationAddr.byte2, ip->DestinationAddr.byte3, ip->DestinationAddr.byte4); printf("sou_mac:%02x-%02x-%02x-%02x-%02x-%02x\n", sou_mac[0], sou_mac[1], sou_mac[2], sou_mac[3], sou_mac[4], sou_mac[5]);printf("des_mac:%02x-%02x-%02x-%02x-%02x-%02x\n", des_mac[0], des_mac[1], des_mac[2], des_mac[3], des_mac[4], des_mac[5]);
然後接下來每接收到一個資料,就進行構建新的幀轉寄出去,目的MAC先匹配list表,如果list沒有找到,那麼我讓他指定了一個mac,比如廣播MAC。源MAC地址則賦值網卡的MAC地址。
注意,傳統乙太網路中資料長度為45-1500,那麼我在構建前把解析出的data作了下判斷長度再構建,因為我已經把sendbuffer聲明為一個固定長度了,為了防止越界,我先進行一個長度判斷。
//以下開始構建幀發送//首先判斷data最大值小於1500if(strlen(data)<1500){//目的MACBYTE send_destmac[6];bool findMac = false;for(int c = 0;c<con;c++){if(ip->DestinationAddr.byte1 == list[c].ip.byte1&&ip->DestinationAddr.byte2 == list[c].ip.byte2&&ip->DestinationAddr.byte3 == list[c].ip.byte3&&ip->DestinationAddr.byte4 == list[c].ip.byte4){printf("Find its MAC!\n");findMac = true;send_destmac[0] = list[c].mac[0]; send_destmac[1] = list[c].mac[1];send_destmac[2] = list[c].mac[2];send_destmac[3] = list[c].mac[3];send_destmac[4] = list[c].mac[4];send_destmac[5] = list[c].mac[5];}}if(!findMac){send_destmac[0] = 0xff; send_destmac[1] = 0xff; send_destmac[2] = 0xff; send_destmac[3] = 0xff; send_destmac[4] = 0xff; send_destmac[5] = 0xff; }printf("destmac:%02x-%02x-%02x-%02x-%02x-%02x\n",send_destmac[0],send_destmac[1],send_destmac[2],send_destmac[3],send_destmac[4],send_destmac[5]);memcpy(send_ethernet.DestMAC, send_destmac, 6);//源MAC地址BYTE send_hostmac[6];//源MAC地址send_hostmac[0] = local_mac[0]; //賦值本地MAC地址send_hostmac[1] = local_mac[1];send_hostmac[2] = local_mac[2];send_hostmac[3] = local_mac[3];send_hostmac[4] = local_mac[4];send_hostmac[5] = local_mac[5];//賦值源MAC地址memcpy(send_ethernet.SourMAC, send_hostmac, 6);send_ethernet.EthType = htons(0x0800);//賦值SendBuffermemcpy(&SendBuffer, &send_ethernet, sizeof(struct EthernetHeader));
以上只是賦值了幀頭,至於IP頭,TCP頭,資料的賦值就參照初級功能的來賦值吧,不要忘了校正和的檢驗。好,大體上就是這樣,接受來資料包並轉寄出去的原理就是這樣。
三、接收
不用多改,就是初級功能中的接收,在此寫一寫小小的最佳化措施,防止接收到過多的資料幀而造成不斷亂蹦,導致你看不到接收的東西。
在列印的時候加一個過濾就好了。部分代碼如下:
在main方法中提示使用者輸入要接收的IP地址
printf("請輸入要接收的IP地址,輸入0.0.0.0代表全部接收,請輸入\n");bool receiveAll = false;u_int ip1,ip2,ip3,ip4;bool legal = false;while(!legal){scanf_s("%d.%d.%d.%d",&ip1,&ip2,&ip3,&ip4);if(ip1==0&&ip2==0&&ip3==0&&ip4==0){receiveAll = true;legal = true;break;}if(ip1<0||ip1>255||ip2<0||ip2>255||ip3<0||ip3>255||ip4<1||ip4>254){legal = false;printf("對不起,IP輸入不合法,請重新輸入:\n");}else{legal = true;}}
列印時的判斷
if(receiveAll||(ip->SourceAddr.byte1==ip1&&ip->SourceAddr.byte2==ip2&&ip->SourceAddr.byte3==ip3&&ip->SourceAddr.byte4==ip4)){printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",ip->SourceAddr.byte1,ip->SourceAddr.byte2,ip->SourceAddr.byte3,ip->SourceAddr.byte4, sport, ip->DestinationAddr.byte1, ip->DestinationAddr.byte2, ip->DestinationAddr.byte3, ip->DestinationAddr.byte4, dport); printf("sou_mac:%02x-%02x-%02x-%02x-%02x-%02x\n", sou_mac[0], sou_mac[1], sou_mac[2], sou_mac[3], sou_mac[4], sou_mac[5]);printf("des_mac:%02x-%02x-%02x-%02x-%02x-%02x\n", des_mac[0], des_mac[1], des_mac[2], des_mac[3], des_mac[4], des_mac[5]);printf("%s\n",data);printf("-----------------------------------------------------\n");}
好,代碼就先放送這麼多,具體的實現只要有了思路我相信肯定不難,如有問題,歡迎與我交流。
我的郵箱 1016903103@qq.com
winpcap是什?可以刪除?對上網有影響?
這個不能刪啊!本地串連的!刪了就不能上網了!
對於WINPCAP
winpcap(windows packet capture)是windows平台下一個免費,公用的網路訪問系統。
開發winpcap這個項目的目的在於為win32應用程式提供訪問網路底層的能力。它提供了以下的各項功能:
1> 捕獲未經處理資料報,包括在共用網路上各主機發送/接收的以及相互之間交換的資料報;
2> 在資料報發往應用程式之前,按照自訂的規則將某些特殊的資料報過濾掉;
3> 在網路上發送原始的資料報;
4> 收集網路通訊過程中的統計資訊。
winpcap的主要功能在於獨立於主機協議(如TCP/IP)而發送和接收未經處理資料報。也就是說,winpcap不能阻塞,過濾或控制其他應用程式資料報的發收,它僅僅只是監聽共用網路上傳送的資料報。因此,它不能用於QoS發送器或個人防火牆。目前,winpcap開發的主要對象是windows NT/2000/XP,這主要是因為在使用winpcap的使用者中只有一小部分是僅使用windows 95/98/Me,並且微軟也已經放棄了對win9x的開發。因此本文相關的程式T-ARP也是面向NT/2000/XP使用者的。其實winpcap中的面向9x系統的概念和NT系統的非常相似,只是在某些實現上有點差異,比如說9x只支援ANSI編碼,而NT系統則提倡使用Unicode編碼。有個軟體叫sniffer pro.可以作網管軟體用,有很多功能,可監視網路運行情況,每台網內機器的資料流量,即時反映每台機器所訪問IP以及它們之間的資料流通情況,可以抓包,可對過濾器進行設定,以便只抓取想要的包,比如POP3包,smtp包,ftp包等,並可從中找到信箱使用者名和密碼,還有ftp使用者名稱和密碼.它還可以在使用交換器的網路上監聽,不過要在交換器上裝它的一個軟體.還有一個簡單的監聽軟體叫 Passwordsniffer,可截獲信箱使用者名和密碼,還有ftp使用者名稱和密碼,它只能用在用HUB網路上著名軟體tcpdump及ids snort都是基於libpcap編寫的,此外Nmap掃描器也是基於libpcap來捕獲目標主機返回的資料包的。
WinPcap是用於網路封包抓取的一套工具,可適用於32位的操作平台上解析網路封包,包含了核心的封包過濾,一個底層動態連結程式庫,和一個高層系統函數庫,及可用來直接存取封包的應用程式介面。
Winpcap是一個免費公開的軟體系統。它用於windows系統下的直接的網路編程。
大多數網路應用程式訪問網路是通過廣泛使用的通訊端。這種方法很容易實現網路資料轉送,因為作業系統負責底層的細節(比如協議棧,資料流組裝等)以及提供了類似於檔案讀寫的函數介面。
但是有時,簡單的方法是不夠的。因為一些應用程式需要一個底層環境去直接操縱網路通訊。因此需要一個不需要協議棧支援的原始的訪問網路的方法。
winpcap適用於下面的開發人員:
1、捕獲未經處理資料包。不管這個包是發往本地機,還是其他機器之間的交換包。
2、在資料包被發送到應用程式之前,通過使用者定義的規則過濾。
3、向網路發送未經處理資料包。
4、對網路通訊量做出統計。
這些功能依賴於Win32系統核心中的裝置驅動以及一些動態連結程式庫。
Winpcap提供了一個強大的編程介面,它很容易地在各個作業系統之間進行移植,也很方便程式員進行開發。
什麼樣的程式需要使用Winpcap
很多不同的工具軟體使用Winpcap於網路分析,故障排除,網路安全監控等方面。Winpcap特別適用於下......餘下全文>>