使用gopacket创建一个从S3文件读取数据的packetSource。

huangapple go评论85阅读模式
英文:

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.Pipegithub.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)
	}
}

注意事项

  1. 此代码仅在 Linux 上进行了测试,但应该也适用于 Windows。
  2. github.com/google/gopacket/pcaplibpcap(或 Windows 上的winpcapnpcap)的封装。这就是为什么使用[]byteio.Reader有点复杂的原因。
  3. 当从 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:

  1. This is tested on Linux only. But it should work on Windows.
  2. github.com/google/gopacket/pcap is a wrapper of libpcap (or winpcap or npcap on Windows). That's why it's a little complicated to work with []byte or io.Reader.
  3. 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.

huangapple
  • 本文由 发表于 2023年3月30日 16:49:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75886017.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定