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:
Leadaxe 2026-08-04 15:50:08 +03:00
commit 2c4ae3b0a4
712 changed files with 185689 additions and 0 deletions

View 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)
}