You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
4.3 KiB
117 lines
4.3 KiB
8 months ago
|
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
|
||
|
}
|