2019-04-29 14:25:05 -07:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-07-09 14:03:03 -07:00
|
|
|
//
|
|
|
|
|
// 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.
|
2018-04-27 10:37:02 -07:00
|
|
|
|
|
|
|
|
// Package stack provides the glue between networking protocols and the
|
|
|
|
|
// consumers of the networking stack.
|
|
|
|
|
//
|
|
|
|
|
// For consumers, the only function of interest is New(), everything else is
|
|
|
|
|
// provided by the tcpip/public package.
|
|
|
|
|
package stack
|
|
|
|
|
|
|
|
|
|
import (
|
2024-11-22 17:06:56 -08:00
|
|
|
"context"
|
2019-09-30 13:54:03 -07:00
|
|
|
"encoding/binary"
|
2020-11-05 15:49:51 -08:00
|
|
|
"fmt"
|
2021-03-16 11:07:02 -07:00
|
|
|
"io"
|
2021-05-26 10:37:59 -07:00
|
|
|
"math/rand"
|
2018-04-27 10:37:02 -07:00
|
|
|
"time"
|
|
|
|
|
|
2019-09-03 15:59:58 -07:00
|
|
|
"golang.org/x/time/rate"
|
2021-03-19 13:44:26 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/atomicbitops"
|
2023-06-01 21:25:01 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/buffer"
|
2022-06-14 20:01:58 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/log"
|
2021-05-26 10:37:59 -07:00
|
|
|
cryptorand "gvisor.dev/gvisor/pkg/rand"
|
2019-06-13 16:49:09 -07:00
|
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/ports"
|
|
|
|
|
"gvisor.dev/gvisor/pkg/waiter"
|
2018-04-27 10:37:02 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2019-10-14 17:45:29 -07:00
|
|
|
// DefaultTOS is the default type of service value for network endpoints.
|
|
|
|
|
DefaultTOS = 0
|
2018-04-27 10:37:02 -07:00
|
|
|
)
|
|
|
|
|
|
2024-05-21 15:15:21 -07:00
|
|
|
// +stateify savable
|
2018-04-27 10:37:02 -07:00
|
|
|
type transportProtocolState struct {
|
|
|
|
|
proto TransportProtocol
|
2024-05-21 15:15:21 -07:00
|
|
|
defaultHandler func(id TransportEndpointID, pkt *PacketBuffer) bool `state:"nosave"`
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2024-03-06 13:22:36 -08:00
|
|
|
// RestoredEndpoint is an endpoint that needs to be restored.
|
|
|
|
|
type RestoredEndpoint interface {
|
|
|
|
|
// Restore restores an endpoint. This can be used to restart background
|
|
|
|
|
// workers such as protocol goroutines. This must be called after all
|
|
|
|
|
// indirect dependencies of the endpoint has been restored, which
|
2019-08-08 12:32:00 -07:00
|
|
|
// generally implies at the end of the restore process.
|
2024-03-06 13:22:36 -08:00
|
|
|
Restore(*Stack)
|
2019-08-08 12:32:00 -07:00
|
|
|
}
|
|
|
|
|
|
2024-03-13 10:33:23 -07:00
|
|
|
// ResumableEndpoint is an endpoint that needs to be resumed after save.
|
|
|
|
|
type ResumableEndpoint interface {
|
|
|
|
|
// Resume resumes an endpoint.
|
|
|
|
|
Resume()
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-14 20:01:58 -07:00
|
|
|
var netRawMissingLogger = log.BasicRateLimitedLogger(time.Minute)
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// Stack is a networking stack, with all supported protocols, NICs, and route
|
|
|
|
|
// table.
|
2022-01-24 19:51:35 -08:00
|
|
|
//
|
|
|
|
|
// LOCK ORDERING: mu > routeMu.
|
2024-05-21 15:15:21 -07:00
|
|
|
//
|
|
|
|
|
// +stateify savable
|
2018-04-27 10:37:02 -07:00
|
|
|
type Stack struct {
|
|
|
|
|
transportProtocols map[tcpip.TransportProtocolNumber]*transportProtocolState
|
|
|
|
|
networkProtocols map[tcpip.NetworkProtocolNumber]NetworkProtocol
|
|
|
|
|
|
2019-10-21 13:21:58 -07:00
|
|
|
// rawFactory creates raw endpoints. If nil, raw endpoints are
|
|
|
|
|
// disabled. It is set during Stack creation and is immutable.
|
2021-09-01 19:41:43 -07:00
|
|
|
rawFactory RawFactory
|
|
|
|
|
packetEndpointWriteSupported bool
|
2019-07-12 18:08:03 -07:00
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
demux *transportDemuxer
|
|
|
|
|
|
|
|
|
|
stats tcpip.Stats
|
|
|
|
|
|
2022-01-24 19:51:35 -08:00
|
|
|
// routeMu protects annotated fields below.
|
2024-05-21 15:15:21 -07:00
|
|
|
routeMu routeStackRWMutex `state:"nosave"`
|
2021-01-30 17:51:47 -08:00
|
|
|
|
2024-06-27 13:09:37 -07:00
|
|
|
// routeTable is a list of routes sorted by prefix length, longest (most specific) first.
|
2022-01-24 19:51:35 -08:00
|
|
|
// +checklocks:routeMu
|
2024-11-20 11:08:45 -08:00
|
|
|
routeTable tcpip.RouteList `state:"nosave"`
|
2021-01-30 17:51:47 -08:00
|
|
|
|
2024-05-21 15:15:21 -07:00
|
|
|
mu stackRWMutex `state:"nosave"`
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocks:mu
|
2024-11-20 11:08:45 -08:00
|
|
|
nics map[tcpip.NICID]*nic `state:"nosave"`
|
2024-06-26 10:31:07 -07:00
|
|
|
// +checklocks:mu
|
2021-05-14 16:29:33 -07:00
|
|
|
defaultForwardingEnabled map[tcpip.NetworkProtocolNumber]struct{}
|
2020-09-03 17:34:56 -07:00
|
|
|
|
2024-06-26 10:31:07 -07:00
|
|
|
// nicIDGen is used to generate NIC IDs.
|
2024-11-20 11:08:45 -08:00
|
|
|
nicIDGen atomicbitops.Int32 `state:"nosave"`
|
2024-06-26 10:31:07 -07:00
|
|
|
|
2020-09-03 17:34:56 -07:00
|
|
|
// cleanupEndpointsMu protects cleanupEndpoints.
|
2024-05-21 15:15:21 -07:00
|
|
|
cleanupEndpointsMu cleanupEndpointsMutex `state:"nosave"`
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocks:cleanupEndpointsMu
|
|
|
|
|
cleanupEndpoints map[TransportEndpoint]struct{}
|
2018-04-27 10:37:02 -07:00
|
|
|
|
|
|
|
|
*ports.PortManager
|
|
|
|
|
|
2018-05-01 22:11:07 -07:00
|
|
|
// clock is used to generate user-visible times.
|
|
|
|
|
clock tcpip.Clock
|
2019-03-12 14:36:58 -07:00
|
|
|
|
|
|
|
|
// handleLocal allows non-loopback interfaces to loop packets.
|
|
|
|
|
handleLocal bool
|
2019-08-02 16:25:34 -07:00
|
|
|
|
2020-06-04 15:38:33 -07:00
|
|
|
// tables are the iptables packet filtering and manipulation rules.
|
2021-06-14 12:24:04 -07:00
|
|
|
// TODO(gvisor.dev/issue/4595): S/R this field.
|
2024-05-21 15:15:21 -07:00
|
|
|
tables *IPTables `state:"nosave"`
|
2019-08-08 12:32:00 -07:00
|
|
|
|
2024-03-06 13:22:36 -08:00
|
|
|
// restoredEndpoints is a list of endpoints that need to be restored if the
|
2019-08-08 12:32:00 -07:00
|
|
|
// stack is being restored.
|
2024-03-06 13:22:36 -08:00
|
|
|
restoredEndpoints []RestoredEndpoint
|
2019-09-03 15:59:58 -07:00
|
|
|
|
2024-03-13 10:33:23 -07:00
|
|
|
// resumableEndpoints is a list of endpoints that need to be resumed
|
|
|
|
|
// after save.
|
|
|
|
|
resumableEndpoints []ResumableEndpoint
|
|
|
|
|
|
2019-09-03 15:59:58 -07:00
|
|
|
// icmpRateLimiter is a global rate limiter for all ICMP messages generated
|
|
|
|
|
// by the stack.
|
|
|
|
|
icmpRateLimiter *ICMPRateLimiter
|
2019-09-30 13:54:03 -07:00
|
|
|
|
2021-08-18 16:56:40 -07:00
|
|
|
// seed is a one-time random value initialized at stack startup.
|
2019-09-30 13:54:03 -07:00
|
|
|
//
|
2019-10-14 17:45:29 -07:00
|
|
|
// TODO(gvisor.dev/issue/940): S/R this field.
|
2019-11-07 09:45:26 -08:00
|
|
|
seed uint32
|
2019-10-16 22:53:20 -07:00
|
|
|
|
2020-07-30 13:28:21 -07:00
|
|
|
// nudConfigs is the default NUD configurations used by interfaces.
|
|
|
|
|
nudConfigs NUDConfigurations
|
|
|
|
|
|
|
|
|
|
// nudDisp is the NUD event dispatcher that is used to send the netstack
|
|
|
|
|
// integrator NUD related events.
|
|
|
|
|
nudDisp NUDDispatcher
|
|
|
|
|
|
2020-03-24 15:33:16 -07:00
|
|
|
// randomGenerator is an injectable pseudo random generator that can be
|
2023-10-28 16:11:16 -07:00
|
|
|
// used when a random number is required. It must not be used in
|
|
|
|
|
// security-sensitive contexts.
|
2024-05-21 15:15:21 -07:00
|
|
|
insecureRNG *rand.Rand `state:"nosave"`
|
2020-06-24 10:21:44 -07:00
|
|
|
|
2021-03-16 11:07:02 -07:00
|
|
|
// secureRNG is a cryptographically secure random number generator.
|
2024-05-21 15:15:21 -07:00
|
|
|
secureRNG cryptorand.RNG `state:"nosave"`
|
2021-03-16 11:07:02 -07:00
|
|
|
|
2020-06-24 10:21:44 -07:00
|
|
|
// sendBufferSize holds the min/default/max send buffer sizes for
|
|
|
|
|
// endpoints other than TCP.
|
2021-01-26 08:23:49 -08:00
|
|
|
sendBufferSize tcpip.SendBufferSizeOption
|
2020-06-24 10:21:44 -07:00
|
|
|
|
|
|
|
|
// receiveBufferSize holds the min/default/max receive buffer sizes for
|
|
|
|
|
// endpoints other than TCP.
|
2021-04-20 09:30:57 -07:00
|
|
|
receiveBufferSize tcpip.ReceiveBufferSizeOption
|
2021-02-02 11:03:37 -08:00
|
|
|
|
|
|
|
|
// tcpInvalidRateLimit is the maximal rate for sending duplicate
|
|
|
|
|
// acknowledgements in response to incoming TCP packets that are for an existing
|
|
|
|
|
// connection but that are invalid due to any of the following reasons:
|
|
|
|
|
//
|
|
|
|
|
// a) out-of-window sequence number.
|
|
|
|
|
// b) out-of-window acknowledgement number.
|
|
|
|
|
// c) PAWS check failure (when implemented).
|
|
|
|
|
//
|
|
|
|
|
// This is required to prevent potential ACK loops.
|
|
|
|
|
// Setting this to 0 will disable all rate limiting.
|
|
|
|
|
tcpInvalidRateLimit time.Duration
|
2021-08-19 13:12:50 -07:00
|
|
|
|
|
|
|
|
// tsOffsetSecret is the secret key for generating timestamp offsets
|
|
|
|
|
// initialized at stack startup.
|
|
|
|
|
tsOffsetSecret uint32
|
2024-11-20 11:08:45 -08:00
|
|
|
|
|
|
|
|
// saveRestoreEnabled indicates whether the stack is saved and restored.
|
|
|
|
|
saveRestoreEnabled bool
|
2019-10-30 15:32:20 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-28 16:22:09 -07:00
|
|
|
// NetworkProtocolFactory instantiates a network protocol.
|
|
|
|
|
//
|
|
|
|
|
// NetworkProtocolFactory must not attempt to modify the stack, it may only
|
|
|
|
|
// query the stack.
|
|
|
|
|
type NetworkProtocolFactory func(*Stack) NetworkProtocol
|
|
|
|
|
|
|
|
|
|
// TransportProtocolFactory instantiates a transport protocol.
|
|
|
|
|
//
|
|
|
|
|
// TransportProtocolFactory must not attempt to modify the stack, it may only
|
|
|
|
|
// query the stack.
|
|
|
|
|
type TransportProtocolFactory func(*Stack) TransportProtocol
|
|
|
|
|
|
2018-08-01 20:21:00 -07:00
|
|
|
// Options contains optional Stack configuration.
|
|
|
|
|
type Options struct {
|
2019-09-25 12:56:00 -07:00
|
|
|
// NetworkProtocols lists the network protocols to enable.
|
2020-09-28 16:22:09 -07:00
|
|
|
NetworkProtocols []NetworkProtocolFactory
|
2019-09-25 12:56:00 -07:00
|
|
|
|
|
|
|
|
// TransportProtocols lists the transport protocols to enable.
|
2020-09-28 16:22:09 -07:00
|
|
|
TransportProtocols []TransportProtocolFactory
|
2019-09-25 12:56:00 -07:00
|
|
|
|
2021-05-26 13:57:22 -07:00
|
|
|
// Clock is an optional clock used for timekeeping.
|
2018-08-01 20:21:00 -07:00
|
|
|
//
|
2021-05-26 13:57:22 -07:00
|
|
|
// If Clock is nil, tcpip.NewStdClock() will be used.
|
2018-08-01 20:21:00 -07:00
|
|
|
Clock tcpip.Clock
|
2018-08-23 08:54:09 -07:00
|
|
|
|
|
|
|
|
// Stats are optional statistic counters.
|
|
|
|
|
Stats tcpip.Stats
|
2019-03-12 14:36:58 -07:00
|
|
|
|
|
|
|
|
// HandleLocal indicates whether packets destined to their source
|
|
|
|
|
// should be handled by the stack internally (true) or outside the
|
|
|
|
|
// stack (false).
|
|
|
|
|
HandleLocal bool
|
2019-04-26 16:50:35 -07:00
|
|
|
|
2020-07-30 13:28:21 -07:00
|
|
|
// NUDConfigs is the default NUD configurations used by interfaces.
|
|
|
|
|
NUDConfigs NUDConfigurations
|
|
|
|
|
|
|
|
|
|
// NUDDisp is the NUD event dispatcher that an integrator can provide to
|
|
|
|
|
// receive NUD related events.
|
|
|
|
|
NUDDisp NUDDispatcher
|
|
|
|
|
|
2019-10-21 13:21:58 -07:00
|
|
|
// RawFactory produces raw endpoints. Raw endpoints are enabled only if
|
|
|
|
|
// this is non-nil.
|
|
|
|
|
RawFactory RawFactory
|
2020-01-03 12:58:40 -08:00
|
|
|
|
2021-09-01 19:41:43 -07:00
|
|
|
// AllowPacketEndpointWrite determines if packet endpoints support write
|
|
|
|
|
// operations.
|
|
|
|
|
AllowPacketEndpointWrite bool
|
|
|
|
|
|
2020-03-24 15:33:16 -07:00
|
|
|
// RandSource is an optional source to use to generate random
|
|
|
|
|
// numbers. If omitted it defaults to a Source seeded by the data
|
2021-05-26 10:37:59 -07:00
|
|
|
// returned by the stack secure RNG.
|
2020-03-24 15:33:16 -07:00
|
|
|
//
|
|
|
|
|
// RandSource must be thread-safe.
|
2021-05-26 10:37:59 -07:00
|
|
|
RandSource rand.Source
|
2020-10-29 12:20:02 -07:00
|
|
|
|
2021-05-26 18:13:05 -07:00
|
|
|
// IPTables are the initial iptables rules. If nil, DefaultIPTables will be
|
|
|
|
|
// used to construct the initial iptables rules.
|
2020-10-29 12:20:02 -07:00
|
|
|
// all traffic.
|
|
|
|
|
IPTables *IPTables
|
2021-03-16 11:07:02 -07:00
|
|
|
|
2021-05-26 18:13:05 -07:00
|
|
|
// DefaultIPTables is an optional iptables rules constructor that is called
|
|
|
|
|
// if IPTables is nil. If both fields are nil, iptables will allow all
|
|
|
|
|
// traffic.
|
2021-11-11 15:54:11 -08:00
|
|
|
DefaultIPTables func(clock tcpip.Clock, rand *rand.Rand) *IPTables
|
2021-05-26 18:13:05 -07:00
|
|
|
|
2021-03-16 11:07:02 -07:00
|
|
|
// SecureRNG is a cryptographically secure random number generator.
|
|
|
|
|
SecureRNG io.Reader
|
2018-08-01 20:21:00 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-09 17:54:51 -07:00
|
|
|
// TransportEndpointInfo holds useful information about a transport endpoint
|
|
|
|
|
// which can be queried by monitoring tools.
|
|
|
|
|
//
|
|
|
|
|
// +stateify savable
|
|
|
|
|
type TransportEndpointInfo struct {
|
|
|
|
|
// The following fields are initialized at creation time and are
|
|
|
|
|
// immutable.
|
|
|
|
|
|
|
|
|
|
NetProto tcpip.NetworkProtocolNumber
|
|
|
|
|
TransProto tcpip.TransportProtocolNumber
|
|
|
|
|
|
|
|
|
|
// The following fields are protected by endpoint mu.
|
|
|
|
|
|
|
|
|
|
ID TransportEndpointID
|
|
|
|
|
// BindNICID and bindAddr are set via calls to Bind(). They are used to
|
|
|
|
|
// reject attempts to send data or connect via a different NIC or
|
|
|
|
|
// address
|
|
|
|
|
BindNICID tcpip.NICID
|
|
|
|
|
BindAddr tcpip.Address
|
|
|
|
|
// RegisterNICID is the default NICID registered as a side-effect of
|
|
|
|
|
// connect or datagram write.
|
|
|
|
|
RegisterNICID tcpip.NICID
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-03 13:40:59 -08:00
|
|
|
// AddrNetProtoLocked unwraps the specified address if it is a V4-mapped V6
|
|
|
|
|
// address and returns the network protocol number to be used to communicate
|
|
|
|
|
// with the specified address. It returns an error if the passed address is
|
|
|
|
|
// incompatible with the receiver.
|
|
|
|
|
//
|
|
|
|
|
// Preconditon: the parent endpoint mu must be held while calling this method.
|
2024-06-27 13:09:37 -07:00
|
|
|
func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6only bool, bind bool) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, tcpip.Error) {
|
2020-10-09 12:07:02 -07:00
|
|
|
netProto := t.NetProto
|
2023-05-15 18:03:37 -07:00
|
|
|
switch addr.Addr.BitLen() {
|
|
|
|
|
case header.IPv4AddressSizeBits:
|
2020-01-13 14:45:31 -08:00
|
|
|
netProto = header.IPv4ProtocolNumber
|
2023-05-15 18:03:37 -07:00
|
|
|
case header.IPv6AddressSizeBits:
|
2020-01-13 14:45:31 -08:00
|
|
|
if header.IsV4MappedAddress(addr.Addr) {
|
|
|
|
|
netProto = header.IPv4ProtocolNumber
|
2023-05-15 18:03:37 -07:00
|
|
|
addr.Addr = tcpip.AddrFrom4Slice(addr.Addr.AsSlice()[header.IPv6AddressSize-header.IPv4AddressSize:])
|
2020-01-13 14:45:31 -08:00
|
|
|
if addr.Addr == header.IPv4Any {
|
2023-05-15 18:03:37 -07:00
|
|
|
addr.Addr = tcpip.Address{}
|
2020-01-13 14:45:31 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-15 18:03:37 -07:00
|
|
|
switch t.ID.LocalAddress.BitLen() {
|
|
|
|
|
case header.IPv4AddressSizeBits:
|
|
|
|
|
if addr.Addr.BitLen() == header.IPv6AddressSizeBits {
|
2021-01-28 17:57:42 -08:00
|
|
|
return tcpip.FullAddress{}, 0, &tcpip.ErrInvalidEndpointState{}
|
2020-01-13 14:45:31 -08:00
|
|
|
}
|
2023-05-15 18:03:37 -07:00
|
|
|
case header.IPv6AddressSizeBits:
|
|
|
|
|
if addr.Addr.BitLen() == header.IPv4AddressSizeBits {
|
2021-01-28 17:57:42 -08:00
|
|
|
return tcpip.FullAddress{}, 0, &tcpip.ErrNetworkUnreachable{}
|
2020-01-13 14:45:31 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-27 13:09:37 -07:00
|
|
|
if !bind && addr.Addr.Unspecified() {
|
|
|
|
|
// If the destination address isn't set, Linux sets it to the
|
|
|
|
|
// source address. If a source address isn't set either, it
|
|
|
|
|
// sets both to the loopback address.
|
|
|
|
|
if t.ID.LocalAddress.Unspecified() {
|
|
|
|
|
switch netProto {
|
|
|
|
|
case header.IPv4ProtocolNumber:
|
|
|
|
|
addr.Addr = header.IPv4Loopback
|
|
|
|
|
case header.IPv6ProtocolNumber:
|
|
|
|
|
addr.Addr = header.IPv6Loopback
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
addr.Addr = t.ID.LocalAddress
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-13 14:45:31 -08:00
|
|
|
switch {
|
2020-10-09 12:07:02 -07:00
|
|
|
case netProto == t.NetProto:
|
|
|
|
|
case netProto == header.IPv4ProtocolNumber && t.NetProto == header.IPv6ProtocolNumber:
|
2020-01-13 14:45:31 -08:00
|
|
|
if v6only {
|
2022-10-19 18:26:36 -07:00
|
|
|
return tcpip.FullAddress{}, 0, &tcpip.ErrHostUnreachable{}
|
2020-01-13 14:45:31 -08:00
|
|
|
}
|
|
|
|
|
default:
|
2021-01-28 17:57:42 -08:00
|
|
|
return tcpip.FullAddress{}, 0, &tcpip.ErrInvalidEndpointState{}
|
2020-01-13 14:45:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return addr, netProto, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-09 17:54:51 -07:00
|
|
|
// IsEndpointInfo is an empty method to implement the tcpip.EndpointInfo
|
|
|
|
|
// marker interface.
|
|
|
|
|
func (*TransportEndpointInfo) IsEndpointInfo() {}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// New allocates a new networking stack with only the requested networking and
|
|
|
|
|
// transport protocols configured with default options.
|
|
|
|
|
//
|
2019-10-16 22:53:20 -07:00
|
|
|
// Note, NDPConfigurations will be fixed before being used by the Stack. That
|
|
|
|
|
// is, if an invalid value was provided, it will be reset to the default value.
|
|
|
|
|
//
|
2018-04-27 10:37:02 -07:00
|
|
|
// Protocol options can be changed by calling the
|
|
|
|
|
// SetNetworkProtocolOption/SetTransportProtocolOption methods provided by the
|
|
|
|
|
// stack. Please refer to individual protocol implementations as to what options
|
|
|
|
|
// are supported.
|
2019-09-25 12:56:00 -07:00
|
|
|
func New(opts Options) *Stack {
|
2018-08-01 20:21:00 -07:00
|
|
|
clock := opts.Clock
|
|
|
|
|
if clock == nil {
|
2021-05-03 16:44:02 -07:00
|
|
|
clock = tcpip.NewStdClock()
|
2018-08-01 20:21:00 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-16 11:07:02 -07:00
|
|
|
if opts.SecureRNG == nil {
|
2021-05-26 10:37:59 -07:00
|
|
|
opts.SecureRNG = cryptorand.Reader
|
2021-03-16 11:07:02 -07:00
|
|
|
}
|
2023-10-28 16:11:16 -07:00
|
|
|
secureRNG := cryptorand.RNGFrom(opts.SecureRNG)
|
2021-03-16 11:07:02 -07:00
|
|
|
|
2021-05-26 18:13:05 -07:00
|
|
|
randSrc := opts.RandSource
|
|
|
|
|
if randSrc == nil {
|
|
|
|
|
var v int64
|
|
|
|
|
if err := binary.Read(opts.SecureRNG, binary.LittleEndian, &v); err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
// Source provided by rand.NewSource is not thread-safe so
|
|
|
|
|
// we wrap it in a simple thread-safe version.
|
|
|
|
|
randSrc = &lockedRandomSource{src: rand.NewSource(v)}
|
|
|
|
|
}
|
2023-10-28 16:11:16 -07:00
|
|
|
insecureRNG := rand.New(randSrc)
|
2021-05-26 18:13:05 -07:00
|
|
|
|
|
|
|
|
if opts.IPTables == nil {
|
|
|
|
|
if opts.DefaultIPTables == nil {
|
|
|
|
|
opts.DefaultIPTables = DefaultTables
|
|
|
|
|
}
|
2023-10-28 16:11:16 -07:00
|
|
|
opts.IPTables = opts.DefaultIPTables(clock, insecureRNG)
|
2021-05-26 18:13:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opts.NUDConfigs.resetInvalidFields()
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
s := &Stack{
|
2021-09-01 19:41:43 -07:00
|
|
|
transportProtocols: make(map[tcpip.TransportProtocolNumber]*transportProtocolState),
|
|
|
|
|
networkProtocols: make(map[tcpip.NetworkProtocolNumber]NetworkProtocol),
|
|
|
|
|
nics: make(map[tcpip.NICID]*nic),
|
|
|
|
|
packetEndpointWriteSupported: opts.AllowPacketEndpointWrite,
|
|
|
|
|
defaultForwardingEnabled: make(map[tcpip.NetworkProtocolNumber]struct{}),
|
|
|
|
|
cleanupEndpoints: make(map[TransportEndpoint]struct{}),
|
|
|
|
|
PortManager: ports.NewPortManager(),
|
|
|
|
|
clock: clock,
|
|
|
|
|
stats: opts.Stats.FillIn(),
|
|
|
|
|
handleLocal: opts.HandleLocal,
|
|
|
|
|
tables: opts.IPTables,
|
2021-09-18 05:57:28 -07:00
|
|
|
icmpRateLimiter: NewICMPRateLimiter(clock),
|
2023-10-28 16:11:16 -07:00
|
|
|
seed: secureRNG.Uint32(),
|
2021-09-01 19:41:43 -07:00
|
|
|
nudConfigs: opts.NUDConfigs,
|
|
|
|
|
nudDisp: opts.NUDDisp,
|
2023-10-28 16:11:16 -07:00
|
|
|
insecureRNG: insecureRNG,
|
|
|
|
|
secureRNG: secureRNG,
|
2021-01-26 08:23:49 -08:00
|
|
|
sendBufferSize: tcpip.SendBufferSizeOption{
|
2020-06-24 10:21:44 -07:00
|
|
|
Min: MinBufferSize,
|
|
|
|
|
Default: DefaultBufferSize,
|
|
|
|
|
Max: DefaultMaxBufferSize,
|
|
|
|
|
},
|
2021-04-20 09:30:57 -07:00
|
|
|
receiveBufferSize: tcpip.ReceiveBufferSizeOption{
|
2020-06-24 10:21:44 -07:00
|
|
|
Min: MinBufferSize,
|
|
|
|
|
Default: DefaultBufferSize,
|
|
|
|
|
Max: DefaultMaxBufferSize,
|
|
|
|
|
},
|
2021-02-02 11:03:37 -08:00
|
|
|
tcpInvalidRateLimit: defaultTCPInvalidRateLimit,
|
2023-10-28 16:11:16 -07:00
|
|
|
tsOffsetSecret: secureRNG.Uint32(),
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add specified network protocols.
|
2020-09-28 16:22:09 -07:00
|
|
|
for _, netProtoFactory := range opts.NetworkProtocols {
|
|
|
|
|
netProto := netProtoFactory(s)
|
2018-04-27 10:37:02 -07:00
|
|
|
s.networkProtocols[netProto.Number()] = netProto
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add specified transport protocols.
|
2020-09-28 16:22:09 -07:00
|
|
|
for _, transProtoFactory := range opts.TransportProtocols {
|
|
|
|
|
transProto := transProtoFactory(s)
|
2018-04-27 10:37:02 -07:00
|
|
|
s.transportProtocols[transProto.Number()] = &transportProtocolState{
|
|
|
|
|
proto: transProto,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 13:21:58 -07:00
|
|
|
// Add the factory for raw endpoints, if present.
|
|
|
|
|
s.rawFactory = opts.RawFactory
|
2019-07-12 18:08:03 -07:00
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// Create the global transport demuxer.
|
|
|
|
|
s.demux = newTransportDemuxer(s)
|
|
|
|
|
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-26 10:31:07 -07:00
|
|
|
// NextNICID allocates the next available NIC ID and returns it.
|
|
|
|
|
func (s *Stack) NextNICID() tcpip.NICID {
|
|
|
|
|
next := s.nicIDGen.Add(1)
|
|
|
|
|
if next < 0 {
|
|
|
|
|
panic("NICID overflow")
|
|
|
|
|
}
|
|
|
|
|
return tcpip.NICID(next)
|
2019-10-30 15:32:20 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// SetNetworkProtocolOption allows configuring individual protocol level
|
|
|
|
|
// options. This method returns an error if the protocol is not supported or
|
|
|
|
|
// option is not supported by the protocol implementation or the provided value
|
|
|
|
|
// is incorrect.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) SetNetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.SettableNetworkProtocolOption) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
netProto, ok := s.networkProtocols[network]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
return netProto.SetOption(option)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NetworkProtocolOption allows retrieving individual protocol level option
|
|
|
|
|
// values. This method returns an error if the protocol is not supported or
|
2022-05-17 17:45:53 -07:00
|
|
|
// option is not supported by the protocol implementation. E.g.:
|
|
|
|
|
//
|
|
|
|
|
// var v ipv4.MyOption
|
|
|
|
|
// err := s.NetworkProtocolOption(tcpip.IPv4ProtocolNumber, &v)
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// ...
|
|
|
|
|
// }
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) NetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.GettableNetworkProtocolOption) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
netProto, ok := s.networkProtocols[network]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
return netProto.Option(option)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetTransportProtocolOption allows configuring individual protocol level
|
|
|
|
|
// options. This method returns an error if the protocol is not supported or
|
|
|
|
|
// option is not supported by the protocol implementation or the provided value
|
|
|
|
|
// is incorrect.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) SetTransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.SettableTransportProtocolOption) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
transProtoState, ok := s.transportProtocols[transport]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
return transProtoState.proto.SetOption(option)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TransportProtocolOption allows retrieving individual protocol level option
|
|
|
|
|
// values. This method returns an error if the protocol is not supported or
|
|
|
|
|
// option is not supported by the protocol implementation.
|
2022-05-17 17:45:53 -07:00
|
|
|
//
|
|
|
|
|
// var v tcp.SACKEnabled
|
|
|
|
|
// if err := s.TransportProtocolOption(tcpip.TCPProtocolNumber, &v); err != nil {
|
|
|
|
|
// ...
|
|
|
|
|
// }
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.GettableTransportProtocolOption) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
transProtoState, ok := s.transportProtocols[transport]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
return transProtoState.proto.Option(option)
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-15 15:45:37 -07:00
|
|
|
// SendBufSizeProto is a protocol that can return its send buffer size.
|
|
|
|
|
type SendBufSizeProto interface {
|
|
|
|
|
SendBufferSize() tcpip.TCPSendBufferSizeRangeOption
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TCPSendBufferLimits returns the TCP send buffer size limit.
|
|
|
|
|
func (s *Stack) TCPSendBufferLimits() tcpip.TCPSendBufferSizeRangeOption {
|
|
|
|
|
return s.transportProtocols[header.TCPProtocolNumber].proto.(SendBufSizeProto).SendBufferSize()
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// SetTransportProtocolHandler sets the per-stack default handler for the given
|
|
|
|
|
// protocol.
|
|
|
|
|
//
|
|
|
|
|
// It must be called only during initialization of the stack. Changing it as the
|
|
|
|
|
// stack is operating is not supported.
|
2024-02-29 11:07:59 -08:00
|
|
|
func (s *Stack) SetTransportProtocolHandler(p tcpip.TransportProtocolNumber, h func(TransportEndpointID, *PacketBuffer) bool) {
|
2018-04-27 10:37:02 -07:00
|
|
|
state := s.transportProtocols[p]
|
|
|
|
|
if state != nil {
|
|
|
|
|
state.defaultHandler = h
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 17:59:12 -07:00
|
|
|
// Clock returns the Stack's clock for retrieving the current time and
|
|
|
|
|
// scheduling work.
|
|
|
|
|
func (s *Stack) Clock() tcpip.Clock {
|
|
|
|
|
return s.clock
|
2018-05-01 22:11:07 -07:00
|
|
|
}
|
|
|
|
|
|
2018-08-23 08:54:09 -07:00
|
|
|
// Stats returns a mutable copy of the current stats.
|
2018-04-27 10:37:02 -07:00
|
|
|
//
|
|
|
|
|
// This is not generally exported via the public interface, but is available
|
|
|
|
|
// internally.
|
2018-08-23 08:54:09 -07:00
|
|
|
func (s *Stack) Stats() tcpip.Stats {
|
|
|
|
|
return s.stats
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
// SetNICForwarding enables or disables packet forwarding on the specified NIC
|
|
|
|
|
// for the passed protocol.
|
2022-02-25 18:03:08 -08:00
|
|
|
//
|
|
|
|
|
// Returns the previous configuration on the NIC.
|
|
|
|
|
func (s *Stack) SetNICForwarding(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, enable bool) (bool, tcpip.Error) {
|
2021-05-14 16:29:33 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
2020-09-29 00:18:37 -07:00
|
|
|
if !ok {
|
2022-02-25 18:03:08 -08:00
|
|
|
return false, &tcpip.ErrUnknownNICID{}
|
2019-12-23 08:53:57 -08:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
return nic.setForwarding(protocol, enable)
|
2018-09-17 13:04:38 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
// NICForwarding returns the forwarding configuration for the specified NIC.
|
|
|
|
|
func (s *Stack) NICForwarding(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber) (bool, tcpip.Error) {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
2020-09-29 00:18:37 -07:00
|
|
|
if !ok {
|
2021-05-14 16:29:33 -07:00
|
|
|
return false, &tcpip.ErrUnknownNICID{}
|
2020-09-29 00:18:37 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
return nic.forwarding(protocol)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetForwardingDefaultAndAllNICs sets packet forwarding for all NICs for the
|
|
|
|
|
// passed protocol and sets the default setting for newly created NICs.
|
|
|
|
|
func (s *Stack) SetForwardingDefaultAndAllNICs(protocol tcpip.NetworkProtocolNumber, enable bool) tcpip.Error {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
doneOnce := false
|
|
|
|
|
for id, nic := range s.nics {
|
2022-02-25 18:03:08 -08:00
|
|
|
if _, err := nic.setForwarding(protocol, enable); err != nil {
|
2021-05-14 16:29:33 -07:00
|
|
|
// Expect forwarding to be settable on all interfaces if it was set on
|
|
|
|
|
// one.
|
|
|
|
|
if doneOnce {
|
|
|
|
|
panic(fmt.Sprintf("nic(id=%d).setForwarding(%d, %t): %s", id, protocol, enable, err))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doneOnce = true
|
2020-09-29 00:18:37 -07:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
if enable {
|
|
|
|
|
s.defaultForwardingEnabled[protocol] = struct{}{}
|
|
|
|
|
} else {
|
|
|
|
|
delete(s.defaultForwardingEnabled, protocol)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
2018-09-17 13:04:38 -07:00
|
|
|
}
|
|
|
|
|
|
2022-05-25 15:15:08 -07:00
|
|
|
// AddMulticastRoute adds a multicast route to be used for the specified
|
|
|
|
|
// addresses and protocol.
|
|
|
|
|
func (s *Stack) AddMulticastRoute(protocol tcpip.NetworkProtocolNumber, addresses UnicastSourceAndMulticastDestination, route MulticastRoute) tcpip.Error {
|
|
|
|
|
netProto, ok := s.networkProtocols[protocol]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return forwardingNetProto.AddMulticastRoute(addresses, route)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-26 08:56:43 -07:00
|
|
|
// RemoveMulticastRoute removes a multicast route that matches the specified
|
|
|
|
|
// addresses and protocol.
|
|
|
|
|
func (s *Stack) RemoveMulticastRoute(protocol tcpip.NetworkProtocolNumber, addresses UnicastSourceAndMulticastDestination) tcpip.Error {
|
|
|
|
|
netProto, ok := s.networkProtocols[protocol]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return forwardingNetProto.RemoveMulticastRoute(addresses)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MulticastRouteLastUsedTime returns a monotonic timestamp that represents the
|
|
|
|
|
// last time that the route that matches the provided addresses and protocol
|
|
|
|
|
// was used or updated.
|
|
|
|
|
func (s *Stack) MulticastRouteLastUsedTime(protocol tcpip.NetworkProtocolNumber, addresses UnicastSourceAndMulticastDestination) (tcpip.MonotonicTime, tcpip.Error) {
|
|
|
|
|
netProto, ok := s.networkProtocols[protocol]
|
|
|
|
|
if !ok {
|
|
|
|
|
return tcpip.MonotonicTime{}, &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return tcpip.MonotonicTime{}, &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return forwardingNetProto.MulticastRouteLastUsedTime(addresses)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-15 09:58:35 -07:00
|
|
|
// EnableMulticastForwardingForProtocol enables multicast forwarding for the
|
|
|
|
|
// provided protocol.
|
|
|
|
|
//
|
|
|
|
|
// Returns true if forwarding was already enabled on the protocol.
|
|
|
|
|
// Additionally, returns an error if:
|
|
|
|
|
//
|
2022-06-22 10:17:32 -07:00
|
|
|
// - The protocol is not found.
|
|
|
|
|
// - The protocol doesn't support multicast forwarding.
|
|
|
|
|
// - The multicast forwarding event dispatcher is nil.
|
2022-06-15 09:58:35 -07:00
|
|
|
//
|
|
|
|
|
// If successful, future multicast forwarding events will be sent to the
|
|
|
|
|
// provided event dispatcher.
|
|
|
|
|
func (s *Stack) EnableMulticastForwardingForProtocol(protocol tcpip.NetworkProtocolNumber, disp MulticastForwardingEventDispatcher) (bool, tcpip.Error) {
|
|
|
|
|
netProto, ok := s.networkProtocols[protocol]
|
|
|
|
|
if !ok {
|
|
|
|
|
return false, &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return false, &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return forwardingNetProto.EnableMulticastForwarding(disp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DisableMulticastForwardingForProtocol disables multicast forwarding for the
|
|
|
|
|
// provided protocol.
|
|
|
|
|
//
|
|
|
|
|
// Returns an error if the provided protocol is not found or if it does not
|
|
|
|
|
// support multicast forwarding.
|
|
|
|
|
func (s *Stack) DisableMulticastForwardingForProtocol(protocol tcpip.NetworkProtocolNumber) tcpip.Error {
|
|
|
|
|
netProto, ok := s.networkProtocols[protocol]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto, ok := netProto.(MulticastForwardingNetworkProtocol)
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forwardingNetProto.DisableMulticastForwarding()
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-04 10:46:16 -07:00
|
|
|
// SetNICMulticastForwarding enables or disables multicast packet forwarding on
|
|
|
|
|
// the specified NIC for the passed protocol.
|
|
|
|
|
//
|
|
|
|
|
// Returns the previous configuration on the NIC.
|
|
|
|
|
func (s *Stack) SetNICMulticastForwarding(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, enable bool) (bool, tcpip.Error) {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return false, &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nic.setMulticastForwarding(protocol, enable)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NICMulticastForwarding returns the multicast forwarding configuration for
|
|
|
|
|
// the specified NIC.
|
|
|
|
|
func (s *Stack) NICMulticastForwarding(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber) (bool, tcpip.Error) {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return false, &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nic.multicastForwarding(protocol)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-08 20:37:14 -08:00
|
|
|
// PortRange returns the UDP and TCP inclusive range of ephemeral ports used in
|
|
|
|
|
// both IPv4 and IPv6.
|
|
|
|
|
func (s *Stack) PortRange() (uint16, uint16) {
|
|
|
|
|
return s.PortManager.PortRange()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetPortRange sets the UDP and TCP IPv4 and IPv6 ephemeral port range
|
|
|
|
|
// (inclusive).
|
|
|
|
|
func (s *Stack) SetPortRange(start uint16, end uint16) tcpip.Error {
|
|
|
|
|
return s.PortManager.SetPortRange(start, end)
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// SetRouteTable assigns the route table to be used by this stack. It
|
|
|
|
|
// specifies which NIC to use for given destination address ranges.
|
2020-02-04 18:04:26 -08:00
|
|
|
//
|
|
|
|
|
// This method takes ownership of the table.
|
2018-04-27 10:37:02 -07:00
|
|
|
func (s *Stack) SetRouteTable(table []tcpip.Route) {
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.Lock()
|
|
|
|
|
defer s.routeMu.Unlock()
|
2024-06-27 13:09:37 -07:00
|
|
|
s.routeTable.Reset()
|
|
|
|
|
for _, r := range table {
|
|
|
|
|
s.addRouteLocked(&r)
|
|
|
|
|
}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2018-08-21 15:25:50 -07:00
|
|
|
// GetRouteTable returns the route table which is currently in use.
|
|
|
|
|
func (s *Stack) GetRouteTable() []tcpip.Route {
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.RLock()
|
|
|
|
|
defer s.routeMu.RUnlock()
|
2024-06-27 13:09:37 -07:00
|
|
|
table := make([]tcpip.Route, 0)
|
|
|
|
|
for r := s.routeTable.Front(); r != nil; r = r.Next() {
|
|
|
|
|
table = append(table, *r)
|
|
|
|
|
}
|
|
|
|
|
return table
|
2018-08-21 15:25:50 -07:00
|
|
|
}
|
|
|
|
|
|
2020-02-04 18:04:26 -08:00
|
|
|
// AddRoute appends a route to the route table.
|
|
|
|
|
func (s *Stack) AddRoute(route tcpip.Route) {
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.Lock()
|
|
|
|
|
defer s.routeMu.Unlock()
|
2024-06-27 13:09:37 -07:00
|
|
|
s.addRouteLocked(&route)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// +checklocks:s.routeMu
|
|
|
|
|
func (s *Stack) addRouteLocked(route *tcpip.Route) {
|
|
|
|
|
routePrefix := route.Destination.Prefix()
|
|
|
|
|
n := s.routeTable.Front()
|
|
|
|
|
for ; n != nil; n = n.Next() {
|
|
|
|
|
if n.Destination.Prefix() < routePrefix {
|
|
|
|
|
s.routeTable.InsertBefore(n, route)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.routeTable.PushBack(route)
|
2020-02-04 18:04:26 -08:00
|
|
|
}
|
|
|
|
|
|
2024-09-17 14:30:56 -07:00
|
|
|
// RemoveRoutes removes matching routes from the route table, it
|
|
|
|
|
// returns the number of routes that are removed.
|
|
|
|
|
func (s *Stack) RemoveRoutes(match func(tcpip.Route) bool) int {
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.Lock()
|
|
|
|
|
defer s.routeMu.Unlock()
|
2020-10-27 00:16:14 -07:00
|
|
|
|
2024-09-17 14:30:56 -07:00
|
|
|
return s.removeRoutesLocked(match)
|
2024-07-09 18:01:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// +checklocks:s.routeMu
|
2024-09-17 14:30:56 -07:00
|
|
|
func (s *Stack) removeRoutesLocked(match func(tcpip.Route) bool) int {
|
|
|
|
|
count := 0
|
2024-06-27 13:09:37 -07:00
|
|
|
for route := s.routeTable.Front(); route != nil; {
|
|
|
|
|
next := route.Next()
|
|
|
|
|
if match(*route) {
|
|
|
|
|
s.routeTable.Remove(route)
|
2024-09-17 14:30:56 -07:00
|
|
|
count++
|
2020-10-27 00:16:14 -07:00
|
|
|
}
|
2024-06-27 13:09:37 -07:00
|
|
|
route = next
|
2020-10-27 00:16:14 -07:00
|
|
|
}
|
2024-09-17 14:30:56 -07:00
|
|
|
return count
|
2020-10-27 00:16:14 -07:00
|
|
|
}
|
|
|
|
|
|
2024-07-09 18:01:07 -07:00
|
|
|
// ReplaceRoute replaces the route in the routing table which matchse
|
|
|
|
|
// the lookup key for the routing table. If there is no match, the given
|
|
|
|
|
// route will still be added to the routing table.
|
|
|
|
|
// The lookup key consists of destination, ToS, scope and output interface.
|
|
|
|
|
func (s *Stack) ReplaceRoute(route tcpip.Route) {
|
|
|
|
|
s.routeMu.Lock()
|
|
|
|
|
defer s.routeMu.Unlock()
|
|
|
|
|
|
|
|
|
|
s.removeRoutesLocked(func(rt tcpip.Route) bool {
|
|
|
|
|
return rt.Equal(route)
|
|
|
|
|
})
|
|
|
|
|
s.addRouteLocked(&route)
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// NewEndpoint creates a new transport layer endpoint of the given protocol.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) NewEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
|
2018-04-27 10:37:02 -07:00
|
|
|
t, ok := s.transportProtocols[transport]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrUnknownProtocol{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-29 02:04:11 -07:00
|
|
|
return t.proto.NewEndpoint(network, waiterQueue)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2019-02-27 14:30:20 -08:00
|
|
|
// NewRawEndpoint creates a new raw transport layer endpoint of the given
|
|
|
|
|
// protocol. Raw endpoints receive all traffic for a given protocol regardless
|
|
|
|
|
// of address.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue, associated bool) (tcpip.Endpoint, tcpip.Error) {
|
2019-10-21 13:21:58 -07:00
|
|
|
if s.rawFactory == nil {
|
2022-06-14 20:01:58 -07:00
|
|
|
netRawMissingLogger.Infof("A process tried to create a raw socket, but --net-raw was not specified. Should runsc be run with --net-raw?")
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrNotPermitted{}
|
2019-04-26 16:50:35 -07:00
|
|
|
}
|
|
|
|
|
|
2019-07-12 18:08:03 -07:00
|
|
|
if !associated {
|
2019-10-21 13:21:58 -07:00
|
|
|
return s.rawFactory.NewUnassociatedEndpoint(s, network, transport, waiterQueue)
|
2019-07-12 18:08:03 -07:00
|
|
|
}
|
|
|
|
|
|
2019-02-27 14:30:20 -08:00
|
|
|
t, ok := s.transportProtocols[transport]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrUnknownProtocol{}
|
2019-02-27 14:30:20 -08:00
|
|
|
}
|
|
|
|
|
|
2020-09-29 02:04:11 -07:00
|
|
|
return t.proto.NewRawEndpoint(network, waiterQueue)
|
2019-02-27 14:30:20 -08:00
|
|
|
}
|
|
|
|
|
|
2019-10-21 13:21:58 -07:00
|
|
|
// NewPacketEndpoint creates a new packet endpoint listening for the given
|
|
|
|
|
// netProto.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) NewPacketEndpoint(cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
|
2019-10-21 13:21:58 -07:00
|
|
|
if s.rawFactory == nil {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrNotPermitted{}
|
2019-10-21 13:21:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s.rawFactory.NewPacketEndpoint(s, cooked, netProto, waiterQueue)
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-09 10:34:30 -08:00
|
|
|
// NICContext is an opaque pointer used to store client-supplied NIC metadata.
|
2022-11-08 13:12:12 -08:00
|
|
|
type NICContext any
|
2020-01-09 10:34:30 -08:00
|
|
|
|
2020-01-08 14:49:12 -08:00
|
|
|
// NICOptions specifies the configuration of a NIC as it is being created.
|
|
|
|
|
// The zero value creates an enabled, unnamed NIC.
|
|
|
|
|
type NICOptions struct {
|
|
|
|
|
// Name specifies the name of the NIC.
|
|
|
|
|
Name string
|
|
|
|
|
|
|
|
|
|
// Disabled specifies whether to avoid calling Attach on the passed
|
|
|
|
|
// LinkEndpoint.
|
|
|
|
|
Disabled bool
|
2020-01-09 10:34:30 -08:00
|
|
|
|
|
|
|
|
// Context specifies user-defined data that will be returned in stack.NICInfo
|
|
|
|
|
// for the NIC. Clients of this library can use it to add metadata that
|
|
|
|
|
// should be tracked alongside a NIC, to avoid having to keep a
|
|
|
|
|
// map[tcpip.NICID]metadata mirroring stack.Stack's nic map.
|
|
|
|
|
Context NICContext
|
2021-12-13 18:28:44 -08:00
|
|
|
|
|
|
|
|
// QDisc is the queue discipline to use for this NIC.
|
|
|
|
|
QDisc QueueingDiscipline
|
2022-11-08 17:34:01 -08:00
|
|
|
|
2024-03-13 12:04:15 -07:00
|
|
|
// DeliverLinkPackets specifies whether the NIC is responsible for
|
|
|
|
|
// delivering raw packets to packet sockets.
|
|
|
|
|
DeliverLinkPackets bool
|
2024-12-03 14:13:59 -08:00
|
|
|
|
|
|
|
|
// EnableExperimentIPOption specifies whether the NIC is responsible for
|
|
|
|
|
// passing the experiment IP option.
|
|
|
|
|
EnableExperimentIPOption bool
|
2020-01-08 14:49:12 -08:00
|
|
|
}
|
|
|
|
|
|
2024-06-18 12:11:19 -07:00
|
|
|
// GetNICByID return a network device associated with the specified ID.
|
|
|
|
|
func (s *Stack) GetNICByID(id tcpip.NICID) (*nic, tcpip.Error) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
n, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil, &tcpip.ErrNoSuchFile{}
|
|
|
|
|
}
|
|
|
|
|
return n, nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-08 14:49:12 -08:00
|
|
|
// CreateNICWithOptions creates a NIC with the provided id, LinkEndpoint, and
|
|
|
|
|
// NICOptions. See the documentation on type NICOptions for details on how
|
|
|
|
|
// NICs can be configured.
|
2020-02-21 11:20:15 -08:00
|
|
|
//
|
|
|
|
|
// LinkEndpoint.Attach will be called to bind ep with a NetworkDispatcher.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOptions) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
2024-05-01 17:43:33 -07:00
|
|
|
if id == 0 {
|
|
|
|
|
return &tcpip.ErrInvalidNICID{}
|
|
|
|
|
}
|
2018-04-27 10:37:02 -07:00
|
|
|
// Make sure id is unique.
|
|
|
|
|
if _, ok := s.nics[id]; ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrDuplicateNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-02-11 12:58:13 -08:00
|
|
|
// Make sure name is unique, unless unnamed.
|
|
|
|
|
if opts.Name != "" {
|
|
|
|
|
for _, n := range s.nics {
|
|
|
|
|
if n.Name() == opts.Name {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrDuplicateNICID{}
|
2020-02-11 12:58:13 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-13 18:28:44 -08:00
|
|
|
n := newNIC(s, id, ep, opts)
|
2021-05-14 16:29:33 -07:00
|
|
|
for proto := range s.defaultForwardingEnabled {
|
2022-02-25 18:03:08 -08:00
|
|
|
if _, err := n.setForwarding(proto, true); err != nil {
|
2021-05-14 16:29:33 -07:00
|
|
|
panic(fmt.Sprintf("newNIC(%d, ...).setForwarding(%d, true): %s", id, proto, err))
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-27 10:37:02 -07:00
|
|
|
s.nics[id] = n
|
2024-07-02 16:45:52 -07:00
|
|
|
ep.SetOnCloseAction(func() {
|
|
|
|
|
s.RemoveNIC(id)
|
|
|
|
|
})
|
2020-01-08 14:49:12 -08:00
|
|
|
if !opts.Disabled {
|
2019-09-17 14:45:41 -07:00
|
|
|
return n.enable()
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-08 14:49:12 -08:00
|
|
|
// CreateNIC creates a NIC with the provided id and LinkEndpoint and calls
|
2020-02-21 11:20:15 -08:00
|
|
|
// LinkEndpoint.Attach to bind ep with a NetworkDispatcher.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) CreateNIC(id tcpip.NICID, ep LinkEndpoint) tcpip.Error {
|
2020-01-08 14:49:12 -08:00
|
|
|
return s.CreateNICWithOptions(id, ep, NICOptions{})
|
2018-05-01 22:11:07 -07:00
|
|
|
}
|
|
|
|
|
|
2020-10-09 12:07:02 -07:00
|
|
|
// GetLinkEndpointByName gets the link endpoint specified by name.
|
|
|
|
|
func (s *Stack) GetLinkEndpointByName(name string) LinkEndpoint {
|
2020-02-21 15:41:56 -08:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
for _, nic := range s.nics {
|
|
|
|
|
if nic.Name() == name {
|
2021-12-13 18:28:44 -08:00
|
|
|
linkEP, ok := nic.NetworkLinkEndpoint.(LinkEndpoint)
|
|
|
|
|
if !ok {
|
|
|
|
|
panic(fmt.Sprintf("unexpected NetworkLinkEndpoint(%#v) is not a LinkEndpoint", nic.NetworkLinkEndpoint))
|
|
|
|
|
}
|
|
|
|
|
return linkEP
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
|
|
|
|
}
|
2020-10-09 12:07:02 -07:00
|
|
|
return nil
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// EnableNIC enables the given NIC so that the link-layer endpoint can start
|
|
|
|
|
// delivering packets to it.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) EnableNIC(id tcpip.NICID) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2020-02-20 14:31:39 -08:00
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2019-09-17 14:45:41 -07:00
|
|
|
return nic.enable()
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-02-20 14:31:39 -08:00
|
|
|
// DisableNIC disables the given NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) DisableNIC(id tcpip.NICID) tcpip.Error {
|
2020-02-20 14:31:39 -08:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2020-02-20 14:31:39 -08:00
|
|
|
}
|
|
|
|
|
|
2020-09-29 00:18:37 -07:00
|
|
|
nic.disable()
|
|
|
|
|
return nil
|
2020-02-20 14:31:39 -08:00
|
|
|
}
|
|
|
|
|
|
2019-02-15 18:39:10 -08:00
|
|
|
// CheckNIC checks if a NIC is usable.
|
|
|
|
|
func (s *Stack) CheckNIC(id tcpip.NICID) bool {
|
|
|
|
|
s.mu.RLock()
|
2020-02-20 14:31:39 -08:00
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2019-02-15 18:39:10 -08:00
|
|
|
nic, ok := s.nics[id]
|
2020-02-20 14:31:39 -08:00
|
|
|
if !ok {
|
|
|
|
|
return false
|
2019-02-15 18:39:10 -08:00
|
|
|
}
|
2020-02-20 14:31:39 -08:00
|
|
|
|
2020-09-29 00:18:37 -07:00
|
|
|
return nic.Enabled()
|
2019-02-15 18:39:10 -08:00
|
|
|
}
|
|
|
|
|
|
2020-02-21 15:41:56 -08:00
|
|
|
// RemoveNIC removes NIC and all related routes from the network stack.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) RemoveNIC(id tcpip.NICID) tcpip.Error {
|
2020-02-21 15:41:56 -08:00
|
|
|
s.mu.Lock()
|
2024-07-10 13:29:15 -07:00
|
|
|
deferAct, err := s.removeNICLocked(id)
|
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
if deferAct != nil {
|
|
|
|
|
deferAct()
|
|
|
|
|
}
|
|
|
|
|
return err
|
2020-06-09 11:31:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// removeNICLocked removes NIC and all related routes from the network stack.
|
|
|
|
|
//
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocks:s.mu
|
2024-07-10 13:29:15 -07:00
|
|
|
func (s *Stack) removeNICLocked(id tcpip.NICID) (func(), tcpip.Error) {
|
2020-02-21 15:41:56 -08:00
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
2024-07-10 13:29:15 -07:00
|
|
|
return nil, &tcpip.ErrUnknownNICID{}
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
|
|
|
|
delete(s.nics, id)
|
|
|
|
|
|
2024-06-18 12:11:19 -07:00
|
|
|
if nic.Primary != nil {
|
|
|
|
|
b := nic.Primary.NetworkLinkEndpoint.(CoordinatorNIC)
|
|
|
|
|
if err := b.DelNIC(nic); err != nil {
|
2024-07-10 13:29:15 -07:00
|
|
|
return nil, err
|
2024-06-18 12:11:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-21 15:41:56 -08:00
|
|
|
// Remove routes in-place. n tracks the number of routes written.
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.Lock()
|
2024-06-27 13:09:37 -07:00
|
|
|
for r := s.routeTable.Front(); r != nil; {
|
|
|
|
|
next := r.Next()
|
|
|
|
|
if r.NIC == id {
|
|
|
|
|
s.routeTable.Remove(r)
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
2024-06-27 13:09:37 -07:00
|
|
|
r = next
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.Unlock()
|
2020-02-21 15:41:56 -08:00
|
|
|
|
2024-07-02 16:45:52 -07:00
|
|
|
return nic.remove(true /* closeLinkEndpoint */)
|
2020-02-21 15:41:56 -08:00
|
|
|
}
|
|
|
|
|
|
2024-06-18 12:11:19 -07:00
|
|
|
// SetNICCoordinator sets a coordinator device.
|
|
|
|
|
func (s *Stack) SetNICCoordinator(id tcpip.NICID, mid tcpip.NICID) tcpip.Error {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
2024-09-27 16:09:48 -07:00
|
|
|
// Setting a coordinator for a coordinator NIC is not allowed.
|
|
|
|
|
if _, ok := nic.NetworkLinkEndpoint.(CoordinatorNIC); ok {
|
|
|
|
|
return &tcpip.ErrNoSuchFile{}
|
|
|
|
|
}
|
2024-06-18 12:11:19 -07:00
|
|
|
m, ok := s.nics[mid]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
b, ok := m.NetworkLinkEndpoint.(CoordinatorNIC)
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrNotSupported{}
|
|
|
|
|
}
|
|
|
|
|
if err := b.AddNIC(nic); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
nic.Primary = m
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-21 23:52:33 -07:00
|
|
|
// SetNICAddress sets the hardware address which is identified by the nic ID.
|
|
|
|
|
func (s *Stack) SetNICAddress(id tcpip.NICID, addr tcpip.LinkAddress) tcpip.Error {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
nic.NetworkLinkEndpoint.SetLinkAddress(addr)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-28 16:59:01 -07:00
|
|
|
// SetNICName sets a NIC's name.
|
|
|
|
|
func (s *Stack) SetNICName(id tcpip.NICID, name string) tcpip.Error {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
nic.name = name
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 00:32:36 -07:00
|
|
|
// SetNICMTU sets a NIC's MTU.
|
|
|
|
|
func (s *Stack) SetNICMTU(id tcpip.NICID, mtu uint32) tcpip.Error {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
nic.NetworkLinkEndpoint.SetMTU(mtu)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// NICInfo captures the name and addresses assigned to a NIC.
|
|
|
|
|
type NICInfo struct {
|
|
|
|
|
Name string
|
|
|
|
|
LinkAddress tcpip.LinkAddress
|
|
|
|
|
ProtocolAddresses []tcpip.ProtocolAddress
|
2018-08-08 22:38:41 -07:00
|
|
|
|
|
|
|
|
// Flags indicate the state of the NIC.
|
|
|
|
|
Flags NICStateFlags
|
|
|
|
|
|
|
|
|
|
// MTU is the maximum transmission unit.
|
|
|
|
|
MTU uint32
|
2019-03-19 08:29:37 -07:00
|
|
|
|
2021-05-21 04:25:28 -07:00
|
|
|
Stats tcpip.NICStats
|
2020-01-09 10:34:30 -08:00
|
|
|
|
2021-01-19 15:05:17 -08:00
|
|
|
// NetworkStats holds the stats of each NetworkEndpoint bound to the NIC.
|
|
|
|
|
NetworkStats map[tcpip.NetworkProtocolNumber]NetworkEndpointStats
|
|
|
|
|
|
2020-01-09 10:34:30 -08:00
|
|
|
// Context is user-supplied data optionally supplied in CreateNICWithOptions.
|
|
|
|
|
// See type NICOptions for more details.
|
|
|
|
|
Context NICContext
|
2020-07-15 14:13:42 -07:00
|
|
|
|
|
|
|
|
// ARPHardwareType holds the ARP Hardware type of the NIC. This is the
|
|
|
|
|
// value sent in haType field of an ARP Request sent by this NIC and the
|
|
|
|
|
// value expected in the haType field of an ARP response.
|
|
|
|
|
ARPHardwareType header.ARPHardwareType
|
2021-05-14 16:29:33 -07:00
|
|
|
|
|
|
|
|
// Forwarding holds the forwarding status for each network endpoint that
|
|
|
|
|
// supports forwarding.
|
|
|
|
|
Forwarding map[tcpip.NetworkProtocolNumber]bool
|
2022-04-04 10:46:16 -07:00
|
|
|
|
|
|
|
|
// MulticastForwarding holds the forwarding status for each network endpoint
|
|
|
|
|
// that supports multicast forwarding.
|
|
|
|
|
MulticastForwarding map[tcpip.NetworkProtocolNumber]bool
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-01-09 13:06:24 -08:00
|
|
|
// HasNIC returns true if the NICID is defined in the stack.
|
|
|
|
|
func (s *Stack) HasNIC(id tcpip.NICID) bool {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
_, ok := s.nics[id]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// NICInfo returns a map of NICIDs to their associated information.
|
|
|
|
|
func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2022-04-04 10:46:16 -07:00
|
|
|
type forwardingFn func(tcpip.NetworkProtocolNumber) (bool, tcpip.Error)
|
|
|
|
|
forwardingValue := func(forwardingFn forwardingFn, proto tcpip.NetworkProtocolNumber, nicID tcpip.NICID, fnName string) (forward bool, ok bool) {
|
|
|
|
|
switch forwarding, err := forwardingFn(proto); err.(type) {
|
|
|
|
|
case nil:
|
|
|
|
|
return forwarding, true
|
|
|
|
|
case *tcpip.ErrUnknownProtocol:
|
|
|
|
|
panic(fmt.Sprintf("expected network protocol %d to be available on NIC %d", proto, nicID))
|
|
|
|
|
case *tcpip.ErrNotSupported:
|
|
|
|
|
// Not all network protocols support forwarding.
|
|
|
|
|
default:
|
|
|
|
|
panic(fmt.Sprintf("nic(id=%d).%s(%d): %s", nicID, fnName, proto, err))
|
|
|
|
|
}
|
|
|
|
|
return false, false
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
nics := make(map[tcpip.NICID]NICInfo)
|
|
|
|
|
for id, nic := range s.nics {
|
2018-08-08 22:38:41 -07:00
|
|
|
flags := NICStateFlags{
|
|
|
|
|
Up: true, // Netstack interfaces are always up.
|
2020-09-29 00:18:37 -07:00
|
|
|
Running: nic.Enabled(),
|
2020-11-12 17:30:31 -08:00
|
|
|
Promiscuous: nic.Promiscuous(),
|
2020-09-29 00:18:37 -07:00
|
|
|
Loopback: nic.IsLoopback(),
|
2018-08-08 22:38:41 -07:00
|
|
|
}
|
2021-01-19 15:05:17 -08:00
|
|
|
|
|
|
|
|
netStats := make(map[tcpip.NetworkProtocolNumber]NetworkEndpointStats)
|
|
|
|
|
for proto, netEP := range nic.networkEndpoints {
|
|
|
|
|
netStats[proto] = netEP.Stats()
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
info := NICInfo{
|
2022-04-04 10:46:16 -07:00
|
|
|
Name: nic.name,
|
|
|
|
|
LinkAddress: nic.NetworkLinkEndpoint.LinkAddress(),
|
|
|
|
|
ProtocolAddresses: nic.primaryAddresses(),
|
|
|
|
|
Flags: flags,
|
|
|
|
|
MTU: nic.NetworkLinkEndpoint.MTU(),
|
|
|
|
|
Stats: nic.stats.local,
|
|
|
|
|
NetworkStats: netStats,
|
|
|
|
|
Context: nic.context,
|
|
|
|
|
ARPHardwareType: nic.NetworkLinkEndpoint.ARPHardwareType(),
|
|
|
|
|
Forwarding: make(map[tcpip.NetworkProtocolNumber]bool),
|
|
|
|
|
MulticastForwarding: make(map[tcpip.NetworkProtocolNumber]bool),
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
2021-05-14 16:29:33 -07:00
|
|
|
|
|
|
|
|
for proto := range s.networkProtocols {
|
2022-04-04 10:46:16 -07:00
|
|
|
if forwarding, ok := forwardingValue(nic.forwarding, proto, id, "forwarding"); ok {
|
2021-05-14 16:29:33 -07:00
|
|
|
info.Forwarding[proto] = forwarding
|
2022-04-04 10:46:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if multicastForwarding, ok := forwardingValue(nic.multicastForwarding, proto, id, "multicastForwarding"); ok {
|
|
|
|
|
info.MulticastForwarding[proto] = multicastForwarding
|
2021-05-14 16:29:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nics[id] = info
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
return nics
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-22 13:46:37 -07:00
|
|
|
// NICStateFlags holds information about the state of an NIC.
|
|
|
|
|
type NICStateFlags struct {
|
|
|
|
|
// Up indicates whether the interface is running.
|
|
|
|
|
Up bool
|
|
|
|
|
|
|
|
|
|
// Running indicates whether resources are allocated.
|
|
|
|
|
Running bool
|
|
|
|
|
|
|
|
|
|
// Promiscuous indicates whether the interface is in promiscuous mode.
|
|
|
|
|
Promiscuous bool
|
|
|
|
|
|
2018-08-08 22:38:41 -07:00
|
|
|
// Loopback indicates whether the interface is a loopback.
|
|
|
|
|
Loopback bool
|
2018-05-22 13:46:37 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 14:57:10 -07:00
|
|
|
// AddProtocolAddress adds an address to the specified NIC, possibly with extra
|
|
|
|
|
// properties.
|
|
|
|
|
func (s *Stack) AddProtocolAddress(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress, properties AddressProperties) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2020-08-25 11:07:32 -07:00
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-15 14:57:10 -07:00
|
|
|
return nic.addAddress(protocolAddress, properties)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RemoveAddress removes an existing network-layer address from the specified
|
|
|
|
|
// NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2018-09-05 17:05:09 -07:00
|
|
|
if nic, ok := s.nics[id]; ok {
|
2020-09-29 00:18:37 -07:00
|
|
|
return nic.removeAddress(addr)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-09-05 17:05:09 -07:00
|
|
|
}
|
|
|
|
|
|
2022-07-07 19:56:11 -07:00
|
|
|
// SetAddressLifetimes sets informational preferred and valid lifetimes, and
|
|
|
|
|
// whether the address should be preferred or deprecated.
|
|
|
|
|
func (s *Stack) SetAddressLifetimes(id tcpip.NICID, addr tcpip.Address, lifetimes AddressLifetimes) tcpip.Error {
|
2022-02-04 10:26:35 -08:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if nic, ok := s.nics[id]; ok {
|
2022-07-07 19:56:11 -07:00
|
|
|
return nic.setAddressLifetimes(addr, lifetimes)
|
2022-02-04 10:26:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-24 13:18:19 -07:00
|
|
|
// AllAddresses returns a map of NICIDs to their protocol addresses (primary
|
|
|
|
|
// and non-primary).
|
|
|
|
|
func (s *Stack) AllAddresses() map[tcpip.NICID][]tcpip.ProtocolAddress {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nics := make(map[tcpip.NICID][]tcpip.ProtocolAddress)
|
|
|
|
|
for id, nic := range s.nics {
|
2020-09-29 00:18:37 -07:00
|
|
|
nics[id] = nic.allPermanentAddresses()
|
2019-09-24 13:18:19 -07:00
|
|
|
}
|
|
|
|
|
return nics
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-07 13:40:43 -08:00
|
|
|
// GetMainNICAddress returns the first non-deprecated primary address and prefix
|
2021-03-22 12:30:03 -07:00
|
|
|
// for the given NIC and protocol. If no non-deprecated primary addresses exist,
|
|
|
|
|
// a deprecated address will be returned. If no deprecated addresses exist, the
|
|
|
|
|
// zero value will be returned.
|
|
|
|
|
func (s *Stack) GetMainNICAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber) (tcpip.AddressWithPrefix, tcpip.Error) {
|
2018-09-05 17:05:09 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2019-09-24 13:18:19 -07:00
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
2021-03-22 12:30:03 -07:00
|
|
|
return tcpip.AddressWithPrefix{}, &tcpip.ErrUnknownNICID{}
|
2018-09-05 17:05:09 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-22 12:30:03 -07:00
|
|
|
return nic.PrimaryAddress(protocol)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2023-12-04 14:28:09 -08:00
|
|
|
func (s *Stack) getAddressEP(nic *nic, localAddr, remoteAddr, srcHint tcpip.Address, netProto tcpip.NetworkProtocolNumber) AssignableAddressEndpoint {
|
2023-05-15 18:03:37 -07:00
|
|
|
if localAddr.BitLen() == 0 {
|
2023-12-04 14:28:09 -08:00
|
|
|
return nic.primaryEndpoint(netProto, remoteAddr, srcHint)
|
2018-12-06 11:47:17 -08:00
|
|
|
}
|
|
|
|
|
return nic.findEndpoint(netProto, localAddr, CanBePrimaryEndpoint)
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-25 15:15:08 -07:00
|
|
|
// NewRouteForMulticast returns a Route that may be used to forward multicast
|
|
|
|
|
// packets.
|
|
|
|
|
//
|
|
|
|
|
// Returns nil if validation fails.
|
|
|
|
|
func (s *Stack) NewRouteForMulticast(nicID tcpip.NICID, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route {
|
2022-11-02 18:52:49 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2022-05-25 15:15:08 -07:00
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok || !nic.Enabled() {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-04 14:28:09 -08:00
|
|
|
if addressEndpoint := s.getAddressEP(nic, tcpip.Address{} /* localAddr */, remoteAddr, tcpip.Address{} /* srcHint */, netProto); addressEndpoint != nil {
|
2024-06-06 09:13:23 -07:00
|
|
|
return constructAndValidateRoute(netProto, addressEndpoint, nic, nic, tcpip.Address{} /* gateway */, tcpip.Address{} /* localAddr */, remoteAddr, s.handleLocal, false /* multicastLoop */, 0 /* mtu */)
|
2022-05-25 15:15:08 -07:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-05 15:49:51 -08:00
|
|
|
// findLocalRouteFromNICRLocked is like findLocalRouteRLocked but finds a route
|
|
|
|
|
// from the specified NIC.
|
|
|
|
|
//
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocksread:s.mu
|
2021-02-06 09:47:26 -08:00
|
|
|
func (s *Stack) findLocalRouteFromNICRLocked(localAddressNIC *nic, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route {
|
2020-11-05 15:49:51 -08:00
|
|
|
localAddressEndpoint := localAddressNIC.getAddressOrCreateTempInner(netProto, localAddr, false /* createTemp */, NeverPrimaryEndpoint)
|
|
|
|
|
if localAddressEndpoint == nil {
|
2020-11-25 14:51:18 -08:00
|
|
|
return nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-06 09:47:26 -08:00
|
|
|
var outgoingNIC *nic
|
2020-11-05 15:49:51 -08:00
|
|
|
// Prefer a local route to the same interface as the local address.
|
|
|
|
|
if localAddressNIC.hasAddress(netProto, remoteAddr) {
|
|
|
|
|
outgoingNIC = localAddressNIC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the remote address isn't owned by the local address's NIC, check all
|
|
|
|
|
// NICs.
|
|
|
|
|
if outgoingNIC == nil {
|
|
|
|
|
for _, nic := range s.nics {
|
|
|
|
|
if nic.hasAddress(netProto, remoteAddr) {
|
|
|
|
|
outgoingNIC = nic
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the remote address is not owned by the stack, we can't return a local
|
|
|
|
|
// route.
|
|
|
|
|
if outgoingNIC == nil {
|
|
|
|
|
localAddressEndpoint.DecRef()
|
2020-11-25 14:51:18 -08:00
|
|
|
return nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := makeLocalRoute(
|
|
|
|
|
netProto,
|
2020-11-18 12:43:51 -08:00
|
|
|
localAddr,
|
2020-11-05 15:49:51 -08:00
|
|
|
remoteAddr,
|
|
|
|
|
outgoingNIC,
|
|
|
|
|
localAddressNIC,
|
|
|
|
|
localAddressEndpoint,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if r.IsOutboundBroadcast() {
|
|
|
|
|
r.Release()
|
2020-11-25 14:51:18 -08:00
|
|
|
return nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-25 14:51:18 -08:00
|
|
|
return r
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findLocalRouteRLocked returns a local route.
|
|
|
|
|
//
|
|
|
|
|
// A local route is a route to some remote address which the stack owns. That
|
|
|
|
|
// is, a local route is a route where packets never have to leave the stack.
|
|
|
|
|
//
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocksread:s.mu
|
2020-11-25 14:51:18 -08:00
|
|
|
func (s *Stack) findLocalRouteRLocked(localAddressNICID tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber) *Route {
|
2023-05-15 18:03:37 -07:00
|
|
|
if localAddr.BitLen() == 0 {
|
2020-11-05 15:49:51 -08:00
|
|
|
localAddr = remoteAddr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if localAddressNICID == 0 {
|
|
|
|
|
for _, localAddressNIC := range s.nics {
|
2020-11-25 14:51:18 -08:00
|
|
|
if r := s.findLocalRouteFromNICRLocked(localAddressNIC, localAddr, remoteAddr, netProto); r != nil {
|
|
|
|
|
return r
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-25 14:51:18 -08:00
|
|
|
return nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if localAddressNIC, ok := s.nics[localAddressNICID]; ok {
|
|
|
|
|
return s.findLocalRouteFromNICRLocked(localAddressNIC, localAddr, remoteAddr, netProto)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-25 14:51:18 -08:00
|
|
|
return nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
2021-02-05 16:44:49 -08:00
|
|
|
// HandleLocal returns true if non-loopback interfaces are allowed to loop packets.
|
|
|
|
|
func (s *Stack) HandleLocal() bool {
|
|
|
|
|
return s.handleLocal
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
func isNICForwarding(nic *nic, proto tcpip.NetworkProtocolNumber) bool {
|
|
|
|
|
switch forwarding, err := nic.forwarding(proto); err.(type) {
|
|
|
|
|
case nil:
|
|
|
|
|
return forwarding
|
|
|
|
|
case *tcpip.ErrUnknownProtocol:
|
|
|
|
|
panic(fmt.Sprintf("expected network protocol %d to be available on NIC %d", proto, nic.ID()))
|
|
|
|
|
case *tcpip.ErrNotSupported:
|
|
|
|
|
// Not all network protocols support forwarding.
|
|
|
|
|
return false
|
|
|
|
|
default:
|
|
|
|
|
panic(fmt.Sprintf("nic(id=%d).forwarding(%d): %s", nic.ID(), proto, err))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 08:07:04 -07:00
|
|
|
// findRouteWithLocalAddrFromAnyInterfaceRLocked returns a route to the given
|
|
|
|
|
// destination address, leaving through the given NIC.
|
|
|
|
|
//
|
|
|
|
|
// Rather than preferring to find a route that uses a local address assigned to
|
|
|
|
|
// the outgoing interface, it finds any NIC that holds a matching local address
|
|
|
|
|
// endpoint.
|
|
|
|
|
//
|
|
|
|
|
// +checklocksread:s.mu
|
2024-06-06 09:13:23 -07:00
|
|
|
func (s *Stack) findRouteWithLocalAddrFromAnyInterfaceRLocked(outgoingNIC *nic, localAddr, remoteAddr, srcHint, gateway tcpip.Address, netProto tcpip.NetworkProtocolNumber, multicastLoop bool, mtu uint32) *Route {
|
2023-10-16 08:07:04 -07:00
|
|
|
for _, aNIC := range s.nics {
|
2023-12-04 14:28:09 -08:00
|
|
|
addressEndpoint := s.getAddressEP(aNIC, localAddr, remoteAddr, srcHint, netProto)
|
2023-10-16 08:07:04 -07:00
|
|
|
if addressEndpoint == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 09:13:23 -07:00
|
|
|
if r := constructAndValidateRoute(netProto, addressEndpoint, aNIC /* localAddressNIC */, outgoingNIC, gateway, localAddr, remoteAddr, s.handleLocal, multicastLoop, mtu); r != nil {
|
2023-10-16 08:07:04 -07:00
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// FindRoute creates a route to the given destination address, leaving through
|
2020-11-05 15:49:51 -08:00
|
|
|
// the given NIC and local address (if provided).
|
|
|
|
|
//
|
|
|
|
|
// If a NIC is not specified, the returned route will leave through the same
|
|
|
|
|
// NIC as the NIC that has the local address assigned when forwarding is
|
|
|
|
|
// disabled. If forwarding is enabled and the NIC is unspecified, the route may
|
|
|
|
|
// leave through any interface unless the route is link-local.
|
|
|
|
|
//
|
|
|
|
|
// If no local address is provided, the stack will select a local address. If no
|
2023-10-25 12:06:44 -07:00
|
|
|
// remote address is provided, the stack will use a remote address equal to the
|
2020-11-05 15:49:51 -08:00
|
|
|
// local address.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber, multicastLoop bool) (*Route, tcpip.Error) {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2023-10-06 14:33:34 -07:00
|
|
|
// Reject attempts to use unsupported protocols.
|
|
|
|
|
if !s.CheckNetworkProtocol(netProto) {
|
|
|
|
|
return nil, &tcpip.ErrUnknownProtocol{}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 13:20:05 -07:00
|
|
|
isLinkLocal := header.IsV6LinkLocalUnicastAddress(remoteAddr) || header.IsV6LinkLocalMulticastAddress(remoteAddr)
|
2020-07-30 12:48:18 -07:00
|
|
|
isLocalBroadcast := remoteAddr == header.IPv4Broadcast
|
2018-12-16 23:04:56 -08:00
|
|
|
isMulticast := header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)
|
2020-11-05 15:49:51 -08:00
|
|
|
isLoopback := header.IsV4LoopbackAddress(remoteAddr) || header.IsV6LoopbackAddress(remoteAddr)
|
|
|
|
|
needRoute := !(isLocalBroadcast || isMulticast || isLinkLocal || isLoopback)
|
|
|
|
|
|
|
|
|
|
if s.handleLocal && !isMulticast && !isLocalBroadcast {
|
2020-11-25 14:51:18 -08:00
|
|
|
if r := s.findLocalRouteRLocked(id, localAddr, remoteAddr, netProto); r != nil {
|
2020-11-05 15:49:51 -08:00
|
|
|
return r, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the interface is specified and we do not need a route, return a route
|
|
|
|
|
// through the interface if the interface is valid and enabled.
|
2019-02-28 14:37:42 -08:00
|
|
|
if id != 0 && !needRoute {
|
2020-09-29 00:18:37 -07:00
|
|
|
if nic, ok := s.nics[id]; ok && nic.Enabled() {
|
2023-12-04 14:28:09 -08:00
|
|
|
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, tcpip.Address{} /* srcHint */, netProto); addressEndpoint != nil {
|
2020-11-05 15:49:51 -08:00
|
|
|
return makeRoute(
|
|
|
|
|
netProto,
|
2023-05-15 18:03:37 -07:00
|
|
|
tcpip.Address{}, /* gateway */
|
2020-11-18 12:43:51 -08:00
|
|
|
localAddr,
|
2020-11-05 15:49:51 -08:00
|
|
|
remoteAddr,
|
2024-06-06 09:13:23 -07:00
|
|
|
nic, /* outgoingNIC */
|
2020-11-05 15:49:51 -08:00
|
|
|
nic, /* localAddressNIC*/
|
|
|
|
|
addressEndpoint,
|
|
|
|
|
s.handleLocal,
|
|
|
|
|
multicastLoop,
|
2024-06-06 09:13:23 -07:00
|
|
|
0, /* mtu */
|
2020-11-05 15:49:51 -08:00
|
|
|
), nil
|
2018-12-06 11:47:17 -08:00
|
|
|
}
|
|
|
|
|
}
|
2020-11-05 15:49:51 -08:00
|
|
|
|
|
|
|
|
if isLoopback {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrBadLocalAddress{}
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrNetworkUnreachable{}
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 16:29:33 -07:00
|
|
|
onlyGlobalAddresses := !header.IsV6LinkLocalUnicastAddress(localAddr) && !isLinkLocal
|
2020-11-05 15:49:51 -08:00
|
|
|
|
|
|
|
|
// Find a route to the remote with the route table.
|
|
|
|
|
var chosenRoute tcpip.Route
|
2021-01-30 17:51:47 -08:00
|
|
|
if r := func() *Route {
|
2022-01-24 19:51:35 -08:00
|
|
|
s.routeMu.RLock()
|
|
|
|
|
defer s.routeMu.RUnlock()
|
2020-11-05 15:49:51 -08:00
|
|
|
|
2024-06-27 13:09:37 -07:00
|
|
|
for route := s.routeTable.Front(); route != nil; route = route.Next() {
|
2023-05-15 18:03:37 -07:00
|
|
|
if remoteAddr.BitLen() != 0 && !route.Destination.Contains(remoteAddr) {
|
2021-01-30 17:51:47 -08:00
|
|
|
continue
|
|
|
|
|
}
|
2020-11-05 15:49:51 -08:00
|
|
|
|
2021-01-30 17:51:47 -08:00
|
|
|
nic, ok := s.nics[route.NIC]
|
|
|
|
|
if !ok || !nic.Enabled() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if id == 0 || id == route.NIC {
|
2023-12-04 14:28:09 -08:00
|
|
|
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, route.SourceHint, netProto); addressEndpoint != nil {
|
2021-01-30 17:51:47 -08:00
|
|
|
var gateway tcpip.Address
|
|
|
|
|
if needRoute {
|
|
|
|
|
gateway = route.Gateway
|
|
|
|
|
}
|
2024-06-06 09:13:23 -07:00
|
|
|
r := constructAndValidateRoute(netProto, addressEndpoint, nic /* outgoingNIC */, nic /* outgoingNIC */, gateway, localAddr, remoteAddr, s.handleLocal, multicastLoop, route.MTU)
|
2021-01-30 17:51:47 -08:00
|
|
|
if r == nil {
|
|
|
|
|
panic(fmt.Sprintf("non-forwarding route validation failed with route table entry = %#v, id = %d, localAddr = %s, remoteAddr = %s", route, id, localAddr, remoteAddr))
|
|
|
|
|
}
|
|
|
|
|
return r
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
2021-01-30 17:51:47 -08:00
|
|
|
}
|
|
|
|
|
|
2023-10-16 08:07:04 -07:00
|
|
|
// If the stack has forwarding enabled, we haven't found a valid route to
|
|
|
|
|
// the remote address yet, and we are routing locally generated traffic,
|
|
|
|
|
// keep track of the first valid route. We keep iterating because we
|
|
|
|
|
// prefer routes that let us use a local address that is assigned to the
|
|
|
|
|
// outgoing interface. There is no requirement to do this from any RFC
|
|
|
|
|
// but simply a choice made to better follow a strong host model which
|
|
|
|
|
// the netstack follows at the time of writing.
|
|
|
|
|
//
|
|
|
|
|
// Note that for incoming traffic that we are forwarding (for which the
|
|
|
|
|
// NIC and local address are unspecified), we do not keep iterating, as
|
|
|
|
|
// there is no reason to prefer routes that let us use a local address
|
|
|
|
|
// when routing forwarded (as opposed to locally-generated) traffic.
|
|
|
|
|
locallyGenerated := (id != 0 || localAddr != tcpip.Address{})
|
2023-05-16 11:32:52 -07:00
|
|
|
if onlyGlobalAddresses && chosenRoute.Equal(tcpip.Route{}) && isNICForwarding(nic, netProto) {
|
2023-10-16 08:07:04 -07:00
|
|
|
if locallyGenerated {
|
2024-06-27 13:09:37 -07:00
|
|
|
chosenRoute = *route
|
2023-10-16 08:07:04 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2024-06-06 09:13:23 -07:00
|
|
|
|
|
|
|
|
if r := s.findRouteWithLocalAddrFromAnyInterfaceRLocked(nic, localAddr, remoteAddr, route.SourceHint, route.Gateway, netProto, multicastLoop, route.MTU); r != nil {
|
2023-10-16 08:07:04 -07:00
|
|
|
return r
|
|
|
|
|
}
|
2019-02-28 14:37:42 -08:00
|
|
|
}
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
2019-02-28 14:37:42 -08:00
|
|
|
|
2021-01-30 17:51:47 -08:00
|
|
|
return nil
|
|
|
|
|
}(); r != nil {
|
|
|
|
|
return r, nil
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
2020-07-30 12:48:18 -07:00
|
|
|
|
2023-05-16 11:32:52 -07:00
|
|
|
if !chosenRoute.Equal(tcpip.Route{}) {
|
2020-11-05 15:49:51 -08:00
|
|
|
// At this point we know the stack has forwarding enabled since chosenRoute is
|
|
|
|
|
// only set when forwarding is enabled.
|
|
|
|
|
nic, ok := s.nics[chosenRoute.NIC]
|
|
|
|
|
if !ok {
|
|
|
|
|
// If the route's NIC was invalid, we should not have chosen the route.
|
|
|
|
|
panic(fmt.Sprintf("chosen route must have a valid NIC with ID = %d", chosenRoute.NIC))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var gateway tcpip.Address
|
|
|
|
|
if needRoute {
|
|
|
|
|
gateway = chosenRoute.Gateway
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use the specified NIC to get the local address endpoint.
|
|
|
|
|
if id != 0 {
|
|
|
|
|
if aNIC, ok := s.nics[id]; ok {
|
2023-12-04 14:28:09 -08:00
|
|
|
if addressEndpoint := s.getAddressEP(aNIC, localAddr, remoteAddr, chosenRoute.SourceHint, netProto); addressEndpoint != nil {
|
2024-06-06 09:13:23 -07:00
|
|
|
if r := constructAndValidateRoute(netProto, addressEndpoint, aNIC /* localAddressNIC */, nic /* outgoingNIC */, gateway, localAddr, remoteAddr, s.handleLocal, multicastLoop, chosenRoute.MTU); r != nil {
|
2020-11-05 15:49:51 -08:00
|
|
|
return r, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-19 18:26:36 -07:00
|
|
|
// TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable.
|
|
|
|
|
return nil, &tcpip.ErrHostUnreachable{}
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if id == 0 {
|
|
|
|
|
// If an interface is not specified, try to find a NIC that holds the local
|
|
|
|
|
// address endpoint to construct a route.
|
2024-06-06 09:13:23 -07:00
|
|
|
if r := s.findRouteWithLocalAddrFromAnyInterfaceRLocked(nic, localAddr, remoteAddr, chosenRoute.SourceHint, gateway, netProto, multicastLoop, chosenRoute.MTU); r != nil {
|
2023-10-16 08:07:04 -07:00
|
|
|
return r, nil
|
2019-02-28 14:37:42 -08:00
|
|
|
}
|
|
|
|
|
}
|
2018-12-06 11:47:17 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-05 15:49:51 -08:00
|
|
|
if needRoute {
|
2022-10-19 18:26:36 -07:00
|
|
|
// TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable.
|
|
|
|
|
return nil, &tcpip.ErrHostUnreachable{}
|
2019-02-07 23:14:06 -08:00
|
|
|
}
|
2020-11-09 13:55:28 -08:00
|
|
|
if header.IsV6LoopbackAddress(remoteAddr) {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrBadLocalAddress{}
|
2020-11-05 15:49:51 -08:00
|
|
|
}
|
2022-10-19 18:26:36 -07:00
|
|
|
// TODO(https://gvisor.dev/issues/8105): This should be ErrNetworkUnreachable.
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrNetworkUnreachable{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CheckNetworkProtocol checks if a given network protocol is enabled in the
|
|
|
|
|
// stack.
|
|
|
|
|
func (s *Stack) CheckNetworkProtocol(protocol tcpip.NetworkProtocolNumber) bool {
|
|
|
|
|
_, ok := s.networkProtocols[protocol]
|
|
|
|
|
return ok
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-08 19:03:54 -08:00
|
|
|
// CheckDuplicateAddress performs duplicate address detection for the address on
|
|
|
|
|
// the specified interface.
|
|
|
|
|
func (s *Stack) CheckDuplicateAddress(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, h DADCompletionHandler) (DADCheckAddressDisposition, tcpip.Error) {
|
2022-11-02 18:52:49 -07:00
|
|
|
s.mu.RLock()
|
2021-02-08 19:03:54 -08:00
|
|
|
nic, ok := s.nics[nicID]
|
2022-11-02 18:52:49 -07:00
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
2021-02-08 19:03:54 -08:00
|
|
|
if !ok {
|
|
|
|
|
return 0, &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nic.checkDuplicateAddress(protocol, addr, h)
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// CheckLocalAddress determines if the given local address exists, and if it
|
|
|
|
|
// does, returns the id of the NIC it's bound to. Returns 0 if the address
|
|
|
|
|
// does not exist.
|
2019-11-06 19:39:57 -08:00
|
|
|
func (s *Stack) CheckLocalAddress(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.NICID {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2022-08-15 16:19:27 -07:00
|
|
|
// If a NIC is specified, use its NIC id.
|
2019-11-06 19:39:57 -08:00
|
|
|
if nicID != 0 {
|
2020-08-25 11:07:32 -07:00
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
2018-04-27 10:37:02 -07:00
|
|
|
return 0
|
|
|
|
|
}
|
2022-08-15 16:19:27 -07:00
|
|
|
// In IPv4, linux only checks the interface. If it matches, then it does
|
|
|
|
|
// not bother with the address.
|
|
|
|
|
// https://github.com/torvalds/linux/blob/15205c2829ca2cbb5ece5ceaafe1171a8470e62b/net/ipv4/igmp.c#L1829-L1837
|
|
|
|
|
if protocol == header.IPv4ProtocolNumber {
|
|
|
|
|
return nic.id
|
|
|
|
|
}
|
2021-02-06 09:07:26 -08:00
|
|
|
if nic.CheckLocalAddress(protocol, addr) {
|
|
|
|
|
return nic.id
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
2021-02-06 09:07:26 -08:00
|
|
|
return 0
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Go through all the NICs.
|
|
|
|
|
for _, nic := range s.nics {
|
2021-02-06 09:07:26 -08:00
|
|
|
if nic.CheckLocalAddress(protocol, addr) {
|
2018-04-27 10:37:02 -07:00
|
|
|
return nic.id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetPromiscuousMode enables or disables promiscuous mode in the given NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) SetPromiscuousMode(nicID tcpip.NICID, enable bool) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2020-08-25 11:07:32 -07:00
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nic.setPromiscuousMode(enable)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetSpoofing enables or disables address spoofing in the given NIC, allowing
|
|
|
|
|
// endpoints to bind to any address in the NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) SetSpoofing(nicID tcpip.NICID, enable bool) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
2020-08-25 11:07:32 -07:00
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nic.setSpoofing(enable)
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-21 19:53:31 -08:00
|
|
|
// LinkResolutionResult is the result of a link address resolution attempt.
|
|
|
|
|
type LinkResolutionResult struct {
|
|
|
|
|
LinkAddress tcpip.LinkAddress
|
2021-03-02 11:55:45 -08:00
|
|
|
Err tcpip.Error
|
2021-01-21 19:53:31 -08:00
|
|
|
}
|
|
|
|
|
|
2021-01-21 23:19:38 -08:00
|
|
|
// GetLinkAddress finds the link address corresponding to a network address.
|
2021-01-15 18:12:50 -08:00
|
|
|
//
|
|
|
|
|
// Returns ErrNotSupported if the stack is not configured with a link address
|
|
|
|
|
// resolver for the specified network protocol.
|
|
|
|
|
//
|
|
|
|
|
// Returns ErrWouldBlock if the link address is not readily available, along
|
|
|
|
|
// with a notification channel for the caller to block on. Triggers address
|
|
|
|
|
// resolution asynchronously.
|
|
|
|
|
//
|
2021-01-21 19:53:31 -08:00
|
|
|
// onResolve will be called either immediately, if resolution is not required,
|
|
|
|
|
// or when address resolution is complete, with the resolved link address and
|
|
|
|
|
// whether resolution succeeded.
|
2021-01-15 18:12:50 -08:00
|
|
|
//
|
|
|
|
|
// If specified, the local address must be an address local to the interface
|
|
|
|
|
// the neighbor cache belongs to. The local address is the source address of
|
|
|
|
|
// a packet prompting NUD/link address resolution.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) GetLinkAddress(nicID tcpip.NICID, addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) tcpip.Error {
|
2018-04-27 10:37:02 -07:00
|
|
|
s.mu.RLock()
|
2021-01-15 18:12:50 -08:00
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-30 11:35:35 -08:00
|
|
|
return nic.getLinkAddress(addr, localAddr, protocol, onResolve)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-25 11:07:32 -07:00
|
|
|
// Neighbors returns all IP to MAC address associations.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) Neighbors(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber) ([]NeighborEntry, tcpip.Error) {
|
2020-08-25 11:07:32 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrUnknownNICID{}
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.neighbors(protocol)
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddStaticNeighbor statically associates an IP address to a MAC address.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) AddStaticNeighbor(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error {
|
2020-08-25 11:07:32 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.addStaticNeighbor(addr, protocol, linkAddr)
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RemoveNeighbor removes an IP to MAC address association previously created
|
2023-10-25 12:06:44 -07:00
|
|
|
// either automatically or by AddStaticNeighbor. Returns ErrBadAddress if there
|
2020-08-25 11:07:32 -07:00
|
|
|
// is no association with the provided address.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) RemoveNeighbor(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
|
2020-08-25 11:07:32 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.removeNeighbor(protocol, addr)
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClearNeighbors removes all IP to MAC address associations.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) ClearNeighbors(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber) tcpip.Error {
|
2020-08-25 11:07:32 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.clearNeighbors(protocol)
|
2020-08-25 11:07:32 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// RegisterTransportEndpoint registers the given endpoint with the stack
|
|
|
|
|
// transport dispatcher. Received packets that match the provided id will be
|
|
|
|
|
// delivered to the given endpoint; specifying a nic is optional, but
|
|
|
|
|
// nic-specific IDs have precedence over global ones.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) RegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
|
2020-06-10 23:48:03 -07:00
|
|
|
return s.demux.registerEndpoint(netProtos, protocol, id, ep, flags, bindToDevice)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2020-06-23 19:14:05 -07:00
|
|
|
// CheckRegisterTransportEndpoint checks if an endpoint can be registered with
|
|
|
|
|
// the stack transport dispatcher.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) CheckRegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
|
2020-06-23 19:14:05 -07:00
|
|
|
return s.demux.checkEndpoint(netProtos, protocol, id, flags, bindToDevice)
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// UnregisterTransportEndpoint removes the endpoint with the given id from the
|
|
|
|
|
// stack transport dispatcher.
|
2021-01-26 10:32:46 -08:00
|
|
|
func (s *Stack) UnregisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) {
|
2020-06-10 23:48:03 -07:00
|
|
|
s.demux.unregisterEndpoint(netProtos, protocol, id, ep, flags, bindToDevice)
|
2018-04-27 10:37:02 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 16:13:43 -07:00
|
|
|
// StartTransportEndpointCleanup removes the endpoint with the given id from
|
|
|
|
|
// the stack transport dispatcher. It also transitions it to the cleanup stage.
|
2021-01-26 10:32:46 -08:00
|
|
|
func (s *Stack) StartTransportEndpointCleanup(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) {
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Lock()
|
2019-10-29 16:13:43 -07:00
|
|
|
s.cleanupEndpoints[ep] = struct{}{}
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Unlock()
|
2019-10-29 16:13:43 -07:00
|
|
|
|
2020-06-10 23:48:03 -07:00
|
|
|
s.demux.unregisterEndpoint(netProtos, protocol, id, ep, flags, bindToDevice)
|
2019-10-29 16:13:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CompleteTransportEndpointCleanup removes the endpoint from the cleanup
|
|
|
|
|
// stage.
|
|
|
|
|
func (s *Stack) CompleteTransportEndpointCleanup(ep TransportEndpoint) {
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Lock()
|
2019-10-29 16:13:43 -07:00
|
|
|
delete(s.cleanupEndpoints, ep)
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Unlock()
|
2019-10-29 16:13:43 -07:00
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:45:26 -08:00
|
|
|
// FindTransportEndpoint finds an endpoint that most closely matches the provided
|
|
|
|
|
// id. If no endpoint is found it returns nil.
|
2020-11-05 15:49:51 -08:00
|
|
|
func (s *Stack) FindTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, id TransportEndpointID, nicID tcpip.NICID) TransportEndpoint {
|
|
|
|
|
return s.demux.findTransportEndpoint(netProto, transProto, id, nicID)
|
2019-11-07 09:45:26 -08:00
|
|
|
}
|
|
|
|
|
|
2019-02-27 14:30:20 -08:00
|
|
|
// RegisterRawTransportEndpoint registers the given endpoint with the stack
|
2019-04-02 11:12:29 -07:00
|
|
|
// transport dispatcher. Received packets that match the provided transport
|
|
|
|
|
// protocol will be delivered to the given endpoint.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) RegisterRawTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) tcpip.Error {
|
2019-09-27 14:12:35 -07:00
|
|
|
return s.demux.registerRawEndpoint(netProto, transProto, ep)
|
2019-02-27 14:30:20 -08:00
|
|
|
}
|
|
|
|
|
|
2019-04-02 11:12:29 -07:00
|
|
|
// UnregisterRawTransportEndpoint removes the endpoint for the transport
|
|
|
|
|
// protocol from the stack transport dispatcher.
|
2021-01-26 10:32:46 -08:00
|
|
|
func (s *Stack) UnregisterRawTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) {
|
2019-09-27 14:12:35 -07:00
|
|
|
s.demux.unregisterRawEndpoint(netProto, transProto, ep)
|
2019-02-27 14:30:20 -08:00
|
|
|
}
|
|
|
|
|
|
2019-08-08 12:32:00 -07:00
|
|
|
// RegisterRestoredEndpoint records e as an endpoint that has been restored on
|
|
|
|
|
// this stack.
|
2024-03-06 13:22:36 -08:00
|
|
|
func (s *Stack) RegisterRestoredEndpoint(e RestoredEndpoint) {
|
2019-08-08 12:32:00 -07:00
|
|
|
s.mu.Lock()
|
2024-03-13 10:33:23 -07:00
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
2024-03-06 13:22:36 -08:00
|
|
|
s.restoredEndpoints = append(s.restoredEndpoints, e)
|
2024-03-13 10:33:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RegisterResumableEndpoint records e as an endpoint that has to be resumed.
|
|
|
|
|
func (s *Stack) RegisterResumableEndpoint(e ResumableEndpoint) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
s.resumableEndpoints = append(s.resumableEndpoints, e)
|
2019-08-08 12:32:00 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 16:13:43 -07:00
|
|
|
// RegisteredEndpoints returns all endpoints which are currently registered.
|
|
|
|
|
func (s *Stack) RegisteredEndpoints() []TransportEndpoint {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
2024-03-13 10:33:23 -07:00
|
|
|
|
2019-10-29 16:13:43 -07:00
|
|
|
var es []TransportEndpoint
|
|
|
|
|
for _, e := range s.demux.protocol {
|
|
|
|
|
es = append(es, e.transportEndpoints()...)
|
|
|
|
|
}
|
|
|
|
|
return es
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CleanupEndpoints returns endpoints currently in the cleanup state.
|
|
|
|
|
func (s *Stack) CleanupEndpoints() []TransportEndpoint {
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Lock()
|
2024-03-13 10:33:23 -07:00
|
|
|
defer s.cleanupEndpointsMu.Unlock()
|
|
|
|
|
|
2019-10-29 16:13:43 -07:00
|
|
|
es := make([]TransportEndpoint, 0, len(s.cleanupEndpoints))
|
|
|
|
|
for e := range s.cleanupEndpoints {
|
|
|
|
|
es = append(es, e)
|
|
|
|
|
}
|
|
|
|
|
return es
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RestoreCleanupEndpoints adds endpoints to cleanup tracking. This is useful
|
|
|
|
|
// for restoring a stack after a save.
|
|
|
|
|
func (s *Stack) RestoreCleanupEndpoints(es []TransportEndpoint) {
|
2020-09-03 17:34:56 -07:00
|
|
|
s.cleanupEndpointsMu.Lock()
|
2024-03-13 10:33:23 -07:00
|
|
|
defer s.cleanupEndpointsMu.Unlock()
|
|
|
|
|
|
2019-10-29 16:13:43 -07:00
|
|
|
for _, e := range es {
|
|
|
|
|
s.cleanupEndpoints[e] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-29 17:21:01 -07:00
|
|
|
// Close closes all currently registered transport endpoints.
|
|
|
|
|
//
|
|
|
|
|
// Endpoints created or modified during this call may not get closed.
|
|
|
|
|
func (s *Stack) Close() {
|
|
|
|
|
for _, e := range s.RegisteredEndpoints() {
|
2020-02-24 10:31:01 -08:00
|
|
|
e.Abort()
|
|
|
|
|
}
|
|
|
|
|
for _, p := range s.transportProtocols {
|
|
|
|
|
p.proto.Close()
|
|
|
|
|
}
|
|
|
|
|
for _, p := range s.networkProtocols {
|
|
|
|
|
p.Close()
|
2019-10-29 17:21:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait waits for all transport and link endpoints to halt their worker
|
|
|
|
|
// goroutines.
|
|
|
|
|
//
|
|
|
|
|
// Endpoints created or modified during this call may not get waited on.
|
|
|
|
|
//
|
|
|
|
|
// Note that link endpoints must be stopped via an implementation specific
|
|
|
|
|
// mechanism.
|
|
|
|
|
func (s *Stack) Wait() {
|
|
|
|
|
for _, e := range s.RegisteredEndpoints() {
|
|
|
|
|
e.Wait()
|
|
|
|
|
}
|
|
|
|
|
for _, e := range s.CleanupEndpoints() {
|
|
|
|
|
e.Wait()
|
|
|
|
|
}
|
2020-02-24 10:31:01 -08:00
|
|
|
for _, p := range s.transportProtocols {
|
|
|
|
|
p.proto.Wait()
|
|
|
|
|
}
|
|
|
|
|
for _, p := range s.networkProtocols {
|
|
|
|
|
p.Wait()
|
|
|
|
|
}
|
2019-10-29 17:21:01 -07:00
|
|
|
|
2024-07-10 13:29:15 -07:00
|
|
|
deferActs := make([]func(), 0)
|
2024-07-10 11:33:01 -07:00
|
|
|
|
2024-07-10 13:29:15 -07:00
|
|
|
s.mu.Lock()
|
2022-01-25 12:22:37 -08:00
|
|
|
for id, n := range s.nics {
|
|
|
|
|
// Remove NIC to ensure that qDisc goroutines are correctly
|
|
|
|
|
// terminated on stack teardown.
|
2024-07-10 13:29:15 -07:00
|
|
|
act, _ := s.removeNICLocked(id)
|
2021-12-13 18:28:44 -08:00
|
|
|
n.NetworkLinkEndpoint.Wait()
|
2024-07-10 13:29:15 -07:00
|
|
|
if act != nil {
|
|
|
|
|
deferActs = append(deferActs, act)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
for _, act := range deferActs {
|
|
|
|
|
act()
|
2019-10-29 17:21:01 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 16:35:30 -08:00
|
|
|
// Destroy destroys the stack with all endpoints.
|
|
|
|
|
func (s *Stack) Destroy() {
|
|
|
|
|
s.Close()
|
|
|
|
|
s.Wait()
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 17:26:26 -07:00
|
|
|
// Pause pauses any protocol level background workers.
|
|
|
|
|
func (s *Stack) Pause() {
|
|
|
|
|
for _, p := range s.transportProtocols {
|
|
|
|
|
p.proto.Pause()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-07 11:14:57 -08:00
|
|
|
func (s *Stack) getNICs() map[tcpip.NICID]*nic {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
nics := s.nics
|
|
|
|
|
return nics
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-20 11:08:45 -08:00
|
|
|
// ReplaceConfig replaces config in the loaded stack.
|
|
|
|
|
func (s *Stack) ReplaceConfig(st *Stack) {
|
|
|
|
|
if st == nil {
|
|
|
|
|
panic("stack.Stack cannot be nil when netstack s/r is enabled")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update route table.
|
|
|
|
|
s.SetRouteTable(st.GetRouteTable())
|
|
|
|
|
|
|
|
|
|
// Update NICs.
|
2025-01-07 11:14:57 -08:00
|
|
|
nics := st.getNICs()
|
2024-11-20 11:08:45 -08:00
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
s.nics = make(map[tcpip.NICID]*nic)
|
2025-01-07 11:14:57 -08:00
|
|
|
for id, nic := range nics {
|
2024-11-20 11:08:45 -08:00
|
|
|
nic.stack = s
|
|
|
|
|
s.nics[id] = nic
|
|
|
|
|
_ = s.NextNICID()
|
|
|
|
|
}
|
2024-12-18 12:48:08 -08:00
|
|
|
s.tables = st.tables
|
2024-11-20 11:08:45 -08:00
|
|
|
}
|
|
|
|
|
|
2024-03-06 13:22:36 -08:00
|
|
|
// Restore restarts the stack after a restore. This must be called after the
|
2019-08-08 12:32:00 -07:00
|
|
|
// entire system has been restored.
|
2024-03-06 13:22:36 -08:00
|
|
|
func (s *Stack) Restore() {
|
|
|
|
|
// RestoredEndpoint.Restore() may call other methods on s, so we can't hold
|
|
|
|
|
// s.mu while restoring the endpoints.
|
2019-08-08 12:32:00 -07:00
|
|
|
s.mu.Lock()
|
2024-03-06 13:22:36 -08:00
|
|
|
eps := s.restoredEndpoints
|
|
|
|
|
s.restoredEndpoints = nil
|
2024-11-20 11:08:45 -08:00
|
|
|
saveRestoreEnabled := s.saveRestoreEnabled
|
2019-08-08 12:32:00 -07:00
|
|
|
s.mu.Unlock()
|
|
|
|
|
for _, e := range eps {
|
2024-03-06 13:22:36 -08:00
|
|
|
e.Restore(s)
|
2019-08-08 12:32:00 -07:00
|
|
|
}
|
2022-04-18 17:26:26 -07:00
|
|
|
// Now resume any protocol level background workers.
|
|
|
|
|
for _, p := range s.transportProtocols {
|
2024-11-20 11:08:45 -08:00
|
|
|
if saveRestoreEnabled {
|
|
|
|
|
p.proto.Restore()
|
|
|
|
|
} else {
|
|
|
|
|
p.proto.Resume()
|
|
|
|
|
}
|
2022-04-18 17:26:26 -07:00
|
|
|
}
|
2019-08-08 12:32:00 -07:00
|
|
|
}
|
|
|
|
|
|
2024-03-13 10:33:23 -07:00
|
|
|
// Resume resumes the stack after a save.
|
|
|
|
|
func (s *Stack) Resume() {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
eps := s.resumableEndpoints
|
|
|
|
|
s.resumableEndpoints = nil
|
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
for _, e := range eps {
|
|
|
|
|
e.Resume()
|
|
|
|
|
}
|
|
|
|
|
// Now resume any protocol level background workers.
|
|
|
|
|
for _, p := range s.transportProtocols {
|
|
|
|
|
p.proto.Resume()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 13:21:58 -07:00
|
|
|
// RegisterPacketEndpoint registers ep with the stack, causing it to receive
|
|
|
|
|
// all traffic of the specified netProto on the given NIC. If nicID is 0, it
|
|
|
|
|
// receives traffic from every NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) RegisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) tcpip.Error {
|
2019-10-21 13:21:58 -07:00
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
// If no NIC is specified, capture on all devices.
|
|
|
|
|
if nicID == 0 {
|
|
|
|
|
// Register with each NIC.
|
|
|
|
|
for _, nic := range s.nics {
|
2024-01-30 10:16:36 -08:00
|
|
|
nic.registerPacketEndpoint(netProto, ep)
|
2019-10-21 13:21:58 -07:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Capture on a specific device.
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2019-10-21 13:21:58 -07:00
|
|
|
}
|
2024-01-30 10:16:36 -08:00
|
|
|
nic.registerPacketEndpoint(netProto, ep)
|
2019-10-21 13:21:58 -07:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnregisterPacketEndpoint unregisters ep for packets of the specified
|
|
|
|
|
// netProto from the specified NIC. If nicID is 0, ep is unregistered from all
|
|
|
|
|
// NICs.
|
|
|
|
|
func (s *Stack) UnregisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
s.unregisterPacketEndpointLocked(nicID, netProto, ep)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-02 18:52:49 -07:00
|
|
|
// +checklocks:s.mu
|
2019-10-21 13:21:58 -07:00
|
|
|
func (s *Stack) unregisterPacketEndpointLocked(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) {
|
|
|
|
|
// If no NIC is specified, unregister on all devices.
|
|
|
|
|
if nicID == 0 {
|
|
|
|
|
// Unregister with each NIC.
|
|
|
|
|
for _, nic := range s.nics {
|
|
|
|
|
nic.unregisterPacketEndpoint(netProto, ep)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unregister in a single device.
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
nic.unregisterPacketEndpoint(netProto, ep)
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-18 07:03:02 -08:00
|
|
|
// WritePacketToRemote writes a payload on the specified NIC using the provided
|
|
|
|
|
// network protocol and remote link address.
|
2023-06-01 21:25:01 -07:00
|
|
|
func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, payload buffer.Buffer) tcpip.Error {
|
2019-10-21 13:21:58 -07:00
|
|
|
s.mu.Lock()
|
2019-11-06 19:39:57 -08:00
|
|
|
nic, ok := s.nics[nicID]
|
2019-10-21 13:21:58 -07:00
|
|
|
s.mu.Unlock()
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownDevice{}
|
2019-10-21 13:21:58 -07:00
|
|
|
}
|
2020-11-18 07:03:02 -08:00
|
|
|
pkt := NewPacketBuffer(PacketBufferOptions{
|
|
|
|
|
ReserveHeaderBytes: int(nic.MaxHeaderLength()),
|
2022-06-07 10:33:35 -07:00
|
|
|
Payload: payload,
|
2020-11-18 07:03:02 -08:00
|
|
|
})
|
2021-11-08 13:26:02 -08:00
|
|
|
defer pkt.DecRef()
|
2021-09-01 19:41:43 -07:00
|
|
|
pkt.NetworkProtocolNumber = netProto
|
2022-01-14 13:20:15 -08:00
|
|
|
return nic.WritePacketToRemote(remote, pkt)
|
2019-10-21 13:21:58 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-01 19:41:43 -07:00
|
|
|
// WriteRawPacket writes data directly to the specified NIC without adding any
|
|
|
|
|
// headers.
|
2023-06-01 21:25:01 -07:00
|
|
|
func (s *Stack) WriteRawPacket(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber, payload buffer.Buffer) tcpip.Error {
|
2021-09-01 19:41:43 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
if !ok {
|
|
|
|
|
return &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkt := NewPacketBuffer(PacketBufferOptions{
|
2022-06-07 10:33:35 -07:00
|
|
|
Payload: payload,
|
2021-09-01 19:41:43 -07:00
|
|
|
})
|
2021-11-08 13:26:02 -08:00
|
|
|
defer pkt.DecRef()
|
2021-09-01 19:41:43 -07:00
|
|
|
pkt.NetworkProtocolNumber = proto
|
2023-06-21 13:38:29 -07:00
|
|
|
return nic.writeRawPacketWithLinkHeaderInPayload(pkt)
|
2021-09-01 19:41:43 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-27 10:37:02 -07:00
|
|
|
// NetworkProtocolInstance returns the protocol instance in the stack for the
|
|
|
|
|
// specified network protocol. This method is public for protocol implementers
|
|
|
|
|
// and tests to use.
|
|
|
|
|
func (s *Stack) NetworkProtocolInstance(num tcpip.NetworkProtocolNumber) NetworkProtocol {
|
|
|
|
|
if p, ok := s.networkProtocols[num]; ok {
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TransportProtocolInstance returns the protocol instance in the stack for the
|
|
|
|
|
// specified transport protocol. This method is public for protocol implementers
|
|
|
|
|
// and tests to use.
|
|
|
|
|
func (s *Stack) TransportProtocolInstance(num tcpip.TransportProtocolNumber) TransportProtocol {
|
|
|
|
|
if pState, ok := s.transportProtocols[num]; ok {
|
|
|
|
|
return pState.proto
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-12 20:38:27 -07:00
|
|
|
// JoinGroup joins the given multicast group on the given NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) JoinGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) tcpip.Error {
|
2019-05-02 19:39:55 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if nic, ok := s.nics[nicID]; ok {
|
|
|
|
|
return nic.joinGroup(protocol, multicastAddr)
|
|
|
|
|
}
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-09-12 20:38:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LeaveGroup leaves the given multicast group on the given NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) LeaveGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) tcpip.Error {
|
2019-05-02 19:39:55 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if nic, ok := s.nics[nicID]; ok {
|
2020-09-29 00:18:37 -07:00
|
|
|
return nic.leaveGroup(protocol, multicastAddr)
|
2019-05-02 19:39:55 -07:00
|
|
|
}
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2018-09-12 20:38:27 -07:00
|
|
|
}
|
2019-08-02 16:25:34 -07:00
|
|
|
|
2020-02-20 14:31:39 -08:00
|
|
|
// IsInGroup returns true if the NIC with ID nicID has joined the multicast
|
|
|
|
|
// group multicastAddr.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) IsInGroup(nicID tcpip.NICID, multicastAddr tcpip.Address) (bool, tcpip.Error) {
|
2020-02-20 14:31:39 -08:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if nic, ok := s.nics[nicID]; ok {
|
|
|
|
|
return nic.isInGroup(multicastAddr), nil
|
|
|
|
|
}
|
2021-01-28 17:57:42 -08:00
|
|
|
return false, &tcpip.ErrUnknownNICID{}
|
2020-02-20 14:31:39 -08:00
|
|
|
}
|
|
|
|
|
|
2019-08-02 16:25:34 -07:00
|
|
|
// IPTables returns the stack's iptables.
|
2020-06-04 15:38:33 -07:00
|
|
|
func (s *Stack) IPTables() *IPTables {
|
|
|
|
|
return s.tables
|
2019-08-02 16:25:34 -07:00
|
|
|
}
|
2019-09-03 15:59:58 -07:00
|
|
|
|
|
|
|
|
// ICMPLimit returns the maximum number of ICMP messages that can be sent
|
|
|
|
|
// in one second.
|
|
|
|
|
func (s *Stack) ICMPLimit() rate.Limit {
|
|
|
|
|
return s.icmpRateLimiter.Limit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetICMPLimit sets the maximum number of ICMP messages that be sent
|
|
|
|
|
// in one second.
|
|
|
|
|
func (s *Stack) SetICMPLimit(newLimit rate.Limit) {
|
|
|
|
|
s.icmpRateLimiter.SetLimit(newLimit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ICMPBurst returns the maximum number of ICMP messages that can be sent
|
|
|
|
|
// in a single burst.
|
|
|
|
|
func (s *Stack) ICMPBurst() int {
|
|
|
|
|
return s.icmpRateLimiter.Burst()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetICMPBurst sets the maximum number of ICMP messages that can be sent
|
|
|
|
|
// in a single burst.
|
|
|
|
|
func (s *Stack) SetICMPBurst(burst int) {
|
|
|
|
|
s.icmpRateLimiter.SetBurst(burst)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AllowICMPMessage returns true if we the rate limiter allows at least one
|
|
|
|
|
// ICMP message to be sent at this instant.
|
|
|
|
|
func (s *Stack) AllowICMPMessage() bool {
|
|
|
|
|
return s.icmpRateLimiter.Allow()
|
|
|
|
|
}
|
2019-09-30 13:54:03 -07:00
|
|
|
|
2020-09-29 00:18:37 -07:00
|
|
|
// GetNetworkEndpoint returns the NetworkEndpoint with the specified protocol
|
|
|
|
|
// number installed on the specified NIC.
|
2021-01-28 17:57:42 -08:00
|
|
|
func (s *Stack) GetNetworkEndpoint(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber) (NetworkEndpoint, tcpip.Error) {
|
2019-10-16 22:53:20 -07:00
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
2020-09-29 00:18:37 -07:00
|
|
|
nic, ok := s.nics[nicID]
|
2019-10-16 22:53:20 -07:00
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return nil, &tcpip.ErrUnknownNICID{}
|
2019-10-16 22:53:20 -07:00
|
|
|
}
|
|
|
|
|
|
2020-10-05 13:15:06 -07:00
|
|
|
return nic.getNetworkEndpoint(proto), nil
|
2019-10-24 11:07:58 -07:00
|
|
|
}
|
|
|
|
|
|
2020-07-30 13:28:21 -07:00
|
|
|
// NUDConfigurations gets the per-interface NUD configurations.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) NUDConfigurations(id tcpip.NICID, proto tcpip.NetworkProtocolNumber) (NUDConfigurations, tcpip.Error) {
|
2020-07-30 13:28:21 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return NUDConfigurations{}, &tcpip.ErrUnknownNICID{}
|
2020-07-30 13:28:21 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.nudConfigs(proto)
|
2020-07-30 13:28:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetNUDConfigurations sets the per-interface NUD configurations.
|
|
|
|
|
//
|
|
|
|
|
// Note, if c contains invalid NUD configuration values, it will be fixed to
|
|
|
|
|
// use default values for the erroneous values.
|
2021-01-31 11:31:55 -08:00
|
|
|
func (s *Stack) SetNUDConfigurations(id tcpip.NICID, proto tcpip.NetworkProtocolNumber, c NUDConfigurations) tcpip.Error {
|
2020-07-30 13:28:21 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if !ok {
|
2021-01-28 17:57:42 -08:00
|
|
|
return &tcpip.ErrUnknownNICID{}
|
2020-07-30 13:28:21 -07:00
|
|
|
}
|
|
|
|
|
|
2021-01-31 11:31:55 -08:00
|
|
|
return nic.setNUDConfigs(proto, c)
|
2020-07-30 13:28:21 -07:00
|
|
|
}
|
|
|
|
|
|
2021-08-26 17:42:15 -07:00
|
|
|
// Seed returns a 32 bit value that can be used as a seed value.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: The seed is generated once during stack initialization only.
|
|
|
|
|
func (s *Stack) Seed() uint32 {
|
|
|
|
|
return s.seed
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-28 16:11:16 -07:00
|
|
|
// InsecureRNG returns a reference to a pseudo random generator that can be used
|
|
|
|
|
// to generate random numbers as required. It is not cryptographically secure
|
|
|
|
|
// and should not be used for security sensitive work.
|
|
|
|
|
func (s *Stack) InsecureRNG() *rand.Rand {
|
|
|
|
|
return s.insecureRNG
|
2020-03-24 15:33:16 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-16 11:07:02 -07:00
|
|
|
// SecureRNG returns the stack's cryptographically secure random number
|
|
|
|
|
// generator.
|
2023-10-28 16:11:16 -07:00
|
|
|
func (s *Stack) SecureRNG() cryptorand.RNG {
|
2021-03-16 11:07:02 -07:00
|
|
|
return s.secureRNG
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 11:07:32 -07:00
|
|
|
// FindNICNameFromID returns the name of the NIC for the given NICID.
|
2020-05-08 15:39:04 -07:00
|
|
|
func (s *Stack) FindNICNameFromID(id tcpip.NICID) string {
|
2020-08-05 14:09:26 -07:00
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
2020-05-08 15:39:04 -07:00
|
|
|
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nic.Name()
|
|
|
|
|
}
|
2020-09-29 00:18:37 -07:00
|
|
|
|
2020-11-05 15:49:51 -08:00
|
|
|
// ParseResult indicates the result of a parsing attempt.
|
|
|
|
|
type ParseResult int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// ParsedOK indicates that a packet was successfully parsed.
|
|
|
|
|
ParsedOK ParseResult = iota
|
|
|
|
|
|
|
|
|
|
// UnknownTransportProtocol indicates that the transport protocol is unknown.
|
|
|
|
|
UnknownTransportProtocol
|
|
|
|
|
|
|
|
|
|
// TransportLayerParseError indicates that the transport packet was not
|
|
|
|
|
// successfully parsed.
|
|
|
|
|
TransportLayerParseError
|
|
|
|
|
)
|
|
|
|
|
|
2021-02-05 16:44:49 -08:00
|
|
|
// ParsePacketBufferTransport parses the provided packet buffer's transport
|
|
|
|
|
// header.
|
2024-02-29 11:07:59 -08:00
|
|
|
func (s *Stack) ParsePacketBufferTransport(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) ParseResult {
|
2021-02-05 16:44:49 -08:00
|
|
|
pkt.TransportProtocolNumber = protocol
|
2020-11-05 15:49:51 -08:00
|
|
|
// Parse the transport header if present.
|
2021-02-05 16:44:49 -08:00
|
|
|
state, ok := s.transportProtocols[protocol]
|
2020-11-05 15:49:51 -08:00
|
|
|
if !ok {
|
|
|
|
|
return UnknownTransportProtocol
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !state.proto.Parse(pkt) {
|
|
|
|
|
return TransportLayerParseError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ParsedOK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// networkProtocolNumbers returns the network protocol numbers the stack is
|
|
|
|
|
// configured with.
|
|
|
|
|
func (s *Stack) networkProtocolNumbers() []tcpip.NetworkProtocolNumber {
|
|
|
|
|
protos := make([]tcpip.NetworkProtocolNumber, 0, len(s.networkProtocols))
|
|
|
|
|
for p := range s.networkProtocols {
|
|
|
|
|
protos = append(protos, p)
|
|
|
|
|
}
|
|
|
|
|
return protos
|
|
|
|
|
}
|
2020-11-18 12:43:51 -08:00
|
|
|
|
2021-02-06 09:47:26 -08:00
|
|
|
func isSubnetBroadcastOnNIC(nic *nic, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) bool {
|
2020-11-18 12:43:51 -08:00
|
|
|
addressEndpoint := nic.getAddressOrCreateTempInner(protocol, addr, false /* createTemp */, NeverPrimaryEndpoint)
|
|
|
|
|
if addressEndpoint == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subnet := addressEndpoint.Subnet()
|
|
|
|
|
addressEndpoint.DecRef()
|
|
|
|
|
return subnet.IsBroadcast(addr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsSubnetBroadcast returns true if the provided address is a subnet-local
|
|
|
|
|
// broadcast address on the specified NIC and protocol.
|
|
|
|
|
//
|
|
|
|
|
// Returns false if the NIC is unknown or if the protocol is unknown or does
|
|
|
|
|
// not support addressing.
|
|
|
|
|
//
|
|
|
|
|
// If the NIC is not specified, the stack will check all NICs.
|
|
|
|
|
func (s *Stack) IsSubnetBroadcast(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) bool {
|
|
|
|
|
s.mu.RLock()
|
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
|
|
|
|
|
if nicID != 0 {
|
|
|
|
|
nic, ok := s.nics[nicID]
|
|
|
|
|
if !ok {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isSubnetBroadcastOnNIC(nic, protocol, addr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, nic := range s.nics {
|
|
|
|
|
if isSubnetBroadcastOnNIC(nic, protocol, addr) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
2021-09-01 19:41:43 -07:00
|
|
|
|
|
|
|
|
// PacketEndpointWriteSupported returns true iff packet endpoints support write
|
|
|
|
|
// operations.
|
|
|
|
|
func (s *Stack) PacketEndpointWriteSupported() bool {
|
|
|
|
|
return s.packetEndpointWriteSupported
|
|
|
|
|
}
|
2024-07-02 16:45:52 -07:00
|
|
|
|
|
|
|
|
// SetNICStack moves the network device to the specified network namespace.
|
|
|
|
|
func (s *Stack) SetNICStack(id tcpip.NICID, peer *Stack) (tcpip.NICID, tcpip.Error) {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
nic, ok := s.nics[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
return 0, &tcpip.ErrUnknownNICID{}
|
|
|
|
|
}
|
|
|
|
|
if s == peer {
|
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
return id, nil
|
|
|
|
|
}
|
|
|
|
|
delete(s.nics, id)
|
|
|
|
|
|
|
|
|
|
// Remove routes in-place. n tracks the number of routes written.
|
|
|
|
|
s.RemoveRoutes(func(r tcpip.Route) bool { return r.NIC == id })
|
|
|
|
|
ne := nic.NetworkLinkEndpoint.(LinkEndpoint)
|
2024-07-10 13:29:15 -07:00
|
|
|
deferAct, err := nic.remove(false /* closeLinkEndpoint */)
|
2024-07-02 16:45:52 -07:00
|
|
|
s.mu.Unlock()
|
2024-07-10 13:29:15 -07:00
|
|
|
if deferAct != nil {
|
|
|
|
|
deferAct()
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2024-07-02 16:45:52 -07:00
|
|
|
|
|
|
|
|
id = tcpip.NICID(peer.NextNICID())
|
|
|
|
|
return id, peer.CreateNICWithOptions(id, ne, NICOptions{Name: nic.Name()})
|
|
|
|
|
}
|
2024-11-20 11:08:45 -08:00
|
|
|
|
|
|
|
|
// EnableSaveRestore marks the saveRestoreEnabled to true.
|
|
|
|
|
func (s *Stack) EnableSaveRestore() {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
s.saveRestoreEnabled = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsSaveRestoreEnabled returns true if save restore is enabled for the stack.
|
|
|
|
|
func (s *Stack) IsSaveRestoreEnabled() bool {
|
|
|
|
|
s.mu.Lock()
|
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
return s.saveRestoreEnabled
|
|
|
|
|
}
|
2024-11-22 17:06:56 -08:00
|
|
|
|
|
|
|
|
// contextID is this package's type for context.Context.Value keys.
|
|
|
|
|
type contextID int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// CtxRestoreStack is a Context.Value key for the stack to be used in restore.
|
|
|
|
|
CtxRestoreStack contextID = iota
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// RestoreStackFromContext returns the stack to be used during restore.
|
|
|
|
|
func RestoreStackFromContext(ctx context.Context) *Stack {
|
|
|
|
|
return ctx.Value(CtxRestoreStack).(*Stack)
|
|
|
|
|
}
|