mirror of
https://github.com/impact-eintr/netstack.git
synced 2025-10-05 21:06:50 +08:00
100 lines
3.5 KiB
Go
100 lines
3.5 KiB
Go
package header
|
||
|
||
import "netstack/tcpip"
|
||
|
||
const (
|
||
// ARPProtocolNumber是ARP协议号,为0x0806
|
||
ARPProtocolNumber tcpip.NetworkProtocolNumber = 0x0806
|
||
|
||
// ARPSize是ARP报文在IPV4网络下的长度
|
||
ARPSize = 2 + 2 + 1 + 1 + 2 + 2*6 + 2*4 // 28 Bytes
|
||
)
|
||
|
||
// ARPOP 代表ARP的操作码
|
||
type ARPOp uint16
|
||
|
||
// RFC 826 定义的操作码
|
||
const (
|
||
// arp 请求
|
||
ARPRequest ARPOp = 1
|
||
// arp应答
|
||
ARPReply ARPOp = 2
|
||
)
|
||
|
||
/*
|
||
ARP报文的封装
|
||
1. 2B 硬件类型(hard type) 硬件类型用来指代需要什么样的物理地址,如果硬件类型为 1,表示以太网地址
|
||
2. 2B 协议类型 协议类型则是需要映射的协议地址类型,如果协议类型是 0x0800,表示 ipv4 协议。
|
||
3. 1B 硬件地址长度 表示硬件地址的长度,单位字节,一般都是以太网地址的长度为 6 字节。
|
||
4. 1B 协议地址长度: 表示协议地址的长度,单位字节,一般都是 ipv4 地址的长度为 4 字节。
|
||
5. 2B 操作码 这些值用于区分具体操作类型,因为字段都相同,所以必须指明操作码,不然连请求还是应答都分不清。
|
||
1=>ARP 请求, 2=>ARP 应答,3=>RARP 请求,4=>RARP 应答。
|
||
6. 6B 源硬件地址 源物理地址,如02:f2:02:f2:02:f2
|
||
7. 4B 源协议地址 源协议地址,如192.168.0.1
|
||
8. 6B 目标硬件地址 目标物理地址,如03:f2:03:f2:03:f2
|
||
9. 4B 目标协议地址 目标协议地址,如 192.168.0.2
|
||
*/
|
||
type ARP []byte
|
||
|
||
// 从报文中得到硬件类型
|
||
func (a ARP) hardwareAddressSpace() uint16 { return uint16(a[0])<<8 | uint16(a[1]) }
|
||
|
||
// 从报文中得到协议类型
|
||
func (a ARP) protocolAddressSpace() uint16 { return uint16(a[2])<<8 | uint16(a[3]) }
|
||
|
||
// 从报文中得到硬件地址的长度
|
||
func (a ARP) hardwareAddressSize() int { return int(a[4]) }
|
||
|
||
// 从报文中得到协议的地址长度
|
||
func (a ARP) protocolAddressSize() int { return int(a[5]) }
|
||
|
||
// Op从报文中得到arp操作码.
|
||
func (a ARP) Op() ARPOp { return ARPOp(a[6])<<8 | ARPOp(a[7]) }
|
||
|
||
// SetOp设置arp操作码.
|
||
func (a ARP) SetOp(op ARPOp) {
|
||
a[6] = uint8(op >> 8)
|
||
a[7] = uint8(op)
|
||
}
|
||
|
||
// SetIPv4OverEthernet设置IPV4网络在以太网中arp报文的硬件和协议信息.
|
||
func (a ARP) SetIPv4OverEthernet() {
|
||
a[0], a[1] = 0, 1 // htypeEthernet
|
||
a[2], a[3] = 0x08, 0x00 // IPv4ProtocolNumber
|
||
a[4] = 6 // macSize
|
||
a[5] = uint8(IPv4AddressSize)
|
||
}
|
||
|
||
// ProtocolAddressSender从报文中得到arp发送方的协议地址,为ipv4地址
|
||
func (a ARP) ProtocolAddressSender() []byte {
|
||
const s = 8 + 6 // 8 是arp的协议头部 6是本机MAC
|
||
return a[s : s+4] // 本机IP
|
||
}
|
||
|
||
// HardwareAddressTarget从报文中得到arp目的方的硬件地址
|
||
func (a ARP) HardwareAddressTarget() []byte {
|
||
const s = 8 + 6 + 4 // 8是arp协议头部 6 是本机MAC 4是本机ip
|
||
return a[s : s+6] // 目标MAC
|
||
}
|
||
|
||
// ProtocolAddressTarget从报文中得到arp目的方的协议地址,为ipv4地址
|
||
func (a ARP) ProtocolAddressTarget() []byte {
|
||
const s = 8 + 6 + 4 + 6 // 8是arp协议头部 6 是本机MAC 4是本机ip 6是目标MAC
|
||
return a[s : s+4] // 目标IP
|
||
}
|
||
|
||
// IsValid检查arp报文是否有效
|
||
func (a ARP) IsValid() bool {
|
||
// 比arp报文的长度小,返回无效
|
||
if len(a) < ARPSize {
|
||
return false
|
||
}
|
||
const htypeEthernet = 1
|
||
const macSize = 6
|
||
// 是否以太网、ipv4、硬件和协议长度都对
|
||
return a.hardwareAddressSpace() == htypeEthernet &&
|
||
a.protocolAddressSpace() == uint16(IPv4ProtocolNumber) &&
|
||
a.hardwareAddressSize() == macSize &&
|
||
a.protocolAddressSize() == IPv4AddressSize
|
||
}
|