github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/tcpip/header/tcp.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package header
    16  
    17  import (
    18  	"encoding/binary"
    19  
    20  	"github.com/google/btree"
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/checksum"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/seqnum"
    24  )
    25  
    26  // These constants are the offsets of the respective fields in the TCP header.
    27  const (
    28  	TCPSrcPortOffset   = 0
    29  	TCPDstPortOffset   = 2
    30  	TCPSeqNumOffset    = 4
    31  	TCPAckNumOffset    = 8
    32  	TCPDataOffset      = 12
    33  	TCPFlagsOffset     = 13
    34  	TCPWinSizeOffset   = 14
    35  	TCPChecksumOffset  = 16
    36  	TCPUrgentPtrOffset = 18
    37  )
    38  
    39  const (
    40  	// MaxWndScale is maximum allowed window scaling, as described in
    41  	// RFC 1323, section 2.3, page 11.
    42  	MaxWndScale = 14
    43  
    44  	// TCPMaxSACKBlocks is the maximum number of SACK blocks that can
    45  	// be encoded in a TCP option field.
    46  	TCPMaxSACKBlocks = 4
    47  )
    48  
    49  // TCPFlags is the dedicated type for TCP flags.
    50  type TCPFlags uint8
    51  
    52  // Intersects returns true iff there are flags common to both f and o.
    53  func (f TCPFlags) Intersects(o TCPFlags) bool {
    54  	return f&o != 0
    55  }
    56  
    57  // Contains returns true iff all the flags in o are contained within f.
    58  func (f TCPFlags) Contains(o TCPFlags) bool {
    59  	return f&o == o
    60  }
    61  
    62  // String implements Stringer.String.
    63  func (f TCPFlags) String() string {
    64  	flagsStr := []byte("FSRPAUEC")
    65  	for i := range flagsStr {
    66  		if f&(1<<uint(i)) == 0 {
    67  			flagsStr[i] = ' '
    68  		}
    69  	}
    70  	return string(flagsStr)
    71  }
    72  
    73  // Flags that may be set in a TCP segment.
    74  const (
    75  	TCPFlagFin TCPFlags = 1 << iota
    76  	TCPFlagSyn
    77  	TCPFlagRst
    78  	TCPFlagPsh
    79  	TCPFlagAck
    80  	TCPFlagUrg
    81  	TCPFlagEce
    82  	TCPFlagCwr
    83  )
    84  
    85  // Options that may be present in a TCP segment.
    86  const (
    87  	TCPOptionEOL           = 0
    88  	TCPOptionNOP           = 1
    89  	TCPOptionMSS           = 2
    90  	TCPOptionWS            = 3
    91  	TCPOptionTS            = 8
    92  	TCPOptionSACKPermitted = 4
    93  	TCPOptionSACK          = 5
    94  )
    95  
    96  // Option Lengths.
    97  const (
    98  	TCPOptionMSSLength           = 4
    99  	TCPOptionTSLength            = 10
   100  	TCPOptionWSLength            = 3
   101  	TCPOptionSackPermittedLength = 2
   102  )
   103  
   104  // TCPFields contains the fields of a TCP packet. It is used to describe the
   105  // fields of a packet that needs to be encoded.
   106  type TCPFields struct {
   107  	// SrcPort is the "source port" field of a TCP packet.
   108  	SrcPort uint16
   109  
   110  	// DstPort is the "destination port" field of a TCP packet.
   111  	DstPort uint16
   112  
   113  	// SeqNum is the "sequence number" field of a TCP packet.
   114  	SeqNum uint32
   115  
   116  	// AckNum is the "acknowledgement number" field of a TCP packet.
   117  	AckNum uint32
   118  
   119  	// DataOffset is the "data offset" field of a TCP packet. It is the length of
   120  	// the TCP header in bytes.
   121  	DataOffset uint8
   122  
   123  	// Flags is the "flags" field of a TCP packet.
   124  	Flags TCPFlags
   125  
   126  	// WindowSize is the "window size" field of a TCP packet.
   127  	WindowSize uint16
   128  
   129  	// Checksum is the "checksum" field of a TCP packet.
   130  	Checksum uint16
   131  
   132  	// UrgentPointer is the "urgent pointer" field of a TCP packet.
   133  	UrgentPointer uint16
   134  }
   135  
   136  // TCPSynOptions is used to return the parsed TCP Options in a syn
   137  // segment.
   138  //
   139  // +stateify savable
   140  type TCPSynOptions struct {
   141  	// MSS is the maximum segment size provided by the peer in the SYN.
   142  	MSS uint16
   143  
   144  	// WS is the window scale option provided by the peer in the SYN.
   145  	//
   146  	// Set to -1 if no window scale option was provided.
   147  	WS int
   148  
   149  	// TS is true if the timestamp option was provided in the syn/syn-ack.
   150  	TS bool
   151  
   152  	// TSVal is the value of the TSVal field in the timestamp option.
   153  	TSVal uint32
   154  
   155  	// TSEcr is the value of the TSEcr field in the timestamp option.
   156  	TSEcr uint32
   157  
   158  	// SACKPermitted is true if the SACK option was provided in the SYN/SYN-ACK.
   159  	SACKPermitted bool
   160  
   161  	// Flags if specified are set on the outgoing SYN. The SYN flag is
   162  	// always set.
   163  	Flags TCPFlags
   164  }
   165  
   166  // SACKBlock represents a single contiguous SACK block.
   167  //
   168  // +stateify savable
   169  type SACKBlock struct {
   170  	// Start indicates the lowest sequence number in the block.
   171  	Start seqnum.Value
   172  
   173  	// End indicates the sequence number immediately following the last
   174  	// sequence number of this block.
   175  	End seqnum.Value
   176  }
   177  
   178  // Less returns true if r.Start < b.Start.
   179  func (r SACKBlock) Less(b btree.Item) bool {
   180  	return r.Start.LessThan(b.(SACKBlock).Start)
   181  }
   182  
   183  // Contains returns true if b is completely contained in r.
   184  func (r SACKBlock) Contains(b SACKBlock) bool {
   185  	return r.Start.LessThanEq(b.Start) && b.End.LessThanEq(r.End)
   186  }
   187  
   188  // TCPOptions are used to parse and cache the TCP segment options for a non
   189  // syn/syn-ack segment.
   190  //
   191  // +stateify savable
   192  type TCPOptions struct {
   193  	// TS is true if the TimeStamp option is enabled.
   194  	TS bool
   195  
   196  	// TSVal is the value in the TSVal field of the segment.
   197  	TSVal uint32
   198  
   199  	// TSEcr is the value in the TSEcr field of the segment.
   200  	TSEcr uint32
   201  
   202  	// SACKBlocks are the SACK blocks specified in the segment.
   203  	SACKBlocks []SACKBlock
   204  }
   205  
   206  // TCP represents a TCP header stored in a byte array.
   207  type TCP []byte
   208  
   209  const (
   210  	// TCPMinimumSize is the minimum size of a valid TCP packet.
   211  	TCPMinimumSize = 20
   212  
   213  	// TCPOptionsMaximumSize is the maximum size of TCP options.
   214  	TCPOptionsMaximumSize = 40
   215  
   216  	// TCPHeaderMaximumSize is the maximum header size of a TCP packet.
   217  	TCPHeaderMaximumSize = TCPMinimumSize + TCPOptionsMaximumSize
   218  
   219  	// TCPProtocolNumber is TCP's transport protocol number.
   220  	TCPProtocolNumber tcpip.TransportProtocolNumber = 6
   221  
   222  	// TCPMinimumMSS is the minimum acceptable value for MSS. This is the
   223  	// same as the value TCP_MIN_MSS defined net/tcp.h.
   224  	TCPMinimumMSS = IPv4MaximumHeaderSize + TCPHeaderMaximumSize + MinIPFragmentPayloadSize - IPv4MinimumSize - TCPMinimumSize
   225  
   226  	// TCPMinimumSendMSS is the minimum value for MSS in a sender. This is the
   227  	// same as the value TCP_MIN_SND_MSS in net/tcp.h.
   228  	TCPMinimumSendMSS = TCPOptionsMaximumSize + MinIPFragmentPayloadSize
   229  
   230  	// TCPMaximumMSS is the maximum acceptable value for MSS.
   231  	TCPMaximumMSS = 0xffff
   232  
   233  	// TCPDefaultMSS is the MSS value that should be used if an MSS option
   234  	// is not received from the peer. It's also the value returned by
   235  	// TCP_MAXSEG option for a socket in an unconnected state.
   236  	//
   237  	// Per RFC 1122, page 85: "If an MSS option is not received at
   238  	// connection setup, TCP MUST assume a default send MSS of 536."
   239  	TCPDefaultMSS = 536
   240  )
   241  
   242  // SourcePort returns the "source port" field of the TCP header.
   243  func (b TCP) SourcePort() uint16 {
   244  	return binary.BigEndian.Uint16(b[TCPSrcPortOffset:])
   245  }
   246  
   247  // DestinationPort returns the "destination port" field of the TCP header.
   248  func (b TCP) DestinationPort() uint16 {
   249  	return binary.BigEndian.Uint16(b[TCPDstPortOffset:])
   250  }
   251  
   252  // SequenceNumber returns the "sequence number" field of the TCP header.
   253  func (b TCP) SequenceNumber() uint32 {
   254  	return binary.BigEndian.Uint32(b[TCPSeqNumOffset:])
   255  }
   256  
   257  // AckNumber returns the "ack number" field of the TCP header.
   258  func (b TCP) AckNumber() uint32 {
   259  	return binary.BigEndian.Uint32(b[TCPAckNumOffset:])
   260  }
   261  
   262  // DataOffset returns the "data offset" field of the TCP header. The return
   263  // value is the length of the TCP header in bytes.
   264  func (b TCP) DataOffset() uint8 {
   265  	return (b[TCPDataOffset] >> 4) * 4
   266  }
   267  
   268  // Payload returns the data in the TCP packet.
   269  func (b TCP) Payload() []byte {
   270  	return b[b.DataOffset():]
   271  }
   272  
   273  // Flags returns the flags field of the TCP header.
   274  func (b TCP) Flags() TCPFlags {
   275  	return TCPFlags(b[TCPFlagsOffset])
   276  }
   277  
   278  // WindowSize returns the "window size" field of the TCP header.
   279  func (b TCP) WindowSize() uint16 {
   280  	return binary.BigEndian.Uint16(b[TCPWinSizeOffset:])
   281  }
   282  
   283  // Checksum returns the "checksum" field of the TCP header.
   284  func (b TCP) Checksum() uint16 {
   285  	return binary.BigEndian.Uint16(b[TCPChecksumOffset:])
   286  }
   287  
   288  // UrgentPointer returns the "urgent pointer" field of the TCP header.
   289  func (b TCP) UrgentPointer() uint16 {
   290  	return binary.BigEndian.Uint16(b[TCPUrgentPtrOffset:])
   291  }
   292  
   293  // SetSourcePort sets the "source port" field of the TCP header.
   294  func (b TCP) SetSourcePort(port uint16) {
   295  	binary.BigEndian.PutUint16(b[TCPSrcPortOffset:], port)
   296  }
   297  
   298  // SetDestinationPort sets the "destination port" field of the TCP header.
   299  func (b TCP) SetDestinationPort(port uint16) {
   300  	binary.BigEndian.PutUint16(b[TCPDstPortOffset:], port)
   301  }
   302  
   303  // SetChecksum sets the checksum field of the TCP header.
   304  func (b TCP) SetChecksum(xsum uint16) {
   305  	checksum.Put(b[TCPChecksumOffset:], xsum)
   306  }
   307  
   308  // SetDataOffset sets the data offset field of the TCP header. headerLen should
   309  // be the length of the TCP header in bytes.
   310  func (b TCP) SetDataOffset(headerLen uint8) {
   311  	b[TCPDataOffset] = (headerLen / 4) << 4
   312  }
   313  
   314  // SetSequenceNumber sets the sequence number field of the TCP header.
   315  func (b TCP) SetSequenceNumber(seqNum uint32) {
   316  	binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seqNum)
   317  }
   318  
   319  // SetAckNumber sets the ack number field of the TCP header.
   320  func (b TCP) SetAckNumber(ackNum uint32) {
   321  	binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ackNum)
   322  }
   323  
   324  // SetFlags sets the flags field of the TCP header.
   325  func (b TCP) SetFlags(flags uint8) {
   326  	b[TCPFlagsOffset] = flags
   327  }
   328  
   329  // SetWindowSize sets the window size field of the TCP header.
   330  func (b TCP) SetWindowSize(rcvwnd uint16) {
   331  	binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd)
   332  }
   333  
   334  // SetUrgentPointer sets the window size field of the TCP header.
   335  func (b TCP) SetUrgentPointer(urgentPointer uint16) {
   336  	binary.BigEndian.PutUint16(b[TCPUrgentPtrOffset:], urgentPointer)
   337  }
   338  
   339  // CalculateChecksum calculates the checksum of the TCP segment.
   340  // partialChecksum is the checksum of the network-layer pseudo-header
   341  // and the checksum of the segment data.
   342  func (b TCP) CalculateChecksum(partialChecksum uint16) uint16 {
   343  	// Calculate the rest of the checksum.
   344  	return checksum.Checksum(b[:b.DataOffset()], partialChecksum)
   345  }
   346  
   347  // IsChecksumValid returns true iff the TCP header's checksum is valid.
   348  func (b TCP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum, payloadLength uint16) bool {
   349  	xsum := PseudoHeaderChecksum(TCPProtocolNumber, src, dst, uint16(b.DataOffset())+payloadLength)
   350  	xsum = checksum.Combine(xsum, payloadChecksum)
   351  	return b.CalculateChecksum(xsum) == 0xffff
   352  }
   353  
   354  // Options returns a slice that holds the unparsed TCP options in the segment.
   355  func (b TCP) Options() []byte {
   356  	return b[TCPMinimumSize:b.DataOffset()]
   357  }
   358  
   359  // ParsedOptions returns a TCPOptions structure which parses and caches the TCP
   360  // option values in the TCP segment. NOTE: Invoking this function repeatedly is
   361  // expensive as it reparses the options on each invocation.
   362  func (b TCP) ParsedOptions() TCPOptions {
   363  	return ParseTCPOptions(b.Options())
   364  }
   365  
   366  func (b TCP) encodeSubset(seq, ack uint32, flags TCPFlags, rcvwnd uint16) {
   367  	binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seq)
   368  	binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ack)
   369  	b[TCPFlagsOffset] = uint8(flags)
   370  	binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd)
   371  }
   372  
   373  // Encode encodes all the fields of the TCP header.
   374  func (b TCP) Encode(t *TCPFields) {
   375  	b.encodeSubset(t.SeqNum, t.AckNum, t.Flags, t.WindowSize)
   376  	b.SetSourcePort(t.SrcPort)
   377  	b.SetDestinationPort(t.DstPort)
   378  	b.SetDataOffset(t.DataOffset)
   379  	b.SetChecksum(t.Checksum)
   380  	b.SetUrgentPointer(t.UrgentPointer)
   381  }
   382  
   383  // EncodePartial updates a subset of the fields of the TCP header. It is useful
   384  // in cases when similar segments are produced.
   385  func (b TCP) EncodePartial(partialChecksum, length uint16, seqnum, acknum uint32, flags TCPFlags, rcvwnd uint16) {
   386  	// Add the total length and "flags" field contributions to the checksum.
   387  	// We don't use the flags field directly from the header because it's a
   388  	// one-byte field with an odd offset, so it would be accounted for
   389  	// incorrectly by the Checksum routine.
   390  	tmp := make([]byte, 4)
   391  	binary.BigEndian.PutUint16(tmp, length)
   392  	binary.BigEndian.PutUint16(tmp[2:], uint16(flags))
   393  	xsum := checksum.Checksum(tmp, partialChecksum)
   394  
   395  	// Encode the passed-in fields.
   396  	b.encodeSubset(seqnum, acknum, flags, rcvwnd)
   397  
   398  	// Add the contributions of the passed-in fields to the checksum.
   399  	xsum = checksum.Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], xsum)
   400  	xsum = checksum.Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], xsum)
   401  
   402  	// Encode the checksum.
   403  	b.SetChecksum(^xsum)
   404  }
   405  
   406  // SetSourcePortWithChecksumUpdate implements ChecksummableTransport.
   407  func (b TCP) SetSourcePortWithChecksumUpdate(new uint16) {
   408  	old := b.SourcePort()
   409  	b.SetSourcePort(new)
   410  	b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
   411  }
   412  
   413  // SetDestinationPortWithChecksumUpdate implements ChecksummableTransport.
   414  func (b TCP) SetDestinationPortWithChecksumUpdate(new uint16) {
   415  	old := b.DestinationPort()
   416  	b.SetDestinationPort(new)
   417  	b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
   418  }
   419  
   420  // UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport.
   421  func (b TCP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) {
   422  	xsum := b.Checksum()
   423  	if fullChecksum {
   424  		xsum = ^xsum
   425  	}
   426  
   427  	xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new)
   428  	if fullChecksum {
   429  		xsum = ^xsum
   430  	}
   431  
   432  	b.SetChecksum(xsum)
   433  }
   434  
   435  // ParseSynOptions parses the options received in a SYN segment and returns the
   436  // relevant ones. opts should point to the option part of the TCP header.
   437  func ParseSynOptions(opts []byte, isAck bool) TCPSynOptions {
   438  	limit := len(opts)
   439  
   440  	synOpts := TCPSynOptions{
   441  		// Per RFC 1122, page 85: "If an MSS option is not received at
   442  		// connection setup, TCP MUST assume a default send MSS of 536."
   443  		MSS: TCPDefaultMSS,
   444  		// If no window scale option is specified, WS in options is
   445  		// returned as -1; this is because the absence of the option
   446  		// indicates that the we cannot use window scaling on the
   447  		// receive end either.
   448  		WS: -1,
   449  	}
   450  
   451  	for i := 0; i < limit; {
   452  		switch opts[i] {
   453  		case TCPOptionEOL:
   454  			i = limit
   455  		case TCPOptionNOP:
   456  			i++
   457  		case TCPOptionMSS:
   458  			if i+4 > limit || opts[i+1] != 4 {
   459  				return synOpts
   460  			}
   461  			mss := uint16(opts[i+2])<<8 | uint16(opts[i+3])
   462  			if mss == 0 {
   463  				return synOpts
   464  			}
   465  			synOpts.MSS = mss
   466  			if mss < TCPMinimumSendMSS {
   467  				synOpts.MSS = TCPMinimumSendMSS
   468  			}
   469  			i += 4
   470  
   471  		case TCPOptionWS:
   472  			if i+3 > limit || opts[i+1] != 3 {
   473  				return synOpts
   474  			}
   475  			ws := int(opts[i+2])
   476  			if ws > MaxWndScale {
   477  				ws = MaxWndScale
   478  			}
   479  			synOpts.WS = ws
   480  			i += 3
   481  
   482  		case TCPOptionTS:
   483  			if i+10 > limit || opts[i+1] != 10 {
   484  				return synOpts
   485  			}
   486  			synOpts.TSVal = binary.BigEndian.Uint32(opts[i+2:])
   487  			if isAck {
   488  				// If the segment is a SYN-ACK then store the Timestamp Echo Reply
   489  				// in the segment.
   490  				synOpts.TSEcr = binary.BigEndian.Uint32(opts[i+6:])
   491  			}
   492  			synOpts.TS = true
   493  			i += 10
   494  		case TCPOptionSACKPermitted:
   495  			if i+2 > limit || opts[i+1] != 2 {
   496  				return synOpts
   497  			}
   498  			synOpts.SACKPermitted = true
   499  			i += 2
   500  
   501  		default:
   502  			// We don't recognize this option, just skip over it.
   503  			if i+2 > limit {
   504  				return synOpts
   505  			}
   506  			l := int(opts[i+1])
   507  			// If the length is incorrect or if l+i overflows the
   508  			// total options length then return false.
   509  			if l < 2 || i+l > limit {
   510  				return synOpts
   511  			}
   512  			i += l
   513  		}
   514  	}
   515  
   516  	return synOpts
   517  }
   518  
   519  // ParseTCPOptions extracts and stores all known options in the provided byte
   520  // slice in a TCPOptions structure.
   521  func ParseTCPOptions(b []byte) TCPOptions {
   522  	opts := TCPOptions{}
   523  	limit := len(b)
   524  	for i := 0; i < limit; {
   525  		switch b[i] {
   526  		case TCPOptionEOL:
   527  			i = limit
   528  		case TCPOptionNOP:
   529  			i++
   530  		case TCPOptionTS:
   531  			if i+10 > limit || (b[i+1] != 10) {
   532  				return opts
   533  			}
   534  			opts.TS = true
   535  			opts.TSVal = binary.BigEndian.Uint32(b[i+2:])
   536  			opts.TSEcr = binary.BigEndian.Uint32(b[i+6:])
   537  			i += 10
   538  		case TCPOptionSACK:
   539  			if i+2 > limit {
   540  				// Malformed SACK block, just return and stop parsing.
   541  				return opts
   542  			}
   543  			sackOptionLen := int(b[i+1])
   544  			if i+sackOptionLen > limit || (sackOptionLen-2)%8 != 0 {
   545  				// Malformed SACK block, just return and stop parsing.
   546  				return opts
   547  			}
   548  			numBlocks := (sackOptionLen - 2) / 8
   549  			opts.SACKBlocks = []SACKBlock{}
   550  			for j := 0; j < numBlocks; j++ {
   551  				start := binary.BigEndian.Uint32(b[i+2+j*8:])
   552  				end := binary.BigEndian.Uint32(b[i+2+j*8+4:])
   553  				opts.SACKBlocks = append(opts.SACKBlocks, SACKBlock{
   554  					Start: seqnum.Value(start),
   555  					End:   seqnum.Value(end),
   556  				})
   557  			}
   558  			i += sackOptionLen
   559  		default:
   560  			// We don't recognize this option, just skip over it.
   561  			if i+2 > limit {
   562  				return opts
   563  			}
   564  			l := int(b[i+1])
   565  			// If the length is incorrect or if l+i overflows the
   566  			// total options length then return false.
   567  			if l < 2 || i+l > limit {
   568  				return opts
   569  			}
   570  			i += l
   571  		}
   572  	}
   573  	return opts
   574  }
   575  
   576  // EncodeMSSOption encodes the MSS TCP option with the provided MSS values in
   577  // the supplied buffer. If the provided buffer is not large enough then it just
   578  // returns without encoding anything. It returns the number of bytes written to
   579  // the provided buffer.
   580  func EncodeMSSOption(mss uint32, b []byte) int {
   581  	if len(b) < TCPOptionMSSLength {
   582  		return 0
   583  	}
   584  	b[0], b[1], b[2], b[3] = TCPOptionMSS, TCPOptionMSSLength, byte(mss>>8), byte(mss)
   585  	return TCPOptionMSSLength
   586  }
   587  
   588  // EncodeWSOption encodes the WS TCP option with the WS value in the
   589  // provided buffer. If the provided buffer is not large enough then it just
   590  // returns without encoding anything. It returns the number of bytes written to
   591  // the provided buffer.
   592  func EncodeWSOption(ws int, b []byte) int {
   593  	if len(b) < TCPOptionWSLength {
   594  		return 0
   595  	}
   596  	b[0], b[1], b[2] = TCPOptionWS, TCPOptionWSLength, uint8(ws)
   597  	return int(b[1])
   598  }
   599  
   600  // EncodeTSOption encodes the provided tsVal and tsEcr values as a TCP timestamp
   601  // option into the provided buffer. If the buffer is smaller than expected it
   602  // just returns without encoding anything. It returns the number of bytes
   603  // written to the provided buffer.
   604  func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int {
   605  	if len(b) < TCPOptionTSLength {
   606  		return 0
   607  	}
   608  	b[0], b[1] = TCPOptionTS, TCPOptionTSLength
   609  	binary.BigEndian.PutUint32(b[2:], tsVal)
   610  	binary.BigEndian.PutUint32(b[6:], tsEcr)
   611  	return int(b[1])
   612  }
   613  
   614  // EncodeSACKPermittedOption encodes a SACKPermitted option into the provided
   615  // buffer. If the buffer is smaller than required it just returns without
   616  // encoding anything. It returns the number of bytes written to the provided
   617  // buffer.
   618  func EncodeSACKPermittedOption(b []byte) int {
   619  	if len(b) < TCPOptionSackPermittedLength {
   620  		return 0
   621  	}
   622  
   623  	b[0], b[1] = TCPOptionSACKPermitted, TCPOptionSackPermittedLength
   624  	return int(b[1])
   625  }
   626  
   627  // EncodeSACKBlocks encodes the provided SACK blocks as a TCP SACK option block
   628  // in the provided slice. It tries to fit in as many blocks as possible based on
   629  // number of bytes available in the provided buffer. It returns the number of
   630  // bytes written to the provided buffer.
   631  func EncodeSACKBlocks(sackBlocks []SACKBlock, b []byte) int {
   632  	if len(sackBlocks) == 0 {
   633  		return 0
   634  	}
   635  	l := len(sackBlocks)
   636  	if l > TCPMaxSACKBlocks {
   637  		l = TCPMaxSACKBlocks
   638  	}
   639  	if ll := (len(b) - 2) / 8; ll < l {
   640  		l = ll
   641  	}
   642  	if l == 0 {
   643  		// There is not enough space in the provided buffer to add
   644  		// any SACK blocks.
   645  		return 0
   646  	}
   647  	b[0] = TCPOptionSACK
   648  	b[1] = byte(l*8 + 2)
   649  	for i := 0; i < l; i++ {
   650  		binary.BigEndian.PutUint32(b[i*8+2:], uint32(sackBlocks[i].Start))
   651  		binary.BigEndian.PutUint32(b[i*8+6:], uint32(sackBlocks[i].End))
   652  	}
   653  	return int(b[1])
   654  }
   655  
   656  // EncodeNOP adds an explicit NOP to the option list.
   657  func EncodeNOP(b []byte) int {
   658  	if len(b) == 0 {
   659  		return 0
   660  	}
   661  	b[0] = TCPOptionNOP
   662  	return 1
   663  }
   664  
   665  // AddTCPOptionPadding adds the required number of TCPOptionNOP to quad align
   666  // the option buffer. It adds padding bytes after the offset specified and
   667  // returns the number of padding bytes added. The passed in options slice
   668  // must have space for the padding bytes.
   669  func AddTCPOptionPadding(options []byte, offset int) int {
   670  	paddingToAdd := -offset & 3
   671  	// Now add any padding bytes that might be required to quad align the
   672  	// options.
   673  	for i := offset; i < offset+paddingToAdd; i++ {
   674  		options[i] = TCPOptionNOP
   675  	}
   676  	return paddingToAdd
   677  }
   678  
   679  // Acceptable checks if a segment that starts at segSeq and has length segLen is
   680  // "acceptable" for arriving in a receive window that starts at rcvNxt and ends
   681  // before rcvAcc, according to the table on page 26 and 69 of RFC 793.
   682  func Acceptable(segSeq seqnum.Value, segLen seqnum.Size, rcvNxt, rcvAcc seqnum.Value) bool {
   683  	if rcvNxt == rcvAcc {
   684  		return segLen == 0 && segSeq == rcvNxt
   685  	}
   686  	if segLen == 0 {
   687  		// rcvWnd is incremented by 1 because that is Linux's behavior despite the
   688  		// RFC.
   689  		return segSeq.InRange(rcvNxt, rcvAcc.Add(1))
   690  	}
   691  	// Page 70 of RFC 793 allows packets that can be made "acceptable" by trimming
   692  	// the payload, so we'll accept any payload that overlaps the receieve window.
   693  	// segSeq < rcvAcc is more correct according to RFC, however, Linux does it
   694  	// differently, it uses segSeq <= rcvAcc, we'd want to keep the same behavior
   695  	// as Linux.
   696  	return rcvNxt.LessThan(segSeq.Add(segLen)) && segSeq.LessThanEq(rcvAcc)
   697  }
   698  
   699  // TCPValid returns true if the pkt has a valid TCP header. It checks whether:
   700  //   - The data offset is too small.
   701  //   - The data offset is too large.
   702  //   - The checksum is invalid.
   703  //
   704  // TCPValid corresponds to net/netfilter/nf_conntrack_proto_tcp.c:tcp_error.
   705  func TCPValid(hdr TCP, payloadChecksum func() uint16, payloadSize uint16, srcAddr, dstAddr tcpip.Address, skipChecksumValidation bool) (csum uint16, csumValid, ok bool) {
   706  	if offset := int(hdr.DataOffset()); offset < TCPMinimumSize || offset > len(hdr) {
   707  		return
   708  	}
   709  
   710  	if skipChecksumValidation {
   711  		csumValid = true
   712  	} else {
   713  		csum = hdr.Checksum()
   714  		csumValid = hdr.IsChecksumValid(srcAddr, dstAddr, payloadChecksum(), payloadSize)
   715  	}
   716  	return csum, csumValid, true
   717  }