github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/tcpip/transport/tcp/segment.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 tcp
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/buffer"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/sync"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/header"
    25  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/seqnum"
    26  	"github.com/ttpreport/gvisor-ligolo/pkg/tcpip/stack"
    27  )
    28  
    29  // queueFlags are used to indicate which queue of an endpoint a particular segment
    30  // belongs to. This is used to track memory accounting correctly.
    31  type queueFlags uint8
    32  
    33  const (
    34  	// SegOverheadSize is the size of an empty seg in memory including packet
    35  	// buffer overhead. It is advised to use SegOverheadSize instead of segSize
    36  	// in all cases where accounting for segment memory overhead is important.
    37  	SegOverheadSize = segSize + stack.PacketBufferStructSize + header.IPv4MaximumHeaderSize
    38  
    39  	recvQ queueFlags = 1 << iota
    40  	sendQ
    41  )
    42  
    43  var segmentPool = sync.Pool{
    44  	New: func() any {
    45  		return &segment{}
    46  	},
    47  }
    48  
    49  // segment represents a TCP segment. It holds the payload and parsed TCP segment
    50  // information, and can be added to intrusive lists.
    51  // segment is mostly immutable, the only field allowed to change is data.
    52  //
    53  // +stateify savable
    54  type segment struct {
    55  	segmentEntry
    56  	segmentRefs
    57  
    58  	ep     *endpoint
    59  	qFlags queueFlags
    60  	id     stack.TransportEndpointID `state:"manual"`
    61  
    62  	pkt stack.PacketBufferPtr
    63  
    64  	sequenceNumber seqnum.Value
    65  	ackNumber      seqnum.Value
    66  	flags          header.TCPFlags
    67  	window         seqnum.Size
    68  	// csum is only populated for received segments.
    69  	csum uint16
    70  	// csumValid is true if the csum in the received segment is valid.
    71  	csumValid bool
    72  
    73  	// parsedOptions stores the parsed values from the options in the segment.
    74  	parsedOptions  header.TCPOptions
    75  	options        []byte `state:".([]byte)"`
    76  	hasNewSACKInfo bool
    77  	rcvdTime       tcpip.MonotonicTime
    78  	// xmitTime is the last transmit time of this segment.
    79  	xmitTime  tcpip.MonotonicTime
    80  	xmitCount uint32
    81  
    82  	// acked indicates if the segment has already been SACKed.
    83  	acked bool
    84  
    85  	// dataMemSize is the memory used by pkt initially. The value is used for
    86  	// memory accounting in the receive buffer instead of pkt.MemSize() because
    87  	// packet contents can be modified, so relying on the computed memory size
    88  	// to "free" reserved bytes could leak memory in the receiver.
    89  	dataMemSize int
    90  
    91  	// lost indicates if the segment is marked as lost by RACK.
    92  	lost bool
    93  }
    94  
    95  func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt stack.PacketBufferPtr) (*segment, error) {
    96  	hdr := header.TCP(pkt.TransportHeader().Slice())
    97  	netHdr := pkt.Network()
    98  	csum, csumValid, ok := header.TCPValid(
    99  		hdr,
   100  		func() uint16 { return pkt.Data().Checksum() },
   101  		uint16(pkt.Data().Size()),
   102  		netHdr.SourceAddress(),
   103  		netHdr.DestinationAddress(),
   104  		pkt.RXChecksumValidated)
   105  	if !ok {
   106  		return nil, fmt.Errorf("header data offset does not respect size constraints: %d < offset < %d, got offset=%d", header.TCPMinimumSize, len(hdr), hdr.DataOffset())
   107  	}
   108  
   109  	s := newSegment()
   110  	s.id = id
   111  	s.options = hdr[header.TCPMinimumSize:]
   112  	s.parsedOptions = header.ParseTCPOptions(hdr[header.TCPMinimumSize:])
   113  	s.sequenceNumber = seqnum.Value(hdr.SequenceNumber())
   114  	s.ackNumber = seqnum.Value(hdr.AckNumber())
   115  	s.flags = hdr.Flags()
   116  	s.window = seqnum.Size(hdr.WindowSize())
   117  	s.rcvdTime = clock.NowMonotonic()
   118  	s.dataMemSize = pkt.MemSize()
   119  	s.pkt = pkt.IncRef()
   120  	s.csumValid = csumValid
   121  
   122  	if !s.pkt.RXChecksumValidated {
   123  		s.csum = csum
   124  	}
   125  	return s, nil
   126  }
   127  
   128  func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, buf buffer.Buffer) *segment {
   129  	s := newSegment()
   130  	s.id = id
   131  	s.rcvdTime = clock.NowMonotonic()
   132  	s.pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf})
   133  	s.dataMemSize = s.pkt.MemSize()
   134  	return s
   135  }
   136  
   137  func (s *segment) clone() *segment {
   138  	t := newSegment()
   139  	t.id = s.id
   140  	t.sequenceNumber = s.sequenceNumber
   141  	t.ackNumber = s.ackNumber
   142  	t.flags = s.flags
   143  	t.window = s.window
   144  	t.rcvdTime = s.rcvdTime
   145  	t.xmitTime = s.xmitTime
   146  	t.xmitCount = s.xmitCount
   147  	t.ep = s.ep
   148  	t.qFlags = s.qFlags
   149  	t.dataMemSize = s.dataMemSize
   150  	t.pkt = s.pkt.Clone()
   151  	return t
   152  }
   153  
   154  func newSegment() *segment {
   155  	s := segmentPool.Get().(*segment)
   156  	*s = segment{}
   157  	s.InitRefs()
   158  	return s
   159  }
   160  
   161  // merge merges data in oth and clears oth.
   162  func (s *segment) merge(oth *segment) {
   163  	s.pkt.Data().Merge(oth.pkt.Data())
   164  	s.dataMemSize = s.pkt.MemSize()
   165  	oth.dataMemSize = oth.pkt.MemSize()
   166  }
   167  
   168  // setOwner sets the owning endpoint for this segment. Its required
   169  // to be called to ensure memory accounting for receive/send buffer
   170  // queues is done properly.
   171  func (s *segment) setOwner(ep *endpoint, qFlags queueFlags) {
   172  	switch qFlags {
   173  	case recvQ:
   174  		ep.updateReceiveMemUsed(s.segMemSize())
   175  	case sendQ:
   176  		// no memory account for sendQ yet.
   177  	default:
   178  		panic(fmt.Sprintf("unexpected queue flag %b", qFlags))
   179  	}
   180  	s.ep = ep
   181  	s.qFlags = qFlags
   182  }
   183  
   184  func (s *segment) DecRef() {
   185  	s.segmentRefs.DecRef(func() {
   186  		if s.ep != nil {
   187  			switch s.qFlags {
   188  			case recvQ:
   189  				s.ep.updateReceiveMemUsed(-s.segMemSize())
   190  			case sendQ:
   191  				// no memory accounting for sendQ yet.
   192  			default:
   193  				panic(fmt.Sprintf("unexpected queue flag %b set for segment", s.qFlags))
   194  			}
   195  		}
   196  		s.pkt.DecRef()
   197  		s.pkt = nil
   198  		segmentPool.Put(s)
   199  	})
   200  }
   201  
   202  // logicalLen is the segment length in the sequence number space. It's defined
   203  // as the data length plus one for each of the SYN and FIN bits set.
   204  func (s *segment) logicalLen() seqnum.Size {
   205  	l := seqnum.Size(s.payloadSize())
   206  	if s.flags.Contains(header.TCPFlagSyn) {
   207  		l++
   208  	}
   209  	if s.flags.Contains(header.TCPFlagFin) {
   210  		l++
   211  	}
   212  	return l
   213  }
   214  
   215  // payloadSize is the size of s.data.
   216  func (s *segment) payloadSize() int {
   217  	return s.pkt.Data().Size()
   218  }
   219  
   220  // segMemSize is the amount of memory used to hold the segment data and
   221  // the associated metadata.
   222  func (s *segment) segMemSize() int {
   223  	return segSize + s.dataMemSize
   224  }
   225  
   226  // sackBlock returns a header.SACKBlock that represents this segment.
   227  func (s *segment) sackBlock() header.SACKBlock {
   228  	return header.SACKBlock{Start: s.sequenceNumber, End: s.sequenceNumber.Add(s.logicalLen())}
   229  }
   230  
   231  func (s *segment) TrimFront(ackLeft seqnum.Size) {
   232  	s.pkt.Data().TrimFront(int(ackLeft))
   233  }
   234  
   235  func (s *segment) ReadTo(dst io.Writer, peek bool) (int, error) {
   236  	return s.pkt.Data().ReadTo(dst, peek)
   237  }