github.com/songzhibin97/gkit@v1.2.13/net/arp/arp.go (about) 1 package arp 2 3 import ( 4 "errors" 5 "net" 6 "time" 7 8 "github.com/google/gopacket" 9 "github.com/google/gopacket/layers" 10 "github.com/google/gopacket/pcap" 11 "github.com/google/gopacket/routing" 12 ) 13 14 type ExtraInfo struct { 15 IFace *net.Interface 16 DstHWAddr net.HardwareAddr 17 SrcIP net.IP 18 } 19 20 func GetRouterInfo(dstIp net.IP) (*ExtraInfo, error) { 21 router, err := routing.New() 22 if err != nil { 23 return nil, err 24 } 25 26 extraInfo := &ExtraInfo{} 27 iFace, gateway, preferredSrc, err := router.Route(dstIp) 28 if err != nil { 29 return nil, err 30 } 31 extraInfo.IFace = iFace 32 extraInfo.SrcIP = preferredSrc 33 handle, err := pcap.OpenLive(iFace.Name, 1024, true, pcap.BlockForever) 34 if err != nil { 35 return nil, err 36 } 37 defer handle.Close() 38 dstHWAddr, err := getHWAddr(dstIp, gateway, preferredSrc, iFace, handle) 39 if err != nil { 40 return nil, err 41 } 42 extraInfo.DstHWAddr = dstHWAddr 43 return extraInfo, nil 44 } 45 46 func getHWAddr(ip, gateway, srcIP net.IP, networkInterface *net.Interface, handle *pcap.Handle) (net.HardwareAddr, error) { 47 arpDst := ip 48 if gateway != nil { 49 arpDst = gateway 50 } 51 52 eth := layers.Ethernet{ 53 SrcMAC: networkInterface.HardwareAddr, 54 DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 55 EthernetType: layers.EthernetTypeARP, 56 } 57 58 arp := layers.ARP{ 59 AddrType: layers.LinkTypeEthernet, 60 Protocol: layers.EthernetTypeIPv4, 61 HwAddressSize: uint8(6), 62 ProtAddressSize: uint8(4), 63 Operation: layers.ARPRequest, 64 SourceHwAddress: []byte(networkInterface.HardwareAddr), 65 SourceProtAddress: srcIP, 66 DstHwAddress: net.HardwareAddr{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 67 DstProtAddress: arpDst, 68 } 69 70 opt := gopacket.SerializeOptions{ 71 FixLengths: true, 72 ComputeChecksums: true, 73 } 74 75 buf := gopacket.NewSerializeBuffer() 76 77 if err := gopacket.SerializeLayers(buf, opt, ð, &arp); err != nil { 78 return nil, err 79 } 80 if err := handle.WritePacketData(buf.Bytes()); err != nil { 81 return nil, err 82 } 83 84 start := time.Now() 85 for { 86 if time.Since(start) > time.Millisecond*time.Duration(1000) { 87 return nil, errors.New("timeout getting ARP reply") 88 } 89 data, _, err := handle.ReadPacketData() 90 if errors.Is(err, pcap.NextErrorTimeoutExpired) { 91 continue 92 } else if err != nil { 93 return nil, err 94 } 95 packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy) 96 if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil { 97 arp := arpLayer.(*layers.ARP) 98 if net.IP(arp.SourceProtAddress).Equal(arpDst) { 99 return net.HardwareAddr(arp.SourceHwAddress), nil 100 } 101 } 102 } 103 }