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, &eth, &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  }