2301_81286386 2024-09-09 15:22 采纳率: 50%
浏览 5
已结题

VS 2022 中解析ARP数据包没有输出结果

请问一下这是怎么回事?

img

#include<Winsock2.h>
#pragma comment(lib, "Ws2_32.lib")      //使用ntohs()函数,转换2B/4B的数据
#pragma comment(lib, "wpcap.lib")
#include"pcap.h"                        //需要另外导入,具体步骤见Winpcap使用说明
#include<fstream>
#include<iostream>                      //格式化输出
#include<iomanip>
using namespace std;             
#include<conio.h>                       //使用_getch()
struct arppkt {
    unsigned short hdtyp;              //硬件地址
    unsigned short protyp;             //协议类型
    unsigned char hdsize;              //硬件地址长度
    unsigned char prosize;             //协议地址长度
    unsigned short op;                 //操作值
    u_char smac[6];                    //源MAC地址
    u_char sip[4];                     //源IP地址
    u_char dmac[6];                    //目的MAC地址
    u_char dip[4];                     //目的IP地址
};
//自定义处理包函数
//pcap_pkthdr是winpcap加入的
//pkt_data表示MAC帧的起始位置
//out是输入流
void packet_handler(const pcap_pkthdr* header, const u_char* pkt_data, ostream&);
void main(int argc, char* argv[])
{
    if (argc != 2)
    {
        cout << "usage:ARPCap logfilename" << endl;
        cout << "press anykey to continue." << endl;    //参数不对,进行提示
        _getch();
        return;
    }
    pcap_if_t* alldevs;                               //网络设备结构
    pcap_if_t* d;
    pcap_t* adhandle=nullptr;
    char errbuf[PCAP_ERRBUF_SIZE];                  //错误信息
    u_int netmask;                                    //子网掩码
    char packet_filter[] = "ether proto \\arp";       //过滤,选择ARP协议
    struct bpf_program fcode;
    struct pcap_pkthdr* header;
    const u_char* pkt_data;
    //获取网络设备列表
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        cout << "Error in pcap_findalldevs:" << errbuf;
        return;
    }
    //选择一个Ethernetka卡
    for (d = alldevs; d; d = d->next)
    {
        //以混杂模式打开网卡,接受所有的帧
        if ((adhandle = pcap_open_live(d->name, 1000, 1, 300, errbuf)) == NULL)
        {
            cout << "\nUnable to open the adapter.";
            pcap_freealldevs(alldevs);              //释放设备列表      
            return;
        }
        if (pcap_datalink(adhandle) == DLT_EN10MB && d->addresses != NULL)
            break;
    }
    if (d == NULL)
    {
        cout << "\nNO interfaces found! Make sure winpcap is installed.\n";
        return;
    }
    //获得子网掩码
    netmask = ((sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    //调试过滤器,只捕获ARP包
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) < 0)
    {
        cout << "\nUnable to compile the packet filter. Check the syntax.\n";
pcap_freealldevs(alldevs);
        return;
    }
    //设置过滤器
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
        cout << "\nError setting the filter.\n";
        pcap_freealldevs(alldevs);
        return;
    }
    cout << "\t\tlistening on " << d->description << "..." << endl << endl;
    ofstream fout(argv[1], ios::app);                  //日志记录文件
    //加入日期记录
    time_t t;
    time(&t);
    fout.seekp(0, ios::end);
    if (fout.tellp() != 0)
        fout << endl;
    fout << "\t\tARP request(1)/replay(2) on " << ctime(&t);
    cout << "sour IP Addr" << "   " << "Sour MAC Address"
        << "   " << "Des IP Addr" << "   " << "Des MAC Address"
        << "   " << "OP" << "   " << "Time" << endl;
    fout << "Sour IP Addr" << "  " << "Sour MAC Address"
        << "  " << "Des IP Addr" << "  " << "Des MAC Address"
        << "  " << "OP" << "  " << "Time" << endl;
    //释放设备列表
    pcap_freealldevs(alldevs);
    //开始捕获MAC帧
    int result;                                 //时间到返回结果
    while ((result = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0)
    {
        if (result == 0)
            continue;
        packet_handler(header, pkt_data, cout);   //解析ARP包,输出结果
        packet_handler(header, pkt_data, fout);   //输出到文件
    }
}
void packet_handler(const pcap_pkthdr* header, const u_char* pkt_data, ostream& out)
{
    int i;
    //从截获的数据帧中找到arp包头的位置
    arppkt* arph = (arppkt*)(pkt_data + 14);    //14为Ethernet帧头的长度
    //输出源IP地址
    for (i = 0; i < 3; i++)
        out << int(arph->sip[i]) << '.';
    out.setf(ios::left);
    out << setw(3) << int(arph->sip[3]) << "  ";
    out.unsetf(ios::left);
    //输出源MAC地址
    char oldfillchar = out.fill('0');
    out.setf(ios::uppercase);       //MAC地址以分开'-'的大写字符表示
    for (i = 0; i < 5; i++)
        out << hex << setw(2) << int(arph->smac[i]) << '_';
    out << hex << setw(2) << int(arph->smac[5]) << "  ";
    out.fill(oldfillchar);
    //输出目的的IP地址
    out.unsetf(ios::hex | ios::uppercase);
    for (i = 0; i < 3; i++)
        out << int(arph->dip[i]) << '.';
    out.setf(ios::left);
    out << setw(3) << int(arph->dip[3]) << " ";
    out.unsetf(ios::left);
    //输出目的MAC地址
    out.fill('0');
    out.setf(ios::uppercase);
    for (i = 0; i < 5; i++)
        out << hex << setw(2) << int(arph->dmac[i]) << '_';
    out << hex << setw(2) << int(arph->dmac[5]) << "  ";
    out.fill(oldfillchar);
    out.unsetf(ios::hex | ios::uppercase);
    out << ntohs(arph->op) << " ";
    struct tm* ltime;                              //时间
    time_t local_time = header->ts.tv_sec;  // 创建一个非 const 的局部副本
    ltime = localtime(&local_time);  // 使用非 const 副本调用 localtime
    out.fill('0');
    out << ltime->tm_hour << ':' << setw(2) << ltime->tm_min << ':' << setw(2) << ltime->tm_sec;
    out.fill(oldfillchar);
    out << endl;
}
  • 写回答

8条回答 默认 最新

  • 才华横溢caozy 2024-09-10 08:38
    关注

    以下答案是由GPT4-pro回答,本人整理后的结果,如有帮助,还请采纳!
    你在使用 WinPcap 进行 ARP 数据包捕获时遇到了解析结果为空的问题。以下是一些可能的原因和解决方法。

    1. 确保 WinPcap 正常工作

    首先,确保你的 WinPcap 已正确安装且正常工作。可以通过以下步骤确认:

    • 确保你的网络接口支持混杂模式。
    • 运行 Wiresharktcpdump 等工具检查是否能够捕获到 ARP 数据包。如果这些工具能正常工作,但你的程序不能,则可能是代码中的问题。

    2. 检查数据链路层类型

    确保你的网络接口是以 Ethernet 方式工作。在你的代码中,有以下判断:

    if (pcap_datalink(adhandle) == DLT_EN10MB && d->addresses != NULL)
        break;
    

    这里 DLT_EN10MB 代表 Ethernet。确保你的网络接口支持 Ethernet 类型。如果接口类型不匹配,数据包可能无法被捕获。

    3. 检查 ARP 过滤器

    你在代码中设置了一个 ARP 过滤器:

    char packet_filter[] = "ether proto \\arp";       //过滤,选择ARP协议
    

    注意到你使用了反斜杠 (\\)。通常情况下,WinPcap 需要用单斜杠 (/)。将其修改为:

    char packet_filter[] = "arp";
    

    然后重新编译并运行代码,看看是否能正确捕获 ARP 数据包。

    4. 验证网络设备的子网掩码

    你在以下代码中获取子网掩码:

    netmask = ((sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    

    确保你的 d->addresses 中的 netmask 是正确的。如果 d->addresses->netmaskNULL,则你需要获取正确的子网掩码值。

    你可以通过以下代码检查 netmask 是否正确:

    if (d->addresses->netmask != NULL) {
        netmask = ((sockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    } else {
        cout << "No netmask available, setting default." << endl;
        netmask = 0xFFFFFF00; // 使用默认的子网掩码
    }
    

    5. 调试信息输出

    在捕获数据包时添加调试信息,以帮助确定问题所在。比如:

    cout << "Result: " << result << endl;
    if (result == 0) {
        cout << "No packets available." << endl;
    } else if (result < 0) {
        cout << "Error: " << pcap_geterr(adhandle) << endl;
    }
    

    6. ARP 数据包解析

    检查你的 ARP 数据包解析代码,确保 ARP 数据包的位置和结构正确。你可以打印数据包的原始数据,确认是否正确解析:

    void packet_handler(const pcap_pkthdr* header, const u_char* pkt_data, ostream& out)
    {
        int i;
        // 从截获的数据帧中找到 ARP 包头的位置
        arppkt* arph = (arppkt*)(pkt_data + 14);    // 14 为 Ethernet 帧头的长度
        // 输出原始数据包
        cout << "Raw Data: ";
        for (int j = 0; j < header->len; ++j) {
            cout << hex << setw(2) << setfill('0') << int(pkt_data[j]) << ' ';
        }
        cout << endl;
        
        // 输出 ARP 数据包内容
        for (i = 0; i < 3; i++)
            out << int(arph->sip[i]) << '.';
        out.setf(ios::left);
        out << setw(3) << int(arph->sip[3]) << "  ";
        out.unsetf(ios::left);
        char oldfillchar = out.fill('0');
        out.setf(ios::uppercase);
        for (i = 0; i < 5; i++)
            out << hex << setw(2) << int(arph->smac[i]) << '_';
        out << hex << setw(2) << int(arph->smac[5]) << "  ";
        out.fill(oldfillchar);
        out.unsetf(ios::hex | ios::uppercase);
        for (i = 0; i < 3; i++)
            out << int(arph->dip[i]) << '.';
        out.setf(ios::left);
        out << setw(3) << int(arph->dip[3]) << " ";
        out.unsetf(ios::left);
        out.fill('0');
        out.setf(ios::uppercase);
        for (i = 0; i < 5; i++)
            out << hex << setw(2) << int(arph->dmac[i]) << '_';
        out << hex << setw(2) << int(arph->dmac[5]) << "  ";
        out.fill(oldfillchar);
        out.unsetf(ios::hex | ios::uppercase);
        out << ntohs(arph->op) << " ";
        struct tm* ltime;
        time_t local_time = header->ts.tv_sec;
        ltime = localtime(&local_time);
        out.fill('0');
        out << ltime->tm_hour << ':' << setw(2) << ltime->tm_min << ':' << setw(2) << ltime->tm_sec;
        out.fill(oldfillchar);
        out << endl;
    }
    

    7. 编译和运行环境

    确保你的编译器和库版本兼容。如果你使用的是 VS 2022,确保 WinPcap 库文件路径已正确配置,并且没有版本冲突。

    8. 其他建议

    • 检查是否有防火墙或网络配置阻止 ARP 包的捕获。
    • 使用 pcap_dump 来将数据包写入文件,并使用 Wireshark 等工具检查文件内容。

    通过这些步骤,你可以逐步排查和解决 ARP 数据包捕获和解析问题。如果还有问题,可以进一步检查错误日志和调试信息。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 9月10日
  • 赞助了问题酬金15元 9月10日
  • 创建了问题 9月9日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?