github.com/20yyq/packet@v0.1.4-0.20231013092308-386a004a3baa/tcp.go (about)

     1  // @@
     2  // @ Author       : Eacher
     3  // @ Date         : 2023-07-14 08:11:29
     4  // @ LastEditTime : 2023-09-04 09:40:14
     5  // @ LastEditors  : Eacher
     6  // @ --------------------------------------------------------------------------------<
     7  // @ Description  : 
     8  // @ --------------------------------------------------------------------------------<
     9  // @ FilePath     : /20yyq/packet/tcp.go
    10  // @@
    11  package packet
    12  
    13  import (
    14  	"encoding/binary"
    15  )
    16  
    17  const (
    18  	SizeofTCPPacket = 0x14
    19  )
    20  
    21  /*
    22  
    23  // 来源: https://support.huawei.com/enterprise/zh/doc/EDOC1100174722?section=j006
    24  
    25      0                   1                   2                   3
    26      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    27     +-------------------------------+-------------------------------+
    28     |          Source Port          |       Destination Port        |
    29     +-------------------------------+-------------------------------+
    30     |                        Sequence Number                        |
    31     +---------------------------------------------------------------+
    32     |                    Acknowledgment Number                      |
    33     +-------+-----------+-+-+-+-+-+-+-------------------------------+
    34     |  Data |           |U|A|P|R|S|F|                               |
    35     | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
    36     |       |           |G|K|H|T|N|N|                               |
    37     +-------+-----------+-+-+-+-+-+-+-------------------------------+
    38     |           Checksum            |         Urgent Pointer        |
    39     +-------------------------------+---------------+---------------+
    40     |                    Options                    |    Padding    |
    41     +-----------------------------------------------+---------------+
    42     |                             data                              |
    43     +---------------------------------------------------------------+
    44  
    45  	字段				长度		含义
    46  Source Port			16比特	源端口,标识哪个应用程序发送。
    47  Destination Port	16比特	目的端口,标识哪个应用程序接收。
    48  Sequence Number		32比特	序号字段。TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。
    49  Acknowledgment Number	32比特	确认号,是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效。
    50  Data Offset			4比特	数据偏移,即首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节。
    51  Reserved			6比特	保留,必须填0。
    52  URG					1比特	紧急指针有效标识。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
    53  ACK					1比特	确认序号有效标识。只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。
    54  PSH					1比特	标识接收方应该尽快将这个报文段交给应用层。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付。
    55  RST					1比特	重建连接标识。当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接。
    56  SYN					1比特	同步序号标识,用来发起一个连接。SYN=1表示这是一个连接请求或连接接受请求。
    57  FIN					1比特	发端完成发送任务标识。用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接。
    58  Window				16比特	窗口:TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端期望接收的字节数。窗口最大为65535字节。
    59  Checksum			16比特	校验字段,包括TCP首部和TCP数据,是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
    60  Urgent Pointer		16比特	紧急指针,只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
    61  Options				可变		选项字段。TCP协议最初只规定了一种选项,即最长报文段长度(只包含数据字段,不包括TCP首部),又称为MSS。MSS告诉对方TCP“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节”。
    62  							新的RFC规定有以下几种选型:选项表结束,空操作,最大报文段长度,窗口扩大因子,时间戳。
    63  								选项表结束。
    64  								空操作:没有特殊含义,一般用于将TCP选项的总长度填充为4字节的整数倍。
    65  								最大报文段长度:又称为MSS,只包含数据字段,不包括TCP首部。
    66  								窗口扩大因子:3字节,其中一个字节表示偏移值S。新的窗口值等于TCP首部中的窗口位数增大到(16+S),相当于把窗口值向左移动S位后获得实际的窗口大小。
    67  								时间戳:10字节,其中最主要的字段是时间戳值(4字节)和时间戳回送应答字段(4字节)。
    68  Padding				可变		填充字段,用来补位,使整个首部长度是4字节的整数倍。
    69   */
    70  type TCPPacket struct {
    71  	SrcPort 	uint16
    72  	DstPort 	uint16
    73  	Sequence 	uint32
    74  	AckNum 		uint32
    75  	orgBites 	uint16
    76  	Window 		uint16
    77  	CheckSum 	uint16
    78  	UrgentPtr 	uint16
    79  
    80  	DataOffset  uint8
    81  	Reserved  	uint8
    82  	URG  		bool
    83  	ACK  		bool
    84  	PSH  		bool
    85  	RST  		bool
    86  	SYN  		bool
    87  	FIN  		bool
    88  	Options 	[]byte
    89  }
    90  
    91  // 14.byte  EthernetPacket
    92  // 20.byte  IPv4Packet 或者 IPv6Packet
    93  // 返回负载下标起始位
    94  func NewTCPPacket(b []byte) (tcp TCPPacket, next uint8) {
    95  	if len(b) < SizeofTCPPacket {
    96  		return
    97  	}
    98  	tcp.SrcPort 	= binary.BigEndian.Uint16(b[:2])
    99  	tcp.DstPort 	= binary.BigEndian.Uint16(b[2:4])
   100  	tcp.Sequence 	= binary.BigEndian.Uint32(b[4:8])
   101  	tcp.AckNum 		= binary.BigEndian.Uint32(b[8:12])
   102  	tcp.orgBites 	= binary.BigEndian.Uint16(b[12:14])
   103  	tcp.Window 		= binary.BigEndian.Uint16(b[14:16])
   104  	tcp.CheckSum 	= binary.BigEndian.Uint16(b[16:18])
   105  	tcp.UrgentPtr 	= binary.BigEndian.Uint16(b[18:20])
   106  	tcp.DataOffset, next = uint8(tcp.orgBites & 0b1111000000000000 >> 10), SizeofTCPPacket
   107  	if tcp.DataOffset < SizeofTCPPacket || len(b) < int(tcp.DataOffset) {
   108  		tcp, next = TCPPacket{}, 0
   109  		return
   110  	}
   111  	if tcp.DataOffset > SizeofTCPPacket {
   112  		tcp.Options, next = make([]byte, tcp.DataOffset - SizeofTCPPacket), tcp.DataOffset
   113  		copy(tcp.Options, b[SizeofTCPPacket:tcp.DataOffset])
   114  	}
   115  	tcp.URG = (tcp.orgBites & 0b0000000000100000) != 0
   116  	tcp.ACK = (tcp.orgBites & 0b0000000000010000) != 0
   117  	tcp.PSH = (tcp.orgBites & 0b0000000000001000) != 0
   118  	tcp.RST = (tcp.orgBites & 0b0000000000000100) != 0
   119  	tcp.SYN = (tcp.orgBites & 0b0000000000000010) != 0
   120  	tcp.FIN = (tcp.orgBites & 0b0000000000000001) != 0
   121  	return
   122  }
   123  
   124  func (tcp TCPPacket) WireFormat() []byte {
   125  	opLen := len(tcp.Options)
   126  	if opLen > 40 {
   127  		return nil
   128  	}
   129  	b := make([]byte, SizeofTCPPacket + opLen)
   130  	if opLen > 0 {
   131  		copy(b[SizeofTCPPacket:], tcp.Options)
   132  		b = append(b, make([]byte, opLen % 4)...)
   133  	}
   134  	binary.BigEndian.PutUint16(b[:2], tcp.SrcPort)
   135  	binary.BigEndian.PutUint16(b[2:4], tcp.DstPort)
   136  	binary.BigEndian.PutUint32(b[4:8], tcp.Sequence)
   137  	binary.BigEndian.PutUint32(b[8:12], tcp.AckNum)
   138  	var tmp uint16
   139  	tmp = uint16(tcp.DataOffset >> 2)
   140  	if tcp.URG {
   141  		tmp |= 0b0000000000100000
   142  	}
   143  	if tcp.ACK {
   144  		tmp |= 0b0000000000010000
   145  	}
   146  	if tcp.PSH {
   147  		tmp |= 0b0000000000001000
   148  	}
   149  	if tcp.RST {
   150  		tmp |= 0b0000000000000100
   151  	}
   152  	if tcp.SYN {
   153  		tmp |= 0b0000000000000010
   154  	}
   155  	if tcp.FIN {
   156  		tmp |= 0b0000000000000001
   157  	}
   158  	binary.BigEndian.PutUint16(b[12:14], tmp)
   159  	binary.BigEndian.PutUint16(b[14:16], tcp.Window)
   160  	binary.BigEndian.PutUint16(b[16:18], tcp.CheckSum)
   161  	binary.BigEndian.PutUint16(b[18:20], tcp.UrgentPtr)
   162  	return b
   163  }