英文:
create packetSource of gopacket with s3 file
问题
当我从S3客户端获取一个pcap文件时,我需要生成一个gopacket的packetSource来读取其中的数据包。但是我在gopacket文档中只找到了OpenOfflineFile函数,它可以用来打开pcap文件。我应该如何使用[]byte(从S3文件中读取)来生成packetSource呢?
我已经阅读了gopacket中OpenOfflineFile函数的源代码,但由于我对uintptr不熟悉,所以仍然感到困惑。我是否可以使用[]byte生成一个uintptr,然后用它来生成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
}
英文:
when I get a pcap file from s3 client, I need to generate a packetSource of gopacket to read packets in it. But I only found OpenOfflineFile function in gopacket document, how could I do to generate packetSource with []byte(which is read from s3 file).
I have read source code of OpenOfflineFile function in gopacket, but I still get confused because I'm unfamiliar with uintptr, can I just generate a unitptr with []byte and then use it to generate 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
}
答案1
得分: 0
尝试使用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)
}
// 如问题描述,buf 是从 S3 文件中读取的。为了使此演示简单且可执行,我们从本地文件中读取它。
buf, err := io.ReadAll(f)
if err != nil {
panic(err)
}
// 将 []byte 转换为 reader。S3 客户端应该提供一个 reader,我们可以直接在文件读取器的位置使用它。尽量避免将响应读取为 []byte,然后将其转换为 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)
}
// 如问题描述,buf 是从 S3 文件中读取的。为了使此演示简单且可执行,我们从本地文件中读取它。
buf, err := io.ReadAll(f)
if err != nil {
panic(err)
}
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
go func() {
// 将 []byte 转换为 reader。S3 客户端应该提供一个 reader,我们可以直接在文件读取器的位置使用它。尽量避免将响应读取为 []byte,然后将其转换为 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 下载文件时,客户端应该提供一个 reader。您可以直接使用该 reader(请参阅我的演示中的注释)。避免自己从 reader 中读取。
英文:
Try github.com/google/gopacket/pcapgo
If the file format is supported by the package github.com/google/gopacket/pcapgo
, considering using it because it makes it easy:
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)
}
}
Use os.Pipe
with github.com/google/gopacket/pcap
If the file format is not supported by github.com/google/gopacket/pcapgo
and we have to go with github.com/google/gopacket/pcap
, a workaround is to create a pipe, and pass the r
file to 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)
}
}
Notes:
- This is tested on Linux only. But it should work on Windows.
github.com/google/gopacket/pcap
is a wrapper oflibpcap
(orwinpcap
ornpcap
on Windows). That's why it's a little complicated to work with[]byte
orio.Reader
.- When you download a file from S3, the client should give you a reader. You can use the reader directly (see the comments in my demo). Avoid reading from the reader yourself.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论