package parser import ( "encoding/binary" "errors" "fmt" ) const ( TCPOptionKindEndList = 0 // 选项表结束(1字节) TCPOptionKindNop = 1 // 无操作(1字节) TCPOptionKindMSS = 2 // 最大报文段长度(4字节,Maximum Segment Size,MSS) TCPOptionKindWindowScale = 3 // 窗口扩大因子(3字节,wscale) TCPOptionKindSACKOK = 4 // sackOK—发送端支持并同意使用SACK选项。 TCPOptionKindSACK = 5 // SACK实际工作的选项。 TCPOptionKindTimestamps = 8 // 时间戳(10字节,TCP Timestamps Option,TSopt) ) // TCP ref: https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE#%E7%8A%B6%E6%80%81%E7%BC%96%E7%A0%81 type TCP struct { BaseLayer SrcPort, DstPort uint16 // 源、目的端口 Seq uint32 // 序列号 Ack uint32 // 确认号 DataOffset uint8 // 数据偏移量(起始) NS, CWR, ECE, URG, ACK, PSH, RST, SYN, FIN bool // 标志符 Window uint16 // 窗口 Checksum uint16 // 校验和 Urgent uint16 // 紧急指针 Options []TCPOption // 可选字段 Padding []byte // 填充 } type TCPOption struct { OptionType uint8 OptionLength uint8 OptionData []byte } func (T *TCP) LayerType() int { return LayerTypeTCP } // DecodeTCP ref: https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE#%E7%8A%B6%E6%80%81%E7%BC%96%E7%A0%81 // 解码TCP包,参考自wiki func DecodeTCP(data []byte) (*TCP, error) { if len(data) < 20 { return nil, fmt.Errorf("[TCP] 无效标头。长度 %d bytes,至少需要20 bytes", len(data)) } tcp := TCP{} tcp.SrcPort = binary.BigEndian.Uint16(data[0:2]) tcp.DstPort = binary.BigEndian.Uint16(data[2:4]) tcp.Seq = binary.BigEndian.Uint32(data[4:8]) tcp.Ack = binary.BigEndian.Uint32(data[8:12]) tcp.DataOffset = data[12] >> 4 { // 位运算取相得应的标志位 tcp.NS = data[12]&0x01 != 0 tcp.CWR = data[13]&0x80 != 0 tcp.ECE = data[13]&0x40 != 0 tcp.URG = data[13]&0x20 != 0 tcp.ACK = data[13]&0x10 != 0 tcp.PSH = data[13]&0x08 != 0 tcp.RST = data[13]&0x04 != 0 tcp.SYN = data[13]&0x02 != 0 tcp.FIN = data[13]&0x01 != 0 } tcp.Window = binary.BigEndian.Uint16(data[14:16]) tcp.Checksum = binary.BigEndian.Uint16(data[16:18]) tcp.Urgent = binary.BigEndian.Uint16(data[18:20]) dataStart := int(tcp.DataOffset) * 4 if dataStart > len(data) { return nil, errors.New("[TCP] 数据偏移大于数据包长度") } tcp.Header = data[:dataStart] tcp.Payload = data[dataStart:] // 20bytes固定头部往后到dataStart都是选项字段了 data = data[20:dataStart] // 解析可选字段 for len(data) > 0 { tcp.Options = append(tcp.Options, TCPOption{OptionType: data[0]}) opt := &tcp.Options[len(tcp.Options)-1] switch opt.OptionType { case TCPOptionKindEndList: // 选项表结束 opt.OptionLength = 1 opt.OptionData = []byte{0} tcp.Padding = data[1:] goto FINISH case TCPOptionKindNop: // 无操作(1字节),用于选项字段之间的字边界对齐。 opt.OptionLength = 1 opt.OptionData = []byte{0} data = data[opt.OptionLength:] default: if len(data) < 2 { return nil, fmt.Errorf("[TCP] 可选字段长度无效") } opt.OptionLength = data[1] if opt.OptionLength < 2 { return nil, fmt.Errorf("[TCP] 可选字段长度无效,%d < 2", opt.OptionLength) } else if int(opt.OptionLength) > len(data) { return nil, fmt.Errorf("[TCP] 无效可选字段长度: %d, 超出剩余的 %d 个字节", opt.OptionLength, len(data)) } opt.OptionData = data[2:opt.OptionLength] data = data[opt.OptionLength:] } } FINISH: return &tcp, nil }