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
709
pkg/tcpip/network/ipv4/icmp.go
Normal file
709
pkg/tcpip/network/ipv4/icmp.go
Normal file
|
|
@ -0,0 +1,709 @@
|
|||
// Copyright 2021 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 ipv4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/checksum"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// icmpv4DestinationUnreachableSockError is a general ICMPv4 Destination
|
||||
// Unreachable error.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationUnreachableSockError struct{}
|
||||
|
||||
// Origin implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin {
|
||||
return tcpip.SockExtErrorOriginICMP
|
||||
}
|
||||
|
||||
// Type implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationUnreachableSockError) Type() uint8 {
|
||||
return uint8(header.ICMPv4DstUnreachable)
|
||||
}
|
||||
|
||||
// Info implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationUnreachableSockError) Info() uint32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4DestinationHostUnreachableSockError)(nil)
|
||||
|
||||
// icmpv4DestinationHostUnreachableSockError is an ICMPv4 Destination Host
|
||||
// Unreachable error.
|
||||
//
|
||||
// It indicates that a packet was not able to reach the destination host.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationHostUnreachableSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationHostUnreachableSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4HostUnreachable)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4DestinationHostUnreachableSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.DestinationHostUnreachableTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4DestinationNetUnreachableSockError)(nil)
|
||||
|
||||
// icmpv4DestinationNetUnreachableSockError is an ICMPv4 Destination Net
|
||||
// Unreachable error.
|
||||
//
|
||||
// It indicates that a packet was not able to reach the destination network.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationNetUnreachableSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationNetUnreachableSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4NetUnreachable)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4DestinationNetUnreachableSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.DestinationNetworkUnreachableTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4DestinationPortUnreachableSockError)(nil)
|
||||
|
||||
// icmpv4DestinationPortUnreachableSockError is an ICMPv4 Destination Port
|
||||
// Unreachable error.
|
||||
//
|
||||
// It indicates that a packet reached the destination host, but the transport
|
||||
// protocol was not active on the destination port.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationPortUnreachableSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationPortUnreachableSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4PortUnreachable)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.DestinationPortUnreachableTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4DestinationProtoUnreachableSockError)(nil)
|
||||
|
||||
// icmpv4DestinationProtoUnreachableSockError is an ICMPv4 Destination Protocol
|
||||
// Unreachable error.
|
||||
//
|
||||
// It indicates that a packet reached the destination host, but the transport
|
||||
// protocol was not reachable
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationProtoUnreachableSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationProtoUnreachableSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4ProtoUnreachable)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4DestinationProtoUnreachableSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.DestinationProtoUnreachableTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4SourceRouteFailedSockError)(nil)
|
||||
|
||||
// icmpv4SourceRouteFailedSockError is an ICMPv4 Destination Unreachable error
|
||||
// due to source route failed.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4SourceRouteFailedSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4SourceRouteFailedSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4SourceRouteFailed)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4SourceRouteFailedSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.SourceRouteFailedTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4SourceHostIsolatedSockError)(nil)
|
||||
|
||||
// icmpv4SourceHostIsolatedSockError is an ICMPv4 Destination Unreachable error
|
||||
// due to source host isolated (not on the network).
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4SourceHostIsolatedSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4SourceHostIsolatedSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4SourceHostIsolated)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4SourceHostIsolatedSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.SourceHostIsolatedTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4DestinationHostUnknownSockError)(nil)
|
||||
|
||||
// icmpv4DestinationHostUnknownSockError is an ICMPv4 Destination Unreachable
|
||||
// error due to destination host unknown/down.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4DestinationHostUnknownSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4DestinationHostUnknownSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4DestinationHostUnknown)
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4DestinationHostUnknownSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.DestinationHostDownTransportError
|
||||
}
|
||||
|
||||
var _ stack.TransportError = (*icmpv4FragmentationNeededSockError)(nil)
|
||||
|
||||
// icmpv4FragmentationNeededSockError is an ICMPv4 Destination Unreachable error
|
||||
// due to fragmentation being required but the packet was set to not be
|
||||
// fragmented.
|
||||
//
|
||||
// It indicates that a link exists on the path to the destination with an MTU
|
||||
// that is too small to carry the packet.
|
||||
//
|
||||
// +stateify savable
|
||||
type icmpv4FragmentationNeededSockError struct {
|
||||
icmpv4DestinationUnreachableSockError
|
||||
|
||||
mtu uint32
|
||||
}
|
||||
|
||||
// Code implements tcpip.SockErrorCause.
|
||||
func (*icmpv4FragmentationNeededSockError) Code() uint8 {
|
||||
return uint8(header.ICMPv4FragmentationNeeded)
|
||||
}
|
||||
|
||||
// Info implements tcpip.SockErrorCause.
|
||||
func (e *icmpv4FragmentationNeededSockError) Info() uint32 {
|
||||
return e.mtu
|
||||
}
|
||||
|
||||
// Kind implements stack.TransportError.
|
||||
func (*icmpv4FragmentationNeededSockError) Kind() stack.TransportErrorKind {
|
||||
return stack.PacketTooBigTransportError
|
||||
}
|
||||
|
||||
func (e *endpoint) checkLocalAddress(addr tcpip.Address) bool {
|
||||
if e.nic.Spoofing() {
|
||||
return true
|
||||
}
|
||||
|
||||
if addressEndpoint := e.AcquireAssignedAddress(addr, false, stack.NeverPrimaryEndpoint, true /* readOnly */); addressEndpoint != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// handleControl handles the case when an ICMP error packet contains the headers
|
||||
// of the original packet that caused the ICMP one to be sent. This information
|
||||
// is used to find out which transport endpoint must be notified about the ICMP
|
||||
// packet. We only expect the payload, not the enclosing ICMP packet.
|
||||
func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.PacketBuffer) {
|
||||
h, ok := pkt.Data().PullUp(header.IPv4MinimumSize)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
hdr := header.IPv4(h)
|
||||
|
||||
// We don't use IsValid() here because ICMP only requires that the IP
|
||||
// header plus 8 bytes of the transport header be included. So it's
|
||||
// likely that it is truncated, which would cause IsValid to return
|
||||
// false.
|
||||
//
|
||||
// Drop packet if it doesn't have the basic IPv4 header or if the
|
||||
// original source address doesn't match an address we own.
|
||||
srcAddr := hdr.SourceAddress()
|
||||
if !e.checkLocalAddress(srcAddr) {
|
||||
return
|
||||
}
|
||||
|
||||
hlen := int(hdr.HeaderLength())
|
||||
if pkt.Data().Size() < hlen || hdr.FragmentOffset() != 0 {
|
||||
// We won't be able to handle this if it doesn't contain the
|
||||
// full IPv4 header, or if it's a fragment not at offset 0
|
||||
// (because it won't have the transport header).
|
||||
return
|
||||
}
|
||||
|
||||
// Keep needed information before trimming header.
|
||||
p := hdr.TransportProtocol()
|
||||
dstAddr := hdr.DestinationAddress()
|
||||
// Skip the ip header, then deliver the error.
|
||||
if _, ok := pkt.Data().Consume(hlen); !ok {
|
||||
panic(fmt.Sprintf("could not consume the IP header of %d bytes", hlen))
|
||||
}
|
||||
e.dispatcher.DeliverTransportError(srcAddr, dstAddr, ProtocolNumber, p, errInfo, pkt)
|
||||
}
|
||||
|
||||
func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
|
||||
received := e.stats.icmp.packetsReceived
|
||||
h := header.ICMPv4(pkt.TransportHeader().Slice())
|
||||
if len(h) < header.ICMPv4MinimumSize {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
// Only do in-stack processing if the checksum is correct.
|
||||
if checksum.Checksum(h, pkt.Data().Checksum()) != 0xffff {
|
||||
received.invalid.Increment()
|
||||
// It's possible that a raw socket expects to receive this regardless
|
||||
// of checksum errors. If it's an echo request we know it's safe because
|
||||
// we are the only handler, however other types do not cope well with
|
||||
// packets with checksum errors.
|
||||
switch h.Type() {
|
||||
case header.ICMPv4Echo:
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
iph := header.IPv4(pkt.NetworkHeader().Slice())
|
||||
var newOptions header.IPv4Options
|
||||
if opts := iph.Options(); len(opts) != 0 {
|
||||
// RFC 1122 section 3.2.2.6 (page 43) (and similar for other round trip
|
||||
// type ICMP packets):
|
||||
// If a Record Route and/or Time Stamp option is received in an
|
||||
// ICMP Echo Request, this option (these options) SHOULD be
|
||||
// updated to include the current host and included in the IP
|
||||
// header of the Echo Reply message, without "truncation".
|
||||
// Thus, the recorded route will be for the entire round trip.
|
||||
//
|
||||
// So we need to let the option processor know how it should handle them.
|
||||
var op optionsUsage
|
||||
if h.Type() == header.ICMPv4Echo {
|
||||
op = &optionUsageEcho{}
|
||||
} else {
|
||||
op = &optionUsageReceive{}
|
||||
}
|
||||
var optProblem *header.IPv4OptParameterProblem
|
||||
newOptions, _, optProblem = e.processIPOptions(pkt, opts, op)
|
||||
if optProblem != nil {
|
||||
if optProblem.NeedICMP {
|
||||
_ = e.protocol.returnError(&icmpReasonParamProblem{
|
||||
pointer: optProblem.Pointer,
|
||||
}, pkt, true /* deliveredLocally */)
|
||||
e.stats.ip.MalformedPacketsReceived.Increment()
|
||||
}
|
||||
return
|
||||
}
|
||||
copied := copy(opts, newOptions)
|
||||
if copied != len(newOptions) {
|
||||
panic(fmt.Sprintf("copied %d bytes of new options, expected %d bytes", copied, len(newOptions)))
|
||||
}
|
||||
for i := copied; i < len(opts); i++ {
|
||||
// Pad with 0 (EOL). RFC 791 page 23 says "The padding is zero".
|
||||
opts[i] = byte(header.IPv4OptionListEndType)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/112892170): Meaningfully handle all ICMP types.
|
||||
switch h.Type() {
|
||||
case header.ICMPv4Echo:
|
||||
received.echoRequest.Increment()
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
case header.ICMPv4EchoReply:
|
||||
received.echoReply.Increment()
|
||||
e.dispatcher.DeliverTransportPacket(header.ICMPv4ProtocolNumber, pkt)
|
||||
case header.ICMPv4DstUnreachable:
|
||||
received.dstUnreachable.Increment()
|
||||
|
||||
mtu := h.MTU()
|
||||
code := h.Code()
|
||||
switch code {
|
||||
case header.ICMPv4NetUnreachable,
|
||||
header.ICMPv4DestinationNetworkUnknown,
|
||||
header.ICMPv4NetUnreachableForTos,
|
||||
header.ICMPv4NetProhibited:
|
||||
e.handleControl(&icmpv4DestinationNetUnreachableSockError{}, pkt)
|
||||
case header.ICMPv4HostUnreachable,
|
||||
header.ICMPv4HostProhibited,
|
||||
header.ICMPv4AdminProhibited,
|
||||
header.ICMPv4HostUnreachableForTos,
|
||||
header.ICMPv4HostPrecedenceViolation,
|
||||
header.ICMPv4PrecedenceCutInEffect:
|
||||
e.handleControl(&icmpv4DestinationHostUnreachableSockError{}, pkt)
|
||||
case header.ICMPv4PortUnreachable:
|
||||
e.handleControl(&icmpv4DestinationPortUnreachableSockError{}, pkt)
|
||||
case header.ICMPv4FragmentationNeeded:
|
||||
networkMTU, err := calculateNetworkMTU(uint32(mtu), header.IPv4MinimumSize)
|
||||
if err != nil {
|
||||
networkMTU = 0
|
||||
}
|
||||
e.handleControl(&icmpv4FragmentationNeededSockError{mtu: networkMTU}, pkt)
|
||||
case header.ICMPv4ProtoUnreachable:
|
||||
e.handleControl(&icmpv4DestinationProtoUnreachableSockError{}, pkt)
|
||||
case header.ICMPv4SourceRouteFailed:
|
||||
e.handleControl(&icmpv4SourceRouteFailedSockError{}, pkt)
|
||||
case header.ICMPv4SourceHostIsolated:
|
||||
e.handleControl(&icmpv4SourceHostIsolatedSockError{}, pkt)
|
||||
case header.ICMPv4DestinationHostUnknown:
|
||||
e.handleControl(&icmpv4DestinationHostUnknownSockError{}, pkt)
|
||||
}
|
||||
case header.ICMPv4SrcQuench:
|
||||
received.srcQuench.Increment()
|
||||
|
||||
case header.ICMPv4Redirect:
|
||||
received.redirect.Increment()
|
||||
|
||||
case header.ICMPv4TimeExceeded:
|
||||
received.timeExceeded.Increment()
|
||||
|
||||
case header.ICMPv4ParamProblem:
|
||||
received.paramProblem.Increment()
|
||||
|
||||
case header.ICMPv4Timestamp:
|
||||
received.timestamp.Increment()
|
||||
|
||||
case header.ICMPv4TimestampReply:
|
||||
received.timestampReply.Increment()
|
||||
|
||||
case header.ICMPv4InfoRequest:
|
||||
received.infoRequest.Increment()
|
||||
|
||||
case header.ICMPv4InfoReply:
|
||||
received.infoReply.Increment()
|
||||
|
||||
default:
|
||||
received.invalid.Increment()
|
||||
}
|
||||
}
|
||||
|
||||
// ======= ICMP Error packet generation =========
|
||||
|
||||
// icmpReason is a marker interface for IPv4 specific ICMP errors.
|
||||
type icmpReason interface {
|
||||
isICMPReason()
|
||||
}
|
||||
|
||||
// icmpReasonNetworkProhibited is an error where the destination network is
|
||||
// prohibited.
|
||||
type icmpReasonNetworkProhibited struct{}
|
||||
|
||||
func (*icmpReasonNetworkProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonHostProhibited is an error where the destination host is
|
||||
// prohibited.
|
||||
type icmpReasonHostProhibited struct{}
|
||||
|
||||
func (*icmpReasonHostProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonAdministrativelyProhibited is an error where the destination is
|
||||
// administratively prohibited.
|
||||
type icmpReasonAdministrativelyProhibited struct{}
|
||||
|
||||
func (*icmpReasonAdministrativelyProhibited) isICMPReason() {}
|
||||
|
||||
// icmpReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type icmpReasonPortUnreachable struct{}
|
||||
|
||||
func (*icmpReasonPortUnreachable) isICMPReason() {}
|
||||
|
||||
// icmpReasonProtoUnreachable is an error where the transport protocol is
|
||||
// not supported.
|
||||
type icmpReasonProtoUnreachable struct{}
|
||||
|
||||
func (*icmpReasonProtoUnreachable) isICMPReason() {}
|
||||
|
||||
// icmpReasonTTLExceeded is an error where a packet's time to live exceeded in
|
||||
// transit to its final destination, as per RFC 792 page 6, Time Exceeded
|
||||
// Message.
|
||||
type icmpReasonTTLExceeded struct{}
|
||||
|
||||
func (*icmpReasonTTLExceeded) isICMPReason() {}
|
||||
|
||||
// icmpReasonReassemblyTimeout is an error where insufficient fragments are
|
||||
// received to complete reassembly of a packet within a configured time after
|
||||
// the reception of the first-arriving fragment of that packet.
|
||||
type icmpReasonReassemblyTimeout struct{}
|
||||
|
||||
func (*icmpReasonReassemblyTimeout) isICMPReason() {}
|
||||
|
||||
// icmpReasonParamProblem is an error to use to request a Parameter Problem
|
||||
// message to be sent.
|
||||
type icmpReasonParamProblem struct {
|
||||
pointer byte
|
||||
}
|
||||
|
||||
func (*icmpReasonParamProblem) isICMPReason() {}
|
||||
|
||||
// icmpReasonNetworkUnreachable is an error in which the network specified in
|
||||
// the internet destination field of the datagram is unreachable.
|
||||
type icmpReasonNetworkUnreachable struct{}
|
||||
|
||||
func (*icmpReasonNetworkUnreachable) isICMPReason() {}
|
||||
|
||||
// icmpReasonFragmentationNeeded is an error where a packet requires
|
||||
// fragmentation while also having the Don't Fragment flag set, as per RFC 792
|
||||
// page 3, Destination Unreachable Message.
|
||||
type icmpReasonFragmentationNeeded struct{}
|
||||
|
||||
func (*icmpReasonFragmentationNeeded) isICMPReason() {}
|
||||
|
||||
// icmpReasonHostUnreachable is an error in which the host specified in the
|
||||
// internet destination field of the datagram is unreachable.
|
||||
type icmpReasonHostUnreachable struct{}
|
||||
|
||||
func (*icmpReasonHostUnreachable) isICMPReason() {}
|
||||
|
||||
// returnError takes an error descriptor and generates the appropriate ICMP
|
||||
// error packet for IPv4 and sends it back to the remote device that sent
|
||||
// the problematic packet. It incorporates as much of that packet as
|
||||
// possible as well as any error metadata as is available. returnError
|
||||
// expects pkt to hold a valid IPv4 packet as per the wire format.
|
||||
func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliveredLocally bool) tcpip.Error {
|
||||
origIPHdr := header.IPv4(pkt.NetworkHeader().Slice())
|
||||
origIPHdrSrc := origIPHdr.SourceAddress()
|
||||
origIPHdrDst := origIPHdr.DestinationAddress()
|
||||
|
||||
// We check we are responding only when we are allowed to.
|
||||
// See RFC 1812 section 4.3.2.7 (shown below).
|
||||
//
|
||||
// =========
|
||||
// 4.3.2.7 When Not to Send ICMP Errors
|
||||
//
|
||||
// An ICMP error message MUST NOT be sent as the result of receiving:
|
||||
//
|
||||
// o An ICMP error message, or
|
||||
//
|
||||
// o A packet which fails the IP header validation tests described in
|
||||
// Section [5.2.2] (except where that section specifically permits
|
||||
// the sending of an ICMP error message), or
|
||||
//
|
||||
// o A packet destined to an IP broadcast or IP multicast address, or
|
||||
//
|
||||
// o A packet sent as a Link Layer broadcast or multicast, or
|
||||
//
|
||||
// o Any fragment of a datagram other then the first fragment (i.e., a
|
||||
// packet for which the fragment offset in the IP header is nonzero).
|
||||
//
|
||||
// TODO(gvisor.dev/issues/4058): Make sure we don't send ICMP errors in
|
||||
// response to a non-initial fragment, but it currently can not happen.
|
||||
if pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(origIPHdrDst) || origIPHdrSrc == header.IPv4Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the packet wasn't delivered locally, do not use the packet's destination
|
||||
// address as the response's source address as we should not not own the
|
||||
// destination address of a packet we are forwarding.
|
||||
localAddr := origIPHdrDst
|
||||
if !deliveredLocally {
|
||||
localAddr = tcpip.Address{}
|
||||
}
|
||||
|
||||
// Even if we were able to receive a packet from some remote, we may not have
|
||||
// a route to it - the remote may be blocked via routing rules. We must always
|
||||
// consult our routing table and find a route to the remote before sending any
|
||||
// packet.
|
||||
route, err := p.stack.FindRoute(pkt.NICID, localAddr, origIPHdrSrc, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer route.Release()
|
||||
|
||||
p.mu.Lock()
|
||||
// We retrieve an endpoint using the newly constructed route's NICID rather
|
||||
// than the packet's NICID. The packet's NICID corresponds to the NIC on
|
||||
// which it arrived, which isn't necessarily the same as the NIC on which it
|
||||
// will be transmitted. On the other hand, the route's NIC *is* guaranteed
|
||||
// to be the NIC on which the packet will be transmitted.
|
||||
netEP, ok := p.eps[route.NICID()]
|
||||
p.mu.Unlock()
|
||||
if !ok {
|
||||
return &tcpip.ErrNotConnected{}
|
||||
}
|
||||
|
||||
transportHeader := pkt.TransportHeader().Slice()
|
||||
|
||||
// Don't respond to icmp error packets.
|
||||
if origIPHdr.Protocol() == uint8(header.ICMPv4ProtocolNumber) {
|
||||
// We need to decide to explicitly name the packets we can respond to or
|
||||
// the ones we can not respond to. The decision is somewhat arbitrary and
|
||||
// if problems arise this could be reversed. It was judged less of a breach
|
||||
// of protocol to not respond to unknown non-error packets than to respond
|
||||
// to unknown error packets so we take the first approach.
|
||||
if len(transportHeader) < header.ICMPv4MinimumSize {
|
||||
// The packet is malformed.
|
||||
return nil
|
||||
}
|
||||
switch header.ICMPv4(transportHeader).Type() {
|
||||
case
|
||||
header.ICMPv4EchoReply,
|
||||
header.ICMPv4Echo,
|
||||
header.ICMPv4Timestamp,
|
||||
header.ICMPv4TimestampReply,
|
||||
header.ICMPv4InfoRequest,
|
||||
header.ICMPv4InfoReply:
|
||||
default:
|
||||
// Assume any type we don't know about may be an error type.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
sent := netEP.stats.icmp.packetsSent
|
||||
icmpType, icmpCode, counter, pointer := func() (header.ICMPv4Type, header.ICMPv4Code, tcpip.MultiCounterStat, byte) {
|
||||
switch reason := reason.(type) {
|
||||
case *icmpReasonNetworkProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4NetProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonHostProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4HostProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonAdministrativelyProhibited:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4AdminProhibited, sent.dstUnreachable, 0
|
||||
case *icmpReasonPortUnreachable:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4PortUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonProtoUnreachable:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4ProtoUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonNetworkUnreachable:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4NetUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonHostUnreachable:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4HostUnreachable, sent.dstUnreachable, 0
|
||||
case *icmpReasonFragmentationNeeded:
|
||||
return header.ICMPv4DstUnreachable, header.ICMPv4FragmentationNeeded, sent.dstUnreachable, 0
|
||||
case *icmpReasonTTLExceeded:
|
||||
return header.ICMPv4TimeExceeded, header.ICMPv4TTLExceeded, sent.timeExceeded, 0
|
||||
case *icmpReasonReassemblyTimeout:
|
||||
return header.ICMPv4TimeExceeded, header.ICMPv4ReassemblyTimeout, sent.timeExceeded, 0
|
||||
case *icmpReasonParamProblem:
|
||||
return header.ICMPv4ParamProblem, header.ICMPv4UnusedCode, sent.paramProblem, reason.pointer
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported ICMP type %T", reason))
|
||||
}
|
||||
}()
|
||||
|
||||
if !p.allowICMPReply(icmpType, icmpCode) {
|
||||
sent.rateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Now work out how much of the triggering packet we should return.
|
||||
// As per RFC 1812 Section 4.3.2.3
|
||||
//
|
||||
// ICMP datagram SHOULD contain as much of the original
|
||||
// datagram as possible without the length of the ICMP
|
||||
// datagram exceeding 576 bytes.
|
||||
//
|
||||
// NOTE: The above RFC referenced is different from the original
|
||||
// recommendation in RFC 1122 and RFC 792 where it mentioned that at
|
||||
// least 8 bytes of the payload must be included. Today linux and other
|
||||
// systems implement the RFC 1812 definition and not the original
|
||||
// requirement. We treat 8 bytes as the minimum but will try send more.
|
||||
mtu := int(route.MTU())
|
||||
const maxIPData = header.IPv4MinimumProcessableDatagramSize - header.IPv4MinimumSize
|
||||
if mtu > maxIPData {
|
||||
mtu = maxIPData
|
||||
}
|
||||
available := mtu - header.ICMPv4MinimumSize
|
||||
|
||||
if available < len(origIPHdr)+header.ICMPv4MinimumErrorPayloadSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
payloadLen := len(origIPHdr) + len(transportHeader) + pkt.Data().Size()
|
||||
if payloadLen > available {
|
||||
payloadLen = available
|
||||
}
|
||||
|
||||
// The buffers used by pkt may be used elsewhere in the system.
|
||||
// For example, an AF_RAW or AF_PACKET socket may use what the transport
|
||||
// protocol considers an unreachable destination. Thus we deep copy pkt to
|
||||
// prevent multiple ownership and SR errors. The new copy is a vectorized
|
||||
// view with the entire incoming IP packet reassembled and truncated as
|
||||
// required. This is now the payload of the new ICMP packet and no longer
|
||||
// considered a packet in its own right.
|
||||
|
||||
payload := buffer.MakeWithView(pkt.NetworkHeader().View())
|
||||
payload.Append(pkt.TransportHeader().View())
|
||||
if dataCap := payloadLen - int(payload.Size()); dataCap > 0 {
|
||||
buf := pkt.Data().ToBuffer()
|
||||
buf.Truncate(int64(dataCap))
|
||||
payload.Merge(&buf)
|
||||
} else {
|
||||
payload.Truncate(int64(payloadLen))
|
||||
}
|
||||
|
||||
icmpPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(route.MaxHeaderLength()) + header.ICMPv4MinimumSize,
|
||||
Payload: payload,
|
||||
})
|
||||
defer icmpPkt.DecRef()
|
||||
|
||||
icmpPkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber
|
||||
|
||||
icmpHdr := header.ICMPv4(icmpPkt.TransportHeader().Push(header.ICMPv4MinimumSize))
|
||||
icmpHdr.SetCode(icmpCode)
|
||||
icmpHdr.SetType(icmpType)
|
||||
icmpHdr.SetPointer(pointer)
|
||||
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data().Checksum()))
|
||||
|
||||
if err := route.WritePacket(
|
||||
stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv4ProtocolNumber,
|
||||
TTL: route.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
},
|
||||
icmpPkt,
|
||||
); err != nil {
|
||||
sent.dropped.Increment()
|
||||
return err
|
||||
}
|
||||
counter.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnReassemblyTimeout implements fragmentation.TimeoutHandler.
|
||||
func (p *protocol) OnReassemblyTimeout(pkt *stack.PacketBuffer) {
|
||||
// OnReassemblyTimeout sends a Time Exceeded Message, as per RFC 792:
|
||||
//
|
||||
// If a host reassembling a fragmented datagram cannot complete the
|
||||
// reassembly due to missing fragments within its time limit it discards the
|
||||
// datagram, and it may send a time exceeded message.
|
||||
//
|
||||
// If fragment zero is not available then no time exceeded need be sent at
|
||||
// all.
|
||||
if pkt != nil {
|
||||
p.returnError(&icmpReasonReassemblyTimeout{}, pkt, true /* deliveredLocally */)
|
||||
}
|
||||
}
|
||||
654
pkg/tcpip/network/ipv4/igmp.go
Normal file
654
pkg/tcpip/network/ipv4/igmp.go
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
// 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 ipv4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"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 (
|
||||
// v1RouterPresentTimeout from RFC 2236 Section 8.11, Page 18
|
||||
// See note on igmpState.igmpV1Present for more detail.
|
||||
v1RouterPresentTimeout = 400 * time.Second
|
||||
|
||||
// v1MaxRespTime from RFC 2236 Section 4, Page 5. "The IGMPv1 router
|
||||
// will send General Queries with the Max Response Time set to 0. This MUST
|
||||
// be interpreted as a value of 100 (10 seconds)."
|
||||
//
|
||||
// Note that the Max Response Time field is a value in units of deciseconds.
|
||||
v1MaxRespTime = 10 * time.Second
|
||||
|
||||
// UnsolicitedReportIntervalMax is the maximum delay between sending
|
||||
// unsolicited IGMP reports.
|
||||
//
|
||||
// Obtained from RFC 2236 Section 8.10, Page 19.
|
||||
UnsolicitedReportIntervalMax = 10 * time.Second
|
||||
)
|
||||
|
||||
type protocolMode int
|
||||
|
||||
const (
|
||||
protocolModeV2OrV3 protocolMode = iota
|
||||
protocolModeV1
|
||||
// protocolModeV1Compatibility is for maintaining compatibility with IGMPv1
|
||||
// Routers.
|
||||
//
|
||||
// Per RFC 2236 Section 4 Page 6: "The IGMPv1 router expects Version 1
|
||||
// Membership Reports in response to its Queries, and will not pay
|
||||
// attention to Version 2 Membership Reports. Therefore, a state variable
|
||||
// MUST be kept for each interface, describing whether the multicast
|
||||
// Querier on that interface is running IGMPv1 or IGMPv2. This variable
|
||||
// MUST be based upon whether or not an IGMPv1 query was heard in the last
|
||||
// [Version 1 Router Present Timeout] seconds".
|
||||
protocolModeV1Compatibility
|
||||
)
|
||||
|
||||
// IGMPVersion is the forced version of IGMP.
|
||||
type IGMPVersion int
|
||||
|
||||
const (
|
||||
_ IGMPVersion = iota
|
||||
// IGMPVersion1 indicates IGMPv1.
|
||||
IGMPVersion1
|
||||
// IGMPVersion2 indicates IGMPv2. Note that IGMP may still fallback to V1
|
||||
// compatibility mode as required by IGMPv2.
|
||||
IGMPVersion2
|
||||
// IGMPVersion3 indicates IGMPv3. Note that IGMP may still fallback to V2
|
||||
// compatibility mode as required by IGMPv3.
|
||||
IGMPVersion3
|
||||
)
|
||||
|
||||
// IGMPEndpoint is a network endpoint that supports IGMP.
|
||||
type IGMPEndpoint interface {
|
||||
// SetIGMPVersion sets the IGMP version.
|
||||
//
|
||||
// Returns the previous IGMP version.
|
||||
SetIGMPVersion(IGMPVersion) IGMPVersion
|
||||
|
||||
// GetIGMPVersion returns the IGMP version.
|
||||
GetIGMPVersion() IGMPVersion
|
||||
}
|
||||
|
||||
// IGMPOptions holds options for IGMP.
|
||||
//
|
||||
// +stateify savable
|
||||
type IGMPOptions struct {
|
||||
// Enabled indicates whether IGMP will be performed.
|
||||
//
|
||||
// When enabled, IGMP may transmit IGMP report and leave messages when
|
||||
// joining and leaving multicast groups respectively, and handle incoming
|
||||
// IGMP 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 = (*igmpState)(nil)
|
||||
|
||||
// igmpState is the per-interface IGMP state.
|
||||
//
|
||||
// igmpState.init() MUST be called after creating an IGMP state.
|
||||
//
|
||||
// +stateify savable
|
||||
type igmpState struct {
|
||||
// The IPv4 endpoint this igmpState is for.
|
||||
ep *endpoint
|
||||
|
||||
genericMulticastProtocol ip.GenericMulticastProtocolState
|
||||
|
||||
// mode is used to configure the version of IGMP to perform.
|
||||
mode protocolMode
|
||||
|
||||
// igmpV1Job is scheduled when this interface receives an IGMPv1 style
|
||||
// message, upon expiration the igmpV1Present flag is cleared.
|
||||
// igmpV1Job may not be nil once igmpState is initialized.
|
||||
igmpV1Job *tcpip.Job
|
||||
}
|
||||
|
||||
// Enabled implements ip.MulticastGroupProtocol.
|
||||
func (igmp *igmpState) Enabled() bool {
|
||||
// No need to perform IGMP on loopback interfaces since they don't have
|
||||
// neighbouring nodes.
|
||||
return igmp.ep.protocol.options.IGMP.Enabled && !igmp.ep.nic.IsLoopback() && igmp.ep.Enabled()
|
||||
}
|
||||
|
||||
// SendReport implements ip.MulticastGroupProtocol.
|
||||
//
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) SendReport(groupAddress tcpip.Address) (bool, tcpip.Error) {
|
||||
igmpType := header.IGMPv2MembershipReport
|
||||
switch igmp.mode {
|
||||
case protocolModeV2OrV3:
|
||||
case protocolModeV1, protocolModeV1Compatibility:
|
||||
igmpType = header.IGMPv1MembershipReport
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mode = %d", igmp.mode))
|
||||
}
|
||||
return igmp.writePacket(groupAddress, groupAddress, igmpType)
|
||||
}
|
||||
|
||||
// SendLeave implements ip.MulticastGroupProtocol.
|
||||
//
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) SendLeave(groupAddress tcpip.Address) tcpip.Error {
|
||||
// As per RFC 2236 Section 6, Page 8: "If the interface state says the
|
||||
// Querier is running IGMPv1, this action SHOULD be skipped. If the flag
|
||||
// saying we were the last host to report is cleared, this action MAY be
|
||||
// skipped."
|
||||
switch igmp.mode {
|
||||
case protocolModeV2OrV3:
|
||||
_, err := igmp.writePacket(header.IPv4AllRoutersGroup, groupAddress, header.IGMPLeaveGroup)
|
||||
return err
|
||||
case protocolModeV1, protocolModeV1Compatibility:
|
||||
return nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mode = %d", igmp.mode))
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldPerformProtocol implements ip.MulticastGroupProtocol.
|
||||
func (igmp *igmpState) ShouldPerformProtocol(groupAddress tcpip.Address) bool {
|
||||
// As per RFC 2236 section 6 page 10,
|
||||
//
|
||||
// The all-systems group (address 224.0.0.1) is handled as a special
|
||||
// case. The host starts in Idle Member state for that group on every
|
||||
// interface, never transitions to another state, and never sends a
|
||||
// report for that group.
|
||||
return groupAddress != header.IPv4AllSystems
|
||||
}
|
||||
|
||||
type igmpv3ReportBuilder struct {
|
||||
igmp *igmpState
|
||||
|
||||
records []header.IGMPv3ReportGroupAddressRecordSerializer
|
||||
}
|
||||
|
||||
// AddRecord implements ip.MulticastGroupProtocolV2ReportBuilder.
|
||||
func (b *igmpv3ReportBuilder) AddRecord(genericRecordType ip.MulticastGroupProtocolV2ReportRecordType, groupAddress tcpip.Address) {
|
||||
var recordType header.IGMPv3ReportRecordType
|
||||
switch genericRecordType {
|
||||
case ip.MulticastGroupProtocolV2ReportRecordModeIsInclude:
|
||||
recordType = header.IGMPv3ReportRecordModeIsInclude
|
||||
case ip.MulticastGroupProtocolV2ReportRecordModeIsExclude:
|
||||
recordType = header.IGMPv3ReportRecordModeIsExclude
|
||||
case ip.MulticastGroupProtocolV2ReportRecordChangeToIncludeMode:
|
||||
recordType = header.IGMPv3ReportRecordChangeToIncludeMode
|
||||
case ip.MulticastGroupProtocolV2ReportRecordChangeToExcludeMode:
|
||||
recordType = header.IGMPv3ReportRecordChangeToExcludeMode
|
||||
case ip.MulticastGroupProtocolV2ReportRecordAllowNewSources:
|
||||
recordType = header.IGMPv3ReportRecordAllowNewSources
|
||||
case ip.MulticastGroupProtocolV2ReportRecordBlockOldSources:
|
||||
recordType = header.IGMPv3ReportRecordBlockOldSources
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognied genericRecordType = %d", genericRecordType))
|
||||
}
|
||||
|
||||
b.records = append(b.records, header.IGMPv3ReportGroupAddressRecordSerializer{
|
||||
RecordType: recordType,
|
||||
GroupAddress: groupAddress,
|
||||
Sources: nil,
|
||||
})
|
||||
}
|
||||
|
||||
// Send implements ip.MulticastGroupProtocolV2ReportBuilder.
|
||||
//
|
||||
// +checklocksread:b.igmp.ep.mu
|
||||
func (b *igmpv3ReportBuilder) Send() (sent bool, err tcpip.Error) {
|
||||
if len(b.records) == 0 {
|
||||
return false, err
|
||||
}
|
||||
|
||||
options := header.IPv4OptionsSerializer{
|
||||
&header.IPv4SerializableRouterAlertOption{},
|
||||
}
|
||||
mtu := int(b.igmp.ep.MTU()) - int(options.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.IGMPv3ReportSerializer{Records: records[:maxRecords]}
|
||||
records = records[maxRecords:]
|
||||
|
||||
icmpView := buffer.NewViewSize(serializer.Length())
|
||||
serializer.SerializeInto(icmpView.AsSlice())
|
||||
if sentWithSpecifiedAddress, err := b.igmp.writePacketInner(
|
||||
icmpView,
|
||||
b.igmp.ep.stats.igmp.packetsSent.v3MembershipReport,
|
||||
options,
|
||||
header.IGMPv3RoutersAddress,
|
||||
); err != nil {
|
||||
if firstErr != nil {
|
||||
firstErr = nil
|
||||
}
|
||||
allSentWithSpecifiedAddress = false
|
||||
} else if !sentWithSpecifiedAddress {
|
||||
allSentWithSpecifiedAddress = false
|
||||
}
|
||||
}
|
||||
|
||||
return allSentWithSpecifiedAddress, firstErr
|
||||
}
|
||||
|
||||
// NewReportV2Builder implements ip.MulticastGroupProtocol.
|
||||
func (igmp *igmpState) NewReportV2Builder() ip.MulticastGroupProtocolV2ReportBuilder {
|
||||
return &igmpv3ReportBuilder{igmp: igmp}
|
||||
}
|
||||
|
||||
// V2QueryMaxRespCodeToV2Delay implements ip.MulticastGroupProtocol.
|
||||
func (*igmpState) V2QueryMaxRespCodeToV2Delay(code uint16) time.Duration {
|
||||
if code > math.MaxUint8 {
|
||||
panic(fmt.Sprintf("got IGMPv3 MaxRespCode = %d, want <= %d", code, math.MaxUint8))
|
||||
}
|
||||
return header.IGMPv3MaximumResponseDelay(uint8(code))
|
||||
}
|
||||
|
||||
// V2QueryMaxRespCodeToV1Delay implements ip.MulticastGroupProtocol.
|
||||
func (*igmpState) V2QueryMaxRespCodeToV1Delay(code uint16) time.Duration {
|
||||
return time.Duration(code) * time.Millisecond
|
||||
}
|
||||
|
||||
// init sets up an igmpState struct, and is required to be called before using
|
||||
// a new igmpState.
|
||||
//
|
||||
// Must only be called once for the lifetime of igmp.
|
||||
func (igmp *igmpState) init(ep *endpoint) {
|
||||
igmp.ep = ep
|
||||
igmp.genericMulticastProtocol.Init(&ep.mu, ip.GenericMulticastProtocolOptions{
|
||||
Rand: ep.protocol.stack.InsecureRNG(),
|
||||
Clock: ep.protocol.stack.Clock(),
|
||||
Protocol: igmp,
|
||||
MaxUnsolicitedReportDelay: UnsolicitedReportIntervalMax,
|
||||
})
|
||||
// As per RFC 2236 Page 9 says "No IGMPv1 Router Present ... is
|
||||
// the initial state.
|
||||
igmp.mode = protocolModeV2OrV3
|
||||
igmp.igmpV1Job = tcpip.NewJob(ep.protocol.stack.Clock(), &ep.mu, func() {
|
||||
igmp.mode = protocolModeV2OrV3
|
||||
})
|
||||
}
|
||||
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) isSourceIPValidLocked(src tcpip.Address, messageType header.IGMPType) bool {
|
||||
if messageType == header.IGMPMembershipQuery {
|
||||
// RFC 2236 does not require the IGMP implementation to check the source IP
|
||||
// for Membership Query messages.
|
||||
return true
|
||||
}
|
||||
|
||||
// As per RFC 2236 section 10,
|
||||
//
|
||||
// Ignore the Report if you cannot identify the source address of the
|
||||
// packet as belonging to a subnet assigned to the interface on which the
|
||||
// packet was received.
|
||||
//
|
||||
// Ignore the Leave message if you cannot identify the source address of
|
||||
// the packet as belonging to a subnet assigned to the interface on which
|
||||
// the packet was received.
|
||||
//
|
||||
// Note: this rule applies to both V1 and V2 Membership Reports.
|
||||
var isSourceIPValid bool
|
||||
igmp.ep.addressableEndpointState.ForEachPrimaryEndpoint(func(addressEndpoint stack.AddressEndpoint) bool {
|
||||
if subnet := addressEndpoint.Subnet(); subnet.Contains(src) {
|
||||
isSourceIPValid = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
return isSourceIPValid
|
||||
}
|
||||
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) isPacketValidLocked(pkt *stack.PacketBuffer, messageType header.IGMPType, hasRouterAlertOption bool) bool {
|
||||
// We can safely assume that the IP header is valid if we got this far.
|
||||
iph := header.IPv4(pkt.NetworkHeader().Slice())
|
||||
|
||||
// As per RFC 2236 section 2,
|
||||
//
|
||||
// All IGMP messages described in this document are sent with IP TTL 1, and
|
||||
// contain the IP Router Alert option [RFC 2113] in their IP header.
|
||||
if !hasRouterAlertOption || iph.TTL() != header.IGMPTTL {
|
||||
return false
|
||||
}
|
||||
|
||||
return igmp.isSourceIPValidLocked(iph.SourceAddress(), messageType)
|
||||
}
|
||||
|
||||
// handleIGMP handles an IGMP packet.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption bool) {
|
||||
received := igmp.ep.stats.igmp.packetsReceived
|
||||
hdr, ok := pkt.Data().PullUp(pkt.Data().Size())
|
||||
if !ok {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
h := header.IGMP(hdr)
|
||||
if len(h) < header.IGMPMinimumSize {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
// As per RFC 1071 section 1.3,
|
||||
//
|
||||
// To check a checksum, the 1's complement sum is computed over the
|
||||
// same set of octets, including the checksum field. If the result
|
||||
// is all 1 bits (-0 in 1's complement arithmetic), the check
|
||||
// succeeds.
|
||||
if pkt.Data().Checksum() != 0xFFFF {
|
||||
received.checksumErrors.Increment()
|
||||
return
|
||||
}
|
||||
|
||||
isValid := func(minimumSize int) bool {
|
||||
return len(hdr) >= minimumSize && igmp.isPacketValidLocked(pkt, h.Type(), hasRouterAlertOption)
|
||||
}
|
||||
|
||||
switch h.Type() {
|
||||
case header.IGMPMembershipQuery:
|
||||
received.membershipQuery.Increment()
|
||||
if len(h) >= header.IGMPv3QueryMinimumSize {
|
||||
if isValid(header.IGMPv3QueryMinimumSize) {
|
||||
igmp.handleMembershipQueryV3(header.IGMPv3Query(h))
|
||||
} else {
|
||||
received.invalid.Increment()
|
||||
}
|
||||
return
|
||||
} else if !isValid(header.IGMPQueryMinimumSize) {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
igmp.handleMembershipQuery(h.GroupAddress(), h.MaxRespTime())
|
||||
case header.IGMPv1MembershipReport:
|
||||
received.v1MembershipReport.Increment()
|
||||
if !isValid(header.IGMPReportMinimumSize) {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
igmp.handleMembershipReport(h.GroupAddress())
|
||||
case header.IGMPv2MembershipReport:
|
||||
received.v2MembershipReport.Increment()
|
||||
if !isValid(header.IGMPReportMinimumSize) {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
igmp.handleMembershipReport(h.GroupAddress())
|
||||
case header.IGMPLeaveGroup:
|
||||
received.leaveGroup.Increment()
|
||||
if !isValid(header.IGMPLeaveMessageMinimumSize) {
|
||||
received.invalid.Increment()
|
||||
return
|
||||
}
|
||||
// As per RFC 2236 Section 6, Page 7: "IGMP messages other than Query or
|
||||
// Report, are ignored in all states"
|
||||
|
||||
default:
|
||||
// As per RFC 2236 Section 2.1 Page 3: "Unrecognized message types should
|
||||
// be silently ignored. New message types may be used by newer versions of
|
||||
// IGMP, by multicast routing protocols, or other uses."
|
||||
received.unrecognized.Increment()
|
||||
}
|
||||
}
|
||||
|
||||
func (igmp *igmpState) resetV1Present() {
|
||||
igmp.igmpV1Job.Cancel()
|
||||
switch igmp.mode {
|
||||
case protocolModeV2OrV3, protocolModeV1:
|
||||
case protocolModeV1Compatibility:
|
||||
igmp.mode = protocolModeV2OrV3
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mode = %d", igmp.mode))
|
||||
}
|
||||
}
|
||||
|
||||
// handleMembershipQuery handles a membership query.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) handleMembershipQuery(groupAddress tcpip.Address, maxRespTime time.Duration) {
|
||||
// As per RFC 2236 Section 6, Page 10: If the maximum response time is zero
|
||||
// then change the state to note that an IGMPv1 router is present and
|
||||
// schedule the query received Job.
|
||||
if maxRespTime == 0 && igmp.Enabled() {
|
||||
switch igmp.mode {
|
||||
case protocolModeV2OrV3, protocolModeV1Compatibility:
|
||||
igmp.igmpV1Job.Cancel()
|
||||
igmp.igmpV1Job.Schedule(v1RouterPresentTimeout)
|
||||
igmp.mode = protocolModeV1Compatibility
|
||||
case protocolModeV1:
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mode = %d", igmp.mode))
|
||||
}
|
||||
|
||||
maxRespTime = v1MaxRespTime
|
||||
}
|
||||
|
||||
igmp.genericMulticastProtocol.HandleQueryLocked(groupAddress, maxRespTime)
|
||||
}
|
||||
|
||||
// handleMembershipQueryV3 handles a membership query.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) handleMembershipQueryV3(igmpHdr header.IGMPv3Query) {
|
||||
sources, ok := igmpHdr.Sources()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
igmp.genericMulticastProtocol.HandleQueryV2Locked(
|
||||
igmpHdr.GroupAddress(),
|
||||
uint16(igmpHdr.MaximumResponseCode()),
|
||||
sources,
|
||||
igmpHdr.QuerierRobustnessVariable(),
|
||||
igmpHdr.QuerierQueryInterval(),
|
||||
)
|
||||
}
|
||||
|
||||
// handleMembershipReport handles a membership report.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) handleMembershipReport(groupAddress tcpip.Address) {
|
||||
igmp.genericMulticastProtocol.HandleReportLocked(groupAddress)
|
||||
}
|
||||
|
||||
// writePacket assembles and sends an IGMP packet.
|
||||
//
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) writePacket(destAddress tcpip.Address, groupAddress tcpip.Address, igmpType header.IGMPType) (bool, tcpip.Error) {
|
||||
igmpView := buffer.NewViewSize(header.IGMPReportMinimumSize)
|
||||
igmpData := header.IGMP(igmpView.AsSlice())
|
||||
igmpData.SetType(igmpType)
|
||||
igmpData.SetGroupAddress(groupAddress)
|
||||
igmpData.SetChecksum(header.IGMPCalculateChecksum(igmpData))
|
||||
|
||||
var reportType tcpip.MultiCounterStat
|
||||
sentStats := igmp.ep.stats.igmp.packetsSent
|
||||
switch igmpType {
|
||||
case header.IGMPv1MembershipReport:
|
||||
reportType = sentStats.v1MembershipReport
|
||||
case header.IGMPv2MembershipReport:
|
||||
reportType = sentStats.v2MembershipReport
|
||||
case header.IGMPLeaveGroup:
|
||||
reportType = sentStats.leaveGroup
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized igmp type = %d", igmpType))
|
||||
}
|
||||
|
||||
return igmp.writePacketInner(
|
||||
igmpView,
|
||||
reportType,
|
||||
header.IPv4OptionsSerializer{
|
||||
&header.IPv4SerializableRouterAlertOption{},
|
||||
},
|
||||
destAddress,
|
||||
)
|
||||
}
|
||||
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) writePacketInner(buf *buffer.View, reportStat tcpip.MultiCounterStat, options header.IPv4OptionsSerializer, destAddress tcpip.Address) (bool, tcpip.Error) {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(igmp.ep.MaxHeaderLength()),
|
||||
Payload: buffer.MakeWithView(buf),
|
||||
})
|
||||
defer pkt.DecRef()
|
||||
|
||||
addressEndpoint := igmp.ep.acquireOutgoingPrimaryAddressRLocked(destAddress, tcpip.Address{} /* srcHint */, false /* allowExpired */)
|
||||
if addressEndpoint == nil {
|
||||
return false, nil
|
||||
}
|
||||
localAddr := addressEndpoint.AddressWithPrefix().Address
|
||||
addressEndpoint.DecRef()
|
||||
addressEndpoint = nil
|
||||
if err := igmp.ep.addIPHeader(localAddr, destAddress, pkt, stack.NetworkHeaderParams{
|
||||
Protocol: header.IGMPProtocolNumber,
|
||||
TTL: header.IGMPTTL,
|
||||
TOS: stack.DefaultTOS,
|
||||
}, options); err != nil {
|
||||
panic(fmt.Sprintf("failed to add IP header: %s", err))
|
||||
}
|
||||
|
||||
sentStats := igmp.ep.stats.igmp.packetsSent
|
||||
if err := igmp.ep.nic.WritePacketToRemote(header.EthernetAddressFromMulticastIPv4Address(destAddress), pkt); err != nil {
|
||||
sentStats.dropped.Increment()
|
||||
return false, err
|
||||
}
|
||||
reportStat.Increment()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// joinGroup handles adding a new group to the membership map, setting up the
|
||||
// IGMP state for the group, and sending and scheduling the required
|
||||
// messages.
|
||||
//
|
||||
// If the group already exists in the membership map, returns
|
||||
// *tcpip.ErrDuplicateAddress.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) joinGroup(groupAddress tcpip.Address) {
|
||||
igmp.genericMulticastProtocol.JoinGroupLocked(groupAddress)
|
||||
}
|
||||
|
||||
// isInGroup returns true if the specified group has been joined locally.
|
||||
//
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) isInGroup(groupAddress tcpip.Address) bool {
|
||||
return igmp.genericMulticastProtocol.IsLocallyJoinedRLocked(groupAddress)
|
||||
}
|
||||
|
||||
// leaveGroup handles removing the group from the membership map, cancels any
|
||||
// delay timers associated with that group, and sends the Leave Group message
|
||||
// if required.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) leaveGroup(groupAddress tcpip.Address) tcpip.Error {
|
||||
// LeaveGroup returns false only if the group was not joined.
|
||||
if igmp.genericMulticastProtocol.LeaveGroupLocked(groupAddress) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &tcpip.ErrBadLocalAddress{}
|
||||
}
|
||||
|
||||
// softLeaveAll leaves all groups from the perspective of IGMP, but remains
|
||||
// joined locally.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) softLeaveAll() {
|
||||
igmp.genericMulticastProtocol.MakeAllNonMemberLocked()
|
||||
}
|
||||
|
||||
// initializeAll attempts to initialize the IGMP state for each group that has
|
||||
// been joined locally.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) initializeAll() {
|
||||
igmp.genericMulticastProtocol.InitializeGroupsLocked()
|
||||
}
|
||||
|
||||
// sendQueuedReports attempts to send any reports that are queued for sending.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) sendQueuedReports() {
|
||||
igmp.genericMulticastProtocol.SendQueuedReportsLocked()
|
||||
}
|
||||
|
||||
// setVersion sets the IGMP version.
|
||||
//
|
||||
// +checklocks:igmp.ep.mu
|
||||
func (igmp *igmpState) setVersion(v IGMPVersion) IGMPVersion {
|
||||
prev := igmp.mode
|
||||
igmp.igmpV1Job.Cancel()
|
||||
|
||||
var prevGenericModeV1 bool
|
||||
switch v {
|
||||
case IGMPVersion3:
|
||||
prevGenericModeV1 = igmp.genericMulticastProtocol.SetV1ModeLocked(false)
|
||||
igmp.mode = protocolModeV2OrV3
|
||||
case IGMPVersion2:
|
||||
// IGMPv1 and IGMPv2 map to V1 of the generic multicast protocol.
|
||||
prevGenericModeV1 = igmp.genericMulticastProtocol.SetV1ModeLocked(true)
|
||||
igmp.mode = protocolModeV2OrV3
|
||||
case IGMPVersion1:
|
||||
// IGMPv1 and IGMPv2 map to V1 of the generic multicast protocol.
|
||||
prevGenericModeV1 = igmp.genericMulticastProtocol.SetV1ModeLocked(true)
|
||||
igmp.mode = protocolModeV1
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized version = %d", v))
|
||||
}
|
||||
|
||||
return toIGMPVersion(prev, prevGenericModeV1)
|
||||
}
|
||||
|
||||
func toIGMPVersion(mode protocolMode, genericV1 bool) IGMPVersion {
|
||||
switch mode {
|
||||
case protocolModeV2OrV3, protocolModeV1Compatibility:
|
||||
if genericV1 {
|
||||
return IGMPVersion2
|
||||
}
|
||||
return IGMPVersion3
|
||||
case protocolModeV1:
|
||||
return IGMPVersion1
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized mode = %d", mode))
|
||||
}
|
||||
}
|
||||
|
||||
// getVersion returns the IGMP version.
|
||||
//
|
||||
// +checklocksread:igmp.ep.mu
|
||||
func (igmp *igmpState) getVersion() IGMPVersion {
|
||||
return toIGMPVersion(igmp.mode, igmp.genericMulticastProtocol.GetV1ModeLocked())
|
||||
}
|
||||
2405
pkg/tcpip/network/ipv4/ipv4.go
Normal file
2405
pkg/tcpip/network/ipv4/ipv4.go
Normal file
File diff suppressed because it is too large
Load diff
14
pkg/tcpip/network/ipv4/ipv4_export.go
Normal file
14
pkg/tcpip/network/ipv4/ipv4_export.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package ipv4
|
||||
|
||||
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)
|
||||
}
|
||||
785
pkg/tcpip/network/ipv4/ipv4_state_autogen.go
Normal file
785
pkg/tcpip/network/ipv4/ipv4_state_autogen.go
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
// automatically generated by stateify.
|
||||
|
||||
package ipv4
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/state"
|
||||
)
|
||||
|
||||
func (i *icmpv4DestinationUnreachableSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationUnreachableSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationUnreachableSockError) StateFields() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationUnreachableSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationUnreachableSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationUnreachableSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationUnreachableSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationHostUnreachableSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationHostUnreachableSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationNetUnreachableSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationNetUnreachableSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationPortUnreachableSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationPortUnreachableSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationProtoUnreachableSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationProtoUnreachableSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceRouteFailedSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4SourceRouteFailedSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceRouteFailedSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceRouteFailedSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4SourceRouteFailedSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceRouteFailedSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4SourceRouteFailedSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceHostIsolatedSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4SourceHostIsolatedSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceHostIsolatedSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceHostIsolatedSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4SourceHostIsolatedSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4SourceHostIsolatedSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4SourceHostIsolatedSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnknownSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4DestinationHostUnknownSockError"
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnknownSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnknownSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationHostUnknownSockError) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (i *icmpv4DestinationHostUnknownSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *icmpv4DestinationHostUnknownSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.icmpv4DestinationUnreachableSockError)
|
||||
}
|
||||
|
||||
func (e *icmpv4FragmentationNeededSockError) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.icmpv4FragmentationNeededSockError"
|
||||
}
|
||||
|
||||
func (e *icmpv4FragmentationNeededSockError) StateFields() []string {
|
||||
return []string{
|
||||
"icmpv4DestinationUnreachableSockError",
|
||||
"mtu",
|
||||
}
|
||||
}
|
||||
|
||||
func (e *icmpv4FragmentationNeededSockError) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (e *icmpv4FragmentationNeededSockError) StateSave(stateSinkObject state.Sink) {
|
||||
e.beforeSave()
|
||||
stateSinkObject.Save(0, &e.icmpv4DestinationUnreachableSockError)
|
||||
stateSinkObject.Save(1, &e.mtu)
|
||||
}
|
||||
|
||||
func (e *icmpv4FragmentationNeededSockError) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (e *icmpv4FragmentationNeededSockError) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &e.icmpv4DestinationUnreachableSockError)
|
||||
stateSourceObject.Load(1, &e.mtu)
|
||||
}
|
||||
|
||||
func (i *IGMPOptions) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.IGMPOptions"
|
||||
}
|
||||
|
||||
func (i *IGMPOptions) StateFields() []string {
|
||||
return []string{
|
||||
"Enabled",
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IGMPOptions) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *IGMPOptions) StateSave(stateSinkObject state.Sink) {
|
||||
i.beforeSave()
|
||||
stateSinkObject.Save(0, &i.Enabled)
|
||||
}
|
||||
|
||||
func (i *IGMPOptions) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (i *IGMPOptions) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &i.Enabled)
|
||||
}
|
||||
|
||||
func (igmp *igmpState) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.igmpState"
|
||||
}
|
||||
|
||||
func (igmp *igmpState) StateFields() []string {
|
||||
return []string{
|
||||
"ep",
|
||||
"genericMulticastProtocol",
|
||||
"mode",
|
||||
"igmpV1Job",
|
||||
}
|
||||
}
|
||||
|
||||
func (igmp *igmpState) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (igmp *igmpState) StateSave(stateSinkObject state.Sink) {
|
||||
igmp.beforeSave()
|
||||
stateSinkObject.Save(0, &igmp.ep)
|
||||
stateSinkObject.Save(1, &igmp.genericMulticastProtocol)
|
||||
stateSinkObject.Save(2, &igmp.mode)
|
||||
stateSinkObject.Save(3, &igmp.igmpV1Job)
|
||||
}
|
||||
|
||||
func (igmp *igmpState) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (igmp *igmpState) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &igmp.ep)
|
||||
stateSourceObject.Load(1, &igmp.genericMulticastProtocol)
|
||||
stateSourceObject.Load(2, &igmp.mode)
|
||||
stateSourceObject.Load(3, &igmp.igmpV1Job)
|
||||
}
|
||||
|
||||
func (e *endpoint) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.endpoint"
|
||||
}
|
||||
|
||||
func (e *endpoint) StateFields() []string {
|
||||
return []string{
|
||||
"nic",
|
||||
"dispatcher",
|
||||
"protocol",
|
||||
"stats",
|
||||
"enabled",
|
||||
"forwarding",
|
||||
"multicastForwarding",
|
||||
"addressableEndpointState",
|
||||
"igmp",
|
||||
}
|
||||
}
|
||||
|
||||
func (e *endpoint) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (e *endpoint) StateSave(stateSinkObject state.Sink) {
|
||||
e.beforeSave()
|
||||
stateSinkObject.Save(0, &e.nic)
|
||||
stateSinkObject.Save(1, &e.dispatcher)
|
||||
stateSinkObject.Save(2, &e.protocol)
|
||||
stateSinkObject.Save(3, &e.stats)
|
||||
stateSinkObject.Save(4, &e.enabled)
|
||||
stateSinkObject.Save(5, &e.forwarding)
|
||||
stateSinkObject.Save(6, &e.multicastForwarding)
|
||||
stateSinkObject.Save(7, &e.addressableEndpointState)
|
||||
stateSinkObject.Save(8, &e.igmp)
|
||||
}
|
||||
|
||||
func (e *endpoint) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (e *endpoint) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &e.nic)
|
||||
stateSourceObject.Load(1, &e.dispatcher)
|
||||
stateSourceObject.Load(2, &e.protocol)
|
||||
stateSourceObject.Load(3, &e.stats)
|
||||
stateSourceObject.Load(4, &e.enabled)
|
||||
stateSourceObject.Load(5, &e.forwarding)
|
||||
stateSourceObject.Load(6, &e.multicastForwarding)
|
||||
stateSourceObject.Load(7, &e.addressableEndpointState)
|
||||
stateSourceObject.Load(8, &e.igmp)
|
||||
}
|
||||
|
||||
func (p *protocol) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.protocol"
|
||||
}
|
||||
|
||||
func (p *protocol) StateFields() []string {
|
||||
return []string{
|
||||
"stack",
|
||||
"eps",
|
||||
"icmpRateLimitedTypes",
|
||||
"defaultTTL",
|
||||
"ids",
|
||||
"hashIV",
|
||||
"idTS",
|
||||
"fragmentation",
|
||||
"options",
|
||||
"multicastRouteTable",
|
||||
"multicastForwardingDisp",
|
||||
}
|
||||
}
|
||||
|
||||
func (p *protocol) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (p *protocol) StateSave(stateSinkObject state.Sink) {
|
||||
p.beforeSave()
|
||||
stateSinkObject.Save(0, &p.stack)
|
||||
stateSinkObject.Save(1, &p.eps)
|
||||
stateSinkObject.Save(2, &p.icmpRateLimitedTypes)
|
||||
stateSinkObject.Save(3, &p.defaultTTL)
|
||||
stateSinkObject.Save(4, &p.ids)
|
||||
stateSinkObject.Save(5, &p.hashIV)
|
||||
stateSinkObject.Save(6, &p.idTS)
|
||||
stateSinkObject.Save(7, &p.fragmentation)
|
||||
stateSinkObject.Save(8, &p.options)
|
||||
stateSinkObject.Save(9, &p.multicastRouteTable)
|
||||
stateSinkObject.Save(10, &p.multicastForwardingDisp)
|
||||
}
|
||||
|
||||
func (p *protocol) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (p *protocol) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &p.stack)
|
||||
stateSourceObject.Load(1, &p.eps)
|
||||
stateSourceObject.Load(2, &p.icmpRateLimitedTypes)
|
||||
stateSourceObject.Load(3, &p.defaultTTL)
|
||||
stateSourceObject.Load(4, &p.ids)
|
||||
stateSourceObject.Load(5, &p.hashIV)
|
||||
stateSourceObject.Load(6, &p.idTS)
|
||||
stateSourceObject.Load(7, &p.fragmentation)
|
||||
stateSourceObject.Load(8, &p.options)
|
||||
stateSourceObject.Load(9, &p.multicastRouteTable)
|
||||
stateSourceObject.Load(10, &p.multicastForwardingDisp)
|
||||
}
|
||||
|
||||
func (o *Options) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.Options"
|
||||
}
|
||||
|
||||
func (o *Options) StateFields() []string {
|
||||
return []string{
|
||||
"IGMP",
|
||||
"AllowExternalLoopbackTraffic",
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Options) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (o *Options) StateSave(stateSinkObject state.Sink) {
|
||||
o.beforeSave()
|
||||
stateSinkObject.Save(0, &o.IGMP)
|
||||
stateSinkObject.Save(1, &o.AllowExternalLoopbackTraffic)
|
||||
}
|
||||
|
||||
func (o *Options) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (o *Options) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &o.IGMP)
|
||||
stateSourceObject.Load(1, &o.AllowExternalLoopbackTraffic)
|
||||
}
|
||||
|
||||
func (s *Stats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.Stats"
|
||||
}
|
||||
|
||||
func (s *Stats) StateFields() []string {
|
||||
return []string{
|
||||
"IP",
|
||||
"IGMP",
|
||||
"ICMP",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (s *Stats) StateSave(stateSinkObject state.Sink) {
|
||||
s.beforeSave()
|
||||
stateSinkObject.Save(0, &s.IP)
|
||||
stateSinkObject.Save(1, &s.IGMP)
|
||||
stateSinkObject.Save(2, &s.ICMP)
|
||||
}
|
||||
|
||||
func (s *Stats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (s *Stats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &s.IP)
|
||||
stateSourceObject.Load(1, &s.IGMP)
|
||||
stateSourceObject.Load(2, &s.ICMP)
|
||||
}
|
||||
|
||||
func (s *sharedStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.sharedStats"
|
||||
}
|
||||
|
||||
func (s *sharedStats) StateFields() []string {
|
||||
return []string{
|
||||
"localStats",
|
||||
"ip",
|
||||
"icmp",
|
||||
"igmp",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sharedStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (s *sharedStats) StateSave(stateSinkObject state.Sink) {
|
||||
s.beforeSave()
|
||||
stateSinkObject.Save(0, &s.localStats)
|
||||
stateSinkObject.Save(1, &s.ip)
|
||||
stateSinkObject.Save(2, &s.icmp)
|
||||
stateSinkObject.Save(3, &s.igmp)
|
||||
}
|
||||
|
||||
func (s *sharedStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (s *sharedStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &s.localStats)
|
||||
stateSourceObject.Load(1, &s.ip)
|
||||
stateSourceObject.Load(2, &s.icmp)
|
||||
stateSourceObject.Load(3, &s.igmp)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4PacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterICMPv4PacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4PacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"echoRequest",
|
||||
"echoReply",
|
||||
"dstUnreachable",
|
||||
"srcQuench",
|
||||
"redirect",
|
||||
"timeExceeded",
|
||||
"paramProblem",
|
||||
"timestamp",
|
||||
"timestampReply",
|
||||
"infoRequest",
|
||||
"infoReply",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4PacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4PacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.echoRequest)
|
||||
stateSinkObject.Save(1, &m.echoReply)
|
||||
stateSinkObject.Save(2, &m.dstUnreachable)
|
||||
stateSinkObject.Save(3, &m.srcQuench)
|
||||
stateSinkObject.Save(4, &m.redirect)
|
||||
stateSinkObject.Save(5, &m.timeExceeded)
|
||||
stateSinkObject.Save(6, &m.paramProblem)
|
||||
stateSinkObject.Save(7, &m.timestamp)
|
||||
stateSinkObject.Save(8, &m.timestampReply)
|
||||
stateSinkObject.Save(9, &m.infoRequest)
|
||||
stateSinkObject.Save(10, &m.infoReply)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4PacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4PacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.echoRequest)
|
||||
stateSourceObject.Load(1, &m.echoReply)
|
||||
stateSourceObject.Load(2, &m.dstUnreachable)
|
||||
stateSourceObject.Load(3, &m.srcQuench)
|
||||
stateSourceObject.Load(4, &m.redirect)
|
||||
stateSourceObject.Load(5, &m.timeExceeded)
|
||||
stateSourceObject.Load(6, &m.paramProblem)
|
||||
stateSourceObject.Load(7, &m.timestamp)
|
||||
stateSourceObject.Load(8, &m.timestampReply)
|
||||
stateSourceObject.Load(9, &m.infoRequest)
|
||||
stateSourceObject.Load(10, &m.infoReply)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4SentPacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterICMPv4SentPacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4SentPacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"multiCounterICMPv4PacketStats",
|
||||
"dropped",
|
||||
"rateLimited",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4SentPacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4SentPacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.multiCounterICMPv4PacketStats)
|
||||
stateSinkObject.Save(1, &m.dropped)
|
||||
stateSinkObject.Save(2, &m.rateLimited)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4SentPacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4SentPacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.multiCounterICMPv4PacketStats)
|
||||
stateSourceObject.Load(1, &m.dropped)
|
||||
stateSourceObject.Load(2, &m.rateLimited)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterICMPv4ReceivedPacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"multiCounterICMPv4PacketStats",
|
||||
"invalid",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.multiCounterICMPv4PacketStats)
|
||||
stateSinkObject.Save(1, &m.invalid)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.multiCounterICMPv4PacketStats)
|
||||
stateSourceObject.Load(1, &m.invalid)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4Stats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterICMPv4Stats"
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4Stats) StateFields() []string {
|
||||
return []string{
|
||||
"packetsSent",
|
||||
"packetsReceived",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4Stats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4Stats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.packetsSent)
|
||||
stateSinkObject.Save(1, &m.packetsReceived)
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4Stats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterICMPv4Stats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.packetsSent)
|
||||
stateSourceObject.Load(1, &m.packetsReceived)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPPacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterIGMPPacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPPacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"membershipQuery",
|
||||
"v1MembershipReport",
|
||||
"v2MembershipReport",
|
||||
"v3MembershipReport",
|
||||
"leaveGroup",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPPacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPPacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.membershipQuery)
|
||||
stateSinkObject.Save(1, &m.v1MembershipReport)
|
||||
stateSinkObject.Save(2, &m.v2MembershipReport)
|
||||
stateSinkObject.Save(3, &m.v3MembershipReport)
|
||||
stateSinkObject.Save(4, &m.leaveGroup)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPPacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPPacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.membershipQuery)
|
||||
stateSourceObject.Load(1, &m.v1MembershipReport)
|
||||
stateSourceObject.Load(2, &m.v2MembershipReport)
|
||||
stateSourceObject.Load(3, &m.v3MembershipReport)
|
||||
stateSourceObject.Load(4, &m.leaveGroup)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPSentPacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterIGMPSentPacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPSentPacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"multiCounterIGMPPacketStats",
|
||||
"dropped",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPSentPacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPSentPacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.multiCounterIGMPPacketStats)
|
||||
stateSinkObject.Save(1, &m.dropped)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPSentPacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPSentPacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.multiCounterIGMPPacketStats)
|
||||
stateSourceObject.Load(1, &m.dropped)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPReceivedPacketStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterIGMPReceivedPacketStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPReceivedPacketStats) StateFields() []string {
|
||||
return []string{
|
||||
"multiCounterIGMPPacketStats",
|
||||
"invalid",
|
||||
"checksumErrors",
|
||||
"unrecognized",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPReceivedPacketStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPReceivedPacketStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.multiCounterIGMPPacketStats)
|
||||
stateSinkObject.Save(1, &m.invalid)
|
||||
stateSinkObject.Save(2, &m.checksumErrors)
|
||||
stateSinkObject.Save(3, &m.unrecognized)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPReceivedPacketStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPReceivedPacketStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.multiCounterIGMPPacketStats)
|
||||
stateSourceObject.Load(1, &m.invalid)
|
||||
stateSourceObject.Load(2, &m.checksumErrors)
|
||||
stateSourceObject.Load(3, &m.unrecognized)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPStats) StateTypeName() string {
|
||||
return "pkg/tcpip/network/ipv4.multiCounterIGMPStats"
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPStats) StateFields() []string {
|
||||
return []string{
|
||||
"packetsSent",
|
||||
"packetsReceived",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPStats) beforeSave() {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPStats) StateSave(stateSinkObject state.Sink) {
|
||||
m.beforeSave()
|
||||
stateSinkObject.Save(0, &m.packetsSent)
|
||||
stateSinkObject.Save(1, &m.packetsReceived)
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPStats) afterLoad(context.Context) {}
|
||||
|
||||
// +checklocksignore
|
||||
func (m *multiCounterIGMPStats) StateLoad(ctx context.Context, stateSourceObject state.Source) {
|
||||
stateSourceObject.Load(0, &m.packetsSent)
|
||||
stateSourceObject.Load(1, &m.packetsReceived)
|
||||
}
|
||||
|
||||
func init() {
|
||||
state.Register((*icmpv4DestinationUnreachableSockError)(nil))
|
||||
state.Register((*icmpv4DestinationHostUnreachableSockError)(nil))
|
||||
state.Register((*icmpv4DestinationNetUnreachableSockError)(nil))
|
||||
state.Register((*icmpv4DestinationPortUnreachableSockError)(nil))
|
||||
state.Register((*icmpv4DestinationProtoUnreachableSockError)(nil))
|
||||
state.Register((*icmpv4SourceRouteFailedSockError)(nil))
|
||||
state.Register((*icmpv4SourceHostIsolatedSockError)(nil))
|
||||
state.Register((*icmpv4DestinationHostUnknownSockError)(nil))
|
||||
state.Register((*icmpv4FragmentationNeededSockError)(nil))
|
||||
state.Register((*IGMPOptions)(nil))
|
||||
state.Register((*igmpState)(nil))
|
||||
state.Register((*endpoint)(nil))
|
||||
state.Register((*protocol)(nil))
|
||||
state.Register((*Options)(nil))
|
||||
state.Register((*Stats)(nil))
|
||||
state.Register((*sharedStats)(nil))
|
||||
state.Register((*multiCounterICMPv4PacketStats)(nil))
|
||||
state.Register((*multiCounterICMPv4SentPacketStats)(nil))
|
||||
state.Register((*multiCounterICMPv4ReceivedPacketStats)(nil))
|
||||
state.Register((*multiCounterICMPv4Stats)(nil))
|
||||
state.Register((*multiCounterIGMPPacketStats)(nil))
|
||||
state.Register((*multiCounterIGMPSentPacketStats)(nil))
|
||||
state.Register((*multiCounterIGMPReceivedPacketStats)(nil))
|
||||
state.Register((*multiCounterIGMPStats)(nil))
|
||||
}
|
||||
203
pkg/tcpip/network/ipv4/stats.go
Normal file
203
pkg/tcpip/network/ipv4/stats.go
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// 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 ipv4
|
||||
|
||||
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 IPv4 protocol family.
|
||||
//
|
||||
// +stateify savable
|
||||
type Stats struct {
|
||||
// IP holds IPv4 statistics.
|
||||
IP tcpip.IPStats
|
||||
|
||||
// IGMP holds IGMP statistics.
|
||||
IGMP tcpip.IGMPStats
|
||||
|
||||
// ICMP holds ICMPv4 statistics.
|
||||
ICMP tcpip.ICMPv4Stats
|
||||
}
|
||||
|
||||
// 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 multiCounterICMPv4Stats
|
||||
igmp multiCounterIGMPStats
|
||||
}
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv4PacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv4PacketStats struct {
|
||||
echoRequest tcpip.MultiCounterStat
|
||||
echoReply tcpip.MultiCounterStat
|
||||
dstUnreachable tcpip.MultiCounterStat
|
||||
srcQuench tcpip.MultiCounterStat
|
||||
redirect tcpip.MultiCounterStat
|
||||
timeExceeded tcpip.MultiCounterStat
|
||||
paramProblem tcpip.MultiCounterStat
|
||||
timestamp tcpip.MultiCounterStat
|
||||
timestampReply tcpip.MultiCounterStat
|
||||
infoRequest tcpip.MultiCounterStat
|
||||
infoReply tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4PacketStats) init(a, b *tcpip.ICMPv4PacketStats) {
|
||||
m.echoRequest.Init(a.EchoRequest, b.EchoRequest)
|
||||
m.echoReply.Init(a.EchoReply, b.EchoReply)
|
||||
m.dstUnreachable.Init(a.DstUnreachable, b.DstUnreachable)
|
||||
m.srcQuench.Init(a.SrcQuench, b.SrcQuench)
|
||||
m.redirect.Init(a.Redirect, b.Redirect)
|
||||
m.timeExceeded.Init(a.TimeExceeded, b.TimeExceeded)
|
||||
m.paramProblem.Init(a.ParamProblem, b.ParamProblem)
|
||||
m.timestamp.Init(a.Timestamp, b.Timestamp)
|
||||
m.timestampReply.Init(a.TimestampReply, b.TimestampReply)
|
||||
m.infoRequest.Init(a.InfoRequest, b.InfoRequest)
|
||||
m.infoReply.Init(a.InfoReply, b.InfoReply)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv4PacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv4SentPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv4SentPacketStats struct {
|
||||
multiCounterICMPv4PacketStats
|
||||
dropped tcpip.MultiCounterStat
|
||||
rateLimited tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4SentPacketStats) init(a, b *tcpip.ICMPv4SentPacketStats) {
|
||||
m.multiCounterICMPv4PacketStats.init(&a.ICMPv4PacketStats, &b.ICMPv4PacketStats)
|
||||
m.dropped.Init(a.Dropped, b.Dropped)
|
||||
m.rateLimited.Init(a.RateLimited, b.RateLimited)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv4SentPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv4ReceivedPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv4ReceivedPacketStats struct {
|
||||
multiCounterICMPv4PacketStats
|
||||
invalid tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4ReceivedPacketStats) init(a, b *tcpip.ICMPv4ReceivedPacketStats) {
|
||||
m.multiCounterICMPv4PacketStats.init(&a.ICMPv4PacketStats, &b.ICMPv4PacketStats)
|
||||
m.invalid.Init(a.Invalid, b.Invalid)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv4ReceivedPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterICMPv4Stats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterICMPv4Stats struct {
|
||||
packetsSent multiCounterICMPv4SentPacketStats
|
||||
packetsReceived multiCounterICMPv4ReceivedPacketStats
|
||||
}
|
||||
|
||||
func (m *multiCounterICMPv4Stats) init(a, b *tcpip.ICMPv4Stats) {
|
||||
m.packetsSent.init(&a.PacketsSent, &b.PacketsSent)
|
||||
m.packetsReceived.init(&a.PacketsReceived, &b.PacketsReceived)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:ICMPv4Stats)
|
||||
|
||||
// LINT.IfChange(multiCounterIGMPPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterIGMPPacketStats struct {
|
||||
membershipQuery tcpip.MultiCounterStat
|
||||
v1MembershipReport tcpip.MultiCounterStat
|
||||
v2MembershipReport tcpip.MultiCounterStat
|
||||
v3MembershipReport tcpip.MultiCounterStat
|
||||
leaveGroup tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPPacketStats) init(a, b *tcpip.IGMPPacketStats) {
|
||||
m.membershipQuery.Init(a.MembershipQuery, b.MembershipQuery)
|
||||
m.v1MembershipReport.Init(a.V1MembershipReport, b.V1MembershipReport)
|
||||
m.v2MembershipReport.Init(a.V2MembershipReport, b.V2MembershipReport)
|
||||
m.v3MembershipReport.Init(a.V3MembershipReport, b.V3MembershipReport)
|
||||
m.leaveGroup.Init(a.LeaveGroup, b.LeaveGroup)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:IGMPPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterIGMPSentPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterIGMPSentPacketStats struct {
|
||||
multiCounterIGMPPacketStats
|
||||
dropped tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPSentPacketStats) init(a, b *tcpip.IGMPSentPacketStats) {
|
||||
m.multiCounterIGMPPacketStats.init(&a.IGMPPacketStats, &b.IGMPPacketStats)
|
||||
m.dropped.Init(a.Dropped, b.Dropped)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:IGMPSentPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterIGMPReceivedPacketStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterIGMPReceivedPacketStats struct {
|
||||
multiCounterIGMPPacketStats
|
||||
invalid tcpip.MultiCounterStat
|
||||
checksumErrors tcpip.MultiCounterStat
|
||||
unrecognized tcpip.MultiCounterStat
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPReceivedPacketStats) init(a, b *tcpip.IGMPReceivedPacketStats) {
|
||||
m.multiCounterIGMPPacketStats.init(&a.IGMPPacketStats, &b.IGMPPacketStats)
|
||||
m.invalid.Init(a.Invalid, b.Invalid)
|
||||
m.checksumErrors.Init(a.ChecksumErrors, b.ChecksumErrors)
|
||||
m.unrecognized.Init(a.Unrecognized, b.Unrecognized)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:IGMPReceivedPacketStats)
|
||||
|
||||
// LINT.IfChange(multiCounterIGMPStats)
|
||||
|
||||
// +stateify savable
|
||||
type multiCounterIGMPStats struct {
|
||||
packetsSent multiCounterIGMPSentPacketStats
|
||||
packetsReceived multiCounterIGMPReceivedPacketStats
|
||||
}
|
||||
|
||||
func (m *multiCounterIGMPStats) init(a, b *tcpip.IGMPStats) {
|
||||
m.packetsSent.init(&a.PacketsSent, &b.PacketsSent)
|
||||
m.packetsReceived.init(&a.PacketsReceived, &b.PacketsReceived)
|
||||
}
|
||||
|
||||
// LINT.ThenChange(../../tcpip.go:IGMPStats)
|
||||
Loading…
Add table
Add a link
Reference in a new issue