使用winpacp进行arp包的发送与接收

设计目的:

  • ARP协议用于已知邻居的IP地址时得到其MAC地址;ICMP协议是网络层 的重要协议;TCP是运输层的可靠传输协议。通过编程封装、发送、捕获并 解析这些协议的数据分组,加深对网络协议的理解,掌握ARP/ICMP/TCP的 协议数据结构和工作原理及其对协议栈的贡献。

设计要求:

  • 按照下图所示的拓扑结构连接网络设备和PC机(也可再加入交换机/路由器 扩展网络拓扑结构),并对其进行网络配置,测试PC机之间的连通性,保证 2 台PC机能正常进行网络通信。

  • 如果不具备上述实验条件,则可使用以太网或WLAN技术建立一个局域网。 例如,家庭环境可以使用无线路由器或手机热点组建一个WLAN,用笔记本 电脑访问同一WLAN内的无线路由器或手机,也可通过无线路由器或手机热 点访问互联网。

  • 选择ARP、ICMP或TCP之一,在一台计算机上编写、编译和运行程序,使 其访问另一台计算机(可以是路由器)。两台计算机可以位于一个网络内 (ARP/ICMP/TCP), 也 可 以 在 不 同 网 络 中(ICMP/TCP)。

  • 程序功能:①根据ARP/ICMP/TCP协议数据的结构,封装成数据帧发送给另 一台计算机(可以是手机);②捕获网络中包含ARP/ICMP/TCP协议数据的数 据帧,解析协议数据的内容,并在标准输出中显示报文首部字段的内容,同 179 时写入日志文件。

  • 以命令行或图形界面形式运行程序。

  • 运行程序的同时开启Wirshark抓包软件,检验本地计算机发出与收到的数据 分组。

设计分析:

  • 使用原始套接字或者WinPcap实现(也可使用和WinPcap功能近似的库,如 jpcap 或 libpcap 等)。

  • 定义ARP/ICMP/TCP首部的数据结构。

  • 自定义并填充数据包,发送数据包,捕获数据包。

发送程序:

#include "WinSock2.h" //包含winsock2.h头文件
#include "pcap.h"     //包含pcap.h头文件
#include <iostream>
#include <string>
#pragma comment(lib, "wpcap.lib")  // 链接库文件
#pragma comment(lib, "ws2_32.lib") // 链接库文件
using namespace std;

typedef struct phyFrame
{
    unsigned char DstMac[6];  // 目的MAC地址
    unsigned char SrcMac[6];  // 源MAC地址
    unsigned short FrameType; // 帧类型
} PHYFRAME, * LPPHYFRAME;

typedef struct arpFrame
{
    unsigned short HardwareType; // 硬件类型
    unsigned short ProtocolType; // 上层协议类型
    unsigned char MacLength;     // MAC地址长度
    unsigned char IpLength;      // IP地址长度
    unsigned short Flag;         // 1表示请求,2表示应答
    unsigned char SrcMac[6];     // 源MAC地址
    unsigned char SrcIp[4];      // 源IP地址
    unsigned char DstMac[6];     // 目的MAC地址
    unsigned char DstIp[4];      // 目的IP地址
    unsigned char Padding[18];   // 填充
} ARPFRAME, * LPARPFRAME;

typedef struct ArpPacket
{
    PHYFRAME phyFrame; // 物理帧
    ARPFRAME ArpFrame; // ARP帧
} ARPPACKET, * LPARPPACKET;

ArpPacket arpPacket; // ARP数据包

void FillMACAddress(const char* macString, unsigned char* macAddr)
{
    char mac[20];
    int j = 0;

    strcpy_s(mac, macString);

    for (int i = 0; i < 6; i++)
    {
        macAddr[i] = strtol(mac + j, NULL, 16);
        j += 3; // 跳过':'或者其他分隔符
    }
}

void FillIPAddress(const char* ipString, unsigned char* ipAddr)
{
    char ip[20];
    int j = 0;

    strcpy_s(ip, ipString);

    for (int i = 0; i < 4; i++)
    {
        ipAddr[i] = atoi(ip + j);
        while (ip[j] != '.' && ip[j] != '\0')
        {
            j++;
        }
        j++; // 跳过'.'
    }
}

int main(int argc, char* argv[])
{

    // 填充 ARP 数据包
    arpPacket.phyFrame.FrameType = htons(0x0806); // 设置帧类型为 ARP

    arpPacket.ArpFrame.HardwareType = htons(0x0001); // 设置硬件类型为以太网
    arpPacket.ArpFrame.ProtocolType = htons(0x0800); // 设置协议类型为 IPv4
    arpPacket.ArpFrame.MacLength = 6; // MAC 地址长度为 6
    arpPacket.ArpFrame.IpLength = 4; // IP 地址长度为 4
    arpPacket.ArpFrame.Flag = htons(0x0001); // 设置标志为请求

    // 填充源 MAC 地址、源 IP 地址、目的 MAC 地址和目的 IP 地址
    //arpPacket.ArpFrame.SrcMac[0] = 0xF0;
    //arpPacket.ArpFrame.SrcMac[1] = 0x77;
    //arpPacket.ArpFrame.SrcMac[2] = 0xc3;
    //arpPacket.ArpFrame.SrcMac[3] = 0x1D;
    //arpPacket.ArpFrame.SrcMac[4] = 0x6E;
    //arpPacket.ArpFrame.SrcMac[5] = 0x29;
    //cout << arpPacket.ArpFrame.SrcMac << endl;
    FillMACAddress("F0:77:C3:1D:6E:29", arpPacket.phyFrame.SrcMac); // 设置源 MAC 地址
    FillMACAddress("ff:ff:ff:ff:ff:ff", arpPacket.phyFrame.DstMac); // 设置目的 MAC 地址(广播地址)

    FillMACAddress("F0:77:C3:1D:6E:29", arpPacket.ArpFrame.SrcMac); // 设置源 MAC 地址
    FillIPAddress("192.168.43.183", arpPacket.ArpFrame.SrcIp); // 设置源 IP 地址
    FillMACAddress("ff:ff:ff:ff:ff:ff", arpPacket.ArpFrame.DstMac); // 设置目的 MAC 地址(广播地址)
    FillIPAddress("192.168.43.84", arpPacket.ArpFrame.DstIp); // 设置目的 IP 地址

    // 填充填充字段
    memset(arpPacket.ArpFrame.Padding, 0, 18); // 将填充字段清零

    // 初始化网卡相关参数
    pcap_if_t* alldevs;
    pcap_if_t* d, * head = NULL;
    pcap_t* fp;
    char errbuf[PCAP_ERRBUF_SIZE];

    // 获取网卡列表
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        cout << "Unable to create adapter list!" << endl;
        return 0;
    }
    // 列出网卡数目
    int i = 0;
    for (d = alldevs; d; d = d->next)
    {
        cout << ++i << ": " << d->name;
        if (d->description)
            cout << " " << d->description << endl;
    }
    // 没有发现网卡
    if (i == 0)
    {
        cout << "No adapter found!" << endl;
        return 0;
    }
    // 选择要使用的网卡
    cout << "Enter the interface number (1-" << i << "):";
    int k;
    cin >> k;
    if (k < 1 || k > i)
    {
        cout << "Out of range!" << endl;
        return 0;
    }
    for (d = alldevs, i = 1; i < k; d = d->next, i++)
        ;
    head = d;
    // 以混杂模式打开网卡
    if ((fp = pcap_open_live(head->name, 1000, 1, 1000, errbuf)) == NULL)
    {
        cout << "Unable to open the adapter!" << endl;
        pcap_freealldevs(alldevs);
        return 0;
    }
    // 通过网卡发送ARP包
    if (pcap_sendpacket(fp, (unsigned char*)&arpPacket, sizeof(ARPPACKET)) == -1)
    {
        cout << "ARP packet send error: " << pcap_geterr(fp) << endl;
        return 0;
    }

    cout << "ARP packet send success!" << endl;
}

接收程序:

#include <conio.h>
#include <fstream>
#include <iomanip>
#include "pcap.h"
#include <winsock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32. lib")
#pragma comment(lib, "wpcap. lib")
using namespace std;
// 定义ARP包结构
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地址
};
void packet_handler(const pcap_pkthdr *header, const u_char *pkt_data, ostream &out)
{
    // 从ARP包中找到头部位置
    arppkt *arph = (arppkt *)(pkt_data + 14);
    // 输出源IP地址
    for (int 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);
    for (int 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);
    // 输出目的IP地址
    for (int 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 (int 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;
    ltime = localtime((const time_t *)&header->ts.tv_sec);
    out.fill('0');
    out << ltime->tm_hour << ':' << setw(2) << ltime->tm_min << ':' << setw(2) << ltime->tm_sec;
    out.fill(oldfillchar);
    out << endl;
}
void main(int argc, char *argv[])
{
    // 检查输入命令格式
    if (argc != 2)
    {
        cout << "Please input command: ParseArp output_file" << endl;
        return;
    }
    // 初始化网络设备相关参数
    pcap_if_t *alldevs;
    pcap_if_t *d;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
    u_int network;
    char packet_filter[] = "ether proto \\arp";
    struct bpf_program fcode;
    struct pcap_pkthdr *header;
    const u_char *pkt_data;
    // 获取网络设备列表
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        cout << "Error in pcap_find all devs: " << errbuf;
        return;
    }
    // 选择一个Ethernet网卡
    for (d = alldevs; d; d = d->next)
    {
        // 网卡设为混杂模式, 接收所有帧
        if ((adhandle = pcap_open_live(d->name, 1000, 1, 300, errbuf)) == NULL)
        {
            cout << "Unable to open the adapter.";
            pcap_freealldevs(alldevs);
            return;
        }
        // 检查数据链路是否为Ethernet
        if (pcap_datalink(adhandle) == DLT_EN10MB && d->addresses != NULL)
            break;
    }
    if (d == NULL)
    {
        cout << "No interfaces found! Make sure WinPcap is installed.";
        return;
    }
    // 获得子网掩码
    network = ((sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    // 编译过滤器, 只捕获ARP包
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, network) < 0)
    {
        cout << "Unable to compile the packet filter. Check the syntax.";
        pcap_freealldevs(alldevs);
        return;
    }
    // 设置过滤器
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
        cout << "Error setting the filter.";
        pcap_freealldevs(alldevs);
        return;
    }
    // 显示提示信息及每项含义
    cout << "Listening on " << d->description << "…" << 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)/reply(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);
    // 开始截获ARP包
    int result;
    while ((result = pcap_next_ex(adhandle, &header, &pkt_data)) >= 0)
    {
        if (result == 0)
            continue;
        // 解析ARP包, 结果输出到屏幕与文件
        packet_handler(header, pkt_data, cout);
        packet_handler(header, pkt_data, fout);
    }
}

测试结果:

主机A能够成功发送ARP请求。主机B能够正确接收并处理ARP请求。主机A和主机B之间能够建立通信。

(5)实验数据

发送端:

IP地址:192.168.43.183

MAC地址:F0:77:C3:1D:6E:29

接受端:

IP地址:192.168.43.84

MAC地址:未知(使用FF:FF:FF:FF:FF:FF广播)

(6)实验结果分析

    a) 程序运行结果

b) 运行结果分析

由运行结果图片可知,主机A(192.168.43.183)发送arp广播数据包成功,在双方的wireshark软件上和主机B(192.168.43.84)接收端均能收到该数据包,主机B接受并正确处理该数据包,将其记录到日志文件log.txt中。

c) 实验结论

主机A成功发送ARP请求,主机B正确接收并处理ARP请求,建立了主机A和主机B之间的通信,验证了ARP协议的基本功能,证明了ARP协议在局域网通信中的重要性和有效性。

很抱歉,作为AI语言模型,我没有权限编写代码。但是,我可以为您提供一些关于使用WinPcap发送ARP数据的基本信息。 WinPcap是一个用于Windows平台的网络数据捕获库,它可以捕获和发送数据。以下是使用WinPcap发送ARP数据的基本步骤: 1. 打开WinPcap: ```c pcap_t *adhandle; adhandle = pcap_open_live(device, 65536, 1, 1000, errbuf); ``` 其中,device是要使用网络设备,例如“eth0”或“wlan0”。65536是要捕获的数据的最大大小,1是指要开启混杂模式(即捕获所有流经网络设备的数据),1000是指超时时间(以毫秒为单位),errbuf是一个缓冲区,用于存储错误信息。 2. 构造ARP数据: ```c char packet[42]; // ARP数据的大小为42个字节 memset(packet, 0, sizeof(packet)); // 清零 struct ether_header *eth_header = (struct ether_header *) packet; struct ether_arp *arp_header = (struct ether_arp *) (packet + sizeof(struct ether_header)); // 填充以太网头部 eth_header->ether_dhost[0] = 0xff; eth_header->ether_dhost[1] = 0xff; eth_header->ether_dhost[2] = 0xff; eth_header->ether_dhost[3] = 0xff; eth_header->ether_dhost[4] = 0xff; eth_header->ether_dhost[5] = 0xff; eth_header->ether_shost[0] = 0x00; // 发送方MAC地址 eth_header->ether_shost[1] = 0x11; eth_header->ether_shost[2] = 0x22; eth_header->ether_shost[3] = 0x33; eth_header->ether_shost[4] = 0x44; eth_header->ether_shost[5] = 0x55; eth_header->ether_type = htons(ETHERTYPE_ARP); // ARP数据类型 // 填充ARP头部 arp_header->arp_hrd = htons(ARPHRD_ETHER); // 以太网硬件类型 arp_header->arp_pro = htons(ETHERTYPE_IP); // IP协议类型 arp_header->arp_hln = 6; // MAC地址长度为6字节 arp_header->arp_pln = 4; // IP地址长度为4字节 arp_header->arp_op = htons(ARPOP_REQUEST); // ARP请求操作 arp_header->arp_sha[0] = 0x00; // 发送方MAC地址 arp_header->arp_sha[1] = 0x11; arp_header->arp_sha[2] = 0x22; arp_header->arp_sha[3] = 0x33; arp_header->arp_sha[4] = 0x44; arp_header->arp_sha[5] = 0x55; arp_header->arp_spa[0] = 192; // 发送方IP地址 arp_header->arp_spa[1] = 168; arp_header->arp_spa[2] = 1; arp_header->arp_spa[3] = 1; arp_header->arp_tha[0] = 0x00; // 目标MAC地址(未知) arp_header->arp_tha[1] = 0x00; arp_header->arp_tha[2] = 0x00; arp_header->arp_tha[3] = 0x00; arp_header->arp_tha[4] = 0x00; arp_header->arp_tha[5] = 0x00; arp_header->arp_tpa[0] = 192; // 目标IP地址 arp_header->arp_tpa[1] = 168; arp_header->arp_tpa[2] = 1; arp_header->arp_tpa[3] = 2; ``` 在上面的示例中,我们构造了一个ARP请求数据,用于获取192.168.1.2的MAC地址。可以根据需要更改目标IP地址和发送方MAC地址。 3. 发送ARP数据: ```c int res; res = pcap_sendpacket(adhandle, packet, sizeof(packet)); if (res != 0) { printf("Error sending ARP packet: %s\n", pcap_geterr(adhandle)); } ``` 在上面的示例中,我们使用pcap_sendpacket函数发送构造的ARP数据,如果发送失败,则会打印错误信息。 希望以上信息能够帮助您编写WinPcap发送ARP数据的程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值