使用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, ð, &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
}
}
}
<- 仅供参考->