下面是 Go 语言发送子网广播的 ARP 请求报文并接收应答报文的示例代码:
”`go package main
import (
"fmt"
"net"
)
func main() {
// 构造目标 IP 地址和子网掩码
targetIP := net.IPv4(192, 168, 1, 255)
mask := net.IPMask(net.IPv4Mask(255, 255, 255, 0))
// 获取本机 IP 和 MAC 地址
localIP := getLocalIP(mask)
localMAC := getLocalMAC()
// 创建 ARP 请求包,并填充各字段值
arpPacket := &arpPacket{
hardwareType: []byte{0x00, 0x01}, // Ethernet
protocolType: []byte{0x08, 0x00}, // IPv4
hardwareSize: []byte{0x06},
protocolSize: []byte{0x04},
opCode: []byte{0x00, 0x01}, // ARP Request
senderHardware: localMAC,
senderProtocol: localIP.To4(),
targetHardware: make([]byte, 6),
targetProtocol: targetIP.To4(),
}
// 发送 ARP 请求报文到子网广播地址
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", targetIP.String(), arpPort))
if err != nil {
panic(err)
}
defer conn.Close()
_, err = conn.Write(arpPacket.Marshal())
if err != nil {
panic(err)
}
// 接收 ARP 应答报文,并解析各字段值
buffer := make([]byte, 1024)
conn.SetReadDeadline(time.Now().Add(arpTimeout))
n, _, err := conn.ReadFrom(buffer)
if err != nil {
panic(err)
}
arpReplyPacket, err := parseARPPacket(buffer[:n])
if err != nil {
panic(err)
}
// 对比应答报文的源 IP 是否是指定的目标主机地址
if arpReplyPacket.senderProtocol.String() == targetIP.String() {
fmt.Println("ARP request succeeded!")
} else {
fmt.Println("ARP request failed!")
}
}
type arpPacket struct {
hardwareType []byte // 硬件类型,例如 Ethernet
protocolType []byte // 协议类型,例如 IPv4
hardwareSize []byte // 硬件地址长度
protocolSize []byte // 协议地址长度
opCode []byte // 操作码,例如 ARP Request 或 ARP Reply
senderHardware []byte // 发送方硬件地址,即本机 MAC 地址
senderProtocol net.IP // 发送方协议地址,即本机 IP 地址
targetHardware []byte // 目标硬件地址,通常为广播地址或某个 MAC 地址(仅在 ARP Reply 中使用)
targetProtocol net.IP // 目标协议地址,即欲查询的 IP 地址(仅在 ARP Request 中使用)
}
func (p *arpPacket) Marshal() []byte {
packetLen := 28 + len(p.hardwareSize) + len(p.protocolSize) + len(p.senderHardware) + len(p.senderProtocol) + len(p.targetHardware) + len(p.targetProtocol)
buffer := make([]byte, packetLen)
// 填充硬件类型和协议类型
copy(buffer[0:2], p.hardwareType)
copy(buffer[2:4], p.protocolType)
// 填充硬件地址长度和协议地址长度
copy(buffer[4:5], p.hardwareSize)
copy(buffer[5:6], p.protocolSize)
// 填充操作码、发送方 MAC 地址和 IP 地址、目标 MAC 地址和 IP 地址
copy(buffer[6:8], p.opCode)
offset := 8
copy(buffer[offset:], p.senderHardware)
offset += len(p.senderHardware)
copy(buffer[offset:], p.senderProtocol.To4())
offset += len(p.senderProtocol.To4())
copy(buffer[offset:], p.targetHardware)
offset += len(p.targetHardware)
copy(buffer[offset:], p.targetProtocol.To4())
return buffer
}
func parseARPPacket(data []byte) (*arpPacket, error) {
if len(data) < 28 {
return nil, fmt.Errorf("invalid ARP packet")
}
packet := &arpPacket{
hardwareType: data[0:2],
protocolType: data[2:4],
hardwareSize: data[4:5],
protocolSize: data[5:6],
opCode: data[6:8],
senderHardware: data[8:14],
senderProtocol: net.IPv4(data[14], data[15], data[16], data[17]),
targetHardware: data[18:24],
targetProtocol: net.IPv4(data[24], data[25], data[26], data[27]),
}
return packet, nil
}
func getLocalIP(mask net.IPMask) net.IP {
addrs, err := net.InterfaceAddrs()
if err != nil {
panic(err)
}
for _, addr := range addrs {
ipnet, ok := addr.(*net.IPNet)
if ok && !ipnet.IP.IsLoopback() && mask.Contains(ipnet.IP) {
return ipnet.IP.Mask(mask)
}
}
panic("no local IP address found")
}
func getLocalMAC() []byte {
ifas, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, ifa := range ifas {
if ifa.Flags&net.FlagUp == 0 || ifa.Flags&net.FlagLoopback != 0 {
continue
}
hwaddr := ifa.HardwareAddr
if len(hwaddr) == 6 && hwaddr[0] != 0x00 && hwaddr[0] != 0xFF<br/><br/><br/><font size=1 color=#CCCCCC>内容由零声教学AI助手提供,问题来源于学员提问</font>