1
1
mirror of https://github.com/wader/fq.git synced 2024-11-24 11:16:09 +03:00
fq/format/pcap/pcap.go
Mattias Wadman af23eb8269 pcap: Don't fail if incl_len > spanlen
Documentation wrong? seems to happen in real pcap files
2022-01-03 21:27:14 +01:00

108 lines
3.0 KiB
Go

package pcap
// https://wiki.wireshark.org/Development/LibpcapFileFormat
// TODO: tshark seems to not support sll2 in pcap, confusing
import (
"github.com/wader/fq/format"
"github.com/wader/fq/format/inet/flowsdecoder"
"github.com/wader/fq/format/registry"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/scalar"
)
var pcapLinkFrameFormat decode.Group
var pcapTCPStreamFormat decode.Group
var pcapIPv4PacketFormat decode.Group
const (
bigEndian = 0xa1b2c3d4
littleEndian = 0xd4c3b2a1
)
var endianMap = scalar.UToSymStr{
bigEndian: "big_endian",
littleEndian: "little_endian",
}
func init() {
registry.MustRegister(decode.Format{
Name: format.PCAP,
Description: "PCAP packet capture",
Groups: []string{format.PROBE},
Dependencies: []decode.Dependency{
{Names: []string{format.LINK_FRAME}, Group: &pcapLinkFrameFormat},
{Names: []string{format.TCP_STREAM}, Group: &pcapTCPStreamFormat},
{Names: []string{format.IPV4_PACKET}, Group: &pcapIPv4PacketFormat},
},
DecodeFn: decodePcap,
})
}
func decodePcap(d *decode.D, in interface{}) interface{} {
endian := d.FieldU32("magic", d.AssertU(bigEndian, littleEndian), endianMap, scalar.Hex)
switch endian {
case bigEndian:
d.Endian = decode.BigEndian
case littleEndian:
d.Endian = decode.LittleEndian
default:
d.Fatalf("unknown endian %d", endian)
}
d.FieldU16("version_major")
d.FieldU16("version_minor")
d.FieldS32("thiszone")
d.FieldU32("sigfigs")
d.FieldU32("snaplen")
linkType := int(d.FieldU32("network", format.LinkTypeMap))
fd := flowsdecoder.New()
d.FieldArray("packets", func(d *decode.D) {
for !d.End() {
d.FieldStruct("packet", func(d *decode.D) {
d.FieldU32("ts_sec")
d.FieldU32("ts_usec")
inclLen := d.FieldU32("incl_len")
origLen := d.FieldU32("orig_len")
// "incl_len: the number of bytes of packet data actually captured and saved in the file. This value should never become larger than orig_len or the snaplen value of the global header"
// "orig_len: the length of the packet as it appeared on the network when it was captured. If incl_len and orig_len differ, the actually saved packet size was limited by snaplen."
// TODO: incl_len seems to be larger than snaplen in real pcap files
// if inclLen > snapLen {
// d.Errorf("incl_len %d > snaplen %d", inclLen, snapLen)
// }
if inclLen > origLen {
d.Errorf("incl_len %d > orig_len %d", inclLen, origLen)
}
bb := d.BitBufRange(d.Pos(), int64(inclLen)*8)
bs, err := bb.Bytes()
if err != nil {
// TODO:
d.IOPanic(err, "BitBufRange: inclLen")
}
if fn, ok := linkToDecodeFn[linkType]; ok {
// TODO: report decode errors
_ = fn(fd, bs)
}
if dv, _, _ := d.TryFieldFormatLen("packet", int64(inclLen)*8, pcapLinkFrameFormat, format.LinkFrameIn{
Type: linkType,
LittleEndian: d.Endian == decode.LittleEndian,
}); dv == nil {
d.FieldRawLen("packet", int64(inclLen)*8)
}
})
}
})
fd.Flush()
fieldFlows(d, fd, pcapTCPStreamFormat, pcapIPv4PacketFormat)
return nil
}