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 (
"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/format/registry"
"github.com/wader/fq/pkg/decode"
2021-12-02 00:48:25 +03:00
"github.com/wader/fq/pkg/scalar"
2021-11-23 00:08:36 +03:00
)
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
const (
bigEndian = 0xa1b2c3d4
littleEndian = 0xd4c3b2a1
)
2021-12-02 00:48:25 +03:00
var endianMap = scalar . UToSymStr {
2021-11-23 00:08:36 +03:00
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 {
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 ,
} )
}
func decodePcap ( d * decode . D , in interface { } ) interface { } {
2021-12-02 00:48:25 +03:00
endian := d . FieldU32 ( "magic" , d . AssertU ( bigEndian , littleEndian ) , endianMap , scalar . Hex )
2021-11-23 00:08:36 +03:00
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" )
2022-01-03 23:26:36 +03:00
d . FieldU32 ( "snaplen" )
2021-12-02 00:48:25 +03:00
linkType := int ( d . FieldU32 ( "network" , format . LinkTypeMap ) )
2021-11-24 23:20:46 +03:00
fd := flowsdecoder . New ( )
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" )
d . FieldU32 ( "ts_usec" )
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-01-24 23:21:48 +03:00
bs := d . MustReadAllBits ( 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-01-03 22:17:01 +03:00
if dv , _ , _ := d . TryFieldFormatLen ( "packet" , int64 ( inclLen ) * 8 , pcapLinkFrameFormat , format . LinkFrameIn {
2022-04-01 17:31:55 +03:00
Type : linkType ,
IsLittleEndian : d . Endian == decode . LittleEndian ,
2022-01-03 22:17:01 +03:00
} ) ; dv == nil {
2021-12-07 20:47:31 +03:00
d . FieldRawLen ( "packet" , int64 ( inclLen ) * 8 )
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
}