GoPacket
- date
- 2023-09-15 21:23:28
GoPacket 是对 libpcap 和 npcap 的 go 封装,其功能就是抓包。
在分析 ksubdomain 时遇到这个库,简单看一下用法。
像 wireshark 这种抓包软件其底层使用的就是 npcap,所以说 GoPacket 库的功能也就类似这种。
项目地址:https://github.com/google/gopacket
应用场景:
- 网络流量分析
- 伪造数据包
- 离线 pcap 文件的读取
在使用 gopacket 包时,首先要确保在 windows 平台下安装了 npcap 或 winpcap,或者是在 linux 平台下安装了 libpcap 库。
npcap:https://nmap.org/npcap
libpcap:https://www.tcpdump.org
库安装:
| go get github.com/google/gopacket
|
抓取数据包
获取网络设备
| func main() {
devs, err := pcap.FindAllDevs()
if err != nil {
return
}
for _, dev := range devs {
for _, addr := range dev.Addresses {
fmt.Println(dev.Name, "=>", addr.IP.String())
}
}
}
|
设备信息:
| // Interface describes a single network interface on a machine.
type Interface struct {
Name string
Description string
Flags uint32
Addresses []InterfaceAddress
}
|
Addresses :
| type InterfaceAddress struct {
IP net.IP
Netmask net.IPMask // Netmask may be nil if we were unable to retrieve it.
Broadaddr net.IP // Broadcast address for this IP may be nil
P2P net.IP // P2P destination address for this IP may be nil
}
|
实时抓包
| var (
device = "\\Device\\NPF_{657E0D44-808F-42EA-82B5-AFAFF6AE862B}" // 设备名称
snapshot_len int32 = 1024 // 读取数据包的最大长度
promiscuous = false // 混杂模式 ( 接受目的地不是本机的包 )
timeout = -1 * time.Second // 抓包超时, -1 表示立即刷新数据包
err error
)
func main() {
// 打开网络设备
handle, err := pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
if err != nil {
return
}
defer handle.Close()
handle.SetBPFFilter("dns")
// 创建数据包源, handle.LinkType() => 以太网链路
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
// 读取数据包
for packet := range packetSource.Packets() {
fmt.Println(packet.String())
}
}
|
设置过滤器:handle.SetBPFFilter("dns")
创建数据包源:
| packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
读取一次数据包:
| packet, _ := packetSource.NextPacket()
|
获得一个读取所有数据包的通道:
| for packet := range packetSource.Packets() {
fmt.Println(packet.String())
}
|
写入读取
读取 pcap 文件:
| handle, _ = pcap.OpenOffline("dump.pcap")
defer handle.Close()
|
写入 pcap 文件:
| dumpFile, _ := os.Create("dump.pcap")
defer dumpFile.Close()
packetWriter := pcapgo.NewWriter(dumpFile)
packet := packetSource.Packets()
for packet := range packet{
packetWriter.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
}
|
数据包解码
Layers 包是 gopacket 的 Go 库中的新功能,在底层 libpcap 库中不存在。它是 gopacket 库的非常有用的一部分。它允许我们轻松地识别数据包是否包含特定类型的层。
| for _, layer := range packet.Layers() {
fmt.Println(layer.LayerType().String()) // 当前层的类型 (TCP/DNS/UDP...)
fmt.Println(layer.LayerContents())
fmt.Println(layer.LayerPayload())
}
|
分析某层的数据:
| for packet := range packetSource.Packets() {
// 判断数据包是否为 dns 数据包
dnsLayer := packet.Layer(layers.LayerTypeDNS)
if dnsLayer != nil {
// 断言为 DNS 类型
dns := dnsLayer.(*layers.DNS)
for _, q := range dns.Questions {
// 遍历 Questions 输出 Name
fmt.Println(string(q.Name))
}
}
}
|
创建与发送
创建
创建一个新的序列化缓冲区;然后把所有层序列化到缓冲区中。
| buffer := gopacket.NewSerializeBuffer()
options := gopacket.SerializeOptions{}
gopacket.SerializeLayers(buffer, options, &layers.Ethernet{}, &layers.IPv4{}, &layers.TCP{}, gopacket.Payload([]byte{65, 66, 67}))
|
发送
| handle.WritePacketData(buffer.Bytes())
|
参考链接