apernet / OpenGFW

OpenGFW is a flexible, easy-to-use, open source implementation of GFW (Great Firewall of China) on Linux
https://gfw.dev/
Mozilla Public License 2.0
9.31k stars 703 forks source link

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

Closed 66hh closed 2 months ago

66hh commented 3 months ago

如题

附上简易实现代码

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
}