OpenGFW icon indicating copy to clipboard operation
OpenGFW copied to clipboard

增加对pcap的支持以方便调试

Open 66hh opened this issue 1 year ago • 0 comments

如题

附上简易实现代码

io/pcap.go

package io

import (
	"context"
	"hash/crc32"
	"sort"
	"strings"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

var _ PacketIO = (*pcapPacketIO)(nil)

type pcapPacketIO struct {
	pcap     *pcap.Handle
	lastTime *time.Time
}

func NewPcapPacketIO(pcapFile string) (PacketIO, error) {
	handle, err := pcap.OpenOffline(pcapFile)

	if err != nil {
		return nil, err
	}

	return &pcapPacketIO{
		pcap:     handle,
		lastTime: nil,
	}, nil
}

func (n *pcapPacketIO) Register(ctx context.Context, cb PacketCallback) error {
	go func() {
		packetSource := gopacket.NewPacketSource(n.pcap, n.pcap.LinkType())
		for packet := range packetSource.Packets() {

			if n.lastTime == nil {
				n.lastTime = &packet.Metadata().Timestamp
			} else {
				t := packet.Metadata().Timestamp.Sub(*n.lastTime)
				time.Sleep(t)
				n.lastTime = &packet.Metadata().Timestamp
			}

			ethernetLayer := packet.Layer(layers.LayerTypeEthernet)

			var id uint32 = 0
			var address []string

			if ethernetLayer.(*layers.Ethernet).EthernetType == 0x0800 {
				ipLayer := packet.Layer(layers.LayerTypeIPv4)
				ipPacket := ipLayer.(*layers.IPv4)
				address = append(address, string(ipPacket.DstIP))
				address = append(address, string(ipPacket.SrcIP))
			}
			if ethernetLayer.(*layers.Ethernet).EthernetType == 0x86DD {
				ipLayer := packet.Layer(layers.LayerTypeIPv6)
				ipPacket := ipLayer.(*layers.IPv6)
				address = append(address, string(ipPacket.DstIP))
				address = append(address, string(ipPacket.SrcIP))
			}

			if len(address) != 0 {
				sort.Sort(sort.StringSlice(address))
				id = crc32.Checksum([]byte(strings.Join(address, ",")), crc32.IEEETable)
			}

			cb(&pcapPacket{
				streamID: id,
				data:     ethernetLayer.LayerPayload(),
			}, nil)

		}

	}()

	return nil
}

func (n *pcapPacketIO) SetVerdict(p Packet, v Verdict, newPacket []byte) error {
	return nil
}

func (n *pcapPacketIO) Close() error {
	return nil
}

var _ Packet = (*pcapPacket)(nil)

type pcapPacket struct {
	streamID uint32
	data     []byte
}

func (p *pcapPacket) StreamID() uint32 {
	return p.streamID
}

func (p *pcapPacket) Data() []byte {
	return p.data
}

66hh avatar Apr 03 '24 11:04 66hh