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} }