安装 gopacket
gopacket 依赖 libpcap,所以需要先安装 libpcap。编译需要开启 CGO。
yum install libpcap-devel # CentOS
apt install libpcap-dev # Ubuntu
apk add libpcap-dev # Alpine
export CGO_ENABLED=1 # 开启 CGO
go get github.com/google/gopacket
读取 pcap 文件
package main
import (
"flag"
"fmt"
"log"
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func main() {
// 获取命令行参数
pcapfile := flag.String("f", "en0.pcap", "pcap file")
flag.Parse()
// 读取 pcap 文件
handle, err := pcap.OpenOffline(*pcapfile)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
packetSources := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSources.Packets() {
// 处理每个数据包
fmt.Println(packet)
}
}
解析数据包
自定义 Packet 结构体
这里我们定义了一个 Packet 结构体,它嵌入了 gopacket.Packet 接口,这样我们的 Packet 结构体就继承了 gopacket.Packet 的所有方法。同时,我们提供了一个 NewPacket 函数来创建 Packet 实例。
// Packet 自定义 Packet 结构体
type Packet struct {
gopacket.Packet
}
// NewPacket 自定义Packet结构体
func NewPacket(packet gopacket.Packet) *Packet {
return &Packet{
Packet: packet,
}
}
解析时间
这个方法用于获取数据包的时间戳,直接从数据包的元数据中获取。
// ParseTime 解析时间
func (p *Packet) ParseTime() time.Time {
return p.Metadata().Timestamp
}
解析 MAC 地址
这个方法用于解析以太网帧中的源 MAC 地址和目的 MAC 地址。
// ParseMac 解析 MAC 地址
func (p *Packet) ParseMac() (srcMac, dstMac net.HardwareAddr) {
if ethLayer := p.Layer(layers.LayerTypeEthernet); ethLayer != nil {
if eth, ok := ethLayer.(*layers.Ethernet); ok {
srcMac = eth.SrcMAC
dstMac = eth.DstMAC
}
}
return
}
解析 IP 地址
这个方法用于解析 IP 层中的源 IP 地址和目的 IP 地址。
// ParseIP 解析 IP 地址
func (p *Packet) ParseIP() (srcIP, dstIP net.IP) {
if ip4Layer := p.Layer(layers.LayerTypeIPv4); ip4Layer != nil {
if ip, ok := ip4Layer.(*layers.IPv4); ok {
srcIP = ip.SrcIP
dstIP = ip.DstIP
}
} else if ip6Layer := p.Layer(layers.LayerTypeIPv6); ip6Layer != nil {
if ip, ok := ip6Layer.(*layers.IPv6); ok {
srcIP = ip.SrcIP
dstIP = ip.DstIP
}
}
return
}
解析端口号
这个方法用于解析传输层中的源端口号和目的端口号。
// ParsePort 解析端口号
func (p *Packet) ParsePort() (srcPort, dstPort uint16) {
if tcpLayer := p.Layer(layers.LayerTypeTCP); tcpLayer != nil {
if tcp, ok := tcpLayer.(*layers.TCP); ok {
srcPort = uint16(tcp.SrcPort)
dstPort = uint16(tcp.DstPort)
}
} else if udpLayer := p.Layer(layers.LayerTypeUDP); udpLayer != nil {
if udp, ok := udpLayer.(*layers.UDP); ok {
srcPort = uint16(udp.SrcPort)
dstPort = uint16(udp.DstPort)
}
}
return
}
自定义字符串输出
这个方法用于自定义数据包的字符串输出,包含时间、源 MAC 地址、目的 MAC 地址、源 IP 地址、目的 IP 地址、源端口号和目的端口号。
// String 自定义字符串输出
func (p *Packet) String() string {
timestamp := p.ParseTime().Format("2006-01-02T15:04:05.000Z07:00")
srcMac, dstMac := p.ParseMac()
srcIP, dstIP := p.ParseIP()
srcPort, dstPort := p.ParsePort()
return fmt.Sprintf(
"%s %s:%d(%s) -> %s:%d(%s)",
timestamp,
srcIP, srcPort, srcMac,
dstIP, dstPort, dstMac,
)
}
处理数据包
这里我们使用 NewPacket 函数创建 Packet 实例,并调用 String 方法输出自定义的字符串。
packetSources := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSources.Packets() {
// 处理每个数据包
fmt.Println(NewPacket(packet))
}
tcpdump -i en0 -nn -c 10 -w en0.pcap # 捕获10个数据包并保存到 en0.pcap 文件
go run main.go -f en0.pcap # 从 en0.pcap 文件中读取数据包并解析
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.834+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
2025-09-04T18:47:21.836+08:00 192.168.111.103:548(00:11:32:fa:ca:27) -> 192.168.111.100:59937(7e:14:5f:df:88:65)
原创
使用 gopacket 解析 pcap 文件
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
赞赏支持
如果觉得文章对你有帮助,可以请作者喝杯咖啡 ☕
评论交流
欢迎留下你的想法