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