基于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,方可编译成功。

相关文章
相关标签/搜索