下面是go语言发送子网广播的arp请求报文并等待应答的示例代码,其中包括指定目标主机地址、目标vlan和网络出接口,以及等待超时时间:
”`go package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"time"
)
const (
EthHdrLen = 14
ArpHdrLen = 28
MacAddrLen = 6
Ipv4AddrLen = 4
BroadcastMac = "ff:ff:ff:ff:ff:ff"
)
type EthHdr struct {
DstMac [MacAddrLen]byte // 目标MAC地址
SrcMac [MacAddrLen]byte // 源MAC地址
Type uint16 // 上层协议类型
}
type ArpHdr struct {
HwType uint16 // 硬件类型:1表示以太网
ProtoType uint16 // 协议类型:0x0800表示IPv4协议
HwAddrSize byte // 硬件地址长度:6字节(MAC地址)
ProtoSize byte // 协议地址长度:4字节(IPv4地址)
Opcode uint16 // 操作码:1表示ARP请求,2表示ARP响应
SndrHwAddr [MacAddrLen]byte // 发送方硬件地址(即源MAC地址)
SndrIpAddr net.IP // 发送方协议地址(即源IP地址)
TgtHwAddr [MacAddrLen]byte // 目标硬件地址(仅在响应中存在)
TgtIpAddr net.IP // 目标协议地址
}
func main() {
dstIP := net.IPv4(192, 168, 1, 2) // 指定目标主机地址
ifaceName := "eth0" // 指定网络出接口
vlanID := uint16(10) // 指定目标vlan
dstMacAddr, _ := net.ParseMAC(BroadcastMac) // 广播地址
// 获取指定接口的IP和MAC地址信息
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
fmt.Println("获取网络接口失败:", err)
return
}
srcMacAddr := iface.HardwareAddr
addrs, err := iface.Addrs()
if err != nil {
fmt.Println("获取IP地址失败:", err)
return
}
var srcIpAddr net.IP = nil
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
srcIpAddr = ipnet.IP.To4()
break
}
}
}
if srcIpAddr == nil {
fmt.Println("无法获取本地IPv4地址")
return
}
conn, err := net.ListenPacket(fmt.Sprintf("vlan%d@%s", vlanID, ifaceName), "arp") // 使用指定的VLAN ID和网络接口监听ARP报文
if err != nil {
fmt.Println("监听ARP报文失败:", err)
return
}
defer conn.Close()
buf := make([]byte, EthHdrLen+ArpHdrLen)
copy(buf[0:6], dstMacAddr)
copy(buf[6:12], srcMacAddr)
binary.BigEndian.PutUint16(buf[12:14], 0x0806) // 上层协议类型为ARP
arp := ArpHdr{
HwType: 1, // 硬件类型为以太网
ProtoType: 0x0800, // 协议类型为IPv4
HwAddrSize: MacAddrLen, // MAC地址长度为6字节
ProtoSize: Ipv4AddrLen, // IPv4地址长度为4字节
SndrHwAddr: [MacAddrLen]byte(srcMacAddr), // 发送方MAC地址为本机MAC地址
SndrIpAddr: srcIpAddr, // 发送方IP地址为本机IPv4地址
TgtIpAddr: dstIP.To4(), // 目标IP地址转换成IPv4格式,填入ARP报文中的目标协议地址字段
}
copy(arp.TgtHwAddr[:], bytes.Repeat([]byte{0xff}, MacAddrLen)) // 广播方式发送请求,目标硬件地址设为全FF
payload := new(bytes.Buffer)
binary.Write(payload, binary.BigEndian, arp)
copy(buf[EthHdrLen:], payload.Bytes())
conn.SetDeadline(time.Now().Add(5 * time.Second)) // 设置超时时间5秒
if _, err := conn.WriteTo(buf, &net.IPNet{IP: dstIP.Mask(net.IPv4Mask(255, 255, 255, 255)), Mask: net.IPv4Mask(255, 255, 255, 255)}); err != nil { // 发送ARP请求报文
fmt.Println("发送ARP请求失败:", err)
return
}
buf = make([]byte, EthHdrLen+ArpHdrLen)
n, _, err := conn.ReadFrom(buf) // 接收ARP响应报文
if err != nil {
fmt.Println("接收ARP响应超时或失败:", err)
return
}
if n < EthHdrLen+ArpHdrLen {
fmt.Println("无效的ARP响应报文长度:", n)
return
}
respMac := net.HardwareAddr(buf[6:12])
if !bytes.Equal(respMac, srcMacAddr) {
fmt.Printf("收到的ARP响应MAC地址不匹配,<br/><br/><br/><font size=1 color=#CCCCCC>内容由零声教学AI助手提供,问题来源于学员提问</font>