ZBLOG

gopacket包编写一个程序,程序中一个协程 局域网内广播发送icmp报文,两秒一次共发送五次;一个协程监听icmp应答报文,将应答报文中的源mac地址与指定的mac地址比对,如果相同则输出报文中的源ip并结束程序

以下是一个使用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, &eth.SrcMAC)
		if err != nil {
			log.Fatal(err)
		}

		copy(eth.DstMAC[:], broadcast[:])
		copy(icmp.Payload[:], []byte("Hello, ICMP!"))

		gopacket.SerializeLayers(buffer, opts, &eth, &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(&eth) != 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>

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

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

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

联系我们

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

微信号:3007537140

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

关注我们
x

注册

已经有帐号?