snapshot: sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
Содержимое пина, зафиксированного в go.mod sing-box-lx, одним коммитом без истории. Полная история SagerNet/gvisor — 1.45 ГБ и клонируется в каждой CI-джобе; наша дельта — одна вставка в одну функцию, история для неё не нужна. Module path github.com/sagernet/gvisor сохранён намеренно: на него опирается replace-директива суперпроекта. Патч поверх — отдельным коммитом, чтобы дельта читалась одним git show и переносилась на новый пин копированием. SPECS/TASKS/048-GVISOR_HANDSHAKE_NIL_CRASH
This commit is contained in:
commit
2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions
251
pkg/tcpip/transport/tcp/segment.go
Normal file
251
pkg/tcpip/transport/tcp/segment.go
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
// Copyright 2018 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/sync"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/seqnum"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// queueFlags are used to indicate which queue of an endpoint a particular segment
|
||||
// belongs to. This is used to track memory accounting correctly.
|
||||
type queueFlags uint8
|
||||
|
||||
const (
|
||||
// SegOverheadSize is the size of an empty seg in memory including packet
|
||||
// buffer overhead. It is advised to use SegOverheadSize instead of segSize
|
||||
// in all cases where accounting for segment memory overhead is important.
|
||||
SegOverheadSize = segSize + stack.PacketBufferStructSize + header.IPv4MaximumHeaderSize
|
||||
|
||||
recvQ queueFlags = 1 << iota
|
||||
sendQ
|
||||
)
|
||||
|
||||
var segmentPool = sync.Pool{
|
||||
New: func() any {
|
||||
return &segment{}
|
||||
},
|
||||
}
|
||||
|
||||
// segment represents a TCP segment. It holds the payload and parsed TCP segment
|
||||
// information, and can be added to intrusive lists.
|
||||
// segment is mostly immutable, the only field allowed to change is data.
|
||||
//
|
||||
// +stateify savable
|
||||
type segment struct {
|
||||
segmentEntry
|
||||
segmentRefs
|
||||
|
||||
ep *Endpoint
|
||||
qFlags queueFlags
|
||||
id stack.TransportEndpointID `state:"manual"`
|
||||
|
||||
pkt *stack.PacketBuffer
|
||||
|
||||
sequenceNumber seqnum.Value
|
||||
ackNumber seqnum.Value
|
||||
flags header.TCPFlags
|
||||
window seqnum.Size
|
||||
// csum is only populated for received segments.
|
||||
csum uint16
|
||||
// csumValid is true if the csum in the received segment is valid.
|
||||
csumValid bool
|
||||
|
||||
// parsedOptions stores the parsed values from the options in the segment.
|
||||
parsedOptions header.TCPOptions
|
||||
options []byte `state:".([]byte)"`
|
||||
hasNewSACKInfo bool
|
||||
rcvdTime tcpip.MonotonicTime
|
||||
// xmitTime is the last transmit time of this segment.
|
||||
xmitTime tcpip.MonotonicTime
|
||||
xmitCount uint32
|
||||
|
||||
// acked indicates if the segment has already been SACKed.
|
||||
acked bool
|
||||
|
||||
// dataMemSize is the memory used by pkt initially. The value is used for
|
||||
// memory accounting in the receive buffer instead of pkt.MemSize() because
|
||||
// packet contents can be modified, so relying on the computed memory size
|
||||
// to "free" reserved bytes could leak memory in the receiver.
|
||||
dataMemSize int
|
||||
|
||||
// lost indicates if the segment is marked as lost by RACK.
|
||||
lost bool
|
||||
}
|
||||
|
||||
func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) (*segment, error) {
|
||||
hdr := header.TCP(pkt.TransportHeader().Slice())
|
||||
var srcAddr tcpip.Address
|
||||
var dstAddr tcpip.Address
|
||||
switch netProto := pkt.NetworkProtocolNumber; netProto {
|
||||
case header.IPv4ProtocolNumber:
|
||||
hdr := header.IPv4(pkt.NetworkHeader().Slice())
|
||||
srcAddr = hdr.SourceAddress()
|
||||
dstAddr = hdr.DestinationAddress()
|
||||
case header.IPv6ProtocolNumber:
|
||||
hdr := header.IPv6(pkt.NetworkHeader().Slice())
|
||||
srcAddr = hdr.SourceAddress()
|
||||
dstAddr = hdr.DestinationAddress()
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown network protocol number %d", netProto))
|
||||
}
|
||||
|
||||
csum, csumValid, ok := header.TCPValid(
|
||||
hdr,
|
||||
func() uint16 { return pkt.Data().Checksum() },
|
||||
uint16(pkt.Data().Size()),
|
||||
srcAddr,
|
||||
dstAddr,
|
||||
pkt.RXChecksumValidated)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("header data offset does not respect size constraints: %d < offset < %d, got offset=%d", header.TCPMinimumSize, len(hdr), hdr.DataOffset())
|
||||
}
|
||||
|
||||
s := newSegment()
|
||||
s.id = id
|
||||
s.options = hdr[header.TCPMinimumSize:]
|
||||
s.parsedOptions = header.ParseTCPOptions(hdr[header.TCPMinimumSize:])
|
||||
s.sequenceNumber = seqnum.Value(hdr.SequenceNumber())
|
||||
s.ackNumber = seqnum.Value(hdr.AckNumber())
|
||||
s.flags = hdr.Flags()
|
||||
s.window = seqnum.Size(hdr.WindowSize())
|
||||
s.rcvdTime = clock.NowMonotonic()
|
||||
s.dataMemSize = pkt.MemSize()
|
||||
s.pkt = pkt.Clone()
|
||||
s.csumValid = csumValid
|
||||
|
||||
if !s.pkt.RXChecksumValidated {
|
||||
s.csum = csum
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, buf buffer.Buffer) *segment {
|
||||
s := newSegment()
|
||||
s.id = id
|
||||
s.rcvdTime = clock.NowMonotonic()
|
||||
s.pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf})
|
||||
s.dataMemSize = s.pkt.MemSize()
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *segment) clone() *segment {
|
||||
t := newSegment()
|
||||
t.id = s.id
|
||||
t.sequenceNumber = s.sequenceNumber
|
||||
t.ackNumber = s.ackNumber
|
||||
t.flags = s.flags
|
||||
t.window = s.window
|
||||
t.rcvdTime = s.rcvdTime
|
||||
t.xmitTime = s.xmitTime
|
||||
t.xmitCount = s.xmitCount
|
||||
t.ep = s.ep
|
||||
t.qFlags = s.qFlags
|
||||
t.dataMemSize = s.dataMemSize
|
||||
t.pkt = s.pkt.Clone()
|
||||
return t
|
||||
}
|
||||
|
||||
func newSegment() *segment {
|
||||
s := segmentPool.Get().(*segment)
|
||||
*s = segment{}
|
||||
s.InitRefs()
|
||||
return s
|
||||
}
|
||||
|
||||
// merge merges data in oth and clears oth.
|
||||
func (s *segment) merge(oth *segment) {
|
||||
s.pkt.Data().Merge(oth.pkt.Data())
|
||||
s.dataMemSize = s.pkt.MemSize()
|
||||
oth.dataMemSize = oth.pkt.MemSize()
|
||||
}
|
||||
|
||||
// setOwner sets the owning endpoint for this segment. Its required
|
||||
// to be called to ensure memory accounting for receive/send buffer
|
||||
// queues is done properly.
|
||||
func (s *segment) setOwner(ep *Endpoint, qFlags queueFlags) {
|
||||
switch qFlags {
|
||||
case recvQ:
|
||||
ep.updateReceiveMemUsed(s.segMemSize())
|
||||
case sendQ:
|
||||
// no memory account for sendQ yet.
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected queue flag %b", qFlags))
|
||||
}
|
||||
s.ep = ep
|
||||
s.qFlags = qFlags
|
||||
}
|
||||
|
||||
func (s *segment) DecRef() {
|
||||
s.segmentRefs.DecRef(func() {
|
||||
if s.ep != nil {
|
||||
switch s.qFlags {
|
||||
case recvQ:
|
||||
s.ep.updateReceiveMemUsed(-s.segMemSize())
|
||||
case sendQ:
|
||||
// no memory accounting for sendQ yet.
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected queue flag %b set for segment", s.qFlags))
|
||||
}
|
||||
}
|
||||
s.pkt.DecRef()
|
||||
s.pkt = nil
|
||||
segmentPool.Put(s)
|
||||
})
|
||||
}
|
||||
|
||||
// logicalLen is the segment length in the sequence number space. It's defined
|
||||
// as the data length plus one for each of the SYN and FIN bits set.
|
||||
func (s *segment) logicalLen() seqnum.Size {
|
||||
l := seqnum.Size(s.payloadSize())
|
||||
if s.flags.Contains(header.TCPFlagSyn) {
|
||||
l++
|
||||
}
|
||||
if s.flags.Contains(header.TCPFlagFin) {
|
||||
l++
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// payloadSize is the size of s.data.
|
||||
func (s *segment) payloadSize() int {
|
||||
return s.pkt.Data().Size()
|
||||
}
|
||||
|
||||
// segMemSize is the amount of memory used to hold the segment data and
|
||||
// the associated metadata.
|
||||
func (s *segment) segMemSize() int {
|
||||
return segSize + s.dataMemSize
|
||||
}
|
||||
|
||||
// sackBlock returns a header.SACKBlock that represents this segment.
|
||||
func (s *segment) sackBlock() header.SACKBlock {
|
||||
return header.SACKBlock{Start: s.sequenceNumber, End: s.sequenceNumber.Add(s.logicalLen())}
|
||||
}
|
||||
|
||||
func (s *segment) TrimFront(ackLeft seqnum.Size) {
|
||||
s.pkt.Data().TrimFront(int(ackLeft))
|
||||
}
|
||||
|
||||
func (s *segment) ReadTo(dst io.Writer, peek bool) (int, error) {
|
||||
return s.pkt.Data().ReadTo(dst, peek)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue