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
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
// Code generated by "stringer -type DHCPv6ConfigurationFromNDPRA"; DO NOT EDIT.
|
||||
|
||||
package ipv6
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[DHCPv6NoConfiguration-1]
|
||||
_ = x[DHCPv6ManagedAddress-2]
|
||||
_ = x[DHCPv6OtherConfigurations-3]
|
||||
}
|
||||
|
||||
const _DHCPv6ConfigurationFromNDPRA_name = "DHCPv6NoConfigurationDHCPv6ManagedAddressDHCPv6OtherConfigurations"
|
||||
|
||||
var _DHCPv6ConfigurationFromNDPRA_index = [...]uint8{0, 21, 41, 66}
|
||||
|
||||
func (i DHCPv6ConfigurationFromNDPRA) String() string {
|
||||
i -= 1
|
||||
if i < 0 || i >= DHCPv6ConfigurationFromNDPRA(len(_DHCPv6ConfigurationFromNDPRA_index)-1) {
|
||||
return "DHCPv6ConfigurationFromNDPRA(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _DHCPv6ConfigurationFromNDPRA_name[_DHCPv6ConfigurationFromNDPRA_index[i]:_DHCPv6ConfigurationFromNDPRA_index[i+1]]
|
||||
}
|
||||
1184
pkg/tcpip/network/ipv6/icmp.go
Normal file
1184
pkg/tcpip/network/ipv6/icmp.go
Normal file
File diff suppressed because it is too large
Load diff
2875
pkg/tcpip/network/ipv6/ipv6.go
Normal file
2875
pkg/tcpip/network/ipv6/ipv6.go
Normal file
File diff suppressed because it is too large
Load diff
14
pkg/tcpip/network/ipv6/ipv6_export.go
Normal file
14
pkg/tcpip/network/ipv6/ipv6_export.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package ipv6
|
||||
|
||||
import (
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
type ExportedEndpoint interface {
|
||||
WritePacketDirect(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error
|
||||
}
|
||||
|
||||
func (e *endpoint) WritePacketDirect(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error {
|
||||
return e.writePacket(r, pkt, pkt.TransportProtocolNumber, true)
|
||||
}
|
||||
1049
pkg/tcpip/network/ipv6/ipv6_state_autogen.go
Normal file
1049
pkg/tcpip/network/ipv6/ipv6_state_autogen.go
Normal file
File diff suppressed because it is too large
Load diff
478
pkg/tcpip/network/ipv6/mld.go
Normal file
478
pkg/tcpip/network/ipv6/mld.go
Normal file
|
|
@ -0,0 +1,478 @@
|
|||
// Copyright 2020 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 ipv6
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/internal/ip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
const (
|
||||
// UnsolicitedReportIntervalMax is the maximum delay between sending
|
||||
// unsolicited MLD reports.
|
||||
//
|
||||
// Obtained from RFC 2710 Section 7.10.
|
||||
UnsolicitedReportIntervalMax = 10 * time.Second
|
||||
)
|
||||
|
||||
// MLDVersion is the forced version of MLD.
|
||||
type MLDVersion int
|
||||
|
||||
const (
|
||||
_ MLDVersion = iota
|
||||
// MLDVersion1 indicates MLDv1.
|
||||
MLDVersion1
|
||||
// MLDVersion2 indicates MLDv2. Note that MLD may still fallback to V1
|
||||
// compatibility mode as required by MLDv2.
|
||||
MLDVersion2
|
||||
)
|
||||
|
||||
// MLDEndpoint is a network endpoint that supports MLD.
|
||||
type MLDEndpoint interface {
|
||||
// SetMLDVersions sets the MLD version.
|
||||
//
|
||||
// Returns the previous MLD version.
|
||||
SetMLDVersion(MLDVersion) MLDVersion
|
||||
|
||||
// GetMLDVersion returns the MLD version.
|
||||
GetMLDVersion() MLDVersion
|
||||
}
|
||||
|
||||
// MLDOptions holds options for MLD.
|
||||
//
|
||||
// +stateify savable
|
||||
type MLDOptions struct {
|
||||
// Enabled indicates whether MLD will be performed.
|
||||
//
|
||||
// When enabled, MLD may transmit MLD report and done messages when
|
||||
// joining and leaving multicast groups respectively, and handle incoming
|
||||
// MLD packets.
|
||||
//
|
||||
// This field is ignored and is always assumed to be false for interfaces
|
||||
// without neighbouring nodes (e.g. loopback).
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
var _ ip.MulticastGroupProtocol = (*mldState)(nil)
|
||||
|
||||
// mldState is the per-interface MLD state.
|
||||
//
|
||||
// mldState.init MUST be called to initialize the MLD state.
|
||||
//
|
||||
// +stateify savable
|
||||
type mldState struct {
|
||||
// The IPv6 endpoint this mldState is for.
|
||||
ep *endpoint
|
||||
|
||||
genericMulticastProtocol ip.GenericMulticastProtocolState
|
||||
}
|
||||
|
||||
// Enabled implements ip.MulticastGroupProtocol.
|
||||
func (mld *mldState) Enabled() bool {
|
||||
// No need to perform MLD on loopback interfaces since they don't have
|
||||
// neighbouring nodes.
|
||||
return mld.ep.protocol.options.MLD.Enabled && !mld.ep.nic.IsLoopback() && mld.ep.Enabled()
|
||||
}
|
||||
|
||||
// SendReport implements ip.MulticastGroupProtocol.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be read locked.
|
||||
func (mld *mldState) SendReport(groupAddress tcpip.Address) (bool, tcpip.Error) {
|
||||
return mld.writePacket(groupAddress, groupAddress, header.ICMPv6MulticastListenerReport)
|
||||
}
|
||||
|
||||
// SendLeave implements ip.MulticastGroupProtocol.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be read locked.
|
||||
func (mld *mldState) SendLeave(groupAddress tcpip.Address) tcpip.Error {
|
||||
_, err := mld.writePacket(header.IPv6AllRoutersLinkLocalMulticastAddress, groupAddress, header.ICMPv6MulticastListenerDone)
|
||||
return err
|
||||
}
|
||||
|
||||
// ShouldPerformProtocol implements ip.MulticastGroupProtocol.
|
||||
func (mld *mldState) ShouldPerformProtocol(groupAddress tcpip.Address) bool {
|
||||
// As per RFC 2710 section 5 page 10,
|
||||
//
|
||||
// The link-scope all-nodes address (FF02::1) is handled as a special
|
||||
// case. The node starts in Idle Listener state for that address on
|
||||
// every interface, never transitions to another state, and never sends
|
||||
// a Report or Done for that address.
|
||||
//
|
||||
// MLD messages are never sent for multicast addresses whose scope is 0
|
||||
// (reserved) or 1 (node-local).
|
||||
if groupAddress == header.IPv6AllNodesMulticastAddress {
|
||||
return false
|
||||
}
|
||||
|
||||
scope := header.V6MulticastScope(groupAddress)
|
||||
return scope != header.IPv6Reserved0MulticastScope && scope != header.IPv6InterfaceLocalMulticastScope
|
||||
}
|
||||
|
||||
type mldv2ReportBuilder struct {
|
||||
mld *mldState
|
||||
|
||||
records []header.MLDv2ReportMulticastAddressRecordSerializer
|
||||
}
|
||||
|
||||
// AddRecord implements ip.MulticastGroupProtocolV2ReportBuilder.
|
||||
func (b *mldv2ReportBuilder) AddRecord(genericRecordType ip.MulticastGroupProtocolV2ReportRecordType, groupAddress tcpip.Address) {
|
||||
var recordType header.MLDv2ReportRecordType
|
||||
switch genericRecordType {
|
||||
case ip.MulticastGroupProtocolV2ReportRecordModeIsInclude:
|
||||
recordType = header.MLDv2ReportRecordModeIsInclude
|
||||
case ip.MulticastGroupProtocolV2ReportRecordModeIsExclude:
|
||||
recordType = header.MLDv2ReportRecordModeIsExclude
|
||||
case ip.MulticastGroupProtocolV2ReportRecordChangeToIncludeMode:
|
||||
recordType = header.MLDv2ReportRecordChangeToIncludeMode
|
||||
case ip.MulticastGroupProtocolV2ReportRecordChangeToExcludeMode:
|
||||
recordType = header.MLDv2ReportRecordChangeToExcludeMode
|
||||
case ip.MulticastGroupProtocolV2ReportRecordAllowNewSources:
|
||||
recordType = header.MLDv2ReportRecordAllowNewSources
|
||||
case ip.MulticastGroupProtocolV2ReportRecordBlockOldSources:
|
||||
recordType = header.MLDv2ReportRecordBlockOldSources
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognied genericRecordType = %d", genericRecordType))
|
||||
}
|
||||
|
||||
b.records = append(b.records, header.MLDv2ReportMulticastAddressRecordSerializer{
|
||||
RecordType: recordType,
|
||||
MulticastAddress: groupAddress,
|
||||
Sources: nil,
|
||||
})
|
||||
}
|
||||
|
||||
// Send implements ip.MulticastGroupProtocolV2ReportBuilder.
|
||||
func (b *mldv2ReportBuilder) Send() (sent bool, err tcpip.Error) {
|
||||
if len(b.records) == 0 {
|
||||
return false, err
|
||||
}
|
||||
|
||||
extensionHeaders := header.IPv6ExtHdrSerializer{
|
||||
header.IPv6SerializableHopByHopExtHdr{
|
||||
&header.IPv6RouterAlertOption{Value: header.IPv6RouterAlertMLD},
|
||||
},
|
||||
}
|
||||
mtu := int(b.mld.ep.MTU()) - extensionHeaders.Length()
|
||||
|
||||
allSentWithSpecifiedAddress := true
|
||||
var firstErr tcpip.Error
|
||||
for records := b.records; len(records) != 0; {
|
||||
spaceLeft := mtu
|
||||
maxRecords := 0
|
||||
|
||||
for ; maxRecords < len(records); maxRecords++ {
|
||||
tmp := spaceLeft - records[maxRecords].Length()
|
||||
if tmp > 0 {
|
||||
spaceLeft = tmp
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
serializer := header.MLDv2ReportSerializer{Records: records[:maxRecords]}
|
||||
records = records[maxRecords:]
|
||||
|
||||
icmpView := buffer.NewViewSize(header.ICMPv6HeaderSize + serializer.Length())
|
||||
icmp := header.ICMPv6(icmpView.AsSlice())
|
||||
serializer.SerializeInto(icmp.MessageBody())
|
||||
if sentWithSpecifiedAddress, err := b.mld.writePacketInner(
|
||||
icmpView,
|
||||
header.ICMPv6MulticastListenerV2Report,
|
||||
b.mld.ep.stats.icmp.packetsSent.multicastListenerReportV2,
|
||||
extensionHeaders,
|
||||
header.MLDv2RoutersAddress,
|
||||
); err != nil {
|
||||
if firstErr != nil {
|
||||
firstErr = nil
|
||||
}
|
||||
allSentWithSpecifiedAddress = false
|
||||
} else if !sentWithSpecifiedAddress {
|
||||
allSentWithSpecifiedAddress = false
|
||||
}
|
||||
}
|
||||
|
||||
return allSentWithSpecifiedAddress, firstErr
|
||||
}
|
||||
|
||||
// NewReportV2Builder implements ip.MulticastGroupProtocol.
|
||||
func (mld *mldState) NewReportV2Builder() ip.MulticastGroupProtocolV2ReportBuilder {
|
||||
return &mldv2ReportBuilder{mld: mld}
|
||||
}
|
||||
|
||||
// V2QueryMaxRespCodeToV2Delay implements ip.MulticastGroupProtocol.
|
||||
func (*mldState) V2QueryMaxRespCodeToV2Delay(code uint16) time.Duration {
|
||||
return header.MLDv2MaximumResponseDelay(code)
|
||||
}
|
||||
|
||||
// V2QueryMaxRespCodeToV1Delay implements ip.MulticastGroupProtocol.
|
||||
func (*mldState) V2QueryMaxRespCodeToV1Delay(code uint16) time.Duration {
|
||||
return time.Duration(code) * time.Millisecond
|
||||
}
|
||||
|
||||
// init sets up an mldState struct, and is required to be called before using
|
||||
// a new mldState.
|
||||
//
|
||||
// Must only be called once for the lifetime of mld.
|
||||
func (mld *mldState) init(ep *endpoint) {
|
||||
mld.ep = ep
|
||||
mld.genericMulticastProtocol.Init(&ep.mu.RWMutex, ip.GenericMulticastProtocolOptions{
|
||||
Rand: ep.protocol.stack.InsecureRNG(),
|
||||
Clock: ep.protocol.stack.Clock(),
|
||||
Protocol: mld,
|
||||
MaxUnsolicitedReportDelay: UnsolicitedReportIntervalMax,
|
||||
})
|
||||
}
|
||||
|
||||
// handleMulticastListenerQuery handles a query message.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) handleMulticastListenerQuery(mldHdr header.MLD) {
|
||||
mld.genericMulticastProtocol.HandleQueryLocked(mldHdr.MulticastAddress(), mldHdr.MaximumResponseDelay())
|
||||
}
|
||||
|
||||
// handleMulticastListenerQueryV2 handles a V2 query message.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) handleMulticastListenerQueryV2(mldHdr header.MLDv2Query) {
|
||||
sources, ok := mldHdr.Sources()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
mld.genericMulticastProtocol.HandleQueryV2Locked(
|
||||
mldHdr.MulticastAddress(),
|
||||
mldHdr.MaximumResponseCode(),
|
||||
sources,
|
||||
mldHdr.QuerierRobustnessVariable(),
|
||||
mldHdr.QuerierQueryInterval(),
|
||||
)
|
||||
}
|
||||
|
||||
// handleMulticastListenerReport handles a report message.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) handleMulticastListenerReport(mldHdr header.MLD) {
|
||||
mld.genericMulticastProtocol.HandleReportLocked(mldHdr.MulticastAddress())
|
||||
}
|
||||
|
||||
// joinGroup handles joining a new group and sending and scheduling the required
|
||||
// messages.
|
||||
//
|
||||
// If the group is already joined, returns *tcpip.ErrDuplicateAddress.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) joinGroup(groupAddress tcpip.Address) {
|
||||
mld.genericMulticastProtocol.JoinGroupLocked(groupAddress)
|
||||
}
|
||||
|
||||
// isInGroup returns true if the specified group has been joined locally.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be read locked.
|
||||
func (mld *mldState) isInGroup(groupAddress tcpip.Address) bool {
|
||||
return mld.genericMulticastProtocol.IsLocallyJoinedRLocked(groupAddress)
|
||||
}
|
||||
|
||||
// leaveGroup handles removing the group from the membership map, cancels any
|
||||
// delay timers associated with that group, and sends the Done message, if
|
||||
// required.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) leaveGroup(groupAddress tcpip.Address) tcpip.Error {
|
||||
// LeaveGroup returns false only if the group was not joined.
|
||||
if mld.genericMulticastProtocol.LeaveGroupLocked(groupAddress) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &tcpip.ErrBadLocalAddress{}
|
||||
}
|
||||
|
||||
// softLeaveAll leaves all groups from the perspective of MLD, but remains
|
||||
// joined locally.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) softLeaveAll() {
|
||||
mld.genericMulticastProtocol.MakeAllNonMemberLocked()
|
||||
}
|
||||
|
||||
// initializeAll attempts to initialize the MLD state for each group that has
|
||||
// been joined locally.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) initializeAll() {
|
||||
mld.genericMulticastProtocol.InitializeGroupsLocked()
|
||||
}
|
||||
|
||||
// sendQueuedReports attempts to send any reports that are queued for sending.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) sendQueuedReports() {
|
||||
mld.genericMulticastProtocol.SendQueuedReportsLocked()
|
||||
}
|
||||
|
||||
// setVersion sets the MLD version.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be locked.
|
||||
func (mld *mldState) setVersion(v MLDVersion) MLDVersion {
|
||||
var prev bool
|
||||
switch v {
|
||||
case MLDVersion2:
|
||||
prev = mld.genericMulticastProtocol.SetV1ModeLocked(false)
|
||||
case MLDVersion1:
|
||||
prev = mld.genericMulticastProtocol.SetV1ModeLocked(true)
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized version = %d", v))
|
||||
}
|
||||
|
||||
return toMLDVersion(prev)
|
||||
}
|
||||
|
||||
func toMLDVersion(v1Generic bool) MLDVersion {
|
||||
if v1Generic {
|
||||
return MLDVersion1
|
||||
}
|
||||
return MLDVersion2
|
||||
}
|
||||
|
||||
// getVersion returns the MLD version.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be read locked.
|
||||
func (mld *mldState) getVersion() MLDVersion {
|
||||
return toMLDVersion(mld.genericMulticastProtocol.GetV1ModeLocked())
|
||||
}
|
||||
|
||||
// writePacket assembles and sends an MLD packet.
|
||||
//
|
||||
// Precondition: mld.ep.mu must be read locked.
|
||||
func (mld *mldState) writePacket(destAddress, groupAddress tcpip.Address, mldType header.ICMPv6Type) (bool, tcpip.Error) {
|
||||
sentStats := mld.ep.stats.icmp.packetsSent
|
||||
var mldStat tcpip.MultiCounterStat
|
||||
switch mldType {
|
||||
case header.ICMPv6MulticastListenerReport:
|
||||
mldStat = sentStats.multicastListenerReport
|
||||
case header.ICMPv6MulticastListenerDone:
|
||||
mldStat = sentStats.multicastListenerDone
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mld type = %d", mldType))
|
||||
}
|
||||
|
||||
icmpView := buffer.NewViewSize(header.ICMPv6HeaderSize + header.MLDMinimumSize)
|
||||
|
||||
icmp := header.ICMPv6(icmpView.AsSlice())
|
||||
header.MLD(icmp.MessageBody()).SetMulticastAddress(groupAddress)
|
||||
extensionHeaders := header.IPv6ExtHdrSerializer{
|
||||
header.IPv6SerializableHopByHopExtHdr{
|
||||
&header.IPv6RouterAlertOption{Value: header.IPv6RouterAlertMLD},
|
||||
},
|
||||
}
|
||||
|
||||
return mld.writePacketInner(
|
||||
icmpView,
|
||||
mldType,
|
||||
mldStat,
|
||||
extensionHeaders,
|
||||
destAddress,
|
||||
)
|
||||
}
|
||||
|
||||
func (mld *mldState) writePacketInner(buf *buffer.View, mldType header.ICMPv6Type, reportStat tcpip.MultiCounterStat, extensionHeaders header.IPv6ExtHdrSerializer, destAddress tcpip.Address) (bool, tcpip.Error) {
|
||||
icmp := header.ICMPv6(buf.AsSlice())
|
||||
icmp.SetType(mldType)
|
||||
|
||||
// As per RFC 2710 section 3,
|
||||
//
|
||||
// All MLD messages described in this document are sent with a link-local
|
||||
// IPv6 Source Address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert
|
||||
// option in a Hop-by-Hop Options header.
|
||||
//
|
||||
// However, this would cause problems with Duplicate Address Detection with
|
||||
// the first address as MLD snooping switches may not send multicast traffic
|
||||
// that DAD depends on to the node performing DAD without the MLD report, as
|
||||
// documented in RFC 4816:
|
||||
//
|
||||
// Note that when a node joins a multicast address, it typically sends a
|
||||
// Multicast Listener Discovery (MLD) report message [RFC2710] [RFC3810]
|
||||
// for the multicast address. In the case of Duplicate Address
|
||||
// Detection, the MLD report message is required in order to inform MLD-
|
||||
// snooping switches, rather than routers, to forward multicast packets.
|
||||
// In the above description, the delay for joining the multicast address
|
||||
// thus means delaying transmission of the corresponding MLD report
|
||||
// message. Since the MLD specifications do not request a random delay
|
||||
// to avoid race conditions, just delaying Neighbor Solicitation would
|
||||
// cause congestion by the MLD report messages. The congestion would
|
||||
// then prevent the MLD-snooping switches from working correctly and, as
|
||||
// a result, prevent Duplicate Address Detection from working. The
|
||||
// requirement to include the delay for the MLD report in this case
|
||||
// avoids this scenario. [RFC3590] also talks about some interaction
|
||||
// issues between Duplicate Address Detection and MLD, and specifies
|
||||
// which source address should be used for the MLD report in this case.
|
||||
//
|
||||
// As per RFC 3590 section 4, we should still send out MLD reports with an
|
||||
// unspecified source address if we do not have an assigned link-local
|
||||
// address to use as the source address to ensure DAD works as expected on
|
||||
// networks with MLD snooping switches:
|
||||
//
|
||||
// MLD Report and Done messages are sent with a link-local address as
|
||||
// the IPv6 source address, if a valid address is available on the
|
||||
// interface. If a valid link-local address is not available (e.g., one
|
||||
// has not been configured), the message is sent with the unspecified
|
||||
// address (::) as the IPv6 source address.
|
||||
//
|
||||
// Once a valid link-local address is available, a node SHOULD generate
|
||||
// new MLD Report messages for all multicast addresses joined on the
|
||||
// interface.
|
||||
//
|
||||
// Routers receiving an MLD Report or Done message with the unspecified
|
||||
// address as the IPv6 source address MUST silently discard the packet
|
||||
// without taking any action on the packets contents.
|
||||
//
|
||||
// Snooping switches MUST manage multicast forwarding state based on MLD
|
||||
// Report and Done messages sent with the unspecified address as the
|
||||
// IPv6 source address.
|
||||
localAddress := mld.ep.getLinkLocalAddressRLocked()
|
||||
if localAddress.BitLen() == 0 {
|
||||
localAddress = header.IPv6Any
|
||||
}
|
||||
|
||||
icmp.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
|
||||
Header: icmp,
|
||||
Src: localAddress,
|
||||
Dst: destAddress,
|
||||
}))
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(mld.ep.MaxHeaderLength()) + extensionHeaders.Length(),
|
||||
Payload: buffer.MakeWithView(buf),
|
||||
})
|
||||
defer pkt.DecRef()
|
||||
|
||||
if err := addIPHeader(localAddress, destAddress, pkt, stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv6ProtocolNumber,
|
||||
TTL: header.MLDHopLimit,
|
||||
}, extensionHeaders); err != nil {
|
||||
panic(fmt.Sprintf("failed to add IP header: %s", err))
|
||||
}
|
||||
if err := mld.ep.nic.WritePacketToRemote(header.EthernetAddressFromMulticastIPv6Address(destAddress), pkt); err != nil {
|
||||
mld.ep.stats.icmp.packetsSent.dropped.Increment()
|
||||
return false, err
|
||||
}
|
||||
reportStat.Increment()
|
||||
return localAddress != header.IPv6Any, nil
|
||||
}
|
||||
2033
pkg/tcpip/network/ipv6/ndp.go
Normal file
2033
pkg/tcpip/network/ipv6/ndp.go
Normal file
File diff suppressed because it is too large
Load diff
145
pkg/tcpip/network/ipv6/stats.go
Normal file
145
pkg/tcpip/network/ipv6/stats.go
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright 2020 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 ipv6
|
||||
|
||||
import (
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/internal/ip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var _ stack.IPNetworkEndpointStats = (*Stats)(nil)
|
||||
|
||||
// Stats holds statistics related to the IPv6 protocol family.
|
||||
//
|
||||
// +stateify savable
|
||||
type Stats struct {
|
||||
// IP holds IPv6 statistics.
|
||||
IP tcpip.IPStats
|
||||
|
||||
// ICMP holds ICMPv6 statistics.
|
||||
ICMP tcpip.ICMPv6Stats
|
||||
|
||||
// UnhandledRouterAdvertisements is the number of Router Advertisements that
|
||||
// were observed but not handled.
|
||||
UnhandledRouterAdvertisements *tcpip.StatCounter
|
||||
}
|
||||
|
||||
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
|
||||
func (*Stats) IsNetworkEndpointStats() {}
|
||||
|
||||
// IPStats implements stack.IPNetworkEndointStats
|
||||
func (s *Stats) IPStats() *tcpip.IPStats {
|
||||
return &s.IP
|
||||
}
|
||||
|
||||
// +stateify savable
|
||||
type sharedStats struct {
|
||||
localStats Stats
|
||||
ip ip.MultiCounterIPStats
|
||||
icmp multiCounterICMPv6Stats
|
||||
}
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv6PacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv6PacketStats struct {
|
||||
echoRequest tcpip.MultiCounterStat
|
||||
echoReply tcpip.MultiCounterStat
|
||||
dstUnreachable tcpip.MultiCounterStat
|
||||
packetTooBig tcpip.MultiCounterStat
|
||||
timeExceeded tcpip.MultiCounterStat
|
||||
paramProblem tcpip.MultiCounterStat
|
||||
routerSolicit tcpip.MultiCounterStat
|
||||
routerAdvert tcpip.MultiCounterStat
|
||||
neighborSolicit tcpip.MultiCounterStat
|
||||
neighborAdvert tcpip.MultiCounterStat
|
||||
redirectMsg tcpip.MultiCounterStat
|
||||
multicastListenerQuery tcpip.MultiCounterStat
|
||||
multicastListenerReport tcpip.MultiCounterStat
|
||||
multicastListenerReportV2 tcpip.MultiCounterStat
|
||||
multicastListenerDone tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv6PacketStats) init(a, b *tcpip.ICMPv6PacketStats) {
|
||||
m.echoRequest.Init(a.EchoRequest, b.EchoRequest)
|
||||
m.echoReply.Init(a.EchoReply, b.EchoReply)
|
||||
m.dstUnreachable.Init(a.DstUnreachable, b.DstUnreachable)
|
||||
m.packetTooBig.Init(a.PacketTooBig, b.PacketTooBig)
|
||||
m.timeExceeded.Init(a.TimeExceeded, b.TimeExceeded)
|
||||
m.paramProblem.Init(a.ParamProblem, b.ParamProblem)
|
||||
m.routerSolicit.Init(a.RouterSolicit, b.RouterSolicit)
|
||||
m.routerAdvert.Init(a.RouterAdvert, b.RouterAdvert)
|
||||
m.neighborSolicit.Init(a.NeighborSolicit, b.NeighborSolicit)
|
||||
m.neighborAdvert.Init(a.NeighborAdvert, b.NeighborAdvert)
|
||||
m.redirectMsg.Init(a.RedirectMsg, b.RedirectMsg)
|
||||
m.multicastListenerQuery.Init(a.MulticastListenerQuery, b.MulticastListenerQuery)
|
||||
m.multicastListenerReport.Init(a.MulticastListenerReport, b.MulticastListenerReport)
|
||||
m.multicastListenerReportV2.Init(a.MulticastListenerReportV2, b.MulticastListenerReportV2)
|
||||
m.multicastListenerDone.Init(a.MulticastListenerDone, b.MulticastListenerDone)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv6PacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv6SentPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv6SentPacketStats struct {
|
||||
multiCounterICMPv6PacketStats
|
||||
dropped tcpip.MultiCounterStat
|
||||
rateLimited tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv6SentPacketStats) init(a, b *tcpip.ICMPv6SentPacketStats) {
|
||||
m.multiCounterICMPv6PacketStats.init(&a.ICMPv6PacketStats, &b.ICMPv6PacketStats)
|
||||
m.dropped.Init(a.Dropped, b.Dropped)
|
||||
m.rateLimited.Init(a.RateLimited, b.RateLimited)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv6SentPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv6ReceivedPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv6ReceivedPacketStats struct {
|
||||
multiCounterICMPv6PacketStats
|
||||
unrecognized tcpip.MultiCounterStat
|
||||
invalid tcpip.MultiCounterStat
|
||||
routerOnlyPacketsDroppedByHost tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv6ReceivedPacketStats) init(a, b *tcpip.ICMPv6ReceivedPacketStats) {
|
||||
m.multiCounterICMPv6PacketStats.init(&a.ICMPv6PacketStats, &b.ICMPv6PacketStats)
|
||||
m.unrecognized.Init(a.Unrecognized, b.Unrecognized)
|
||||
m.invalid.Init(a.Invalid, b.Invalid)
|
||||
m.routerOnlyPacketsDroppedByHost.Init(a.RouterOnlyPacketsDroppedByHost, b.RouterOnlyPacketsDroppedByHost)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv6ReceivedPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv6Stats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv6Stats struct {
|
||||
packetsSent multiCounterICMPv6SentPacketStats
|
||||
packetsReceived multiCounterICMPv6ReceivedPacketStats
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv6Stats) init(a, b *tcpip.ICMPv6Stats) {
|
||||
m.packetsSent.init(&a.PacketsSent, &b.PacketsSent)
|
||||
m.packetsReceived.init(&a.PacketsReceived, &b.PacketsReceived)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv6Stats)
|
||||
Loading…
Add table
Add a link
Reference in a new issue