2021-11-23 00:08:36 +03:00
package pcap
// https://wiki.wireshark.org/Development/LibpcapFileFormat
2021-12-09 16:19:09 +03:00
// TODO: tshark seems to not support sll2 in pcap, confusing
2021-11-23 00:08:36 +03:00
import (
2022-10-09 20:05:30 +03:00
"embed"
2021-11-23 00:08:36 +03:00
"github.com/wader/fq/format"
2021-11-24 23:20:46 +03:00
"github.com/wader/fq/format/inet/flowsdecoder"
2021-11-23 00:08:36 +03:00
"github.com/wader/fq/pkg/decode"
2022-07-16 19:39:57 +03:00
"github.com/wader/fq/pkg/interp"
2021-12-02 00:48:25 +03:00
"github.com/wader/fq/pkg/scalar"
2021-11-23 00:08:36 +03:00
)
2022-10-09 20:05:30 +03:00
//go:embed pcap.md
var pcapFS embed . FS
2022-01-03 22:17:01 +03:00
var pcapLinkFrameFormat decode . Group
2021-11-24 23:20:46 +03:00
var pcapTCPStreamFormat decode . Group
var pcapIPv4PacketFormat decode . Group
2021-11-23 00:08:36 +03:00
2022-08-18 15:09:42 +03:00
// writing application writes 0xa1b2c3d4 in native endian
2021-11-23 00:08:36 +03:00
const (
2022-08-18 15:09:42 +03:00
// timestamp is seconds + microseconds
2021-11-23 00:08:36 +03:00
bigEndian = 0xa1b2c3d4
littleEndian = 0xd4c3b2a1
2022-08-18 15:09:42 +03:00
// timestamp is seconds + nanoseconds
bigEndianNS = 0xa1b23c4d
littleEndianNS = 0x4d3cb2a1
2021-11-23 00:08:36 +03:00
)
2022-09-30 14:58:23 +03:00
var endianMap = scalar . UintMapSymStr {
2022-08-18 15:09:42 +03:00
bigEndian : "big_endian" ,
littleEndian : "little_endian" ,
bigEndianNS : "big_endian_ns" ,
littleEndianNS : "little_endian_ns" ,
2021-11-23 00:08:36 +03:00
}
func init ( ) {
2022-07-16 19:39:57 +03:00
interp . RegisterFormat ( decode . Format {
2021-11-23 00:08:36 +03:00
Name : format . PCAP ,
Description : "PCAP packet capture" ,
Groups : [ ] string { format . PROBE } ,
Dependencies : [ ] decode . Dependency {
2022-01-03 22:17:01 +03:00
{ Names : [ ] string { format . LINK_FRAME } , Group : & pcapLinkFrameFormat } ,
2021-11-24 23:20:46 +03:00
{ Names : [ ] string { format . TCP_STREAM } , Group : & pcapTCPStreamFormat } ,
{ Names : [ ] string { format . IPV4_PACKET } , Group : & pcapIPv4PacketFormat } ,
2021-11-23 00:08:36 +03:00
} ,
DecodeFn : decodePcap ,
} )
2022-10-09 20:05:30 +03:00
interp . RegisterFS ( pcapFS )
2021-11-23 00:08:36 +03:00
}
2022-07-19 19:33:50 +03:00
func decodePcap ( d * decode . D , _ any ) any {
2022-08-18 15:09:42 +03:00
var endian decode . Endian
linkType := 0
timestampUNSStr := "ts_usec"
d . FieldStruct ( "header" , func ( d * decode . D ) {
2022-09-30 14:58:23 +03:00
magic := d . FieldU32 ( "magic" , d . UintAssert (
2022-08-18 15:09:42 +03:00
bigEndian ,
littleEndian ,
bigEndianNS ,
littleEndianNS ,
2022-09-30 14:58:23 +03:00
) , endianMap , scalar . UintHex )
2022-08-18 15:09:42 +03:00
switch magic {
case bigEndian :
endian = decode . BigEndian
case littleEndian :
endian = decode . LittleEndian
case bigEndianNS :
endian = decode . BigEndian
timestampUNSStr = "ts_nsec"
case littleEndianNS :
endian = decode . LittleEndian
timestampUNSStr = "ts_nsec"
}
d . Endian = 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 ) )
} )
2021-11-24 23:20:46 +03:00
2022-08-18 15:09:42 +03:00
d . Endian = endian
2023-01-28 22:48:31 +03:00
fd := flowsdecoder . New ( flowsdecoder . DecoderOptions { CheckTCPOptions : false } )
2021-11-23 00:08:36 +03:00
d . FieldArray ( "packets" , func ( d * decode . D ) {
for ! d . End ( ) {
d . FieldStruct ( "packet" , func ( d * decode . D ) {
d . FieldU32 ( "ts_sec" )
2022-08-18 15:09:42 +03:00
d . FieldU32 ( timestampUNSStr )
2021-11-23 00:08:36 +03:00
inclLen := d . FieldU32 ( "incl_len" )
origLen := d . FieldU32 ( "orig_len" )
2021-11-24 23:20:46 +03:00
2022-01-03 23:26:36 +03:00
// "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)
// }
2021-12-07 20:47:31 +03:00
if inclLen > origLen {
d . Errorf ( "incl_len %d > orig_len %d" , inclLen , origLen )
}
2022-06-30 13:13:36 +03:00
bs := d . ReadAllBits ( d . BitBufRange ( d . Pos ( ) , int64 ( inclLen ) * 8 ) )
2021-11-24 23:20:46 +03:00
if fn , ok := linkToDecodeFn [ linkType ] ; ok {
2021-12-06 19:56:48 +03:00
// TODO: report decode errors
_ = fn ( fd , bs )
2021-11-24 23:20:46 +03:00
}
2022-04-11 23:45:46 +03:00
d . FieldFormatOrRawLen (
"packet" ,
int64 ( inclLen ) * 8 ,
pcapLinkFrameFormat , format . LinkFrameIn {
Type : linkType ,
IsLittleEndian : d . Endian == decode . LittleEndian ,
} ,
)
2021-11-23 00:08:36 +03:00
} )
}
} )
2021-11-24 23:20:46 +03:00
fd . Flush ( )
fieldFlows ( d , fd , pcapTCPStreamFormat , pcapIPv4PacketFormat )
2021-11-23 00:08:36 +03:00
return nil
}