1、背景html
2、WinPcap中文技術文檔ios
http://www.ferrisxu.com/WinPcap/html/index.html編程
2、須要使用到的動態庫和外部頭文件網絡
① 庫文件:Packet.dll、Packet.lib、wpcap.dll、wpcap.libide
② 頭文件spa
3、用vs建立工程(我這裏使用的是vs2015)3d
工程建立完畢須要配置工程屬性調試
① 右鍵工程屬性-->VC++目錄-->找到包含目錄、庫目錄,把剛纔的庫文件路徑和頭文件的路徑添加進去,以下圖所示code
② 找到連接器--->附加依賴項,添加Packet.lib、wpcap.lib庫文件htm
4、示例代碼
① 頭文件
/***************************************************************************** * * * @file RawEtherSniffer.h * * @brief 經過原始以太網解析FPGA發送的數據 * * Details. * * * * @author jiang shuang * * @email * * @version 1.0.0.0(版本號) * * @date * * @license * * * *----------------------------------------------------------------------------* * Remark : Description * *----------------------------------------------------------------------------* * Change History : * * <Date> | <Version> | <Author> | <Description> * *----------------------------------------------------------------------------* * 2019/09/10 | 1.0.0.0 | jiangshuang | Create file * *----------------------------------------------------------------------------* * * *****************************************************************************/ #pragma once #define WIN32 #include <iostream> #include <stdio.h> #include <stdlib.h> #include <pcap.h> class RawEtherTools { public: RawEtherTools(); ~RawEtherTools(); /** * @brief 以太網數據數據幀嗅探器 * @input 無 * @output 無 * @return 無 */ void CaptureRawEtherFrame(); int ethernet_protocol_packet_handle(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content); };
② cpp文件
#define _CRT_SECURE_NO_WARNINGS #include "Tools.h" using namespace std; // 以太網協議格式的定義 typedef struct ether_header { u_char ether_dhost[6]; // 目標MAC地址 u_char ether_shost[6]; // 源MAC地址 u_short ether_type; // 以太網類型 }ether_header; // 用戶保存4字節的IP地址 typedef struct ip_address { u_char byte1; u_char byte2; u_char byte3; u_char byte4; }ip_address; // 用於保存IPV4的首部 typedef struct ip_header { #ifdef WORDS_BIGENDIAN u_char ip_version : 4, header_length : 4; #else u_char header_length : 4, ip_version : 4; #endif u_char ver_ihl; // 版本以及首部長度,各4位 u_char tos; // 服務質量 u_short tlen; // 總長度 u_short identification; // 身份識別 u_short offset; // 分組偏移 u_char ttl; // 生命週期 u_char proto; // 協議類型 u_short checksum; // 包頭測驗碼 ip_address saddr; // 源IP地址 ip_address daddr; // 目的IP地址 u_int op_pad; // 可選 填充字段 }ip_header; RawEtherTools::RawEtherTools() { } RawEtherTools::~RawEtherTools() { } /** * @brief * @input 無 * @output 無 * @return 無 */ void RawEtherTools::CaptureRawEtherFrame() { struct pcap_pkthdr *header; pcap_if_t * allDevs; pcap_if_t * dev; u_int netmask; int inum; int i = 0; int res; const u_char *pkt_data; time_t local_tv_sec; struct tm *ltime; char timestr[16]; ip_header *ih; char errbuf[PCAP_ERRBUF_SIZE]; if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &allDevs, errbuf) > 0) { printf("pcap_findallDevs_ex failed\n"); } for (dev = allDevs; dev; dev = dev->next) { printf("%d. %s", ++i, dev->name); if (dev->description) { printf("(%s)\n", dev->description); } else { printf("No description available\n"); } } if (0 == i) { printf("\nNo interface found!Make sure WinPcap is installed\n"); return; } printf("Enter the interface number(1-%d):", i); scanf_s("%d", &inum); if (inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); pcap_freealldevs(allDevs); return; } for (dev = allDevs, i = 0; i < inum - 1; dev = dev->next, i++); pcap_t * handler; // 設備名,要捕捉的數據包的部分(65536保證能捕獲到不一樣數據鏈路層上的每一個數據包的所有內容),混雜模式,讀取超時時間,錯誤緩衝池 if ((handler = pcap_open_live(dev->name, 65536, 1, 1000, errbuf)) == NULL) { fprintf(stderr, "\nUnable to open the adapter.%s is not supported by WinPcap\n", errbuf); pcap_freealldevs(allDevs); return; } // 檢查數據鏈路層(只考慮了以太網) if (pcap_datalink(handler) != DLT_EN10MB) { fprintf(stderr, "\nThis program works only on Ethernet networks.\n"); pcap_freealldevs(allDevs); return; } if (dev->addresses != NULL) { // 得到接口的第一個地址的掩碼 netmask = ((struct sockaddr_in*)(dev->addresses->netmask))->sin_addr.S_un.S_addr; } else { netmask = 0xffffff; } while ((res = pcap_next_ex(handler, &header, &pkt_data)) >= 0) { // 請求超時 if (0 == res) { continue; } // 分析數據包 int ret = ethernet_protocol_packet_handle(NULL, header, pkt_data); if (ret == -1) continue; // 將時間戳轉換成可識別的格式 local_tv_sec = header->ts.tv_sec; ltime = localtime(&local_tv_sec); strftime(timestr, sizeof(timestr), "%H:%M:%S", ltime); ih = (ip_header *)(pkt_data + 14); //以太網頭部長度 // 輸出時間和IP信息 //printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len); printf(" len:%d ", header->len); printf("%d.%d.%d.%d -> %d.%d.%d.%d\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4); printf("%02x%02x%02x%02x -> %02x%02x%02x%02x\n", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4, ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4); //輸出每一個包的byte數據ws2_32.lib for (int k = 0; k < header->len; k++) { if (k % 16 == 0 && k != 0)//輸出美觀 printf("\n"); printf("%02x ", *(pkt_data + k)); } printf("\n"); } if (-1 == res) { printf("Error reading the packet:%s\n", pcap_geterr(handler)); return; } pcap_freealldevs(allDevs); } /** * @brief 抓取以太網協議包 * @input 無 * @output 無 * @return 無 */ int RawEtherTools::ethernet_protocol_packet_handle(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content) { u_short ethernet_type; // 以太網類型 struct ether_header *ethernet_protocol; // 以太網協議變量 u_char *mac_string; // 以太網地址 ethernet_protocol = (struct ether_header*)packet_content;// 獲取以太網數據內容 ethernet_type = ntohs(ethernet_protocol->ether_type); // 獲取以太網類型 if (ethernet_type != 0x00FF) { return -1; } printf("Ethernet type is : %04x\n", ethernet_type); // 獲取以太網源地址 mac_string = ethernet_protocol->ether_shost; printf(" MAC Source Address is === %02x:%02x:%02x:%02x:%02x:%02x", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5) ); // 獲取以太網目的地址 mac_string = ethernet_protocol->ether_dhost; printf(" MAC Target Address === %02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5) ); printf("%d", sizeof(packet_content)); return 0; }
③ Main.cpp
#include <iostream> #include "Tools.h" using namespace std; int main() { RawEtherTools *raw = new RawEtherTools(); raw->CaptureRawEtherFrame(); system("pause"); return 0; }
5、編譯程序
① 錯誤1 編譯程序報錯,以下圖所示
解決辦法:
ws2_32.lib文件,提供了對如下網絡相關API的支持,若使用其中的API,則應該將ws2_32.lib加入工程
在工程屬性--->連接器--->附加依賴項,添加ws2_32.lib庫文件
② 錯誤2 編譯程序報錯,以下圖所示
解決辦法:
1.error C3861: 「pcap_findalldevs_ex」: 找不到標識符
2.error C2065: 「PCAP_SRC_IF_STRING」: 未聲明的標識符
在WinPcap編程調試解決辦法 中,須要項目屬性-》配置屬性-》C/C++-》預處理器-》預處理器定義中添加HAVE_REMOTE,方可編譯成功。