2021-11-24 23:20:46 +03:00
|
|
|
package inet
|
|
|
|
|
|
|
|
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/wader/fq/format"
|
|
|
|
"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-24 23:20:46 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2022-07-16 19:39:57 +03:00
|
|
|
interp.RegisterFormat(decode.Format{
|
2021-11-24 23:20:46 +03:00
|
|
|
Name: format.TCP_SEGMENT,
|
|
|
|
Description: "Transmission control protocol segment",
|
2022-04-01 17:31:55 +03:00
|
|
|
Groups: []string{format.IP_PACKET},
|
2021-11-24 23:20:46 +03:00
|
|
|
DecodeFn: decodeTCP,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
tcpOptionEnd = 0
|
|
|
|
tcpOptionNop = 1
|
|
|
|
)
|
|
|
|
|
2021-12-02 00:48:25 +03:00
|
|
|
var tcpOptionsMap = scalar.UToScalar{
|
2021-11-24 23:20:46 +03:00
|
|
|
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"},
|
|
|
|
}
|
|
|
|
|
2022-05-20 16:10:41 +03:00
|
|
|
func decodeTCP(d *decode.D, in any) any {
|
2022-04-01 17:31:55 +03:00
|
|
|
if ipi, ok := in.(format.IPPacketIn); ok && ipi.Protocol != format.IPv4ProtocolTCP {
|
|
|
|
d.Fatalf("incorrect protocol %d", ipi.Protocol)
|
|
|
|
}
|
|
|
|
|
2021-12-02 00:48:25 +03:00
|
|
|
d.FieldU16("source_port", format.TCPPortMap)
|
|
|
|
d.FieldU16("destination_port", format.TCPPortMap)
|
2021-11-24 23:20:46 +03:00
|
|
|
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()
|
2022-05-07 13:46:34 +03:00
|
|
|
d.FieldU16("checksum", scalar.ActualHex)
|
2021-11-24 23:20:46 +03:00
|
|
|
// checksumEnd := d.Pos()
|
|
|
|
d.FieldU16("urgent_pointer")
|
|
|
|
optionsLen := (int64(dataOffset) - 5) * 8 * 4
|
|
|
|
if optionsLen > 0 {
|
2022-01-13 20:34:59 +03:00
|
|
|
d.FramedFn(optionsLen, func(d *decode.D) {
|
2021-11-24 23:20:46 +03:00
|
|
|
d.FieldArray("options", func(d *decode.D) {
|
|
|
|
for !d.End() {
|
|
|
|
d.FieldStruct("option", func(d *decode.D) {
|
2021-12-02 00:48:25 +03:00
|
|
|
kind := d.FieldU8("kind", tcpOptionsMap)
|
2021-11-24 23:20:46 +03:00
|
|
|
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))
|
2021-12-02 00:48:25 +03:00
|
|
|
// _ = d.FieldMustGet("checksum").TryScalarFn(d.ValidateUBytes(tcpChecksum.Sum(nil)), scalar.Hex)
|
2021-11-24 23:20:46 +03:00
|
|
|
|
2022-04-01 17:31:55 +03:00
|
|
|
d.FieldRawLen("payload", d.BitsLeft())
|
2021-11-24 23:20:46 +03:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|