ZBLOG

go语言发送子网广播的arp请求报文,需要指定目标主机地址, 可选择指定目标vlan和网络出接口,以以上参数构造发送arp请求报文,之后如果接收到arp应答报文,则对比应答报文的源ip是否是指定的目标主机地址,是的话输出成功,否则输出失败,等待 5s没有接收到回包则返回失败

下面是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>

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=1588

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?