来源:http://blog.chinaunix.net/u/8780/showart.php?id=147506
一. 关于 ARP 协议的基础知识
1 . ARP 的工作原理
以太网设备比如网卡都有全球唯一的 MAC 地址,MAC地址是网卡的物理地址,它由48位二进制数表示。其中前面24位表示网络厂商标识符,是由生产网卡的厂商向IEEE申请的厂商地址。后24位表示序号,由厂商自行分配。每个不同的网络厂商会有不同的厂商标识符,而每个厂商所生产出来的网卡都是依序号不断变化的。 网卡等是以 MAC 地址来传输以太网数据包的(它们识别不了 IP 包中的 IP 地址),所以在以太网中进行 IP 通信的时候就需要一个协议来建立 IP 地址与 MAC 地址的对应关系,以使 IP 数据包能发到一个确定的地方去。这就是 ARP(Address Resolution Protocol ,地址解析协议 ) 。
arp命令 可以查询本地arp缓存:
arp –a
可以发现类似于这样的条目
192.168.45.100 01-23-45-67-89-ab dynamic
这就是存储的关于IP 地址与MAC 地址的对应关系,dynamic 表示是临时存储在ARP 缓存中的条目,过一段时间就会超时被删除(xp/2003 系统是2 分钟) 。
这样一来,某台电脑要和一台机器(比如192.168..45.1) 通信的时候,它会首先去检查arp 缓存,查找是否有对应的arp 条目,如果没有,它就会给这个以太网络发ARP 请求包 广播询问192.168.45.1 的对应MAC 地址,当然,网络中每台电脑都会收到这个请求包,但是它们发现192.168.45.1 并非自己,就不会做出相应,而192.168.45.1 就会回复一个ARP 应答包 ,告诉它的MAC 地址是xx-xx-xx-xx-xx-xx, 于是发出ARP请求的计算机中的ARP 缓存就会相应刷新, 多了这么一条:
192.168.45.1 xx-xx-xx-xx-xx-xx dynamic
ARP 缓存是为了避免每发一个IP 包都要发个广播查询地址。
网络设备是无法识别ARP 包的真伪的,如果按照ARP 的格式来发送数据包,只要信息有效计算机就会根据包中的内容做相应的反应.
2 .ARP 包的格式
从网络底层看来,一个ARP 包是分为两个部分的, 前面一个是物理帧头 ,后面一个才是 ARP 帧 。
首先,物理帧头,它将存在于任何一个协议数据包的前面,被称为 DLC Header ,因为这个帧头是在数据链路层构造的,并且其主要内容为收发双方的物理地址,以便硬件设备识别。
DLC Header | |||
字段 | 长度(Byte) | 默认值 | 备注 |
接收方MAC | 6 |
| 广播时, 为 ff-ff-ff-ff-ff-ff |
发送方MAC | 6 |
|
|
Ethertype | 2 | 0x0806 | 0x0806 是ARP 帧的类型值 |
图1 物理帧头格式
ARP 帧的格式.
ARP Frame | |||
字段 | 长度(Byte) | 默认值 | 备注 |
硬件类型 | 2 | 0x1 | 以太网类型值 |
上层协议类型 | 2 | 0x0800 | 上层协议为IP 协议 |
MAC 地址长度 | 1 | 0x6 | 以太网MAC 地址长度为 6 |
IP 地址长度 | 1 | 0x4 | IP 地址长度为 4 |
操作码 | 2 |
| 0x1 表示ARP 请求包,0x2 表示应答包 |
发送方MAC | 6 |
|
|
发送方IP | 4 |
|
|
接收方MAC | 6 |
|
|
接收方IP | 4 |
|
|
填充数据 | 18 |
| 因为物理帧最小长度为64 字节, 前面的42 字节再加上4 个CRC 校验字节, 还差18 个字节 |
图2 ARP 帧格式
DLC Header
| ||
字段
|
长度(Byte)
|
填充值
|
接收方MAC
|
6
|
ffffffffffff
|
发送方MAC
|
6
|
aaaaaaaaaaaa
|
Ethertype
|
2
|
0x0806
|
ARP Frame
| ||
字段
|
长度(Byte)
|
填充值
|
硬件类型
|
2
|
1
|
上层协议类型
|
2
|
0800
|
MAC地址长度
|
1
|
6
|
IP地址长度
|
1
|
4
|
操作码
|
2
|
1
|
发送方MAC
|
6
|
aaaaaaaaaaaa
|
发送方IP
|
4
|
192.168.0.1
|
接收方MAC
|
6
|
任意值 xxxxxxxxxxxx
|
接收方IP
|
4
|
192.168.0.99
|
填充数据
|
18
|
0
|
DLC Header
| ||
字段
|
长度(Byte)
|
填充值
|
接收方MAC
|
6
|
bbbbbbbbbbbb
|
发送方MAC
|
6
|
aaaaaaaaaaaa
|
Ethertype
|
2
|
0x0806
|
ARP Frame
| ||
字段
|
长度(Byte)
|
填充值
|
硬件类型
|
2
|
1
|
上层协议类型
|
2
|
0800
|
MAC地址长度
|
1
|
6
|
IP地址长度
|
1
|
4
|
操作码
|
2
|
2
|
发送方MAC
|
6
|
aaaaaaaaaaaa
|
发送方IP
|
4
|
192.168.0.1
|
接收方MAC
|
6
|
bbbbbbbbbbbb
|
接收方IP
|
4
|
192.168.0.99
|
填充数据
|
18
|
0
|
1. 填充数据包
相应的数据结构:
// DLC Header
typedef struct tagDLCHeader {
unsigned char DesMAC[6]; /* destination HW addrress */
unsigned char SrcMAC[6]; /* source HW addresss */
unsigned short Ethertype; /* ethernet type */
} DLCHEADER, *PDLCHEADER;
// ARP Frame
typedef struct tagARPFrame {
unsigned short HW_Type; /* hardware address */
unsigned short Prot_Type; /* protocol address */
unsigned char HW_Addr_Len; /* length of hardware address */
unsigned char Prot_Addr_Len; /* length of protocol address */
unsigned short Opcode; /* ARP/RARP */
unsigned char Send_HW_Addr[6]; /* sender hardware address */
unsigned long Send_Prot_Addr; /* sender protocol address */
unsigned char Targ_HW_Addr[6]; /* target hardware address */
unsigned long Targ_Prot_Addr; /* target protocol address */
unsigned char padding[18];
} ARPFRAME, *PARPFRAME;
// ARP Packet = DLC header + ARP Frame
typedef struct tagARPPacket {
DLCHEADER dlcHeader;
ARPFRAME arpFrame;
} ARPPACKET, *PARPPACKET;
在没有安全防护的网络里......
1) 如果 发一个请求包广播,其中的 ARP 帧里相关的信息填成这样:
发送方MAC | 6 | 随便乱填一个错误的 |
发送方IP | 4 | 填上本机的IP |
本机将会显示一个 IP 地址冲突的提示。同样的道理,如果发送方 IP 填成别人的,然后,每隔x 秒发一次 ………
2) 假设A、B都靠一个网关 192.168.0.1 上网 ,如果A想让B( 192.168.0.77) 上不了网,就可以伪装成网关给 192.168.0.77 发一个错误的 ARP 响应包 ,如:
发送方MAC | 6 | 随便乱填一个错误的 |
发送方IP | 4 | 网关IP 192.168.0.1 |
接收方就填 192.168.0.77 的相关信息,........