Part1前言
gopacket是谷歌开源的一款抓包库,为go语音提供了处理网卡包的能力。其底层基于libpcap。github地址 https://github.com/google/gopacket。
本文主要从一个新手的角度从零开始使用该库。
Part2go环境搭建
下载地址https://golang.google.cn/doc/install
安装之后,输入go version
即可查看版本号
vscode调试使用按住ctrl +shift +P。接下来全选进行安装,即可完成代码提升等相关工具的安装。
Part3gopacket安装
安装命令
go get github.com/google/gopacket
go get github.com/google/gopacket/pcap@v1.1.19
执行完之后,还需要安装抓包库,但是由于我已经安装过了wireshark,所以不需要进行安装了。
1hello示例
package main
import (
"fmt"
"github.com/google/gopacket/pcap"
)
func main() {
version := pcap.Version()
fmt.Println(version)
}
输出结果
Npcap version 0.9991, based on libpcap version 1.9.1
2网卡查找
package main
import (
"fmt"
"log"
"github.com/google/gopacket/pcap"
)
func findDevices() {
// 得到所有的(网络)设备
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
// 打印设备信息
fmt.Println("Devices found:")
for _, device := range devices {
fmt.Println("\nName: ", device.Name)
fmt.Println("Description: ", device.Description)
fmt.Println("Devices addresses: ", device.Description)
for _, address := range device.Addresses {
fmt.Println("- IP address: ", address.IP)
fmt.Println("- Subnet mask: ", address.Netmask)
}
}
}
即可打印本机的所有网卡
3抓取数据
抓取数据调试了好久,一直抓不到数据,后来发现必须要设置抓包条件,默认不设置就不抓取数据。这里设置了抓取端口为443的数据。err = handle.SetBPFFilter("tcp and port 443")
package main
import (
"fmt"
"log"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
func findDevices(ip string) (name string) {
// 得到所有的(网络)设备
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
// 打印设备信息
fmt.Println("Devices found:")
for _, device := range devices {
fmt.Println("\nName: ", device.Name)
fmt.Println("Description: ", device.Description)
fmt.Println("Devices addresses: ", device.Description)
for _, address := range device.Addresses {
fmt.Println("- IP address: ", address.IP)
fmt.Println("- Subnet mask: ", address.Netmask)
if ip == address.IP.String() {
name = device.Name
}
}
}
return
}
func Realtimecapture(ethName string) {
// Open device
var (
device string = ethName
snapshot_len int32 = 1024
promiscuous bool = false
err error
timeout time.Duration = 30 * time.Second
handle *pcap.Handle
)
handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
err = handle.SetBPFFilter("tcp and port 443")
if err != nil {
log.Fatal(err)
}
// Use the handle as a packet source to process all packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
fmt.Println(packet) // Do something with a packet here.
}
}
4写成pcap文件
还可以将网卡数据保存为pcap格式的文件,这样还可以通过wireshark进行分析。
func WritePcap(ethName string) {
// Open device
var (
device string = ethName
snapshot_len int32 = 1600
promiscuous bool = false
err error
timeout time.Duration = 30 * time.Second
handle *pcap.Handle
packetCount int = 0
)
f, _ := os.Create("test.pcap")
w := pcapgo.NewWriter(f)
var snapshotlen uint32 = 1600
w.WriteFileHeader(snapshotlen, layers.LinkTypeEthernet)
defer f.Close()
handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
err = handle.SetBPFFilter("tcp || udp")
if err != nil {
log.Fatal(err)
}
// Use the handle as a packet source to process all packets
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
fmt.Println(packet) // Do something with a packet here.
w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
packetCount++
// Only capture 100 and then stop
if packetCount > 100 {
break
}
}
}
5读取pcap
还可以读取wireshark保存的文件,用来对包进行分析
func ReadPcap() {
var (
pcapFile string = "test.pcap"
handle *pcap.Handle
err error
)
// Open file instead of device
handle, err = pcap.OpenOffline(pcapFile)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
// Loop through packets in file
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
fmt.Println(packet)
}
}
6解码各层数据
我们可以将原始数据包数据强制转换为已知的格式,这里是Layer格式。layers层是gopacket的Go库中的新功能,在底层libpcap库中不存在。它是gopacket库的非常有用的一部分。它允许我们轻松地识别数据包是否包含特定类型的层。
func printPacketInfo(packet gopacket.Packet) {
ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
if ethernetLayer != nil {
fmt.Println("Ethernet layer detected.")
ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
fmt.Println("Source MAC: ", ethernetPacket.SrcMAC)
fmt.Println("Destination MAC: ", ethernetPacket.DstMAC)
// Ethernet type is typically IPv4 but could be ARP or other
fmt.Println("Ethernet type: ", ethernetPacket.EthernetType)
fmt.Println()
}
}
Part4总结
本文主要介绍了如何从零开始进行gopacket的使用。其实整个gopacket的应用非常简洁,比较好入门。只不过需要从新学习一门新语言go。最近准备对go语言进行一些研究和学习。