snapshot: sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1 + SPEC 048 guard
Обновление снапшота с v0.0.0-20250811.0 на пин, которого требует sing-box после мержа 235 коммитов (upstream d620bbbf2 "Update gvisor to 20260727.0"). Прежний снапшот был взят 2026-08-04 ровно с той версии, на которой тогда стоял апстрим; разрыв возник 2026-08-05 вместе с его бампом. За год апстрим-gvisor изменил ~14 000 строк в 292 файлах. Значимое для нас — сетевой стек: tcp/connect.go (PMTU-discovery + исправление начального RTT/RTO: раньше задержка ACK внутри стека завышала стартовый таймаут на несколько RTT), tcp/snd.go, tcp/rcv.go, stack/conntrack.go, stack/packet_buffer.go. Всего 30 файлов в TCP и 37 в stack. Баг SPEC 048 апстрим НЕ исправил — проверено по коду новой версии: handleConnecting по-прежнему проверяет состояние endpoint'а, но не ep.h, а performHandshake так же зануляет h и отпускает мьютекс до Close(). Поэтому guard перенесён (12 строк) вместе со своим тестом (45 строк). Red/green проверен на новой базе: без guard'а тест падает с той же nil-паникой, что в полевом крашдампе; с ним зелёный.
This commit is contained in:
parent
ffebe42860
commit
117243aa02
293 changed files with 16413 additions and 2842 deletions
|
|
@ -654,11 +654,29 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r
|
|||
|
||||
case header.ICMPv6EchoRequest:
|
||||
received.echoRequest.Increment()
|
||||
if len(h) < header.ICMPv6EchoMinimumSize {
|
||||
received.invalid.Increment()
|
||||
replyPayload := pkt.Data().ToBuffer()
|
||||
replyHeader := make([]byte, header.ICMPv6EchoMinimumSize)
|
||||
copy(replyHeader, h[:header.ICMPv6EchoMinimumSize])
|
||||
|
||||
// It's possible that a raw socket or per-stack default handler expects
|
||||
// to receive this packet.
|
||||
defaultHandlerHandled := false
|
||||
if dispatcher, ok := e.dispatcher.(stack.TransportDispatcherWithDefaultHandlerResult); ok {
|
||||
_, defaultHandlerHandled = dispatcher.DeliverTransportPacketWithDefaultHandlerResult(header.ICMPv6ProtocolNumber, pkt)
|
||||
} else {
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt)
|
||||
}
|
||||
pkt = nil
|
||||
|
||||
// Skip the built-in ICMP echo reply if the request was consumed by a
|
||||
// per-stack default handler.
|
||||
if defaultHandlerHandled {
|
||||
replyPayload.Release()
|
||||
return
|
||||
}
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt)
|
||||
|
||||
e.sendICMPEchoReply(replyPayload, replyHeader, srcAddr, dstAddr, iph)
|
||||
|
||||
case header.ICMPv6EchoReply:
|
||||
received.echoReply.Increment()
|
||||
if len(h) < header.ICMPv6EchoMinimumSize {
|
||||
|
|
@ -666,6 +684,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r
|
|||
return
|
||||
}
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv6ProtocolNumber, pkt)
|
||||
|
||||
case header.ICMPv6TimeExceeded:
|
||||
received.timeExceeded.Increment()
|
||||
|
||||
|
|
@ -852,6 +871,62 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r
|
|||
}
|
||||
}
|
||||
|
||||
func (e *endpoint) sendICMPEchoReply(replyPayload buffer.Buffer, replyHeader []byte, srcAddr, dstAddr tcpip.Address, ipHdr header.IPv6) {
|
||||
sent := e.stats.icmp.packetsSent
|
||||
|
||||
// As per RFC 4291 section 2.7, multicast addresses must not be used as
|
||||
// source addresses in IPv6 packets.
|
||||
localAddr := dstAddr
|
||||
if header.IsV6MulticastAddress(dstAddr) {
|
||||
localAddr = tcpip.Address{}
|
||||
}
|
||||
|
||||
r, err := e.protocol.stack.FindRoute(e.nic.ID(), localAddr, srcAddr, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
// If we cannot find a route to the destination, silently drop the packet.
|
||||
replyPayload.Release()
|
||||
return
|
||||
}
|
||||
defer r.Release()
|
||||
|
||||
if !e.protocol.allowICMPReply(header.ICMPv6EchoReply) {
|
||||
sent.rateLimited.Increment()
|
||||
replyPayload.Release()
|
||||
return
|
||||
}
|
||||
|
||||
replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize,
|
||||
Payload: replyPayload,
|
||||
})
|
||||
defer replyPkt.DecRef()
|
||||
icmp := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize))
|
||||
replyPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
copy(icmp, replyHeader)
|
||||
icmp.SetType(header.ICMPv6EchoReply)
|
||||
replyData := replyPkt.Data()
|
||||
icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
|
||||
Header: icmp,
|
||||
Src: r.LocalAddress(),
|
||||
Dst: r.RemoteAddress(),
|
||||
PayloadCsum: replyData.Checksum(),
|
||||
PayloadLen: replyData.Size(),
|
||||
}))
|
||||
replyTClass, _ := ipHdr.TOS()
|
||||
if err := r.WritePacket(stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv6ProtocolNumber,
|
||||
TTL: r.DefaultTTL(),
|
||||
// Even though RFC 4443 does not mention anything about it, Linux uses the
|
||||
// TrafficClass of the received echo request when replying.
|
||||
// https://github.com/torvalds/linux/blob/0280e3c58f9/net/ipv6/icmp.c#L797
|
||||
TOS: replyTClass,
|
||||
}, replyPkt); err != nil {
|
||||
sent.dropped.Increment()
|
||||
return
|
||||
}
|
||||
sent.echoReply.Increment()
|
||||
}
|
||||
|
||||
// LinkAddressProtocol implements stack.LinkAddressResolver.
|
||||
func (*endpoint) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
return header.IPv6ProtocolNumber
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue