基于WinPcap实现的Raw EtherNet 抓包、发包程序
2021-01-26 15:14
标签:eth herf scanf cap ace off 包头 color === 一、背景 二、WinPcap中文技术文档 http://www.ferrisxu.com/WinPcap/html/index.html 二、需要使用到的动态库和外部头文件 ① 库文件:Packet.dll、Packet.lib、wpcap.dll、wpcap.lib ② 头文件 三、用vs创建工程(我这里使用的是vs2015) 工程创建完毕需要配置工程属性 ① 右键工程属性-->VC++目录-->找到包含目录、库目录,把刚才的库文件路径和头文件的路径添加进去,如下图所示 ② 找到链接器--->附加依赖项,添加Packet.lib、wpcap.lib库文件 四、示例代码 ① 头文件 ② cpp文件 ③ Main.cpp 五、编译程序 ① 错误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,方可编译成功。 基于WinPcap实现的Raw EtherNet 抓包、发包程序 标签:eth herf scanf cap ace off 包头 color === 原文地址:https://www.cnblogs.com/jiangson/p/11890626.html/***************************************************************************** * *
* @file RawEtherSniffer.h *
* @brief 通过原始以太网解析FPGA发送的数据 *
* Details. *
* *
* @author jiang shuang *
* @email *
* @version 1.0.0.0(版本号) *
* @date *
* @license *
* *
*----------------------------------------------------------------------------*
* Remark : Description *
*----------------------------------------------------------------------------*
* Change History : *
*
#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 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 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;
}
#include
上一篇:C#中关于值类型和引用类型的区别
文章标题:基于WinPcap实现的Raw EtherNet 抓包、发包程序
文章链接:http://soscw.com/index.php/essay/47330.html