ARP详解及组包案例

ARP是什么

地址解析协议(Address Resolution Protocol,ARP)是一种用于在IPv4网络中将IP地址映射到物理MAC地址的协议。它在局域网中帮助设备找到其他设备的物理地址,以便将网络数据包正确地传送到目标设备。

ARP报文传输过程:

当一个设备(主机或路由器)需要发送数据包到一个目标设备的IP地址时,它首先会检查本地的ARP缓存表,查看是否已经知道了目标IP对应的MAC地址。如果没有,设备会执行以下步骤来获取目标设备的MAC地址:

ARP请求(ARP Request):
发送方设备创建一个ARP请求报文,其中包含以下字段:
    源MAC地址
    源IP地址
    目标IP地址(待查询的IP地址)
    这个ARP请求报文会以广播方式发送到本地局域网中的所有设备。

ARP应答(ARP Reply):
目标设备接收到广播的ARP请求后,会检查请求中的目标IP地址是否与自己的IP地址匹配。如果匹配,它将创建一个ARP应答报文,其中包含以下字段:
    源MAC地址
    源IP地址
    目标MAC地址(请求方的MAC地址)
    目标IP地址(请求方的IP地址)
    这个ARP应答报文会单播发送给请求方,以便请求方可以更新自己的ARP缓存表,将目标IP和MAC地址映射存储起来。

ARP报文字段

ARP头部字段1.Dest MAC:目的MAC地址
2.Src MAC:源MAC地址
3.帧类型:0x0806
4.硬件类型:1(以太网)
5.协议类型:0x0800(IP地址)
6.硬件地址长度:6
7.协议地址长度:4
8.OP:1(ARP请求),2(ARP应答),3(RARP请求),4(RARP应答)

ARP请求抓包对应字段

ARP请求对应字段

ARP应答抓包对应字段

ARP应答对应字段

以太网头部

struct ether_header 所在位置:#include <net/ethernet.h> (首选)
struct ether_header
struct ethhdr; 所在位置:#include<linux/if_ether.h>
struct ethhdr

ARP头部

struct arphdr ; 所在位置 /usr/include/net/if_arp.h #include <net/if_arp.h>

struct arphdr

编码案例:组包获取ip对应mac

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netpacket/packet.h>
#include <unistd.h>
#include <sys/ioctl.h>

//#define TARGET_IP "192.168.xxx.xxx"

void get_mac_address(const char *target_ip) {
    // 创建原生套接字以发送和接收以太网帧
    int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (sock == -1) {
        perror("socket");
        return;
    }

    // 设置发送套接字地址结构
    struct sockaddr_ll socket_address;
    struct ifreq ifr;

    memset(&socket_address, 0, sizeof(struct sockaddr_ll));
    socket_address.sll_family = PF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);

    // 设置要使用的网络接口名
    strncpy(ifr.ifr_name, "ens33", IFNAMSIZ);
    if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
        perror("ioctl");
        close(sock);
        exit(2);
    }
    socket_address.sll_ifindex = ifr.ifr_ifindex;

    // 构建以太网帧头部
    struct ether_header eth_hdr;
    struct ether_arp arp_hdr;
    unsigned char broadcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    unsigned char my_mac[6] =YOURMAC;
    const char *my_ip = "xxx";

    memcpy(eth_hdr.ether_dhost, broadcast_mac, 6);
    memcpy(eth_hdr.ether_shost, my_mac, 6);
    eth_hdr.ether_type = htons(ETH_P_ARP);

    // 构建ARP请求包
    arp_hdr.arp_hrd = htons(ARPHRD_ETHER);
    arp_hdr.arp_pro = htons(ETH_P_IP);
    arp_hdr.arp_hln = 6;
    arp_hdr.arp_pln = 4;
    arp_hdr.arp_op = htons(ARPOP_REQUEST);

    memcpy(arp_hdr.arp_sha, my_mac, 6);
    inet_pton(AF_INET, my_ip, arp_hdr.arp_spa);
    memset(arp_hdr.arp_tha, 0, 6);
    inet_pton(AF_INET, target_ip, arp_hdr.arp_tpa);

    // 构建完整的以太网帧
    unsigned char buffer[sizeof(struct ether_header) + sizeof(struct ether_arp)];
    memcpy(buffer, &eth_hdr, sizeof(struct ether_header));
    memcpy(buffer + sizeof(struct ether_header), &arp_hdr, sizeof(struct ether_arp));

    // 发送ARP请求
    if (sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll)) == -1) {
        perror("sendto");
        close(sock);
        exit(3);
    }

    // 接收并解析ARP响应
    unsigned char response_buffer[1024];
    ssize_t response_len = recv(sock, response_buffer, sizeof(response_buffer), 0);
    if (response_len < 0) {
        perror("recv");
        close(sock);
        exit(4);
    }

    // 解析收到的以太网帧
    if (response_len >= sizeof(struct ether_header) + sizeof(struct ether_arp)) {
        struct ether_header *received_eth_hdr = (struct ether_header *)response_buffer;
        if (ntohs(received_eth_hdr->ether_type) == ETH_P_ARP) {
            struct ether_arp *received_arp_hdr = (struct ether_arp *)(response_buffer + sizeof(struct ether_header));
            if (ntohs(received_arp_hdr->arp_op) == ARPOP_REPLY) {
                // 输出目标IP的MAC地址
                printf("MAC Address of %s: %02X:%02X:%02X:%02X:%02X:%02X\n",
                       target_ip,
                       received_arp_hdr->arp_sha[0],
                       received_arp_hdr->arp_sha[1],
                       received_arp_hdr->arp_sha[2],
                       received_arp_hdr->arp_sha[3],
                       received_arp_hdr->arp_sha[4],
                       received_arp_hdr->arp_sha[5]);
            }
        }
    }

    // 关闭套接字
    close(sock);
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <target_ip>\n", argv[0]);
        return 1;
    }

    const char *target_ip = argv[1];
    get_mac_address(target_ip);

    return 0;
}
运行结果

运行结果

总结

当涉及ARP(地址解析协议)时,它是IPv4网络中的关键协议,用于将IP地址映射到物理MAC地址。ARP协议帮助设备在局域网内找到其他设备的物理地址,从而确保网络数据包能够正确传递到目标设备。

ARP报文的传输过程包括两个关键步骤:ARP请求和ARP应答。当设备需要将数据包发送到目标IP地址时,它会首先检查本地ARP缓存表,以查找目标IP对应的MAC地址。如果没有找到,设备会广播发送ARP请求,其中包含源MAC和IP地址以及目标IP地址。目标设备接收到请求后,如果它的IP地址匹配目标IP,它会发送ARP应答,其中包含自己的MAC和IP地址,以便请求方可以更新ARP缓存表。

ARP报文包含多个字段,如目标MAC地址、源MAC地址、硬件类型、协议类型、操作码等。这些字段在报文中起到关键作用,确保正确地执行地址解析过程。

为了进一步理解ARP,本文提供了一个使用C语言编写的ARP请求示例代码。该代码展示了构建ARP请求报文的过程,以及如何解析收到的ARP应答报文,从而获取目标IP的MAC地址。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值