go的实现arp客户端

使用go实现arp客户端

net包是Go语言标准库中与网络编程有关的包,它提供了一套用于创建各种类型的网络连接的函数和接口,提供了TCP、UDP、Unix 域套接字等传输层协议的支持。

net包的主要功能如下所示:

  • 创建和管理 TCP 和 UDP 连接;
  • 解析和格式化 IP 地址和域名;
  • 实现 DNS 查询;
  • 提供了可移植的网络 I/O 接口,包括对非阻塞模式和超时控制的支持;

1、使用 net.ParseIP() 方法将字符串形式的 IP 地址解析成 net.IP 类型的变量。

类型net.IP定义表示了一个 IPv4 或 IPv6 地址,它是一个字节数组类型[]byte 的别名。

2 、使用net.Interfaces()方法获取网络接口信息

这个方法会返回一个[]net.Interface切片,其中包含了主机上所有网络接口的信息。

3、使用pcap.OpenLive() 打开指定的网络设备进行实时捕获数据包

复制代码
func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error)
  • device:网络设备的名称,如eth0; 也可以使用通过pcap.FindAllDevs()获得的设备的名称;

  • snaplen: 每个数据包读取的最大长度 65535;

  • promisc:是否将网口设置为混杂模式,即是否接收目的地址不为本机的包,true;

  • timeout:设置抓到包返回的超时。如果设置成30s,那么每30s才会刷新一次数据包;设置成负数,会立刻刷新数据包,即不做等待;

  • handler :是一个*Handle类型的返回值,可以作为gopacket其他函数调用时作为函数参数来传递。

    package main

    import (
    "fmt"
    "net"
    "os"
    "time"

    复制代码
      "github.com/google/gopacket"
      "github.com/google/gopacket/layers"
      "github.com/google/gopacket/pcap"

    )

    func main() {
    if len(os.Args) != 3 {
    fmt.Println("Usage: ./arp_client <interface> <target_ip>")
    return
    }

    复制代码
      ifaceName := os.Args[1]
      targetIP := net.ParseIP(os.Args[2])
      if targetIP == nil {
      	fmt.Println("Invalid target IP address")
      	return
      }
    
      // 获取接口信息
      iface, err := net.InterfaceByName(ifaceName)
      if err != nil {
      	fmt.Printf("Failed to get interface %s: %v\n", ifaceName, err)
      	return
      }
    
      // 打开pcap句柄
      handle, err := pcap.OpenLive(ifaceName, 65536, true, pcap.BlockForever)
      if err != nil {
      	fmt.Printf("Failed to open pcap handle: %v\n", err)
      	return
      }
      defer handle.Close()
    
      // 构造第二层(Layer 2)的数据结构
      eth := layers.Ethernet{
      	SrcMAC:       iface.HardwareAddr,
      	DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
      	EthernetType: layers.EthernetTypeARP,
      }

    // 构造ARP(第三层 layer 3)请求数据结构
    arp := layers.ARP{
    AddrType: layers.LinkTypeEthernet,
    Protocol: layers.EthernetTypeIPv4,
    HwAddressSize: 6,
    ProtAddressSize: 4,
    Operation: layers.ARPRequest,
    SourceHwAddress: []byte(iface.HardwareAddr),
    SourceProtAddress: []byte{0, 0, 0, 0}, // 通常设为0.0.0.0
    DstHwAddress: []byte{0, 0, 0, 0, 0, 0},
    DstProtAddress: []byte(targetIP.To4()),
    }

    复制代码
      buf := gopacket.NewSerializeBuffer()
      opts := gopacket.SerializeOptions{
      	FixLengths:       true,
      	ComputeChecksums: true,
      }
    
      // 序列化数据包
      err = gopacket.SerializeLayers(buf, opts, &eth, &arp)
      if err != nil {
      	fmt.Printf("Failed to serialize packet: %v\n", err)
      	return
      }
    
      // 发送ARP请求
      err = handle.WritePacketData(buf.Bytes())
      if err != nil {
      	fmt.Printf("Failed to send packet: %v\n", err)
      	return
      }
    
      fmt.Printf("ARP request sent to %s via %s\n", targetIP, ifaceName)
    
      // 设置超时并监听响应
      start := time.Now()
      timeout := 5 * time.Second
      packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    
      for {
      	if time.Since(start) > timeout {
      		fmt.Println("Timeout waiting for ARP response")
      		return
      	}
    
      	packet, err := packetSource.NextPacket()
      	if err != nil {
      		continue
      	}
    
      	arpLayer := packet.Layer(layers.LayerTypeARP)
      	if arpLayer == nil {
      		continue
      	}
    
      	arpResponse, _ := arpLayer.(*layers.ARP)
      	if arpResponse.Operation == layers.ARPReply &&
      		net.IP(arpResponse.SourceProtAddress).Equal(targetIP) {
      		fmt.Printf("ARP response received: %s is at %s\n",
      			targetIP, net.HardwareAddr(arpResponse.SourceHwAddress))
      		return
      	}
      }

    }

<- 仅供参考->