1、首先以太网封装格式:
以太网头部(用的是系统自带的 #include <net/ethernet.h>):
struct ether_header
{
u_int8_t ether_dhost[ETH_ALEN]; // 目的MAC地址
u_int8_t ether_shost[ETH_ALEN]; // 源MAC地址
u_int16_t ether_type; // 以太网帧类型 //ARP包协议类型是0x0806,宏ETHERTYPE_ARP
} __attribute__ ((__packed__));
目的地址:目的MAC地址。
源地址:源MAC地址。
类型:0x0800 :IP数据包
0x0806 :ARP请求应答
0x8035 :RARP请求应答
CRC:用于对帧内部数据进行校验,保证数据传输的正确性,通常由硬件实现,例如在网卡设备中实现网络数据的CRC校验。一般在组包时可以忽略。
2、ARP包PING原理
A只知道B的IP地址192.168.100.28,所以A发送ARP请求包,在局域网内广播,问everybody谁的ip是192.168.100.28。这个时候局域网里所有的活动主机收到包后,会分析目的IP是否是本机,不是则丢弃。故此时只会有B机器响应。B将自己的MAC地址填充进去,然后交换交换两个目的地址和两个发送端地址,以构建ARP应答并返回。A收到响应包判断B机器存活。
故我们要做的就是构造ARP请求包(广播),解析ARP响应包。
3、构建ARP请求包(发包sendto)
ARP包封装格式
以太网首部在第一部分已经介绍过
硬件类型字段:1 表示硬件地址的类型。
协议类型字段:0x800,表示要映射的协议地址类型,它的值为0x800,表示IP地址。
硬件地址长度:0x06(对MAC地址来说),对应硬件地址的长度
协议地址长度:0x04(对IP地址来说),对应协议地址。
操作(op):ARP请求(值为1),ARP应答(值为2),RARP请求(值为3),RARP应答(值为4)。
最后四个字段指定通信双方的以太网地址和IP地址。
注意:ARP请求/应答报文的长度为28字节。
一个完整的携带ARP请求/应答报文的以太帧长度为46字节,但是有的实现要求以太帧数据部分长度至少46字节,这样ARP会增加一些填充字节,这样一个携带ARP请求/应答报文的以太帧长度变为64字节。(6B目的MAC、6B源MAC、2B类型、46字节内容,4BCRC校验)
ARP结构体定义:
struct arphdr
在头文件<net/if_arp.h>中,对ARP首部进行了封装:
struct ether_arp {
struct arphdr ea_hdr; /* fixed-size 8 bytes header */
u_int8_t arp_sha[ETH_ALEN]; /* sender hardware address */
u_int8_t arp_spa[4]; /* sender protocol address */
u_int8_t arp_tha[ETH_ALEN]; /* target hardware address */
u_int8_t arp_tpa[4]; /* target protocol address */
};
#define arp_