1
1
mirror of https://github.com/wader/fq.git synced 2024-12-25 14:23:18 +03:00
fq/format/inet/tcp_segment.go

90 lines
2.6 KiB
Go
Raw Normal View History

package inet
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol
import (
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)
func init() {
interp.RegisterFormat(decode.Format{
Name: format.TCP_SEGMENT,
Description: "Transmission control protocol segment",
Groups: []string{format.IP_PACKET},
DecodeFn: decodeTCP,
})
}
const (
tcpOptionEnd = 0
tcpOptionNop = 1
)
var tcpOptionsMap = scalar.UToScalar{
tcpOptionEnd: {Sym: "end", Description: "End of options list"},
tcpOptionNop: {Sym: "nop", Description: "No operation"},
2: {Sym: "maxseg", Description: "Maximum segment size"},
3: {Sym: "winscale", Description: "Window scale"},
4: {Sym: "sack_permitted", Description: "Selective Acknowledgement permitted"},
5: {Sym: "sack", Description: "Selective ACKnowledgement"},
8: {Sym: "timestamp", Description: "Timestamp and echo of previous timestamp"},
}
func decodeTCP(d *decode.D, in any) any {
if ipi, ok := in.(format.IPPacketIn); ok && ipi.Protocol != format.IPv4ProtocolTCP {
d.Fatalf("incorrect protocol %d", ipi.Protocol)
}
d.FieldU16("source_port", format.TCPPortMap)
d.FieldU16("destination_port", format.TCPPortMap)
d.FieldU32("sequence_number")
d.FieldU32("acknowledgment_number")
dataOffset := d.FieldU4("data_offset")
d.FieldU3("reserved")
d.FieldBool("ns")
d.FieldBool("cwr")
d.FieldBool("ece")
d.FieldBool("urg")
d.FieldBool("ack")
d.FieldBool("psh")
d.FieldBool("rst")
d.FieldBool("syn")
d.FieldBool("fin")
d.FieldU16("window_size")
// checksumStart := d.Pos()
d.FieldU16("checksum", scalar.ActualHex)
// checksumEnd := d.Pos()
d.FieldU16("urgent_pointer")
optionsLen := (int64(dataOffset) - 5) * 8 * 4
if optionsLen > 0 {
d.FramedFn(optionsLen, func(d *decode.D) {
d.FieldArray("options", func(d *decode.D) {
for !d.End() {
d.FieldStruct("option", func(d *decode.D) {
kind := d.FieldU8("kind", tcpOptionsMap)
switch kind {
case tcpOptionEnd, tcpOptionNop:
default:
l := d.FieldU8("length")
d.FieldRawLen("data", (int64(l-2))*8)
}
})
}
})
})
}
// TODO: need to pass ipv4 pseudo header somehow
// tcpChecksum := &checksum.IPv4{}
// d.MustCopy(tcpChecksum, d.BitBufRange(0, checksumStart))
// d.MustCopy(tcpChecksum, d.BitBufRange(checksumEnd, d.Len()-checksumEnd))
// _ = d.FieldMustGet("checksum").TryScalarFn(d.ValidateUBytes(tcpChecksum.Sum(nil)), scalar.Hex)
d.FieldRawLen("payload", d.BitsLeft())
return nil
}