bcap/decoder.go

228 lines
6.6 KiB
Go
Raw Normal View History

2026-03-24 23:39:55 +08:00
package bcap
import (
"net"
"strconv"
"time"
"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)
type DecodeOptions struct {
BaseTime time.Time
SrcMACOverride net.HardwareAddr
}
type Decoder struct{}
func NewDecoder() *Decoder {
return &Decoder{}
}
func (d *Decoder) Decode(packet gopacket.Packet) (Packet, error) {
return d.DecodeWithOptions(packet, DecodeOptions{})
}
func (d *Decoder) DecodeWithOptions(packet gopacket.Packet, opts DecodeOptions) (Packet, error) {
var decoded Packet
decoded.Raw.Packet = packet
if metadata := packet.Metadata(); metadata != nil {
decoded.Meta.Timestamp = metadata.Timestamp
decoded.Meta.TimestampMicros = metadata.Timestamp.UnixMicro()
decoded.Meta.CaptureLength = metadata.CaptureLength
decoded.Meta.Length = metadata.Length
if !opts.BaseTime.IsZero() {
decoded.Meta.RelativeTime = metadata.Timestamp.Sub(opts.BaseTime)
}
} else {
decoded.Meta.Timestamp = time.Now()
decoded.Meta.TimestampMicros = decoded.Meta.Timestamp.UnixMicro()
}
decodeLinkLayer(&decoded, packet)
if len(opts.SrcMACOverride) > 0 {
decoded.Link.SrcMAC = append(net.HardwareAddr(nil), opts.SrcMACOverride...)
}
if arpLayer := packet.Layer(layers.LayerTypeARP); arpLayer != nil {
arp, ok := arpLayer.(*layers.ARP)
if !ok {
return decoded, NewParseError(ErrTypeNetwork, "ARP", "invalid arp layer", nil)
}
decodeARP(&decoded, arp)
return decoded, nil
}
if err := decodeNetworkLayer(&decoded, packet); err != nil {
return decoded, err
}
decodeTransportLayer(&decoded, packet)
return decoded, nil
}
func decodeLinkLayer(decoded *Packet, packet gopacket.Packet) {
decoded.Link.Kind = LinkKindUnknown
if ethLayer := packet.Layer(layers.LayerTypeEthernet); ethLayer != nil {
if eth, ok := ethLayer.(*layers.Ethernet); ok {
decoded.Link.Kind = LinkKindEthernet
decoded.Link.SrcMAC = append(net.HardwareAddr(nil), eth.SrcMAC...)
decoded.Link.DstMAC = append(net.HardwareAddr(nil), eth.DstMAC...)
return
}
}
if sllLayer := packet.Layer(layers.LayerTypeLinuxSLL); sllLayer != nil {
if sll, ok := sllLayer.(*layers.LinuxSLL); ok {
decoded.Link.Kind = LinkKindLinuxSLL
if sll.AddrType == 1 && sll.AddrLen == 6 {
decoded.Link.SrcMAC = append(net.HardwareAddr(nil), sll.Addr...)
}
return
}
}
if sll2Layer := packet.Layer(layers.LayerTypeLinuxSLL2); sll2Layer != nil {
if sll2, ok := sll2Layer.(*layers.LinuxSLL2); ok {
decoded.Link.Kind = LinkKindLinuxSLL2
if sll2.ARPHardwareType == 1 && sll2.AddrLength == 6 {
decoded.Link.SrcMAC = append(net.HardwareAddr(nil), sll2.Addr...)
}
}
}
}
func decodeARP(decoded *Packet, arp *layers.ARP) {
decoded.Network.Family = NetworkFamilyARP
decoded.Network.ProtocolNumber = uint16(arp.Protocol)
decoded.Network.ARP = &ARPFacts{
Operation: arp.Operation,
SenderMAC: append(net.HardwareAddr(nil), arp.SourceHwAddress...),
TargetMAC: append(net.HardwareAddr(nil), arp.DstHwAddress...),
SenderIP: arpProtocolAddressString(arp.SourceProtAddress),
TargetIP: arpProtocolAddressString(arp.DstProtAddress),
}
decoded.Network.SrcIP = decoded.Network.ARP.SenderIP
decoded.Network.DstIP = decoded.Network.ARP.TargetIP
decoded.Transport.Kind = ProtocolARP
}
func arpProtocolAddressString(raw []byte) string {
switch len(raw) {
case net.IPv4len:
return net.IP(raw).String()
case net.IPv6len:
return net.IP(raw).String()
default:
return ""
}
}
func decodeNetworkLayer(decoded *Packet, packet gopacket.Packet) error {
nw := packet.NetworkLayer()
if nw == nil {
return NewParseError(ErrTypeNetwork, "Network", "no valid network layer found", nil)
}
src, dst := nw.NetworkFlow().Endpoints()
decoded.Network.SrcIP = src.String()
decoded.Network.DstIP = dst.String()
switch layer := nw.(type) {
case *layers.IPv4:
decoded.Network.Family = NetworkFamilyIPv4
decoded.Network.TTL = layer.TTL
decoded.Network.ProtocolNumber = uint16(layer.Protocol)
case *layers.IPv6:
decoded.Network.Family = NetworkFamilyIPv6
decoded.Network.HopLimit = layer.HopLimit
decoded.Network.ProtocolNumber = uint16(layer.NextHeader)
default:
decoded.Network.Family = NetworkFamilyUnknown
}
return nil
}
func decodeTransportLayer(decoded *Packet, packet gopacket.Packet) {
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
if tcp, ok := tcpLayer.(*layers.TCP); ok {
payloadLen := len(tcpLayer.LayerPayload())
decoded.Transport.Kind = ProtocolTCP
decoded.Transport.Payload = payloadLen
decoded.Transport.TCP = &TCPFacts{
SrcPort: strconv.Itoa(int(tcp.SrcPort)),
DstPort: strconv.Itoa(int(tcp.DstPort)),
Seq: tcp.Seq,
Ack: tcp.Ack,
Window: tcp.Window,
SYN: tcp.SYN,
ACK: tcp.ACK,
FIN: tcp.FIN,
RST: tcp.RST,
ECE: tcp.ECE,
CWR: tcp.CWR,
PSH: tcp.PSH,
Checksum: tcp.Checksum,
Payload: payloadLen,
}
return
}
}
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
if udp, ok := udpLayer.(*layers.UDP); ok {
payloadLen := len(udpLayer.LayerPayload())
decoded.Transport.Kind = ProtocolUDP
decoded.Transport.Payload = payloadLen
decoded.Transport.UDP = &UDPFacts{
SrcPort: strconv.Itoa(int(udp.SrcPort)),
DstPort: strconv.Itoa(int(udp.DstPort)),
Length: udp.Length,
Payload: payloadLen,
}
return
}
}
if icmpLayer := packet.Layer(layers.LayerTypeICMPv4); icmpLayer != nil {
if icmp, ok := icmpLayer.(*layers.ICMPv4); ok {
payloadLen := len(icmpLayer.LayerPayload())
decoded.Transport.Kind = ProtocolICMPv4
decoded.Transport.Payload = payloadLen
decoded.Transport.ICMP = &ICMPFacts{
Version: 4,
Type: uint8(icmp.TypeCode.Type()),
Code: uint8(icmp.TypeCode.Code()),
Checksum: icmp.Checksum,
ID: icmp.Id,
Seq: icmp.Seq,
Payload: payloadLen,
}
return
}
}
if icmpLayer := packet.Layer(layers.LayerTypeICMPv6); icmpLayer != nil {
if icmp, ok := icmpLayer.(*layers.ICMPv6); ok {
payloadLen := len(icmpLayer.LayerPayload())
decoded.Transport.Kind = ProtocolICMPv6
decoded.Transport.Payload = payloadLen
decoded.Transport.ICMP = &ICMPFacts{
Version: 6,
Type: uint8(icmp.TypeCode.Type()),
Code: uint8(icmp.TypeCode.Code()),
Checksum: icmp.Checksum,
Payload: payloadLen,
}
return
}
}
var payloadLen int
if app := packet.ApplicationLayer(); app != nil {
payloadLen = len(app.Payload())
} else if nw := packet.NetworkLayer(); nw != nil {
payloadLen = len(nw.LayerPayload())
}
decoded.Transport.Kind = ProtocolUnknown
decoded.Transport.Payload = payloadLen
decoded.Transport.Unknown = &UnknownTransportFacts{Payload: payloadLen}
}