基於WinPcap實現的Raw EtherNet 抓包、發包程序

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,方可編譯成功。

相關文章
相關標籤/搜索