只是一个简单的计网课设
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.
eruhs/core/parser/tcp.go

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
}