一、背景
二、中文技术文档
二、需要使用到的动态库和外部头文件
① 库文件:.dll、.lib、wpcap.dll、wpcap.lib

② 头文件
三、用vs创建工程(我这里使用的是)
工程创建完毕需要配置工程属性
① 右键工程属性–>VC++目录–>找到包含目录、库目录,把刚才的库文件路径和头文件的路径添加进去,如下图所示

② 找到链接器—>附加依赖项,添加.lib、wpcap.lib库文件

四、示例代码
① 头文件
/***************************************************************************** * *
* @file RawEtherSniffer.h *
* @brief 通过原始以太网解析FPGA发送的数据 *
* Details. *
* *
* @author jiang shuang *
* @email *
* @version 1.0.0.0(版本号) *
* @date *
* @license *
* *
*----------------------------------------------------------------------------*
* Remark : Description *
*----------------------------------------------------------------------------*
* Change History : *
* | | | *
*----------------------------------------------------------------------------*
* 2019/09/10 | 1.0.0.0 | jiangshuang | Create file *
*----------------------------------------------------------------------------*
* *
*****************************************************************************/
#pragma once
#define WIN32
#include
#include
#include
#include
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 failedn");
}
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 availablen");
}
}
if (0 == i) {
printf("nNo interface found!Make sure WinPcap is installedn");
return;
}
printf("Enter the interface number(1-%d):", i);
scanf_s("%d", &inum);
if (inum i) {
printf("nInterface number out of range.n");
pcap_freealldevs(allDevs);
return;
}
for (dev = allDevs, i = 0; i 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 WinPcapn", 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.%dn",
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("xxxx -> xxxxn",
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 len; k++)
{
if (k % 16 == 0 && k != 0)//输出美观
printf("n");
printf("x ", *(pkt_data + k));
}
printf("n");
}
if (-1 == res) {
printf("Error reading the packet:%sn", 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 : xn", ethernet_type);
// 获取以太网源地址
mac_string = ethernet_protocol->ether_shost;
printf(" MAC Source Address is === x:x:x:x:x:x",
*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 === x:x:x:x:x:xn",
*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
#include "Tools.h"
using namespace std;
int main()
{
RawEtherTools *raw = new RawEtherTools();
raw->CaptureRawEtherFrame();
system("pause");
return 0;
}
五、编译程序
① 错误1 编译程序报错,如下图所示

解决办法:
.lib文件,提供了对以下网络相关API的支持,若使用其中的API,则应该将.lib加入工程
在工程属性—>链接器—>附加依赖项,添加.lib库文件

② 错误2 编译程序报错,如下图所示

解决办法:
1.error C3861: “”: 找不到标识符
2.error C2065: “”: 未声明的标识符
在编程调试解决办法 中,需要项目属性-》配置属性-》C/C++-》预处理器-》预处理器定义中添加,方可编译成功。



发表回复