以下是一个使用gopacket包编写的示例程序,实现了局域网内广播发送icmp报文并监听应答报文,并根据源mac地址与指定的mac地址比对来输出源ip的功能。
”`go package main
import (
"fmt"
"log"
"net"
"os"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
var (
iface string = "eth0" // 网络接口名字
targetMac string = "00:11:22:33:44:55" // 指定的目标mac地址
broadcast net.HardwareAddr
handle *pcap.Handle
stopSignal chan bool = make(chan bool)
)
func main() {
var err error
// 获取网络接口信息
iface, err := net.InterfaceByName(iface)
if err != nil {
log.Fatal(err)
}
// 获取网络接口的广播地址
broadcastIP := getBroadcastIP(iface)
broadcast, err = net.ParseMAC("ff:ff:ff:ff:ff:ff")
if err != nil {
log.Fatal(err)
}
fmt.Printf("广播地址:%s\n", broadcastIP)
go sendICMP(broadcastIP) // 启动发送ICMP报文的协程
go listenICMP() // 启动监听ICMP应答报文的协程
time.Sleep(10 * time.Second) // 等待10秒钟,让程序运行一段时间后结束
stopSignal <- true // 发送停止信号给协程,使其退出
}
// 获取网络接口的广播地址 func getBroadcastIP(iface *net.Interface) net.IP {
addrs, err := iface.Addrs()
if err != nil {
log.Fatal(err)
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok || ipNet.IP.IsLoopback() {
continue
}
if ipNet.IP.To4() != nil {
return ipNet.IP.Mask(ipNet.IP.DefaultMask()).To4()
}
}
return nil
}
// 发送ICMP报文的协程 func sendICMP(broadcastIP net.IP) {
var eth layers.Ethernet
var icmp layers.ICMPv4
buffer := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}
fmt.Println("开始发送ICMP报文...")
ticker := time.NewTicker(2 * time.Second)
for i := 0; i < 5; i++ {
select {
case <-ticker.C:
srcMacAddr, _ := net.ParseMAC(iface.HardwareAddr.String())
err := pcapgo.MacAddrFromString(targetMac, ð.SrcMAC)
if err != nil {
log.Fatal(err)
}
copy(eth.DstMAC[:], broadcast[:])
copy(icmp.Payload[:], []byte("Hello, ICMP!"))
gopacket.SerializeLayers(buffer, opts, ð, &icmp)
err = handle.WritePacketData(buffer.Bytes())
if err != nil {
log.Fatal(err)
}
fmt.Printf("第 %d 次发送 ICMP 报文\n", i+1)
case <-stopSignal:
fmt.Println("停止发送ICMP报文")
return
}
}
ticker.Stop()
}
// 监听ICMP应答报文的协程 func listenICMP() {
var eth layers.Ethernet
var icmp layers.ICMPv4
fmt.Println("开始监听ICMP应答报文...")
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
if packet.Layer(ð) != nil && packet.Layer(&icmp) != nil {
srcMacAddr, _ := net.ParseMAC(iface.HardwareAddr.String())
if eth.SrcMAC.String() == targetMac && eth.DstMAC.String() == srcMacAddr.String() {
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
ip, _ := ipLayer.(*layers.IPv4)
fmt.Printf("源IP地址:%s\n", ip.SrcIP)
handle.Close()
os.Exit(0) // 结束程序
}
}
}
}
fmt.Println("停止监听ICMP应答报文")
}
func init() {
var err error
handle, err = pcap.OpenLive(iface, 65536, true, pcap.BlockForever)
if err != nil {
log.Fatal(err)
}
err = handle.SetBPFFilter("icmp") // 设置过滤器,只捕获 ICMP 协议的包
if err != nil {
log.Fatal(err)
}
log.Printf("使用接口<br/><br/><br/><font size=1 color=#CCCCCC>内容由零声教学AI助手提供,问题来源于学员提问</font>