当我从s3客户端获取pcap文件时,我需要生成gopacket的packetsource来读取其中的数据包。但是我只在gopacket文档中找到了openofflinefile函数,我该如何用[]byte(从s3文件读取)生成packetsource。
我已经阅读了gopacket中openofflinefile函数的源代码,但我仍然很困惑,因为我不熟悉uintptr,我可以直接用[]byte生成一个unitptr,然后用它来生成packetsource吗?
func openOffline(file string) (handle *Handle, err error) {
err = LoadWinPCAP()
if err != nil {
return nil, err
}
buf := make([]byte, errorBufferSize)
f, err := syscall.BytePtrFromString(file)
if err != nil {
return nil, err
}
var cptr uintptr
if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
} else {
cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
}
if cptr == 0 {
return nil, errors.New(byteSliceToString(buf))
}
h := &Handle{cptr: pcapTPtr(cptr)}
return h, nil
}
正确答案
尝试 github.com/google/gopacket/pcapgo
如果 github.com/google/gopacket/pcapgo
包支持该文件格式,请考虑使用它,因为它很容易:
package main
import (
"bytes"
"io"
"log"
"os"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"
)
func main() {
f, err := os.open("test.pcap")
if err != nil {
panic(err)
}
// as described in the question, buf is read from s3 file. in order to
// make this demo simple and executable, we read it from a local file.
buf, err := io.readall(f)
if err != nil {
panic(err)
}
// convert []byte into a reader. the s3 client should give us a reader
// that we can use directly in the place of the filereader. try the best
// to avoid reading the response as []byte and then convert it into a reader.
filereader := bytes.newreader(buf)
r, err := pcapgo.newreader(filereader)
if err != nil {
panic(err)
}
source := gopacket.newpacketsource(r, layers.layertypeethernet)
for packet := range source.packets() {
log.printf("%v", packet)
}
}
将 os.pipe
与 github.com/google/gopacket/pcap
结合使用
如果 github.com/google/gopacket/pcapgo
不支持该文件格式,而我们必须使用 github.com/google/gopacket/pcap
,解决方法是创建一个管道,并将 r
文件传递给pcap.openofflinefile
:
package main
import (
"bytes"
"io"
"log"
"os"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func main() {
f, err := os.Open("test.pcap")
if err != nil {
panic(err)
}
// As described in the question, buf is read from S3 file. In order to
// make this demo simple and executable, we read it from a local file.
buf, err := io.ReadAll(f)
if err != nil {
panic(err)
}
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
go func() {
// Convert []byte into a reader. The S3 client should give us a reader
// that we can use directly in the place of the fileReader. Try the best
// to avoid reading the response as []byte and then convert it into a reader.
fileReader := bytes.NewReader(buf)
_, err := io.Copy(w, fileReader)
defer w.Close()
if err != nil {
panic(err)
}
}()
handle, err := pcap.OpenOfflineFile(r)
if err != nil {
panic(err)
}
source := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
for packet := range source.Packets() {
log.Printf("%v", packet)
}
}
注释:
- 这仅在 linux 上进行了测试。但它应该可以在 windows 上运行。
-
github.com/google/gopacket/pcap
是libpcap
(或 windows 上的winpcap
或npcap
)的包装器。这就是为什么使用[]byte
或io.reader
有点复杂。 - 当您从 s3 下载文件时,客户端应该为您提供一个阅读器。您可以直接使用阅读器(请参阅我的演示中的评论)。避免自己阅读读者的内容。