go的实现arp客户端

发布于:2025-08-29 ⋅ 阅读:(17) ⋅ 点赞:(0)

使用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
		}
	}
}

<- 仅供参考->


网站公告

今日签到

点亮在社区的每一天
去签到