Files

794 lines
26 KiB
Go
Raw Permalink Normal View History

// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package loopback_test
import (
2021-01-07 14:14:58 -08:00
"bytes"
"testing"
2020-09-29 13:44:03 -07:00
"time"
"github.com/google/go-cmp/cmp"
2023-06-01 21:25:01 -07:00
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/tcpip"
2021-01-07 14:14:58 -08:00
"gvisor.dev/gvisor/pkg/tcpip/checker"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/tests/utils"
"gvisor.dev/gvisor/pkg/tcpip/testutil"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
2020-11-18 12:43:51 -08:00
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
)
2020-09-29 13:44:03 -07:00
var _ ipv6.NDPDispatcher = (*ndpDispatcher)(nil)
type ndpDispatcher struct{}
2021-03-04 11:37:12 -08:00
func (*ndpDispatcher) OnDuplicateAddressDetectionResult(tcpip.NICID, tcpip.Address, stack.DADResult) {
2020-09-29 13:44:03 -07:00
}
func (*ndpDispatcher) OnOffLinkRouteUpdated(tcpip.NICID, tcpip.Subnet, tcpip.Address, header.NDPRoutePreference) {
2020-09-29 13:44:03 -07:00
}
func (*ndpDispatcher) OnOffLinkRouteInvalidated(tcpip.NICID, tcpip.Subnet, tcpip.Address) {}
2020-09-29 13:44:03 -07:00
func (*ndpDispatcher) OnOnLinkPrefixDiscovered(tcpip.NICID, tcpip.Subnet) {
2020-09-29 13:44:03 -07:00
}
func (*ndpDispatcher) OnOnLinkPrefixInvalidated(tcpip.NICID, tcpip.Subnet) {}
2022-07-07 19:56:11 -07:00
func (*ndpDispatcher) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) stack.AddressDispatcher {
return nil
2020-09-29 13:44:03 -07:00
}
func (*ndpDispatcher) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) {}
func (*ndpDispatcher) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) {}
func (*ndpDispatcher) OnRecursiveDNSServerOption(tcpip.NICID, []tcpip.Address, time.Duration) {}
func (*ndpDispatcher) OnDNSSearchListOption(tcpip.NICID, []string, time.Duration) {}
func (*ndpDispatcher) OnDHCPv6Configuration(tcpip.NICID, ipv6.DHCPv6ConfigurationFromNDPRA) {}
// TestInitialLoopbackAddresses tests that the loopback interface does not
// auto-generate a link-local address when it is brought up.
func TestInitialLoopbackAddresses(t *testing.T) {
const nicID = 1
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocolWithOptions(ipv6.Options{
2020-11-24 01:17:25 -08:00
NDPDisp: &ndpDispatcher{},
AutoGenLinkLocal: true,
2020-09-29 13:44:03 -07:00
OpaqueIIDOpts: ipv6.OpaqueInterfaceIdentifierOptions{
NICNameFromID: func(nicID tcpip.NICID, nicName string) string {
t.Fatalf("should not attempt to get name for NIC with ID = %d; nicName = %s", nicID, nicName)
return ""
},
},
})},
})
2022-12-08 16:35:30 -08:00
defer s.Destroy()
2020-09-29 13:44:03 -07:00
if err := s.CreateNIC(nicID, loopback.New()); err != nil {
t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
}
nicsInfo := s.NICInfo()
if nicInfo, ok := nicsInfo[nicID]; !ok {
t.Fatalf("did not find NIC with ID = %d in s.NICInfo() = %#v", nicID, nicsInfo)
} else if got := len(nicInfo.ProtocolAddresses); got != 0 {
t.Fatalf("got len(nicInfo.ProtocolAddresses) = %d, want = 0; nicInfo.ProtocolAddresses = %#v", got, nicInfo.ProtocolAddresses)
}
}
2020-11-18 12:43:51 -08:00
// TestLoopbackAcceptAllInSubnetUDP tests that a loopback interface considers
// itself bound to all addresses in the subnet of an assigned address and UDP
// traffic is sent/received correctly.
func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) {
const (
nicID = 1
localPort = 80
)
data := []byte{1, 2, 3, 4}
ipv4ProtocolAddress := tcpip.ProtocolAddress{
Protocol: header.IPv4ProtocolNumber,
AddressWithPrefix: utils.Ipv4Addr,
}
2023-05-16 11:32:52 -07:00
addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address
ipv4Bytes := addrCopy.AsSlice()
ipv4Bytes[len(ipv4Bytes)-1]++
2023-05-15 18:03:37 -07:00
otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes)
ipv6ProtocolAddress := tcpip.ProtocolAddress{
Protocol: header.IPv6ProtocolNumber,
AddressWithPrefix: utils.Ipv6Addr,
}
2023-05-16 11:32:52 -07:00
addrCopy = utils.Ipv6Addr.Address
ipv6Bytes := addrCopy.AsSlice()
ipv6Bytes[len(ipv6Bytes)-1]++
2023-05-15 18:03:37 -07:00
otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes)
tests := []struct {
name string
addAddress tcpip.ProtocolAddress
bindAddr tcpip.Address
dstAddr tcpip.Address
expectRx bool
}{
{
name: "IPv4 bind to wildcard and send to assigned address",
addAddress: ipv4ProtocolAddress,
2020-11-18 12:43:51 -08:00
dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
expectRx: true,
},
{
name: "IPv4 bind to wildcard and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
dstAddr: otherIPv4Address,
expectRx: true,
},
{
name: "IPv4 bind to wildcard send to other address",
addAddress: ipv4ProtocolAddress,
dstAddr: utils.RemoteIPv4Addr,
expectRx: false,
},
{
name: "IPv4 bind to other subnet-local address and send to assigned address",
addAddress: ipv4ProtocolAddress,
bindAddr: otherIPv4Address,
2020-11-18 12:43:51 -08:00
dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
expectRx: false,
},
{
name: "IPv4 bind and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
bindAddr: otherIPv4Address,
dstAddr: otherIPv4Address,
expectRx: true,
},
{
name: "IPv4 bind to assigned address and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
2020-11-18 12:43:51 -08:00
bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
dstAddr: otherIPv4Address,
expectRx: false,
},
{
name: "IPv6 bind and send to assigned address",
addAddress: ipv6ProtocolAddress,
bindAddr: utils.Ipv6Addr.Address,
dstAddr: utils.Ipv6Addr.Address,
expectRx: true,
},
{
name: "IPv6 bind to wildcard and send to other subnet-local address",
addAddress: ipv6ProtocolAddress,
dstAddr: otherIPv6Address,
expectRx: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
})
2022-12-08 16:35:30 -08:00
defer s.Destroy()
if err := s.CreateNIC(nicID, loopback.New()); err != nil {
t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
}
2021-09-15 14:57:10 -07:00
if err := s.AddProtocolAddress(nicID, test.addAddress, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, test.addAddress, err)
}
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
{
Destination: header.IPv6EmptySubnet,
NIC: nicID,
},
})
var wq waiter.Queue
rep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq)
if err != nil {
t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
}
defer rep.Close()
bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort}
if err := rep.Bind(bindAddr); err != nil {
t.Fatalf("rep.Bind(%+v): %s", bindAddr, err)
}
sep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq)
if err != nil {
t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
}
defer sep.Close()
wopts := tcpip.WriteOptions{
To: &tcpip.FullAddress{
Addr: test.dstAddr,
Port: localPort,
},
}
var r bytes.Reader
r.Reset(data)
n, err := sep.Write(&r, wopts)
if err != nil {
t.Fatalf("sep.Write(_, _): %s", err)
}
if want := int64(len(data)); n != want {
t.Fatalf("got sep.Write(_, _) = (%d, nil), want = (%d, nil)", n, want)
}
2021-01-07 14:14:58 -08:00
var buf bytes.Buffer
opts := tcpip.ReadOptions{NeedRemoteAddr: true}
if res, err := rep.Read(&buf, opts); test.expectRx {
if err != nil {
t.Fatalf("rep.Read(_, %#v): %s", opts, err)
}
2021-01-07 14:14:58 -08:00
if diff := cmp.Diff(tcpip.ReadResult{
Count: buf.Len(),
Total: buf.Len(),
RemoteAddr: tcpip.FullAddress{
Addr: test.addAddress.AddressWithPrefix.Address,
},
}, res,
checker.IgnoreCmpPath("ControlMessages", "RemoteAddr.NIC", "RemoteAddr.Port"),
); diff != "" {
t.Errorf("rep.Read: unexpected result (-want +got):\n%s", diff)
}
if diff := cmp.Diff(data, buf.Bytes()); diff != "" {
t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff)
}
2021-01-28 17:57:42 -08:00
} else if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
t.Fatalf("got rep.Read = (%v, %s) [with data %x], want = (_, %s)", res, err, buf.Bytes(), &tcpip.ErrWouldBlock{})
}
})
}
}
// TestLoopbackSubnetLifetimeBoundToAddr tests that the lifetime of an address
// in a loopback interface's associated subnet is bound to the permanently bound
// address.
func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) {
const nicID = 1
protoAddr := tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: utils.Ipv4Addr,
}
2023-05-16 11:32:52 -07:00
addrCopy := utils.Ipv4Addr.Address
addrBytes := addrCopy.AsSlice()
addrBytes[len(addrBytes)-1]++
2023-05-15 18:03:37 -07:00
otherAddr := tcpip.AddrFromSlice(addrBytes)
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
})
2022-12-08 16:35:30 -08:00
defer s.Destroy()
if err := s.CreateNIC(nicID, loopback.New()); err != nil {
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
}
2021-09-15 14:57:10 -07:00
if err := s.AddProtocolAddress(nicID, protoAddr, stack.AddressProperties{}); err != nil {
t.Fatalf("s.AddProtocolAddress(%d, %+v, {}): %s", nicID, protoAddr, err)
}
s.SetRouteTable([]tcpip.Route{
{
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
})
r, err := s.FindRoute(nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, false /* multicastLoop */)
if err != nil {
t.Fatalf("s.FindRoute(%d, %s, %s, %d, false): %s", nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, err)
}
defer r.Release()
params := stack.NetworkHeaderParams{
Protocol: 111,
TTL: 64,
TOS: stack.DefaultTOS,
}
2022-06-07 10:33:35 -07:00
data := []byte{1, 2, 3, 4}
2021-04-21 18:07:13 -07:00
if err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(r.MaxHeaderLength()),
2023-06-01 21:25:01 -07:00
Payload: buffer.MakeWithData(data),
})); err != nil {
2021-04-21 18:07:13 -07:00
t.Fatalf("r.WritePacket(%#v, _): %s", params, err)
}
// Removing the address should make the endpoint invalid.
if err := s.RemoveAddress(nicID, protoAddr.AddressWithPrefix.Address); err != nil {
t.Fatalf("s.RemoveAddress(%d, %s): %s", nicID, protoAddr.AddressWithPrefix.Address, err)
}
2021-01-28 17:57:42 -08:00
{
2021-04-21 18:07:13 -07:00
err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{
2021-01-28 17:57:42 -08:00
ReserveHeaderBytes: int(r.MaxHeaderLength()),
2023-06-01 21:25:01 -07:00
Payload: buffer.MakeWithData(data),
2021-01-28 17:57:42 -08:00
}))
if _, ok := err.(*tcpip.ErrInvalidEndpointState); !ok {
2021-04-21 18:07:13 -07:00
t.Fatalf("got r.WritePacket(%#v, _) = %s, want = %s", params, err, &tcpip.ErrInvalidEndpointState{})
2021-01-28 17:57:42 -08:00
}
}
}
2020-11-18 12:43:51 -08:00
// TestLoopbackAcceptAllInSubnetTCP tests that a loopback interface considers
// itself bound to all addresses in the subnet of an assigned address and TCP
// traffic is sent/received correctly.
func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) {
const (
nicID = 1
localPort = 80
)
ipv4ProtocolAddress := tcpip.ProtocolAddress{
Protocol: header.IPv4ProtocolNumber,
AddressWithPrefix: utils.Ipv4Addr,
2020-11-18 12:43:51 -08:00
}
ipv4ProtocolAddress.AddressWithPrefix.PrefixLen = 8
2023-05-16 11:32:52 -07:00
addrCopy := ipv4ProtocolAddress.AddressWithPrefix.Address
ipv4Bytes := addrCopy.AsSlice()
2020-11-18 12:43:51 -08:00
ipv4Bytes[len(ipv4Bytes)-1]++
2023-05-15 18:03:37 -07:00
otherIPv4Address := tcpip.AddrFromSlice(ipv4Bytes)
2020-11-18 12:43:51 -08:00
ipv6ProtocolAddress := tcpip.ProtocolAddress{
Protocol: header.IPv6ProtocolNumber,
AddressWithPrefix: utils.Ipv6Addr,
2020-11-18 12:43:51 -08:00
}
2023-05-16 11:32:52 -07:00
addrCopy = utils.Ipv6Addr.Address
ipv6Bytes := addrCopy.AsSlice()
2020-11-18 12:43:51 -08:00
ipv6Bytes[len(ipv6Bytes)-1]++
2023-05-15 18:03:37 -07:00
otherIPv6Address := tcpip.AddrFromSlice(ipv6Bytes)
2020-11-18 12:43:51 -08:00
tests := []struct {
name string
addAddress tcpip.ProtocolAddress
bindAddr tcpip.Address
dstAddr tcpip.Address
expectAccept bool
}{
{
name: "IPv4 bind to wildcard and send to assigned address",
addAddress: ipv4ProtocolAddress,
dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
expectAccept: true,
},
{
name: "IPv4 bind to wildcard and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
dstAddr: otherIPv4Address,
expectAccept: true,
},
{
name: "IPv4 bind to wildcard send to other address",
addAddress: ipv4ProtocolAddress,
dstAddr: utils.RemoteIPv4Addr,
2020-11-18 12:43:51 -08:00
expectAccept: false,
},
{
name: "IPv4 bind to other subnet-local address and send to assigned address",
addAddress: ipv4ProtocolAddress,
bindAddr: otherIPv4Address,
dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
expectAccept: false,
},
{
name: "IPv4 bind and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
bindAddr: otherIPv4Address,
dstAddr: otherIPv4Address,
expectAccept: true,
},
{
name: "IPv4 bind to assigned address and send to other subnet-local address",
addAddress: ipv4ProtocolAddress,
bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
dstAddr: otherIPv4Address,
expectAccept: false,
},
{
name: "IPv6 bind and send to assigned address",
addAddress: ipv6ProtocolAddress,
bindAddr: utils.Ipv6Addr.Address,
dstAddr: utils.Ipv6Addr.Address,
2020-11-18 12:43:51 -08:00
expectAccept: true,
},
{
name: "IPv6 bind to wildcard and send to other subnet-local address",
addAddress: ipv6ProtocolAddress,
dstAddr: otherIPv6Address,
expectAccept: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
})
2022-12-08 16:35:30 -08:00
defer s.Destroy()
2020-11-18 12:43:51 -08:00
if err := s.CreateNIC(nicID, loopback.New()); err != nil {
t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
}
2021-09-15 14:57:10 -07:00
if err := s.AddProtocolAddress(nicID, test.addAddress, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, test.addAddress, err)
2020-11-18 12:43:51 -08:00
}
s.SetRouteTable([]tcpip.Route{
{
2020-11-18 12:43:51 -08:00
Destination: header.IPv4EmptySubnet,
NIC: nicID,
},
{
2020-11-18 12:43:51 -08:00
Destination: header.IPv6EmptySubnet,
NIC: nicID,
},
})
var wq waiter.Queue
2021-11-13 12:51:42 -08:00
we, ch := waiter.NewChannelEntry(waiter.ReadableEvents)
wq.EventRegister(&we)
2020-11-18 12:43:51 -08:00
defer wq.EventUnregister(&we)
listeningEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq)
if err != nil {
2022-08-31 13:02:23 -07:00
t.Fatalf("NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.addAddress.Protocol, err)
2020-11-18 12:43:51 -08:00
}
defer listeningEndpoint.Close()
bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort}
if err := listeningEndpoint.Bind(bindAddr); err != nil {
t.Fatalf("listeningEndpoint.Bind(%#v): %s", bindAddr, err)
}
if err := listeningEndpoint.Listen(1); err != nil {
t.Fatalf("listeningEndpoint.Listen(1): %s", err)
}
connectingEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq)
if err != nil {
2022-08-31 13:02:23 -07:00
t.Fatalf("s.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.addAddress.Protocol, err)
2020-11-18 12:43:51 -08:00
}
defer connectingEndpoint.Close()
connectAddr := tcpip.FullAddress{
Addr: test.dstAddr,
Port: localPort,
}
2021-01-28 17:57:42 -08:00
{
err := connectingEndpoint.Connect(connectAddr)
if _, ok := err.(*tcpip.ErrConnectStarted); !ok {
t.Fatalf("connectingEndpoint.Connect(%#v): %s", connectAddr, err)
}
2020-11-18 12:43:51 -08:00
}
if !test.expectAccept {
2021-01-28 17:57:42 -08:00
_, _, err := listeningEndpoint.Accept(nil)
if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
t.Fatalf("got listeningEndpoint.Accept(nil) = %s, want = %s", err, &tcpip.ErrWouldBlock{})
2020-11-18 12:43:51 -08:00
}
return
}
// Wait for the listening endpoint to be "readable". That is, wait for a
// new connection.
<-ch
var addr tcpip.FullAddress
if _, _, err := listeningEndpoint.Accept(&addr); err != nil {
t.Fatalf("listeningEndpoint.Accept(nil): %s", err)
}
if addr.Addr != test.addAddress.AddressWithPrefix.Address {
t.Errorf("got addr.Addr = %s, want = %s", addr.Addr, test.addAddress.AddressWithPrefix.Address)
}
})
}
}
func TestExternalLoopbackTraffic(t *testing.T) {
const (
nicID1 = 1
nicID2 = 2
numPackets = 1
2021-04-08 15:28:58 -07:00
ttl = 64
)
ipv4Loopback := testutil.MustParse4("127.0.0.1")
loopbackSourcedICMPv4 := func(e *channel.Endpoint) {
2021-04-08 15:28:58 -07:00
utils.RxICMPv4EchoRequest(e, ipv4Loopback, utils.Ipv4Addr.Address, ttl)
}
loopbackSourcedICMPv6 := func(e *channel.Endpoint) {
2021-04-08 15:28:58 -07:00
utils.RxICMPv6EchoRequest(e, header.IPv6Loopback, utils.Ipv6Addr.Address, ttl)
}
loopbackDestinedICMPv4 := func(e *channel.Endpoint) {
2021-04-08 15:28:58 -07:00
utils.RxICMPv4EchoRequest(e, utils.RemoteIPv4Addr, ipv4Loopback, ttl)
}
loopbackDestinedICMPv6 := func(e *channel.Endpoint) {
2021-04-08 15:28:58 -07:00
utils.RxICMPv6EchoRequest(e, utils.RemoteIPv6Addr, header.IPv6Loopback, ttl)
}
invalidSrcAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter {
return s.InvalidSourceAddressesReceived
}
invalidDestAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter {
return s.InvalidDestinationAddressesReceived
}
tests := []struct {
2021-03-23 09:54:57 -07:00
name string
allowExternalLoopback bool
forwarding bool
rxICMP func(*channel.Endpoint)
invalidAddressStat func(tcpip.IPStats) *tcpip.StatCounter
shouldAccept bool
}{
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: false,
rxICMP: loopbackSourcedICMPv4,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: false,
rxICMP: loopbackSourcedICMPv4,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: true,
rxICMP: loopbackSourcedICMPv4,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: true,
rxICMP: loopbackSourcedICMPv4,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback destined traffic without forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: false,
rxICMP: loopbackDestinedICMPv4,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback destined traffic without forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: false,
rxICMP: loopbackDestinedICMPv4,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback destined traffic with forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: true,
rxICMP: loopbackDestinedICMPv4,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv4 external loopback destined traffic with forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: true,
rxICMP: loopbackDestinedICMPv4,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: false,
rxICMP: loopbackSourcedICMPv6,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: false,
rxICMP: loopbackSourcedICMPv6,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: true,
rxICMP: loopbackSourcedICMPv6,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: true,
rxICMP: loopbackSourcedICMPv6,
invalidAddressStat: invalidSrcAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback destined traffic without forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: false,
rxICMP: loopbackDestinedICMPv6,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback destined traffic without forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: false,
rxICMP: loopbackDestinedICMPv6,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback destined traffic with forwarding and drop external loopback disabled",
allowExternalLoopback: true,
forwarding: true,
rxICMP: loopbackDestinedICMPv6,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: true,
},
{
2021-03-23 09:54:57 -07:00
name: "IPv6 external loopback destined traffic with forwarding and drop external loopback enabled",
allowExternalLoopback: false,
forwarding: true,
rxICMP: loopbackDestinedICMPv6,
invalidAddressStat: invalidDestAddrStat,
shouldAccept: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
ipv4.NewProtocolWithOptions(ipv4.Options{
2021-03-23 09:54:57 -07:00
AllowExternalLoopbackTraffic: test.allowExternalLoopback,
}),
ipv6.NewProtocolWithOptions(ipv6.Options{
2021-03-23 09:54:57 -07:00
AllowExternalLoopbackTraffic: test.allowExternalLoopback,
}),
},
TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6},
})
2022-12-08 16:35:30 -08:00
defer s.Destroy()
e := channel.New(1, header.IPv6MinimumMTU, "")
if err := s.CreateNIC(nicID1, e); err != nil {
t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
}
2021-09-15 14:57:10 -07:00
v4Addr := tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: utils.Ipv4Addr,
}
2021-09-15 14:57:10 -07:00
if err := s.AddProtocolAddress(nicID1, v4Addr, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, v4Addr, err)
}
v6Addr := tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: utils.Ipv6Addr,
}
if err := s.AddProtocolAddress(nicID1, v6Addr, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID1, v6Addr, err)
}
if err := s.CreateNIC(nicID2, loopback.New()); err != nil {
t.Fatalf("CreateNIC(%d, _): %s", nicID2, err)
}
2021-09-15 14:57:10 -07:00
protocolAddrV4 := tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: ipv4Loopback,
PrefixLen: 8,
},
}
2021-09-15 14:57:10 -07:00
if err := s.AddProtocolAddress(nicID2, protocolAddrV4, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID2, protocolAddrV4, err)
}
protocolAddrV6 := tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: header.IPv6Loopback.WithPrefix(),
}
if err := s.AddProtocolAddress(nicID2, protocolAddrV6, stack.AddressProperties{}); err != nil {
t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID2, protocolAddrV6, err)
}
if test.forwarding {
if err := s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, true); err != nil {
t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ipv4.ProtocolNumber, err)
}
if err := s.SetForwardingDefaultAndAllNICs(ipv6.ProtocolNumber, true); err != nil {
t.Fatalf("SetForwardingDefaultAndAllNICs(%d, true): %s", ipv6.ProtocolNumber, err)
}
}
s.SetRouteTable([]tcpip.Route{
2022-05-18 00:52:48 -07:00
{
Destination: header.IPv4EmptySubnet,
NIC: nicID1,
},
2022-05-18 00:52:48 -07:00
{
Destination: header.IPv6EmptySubnet,
NIC: nicID1,
},
2022-05-18 00:52:48 -07:00
{
Destination: ipv4Loopback.WithPrefix().Subnet(),
NIC: nicID2,
},
2022-05-18 00:52:48 -07:00
{
Destination: header.IPv6Loopback.WithPrefix().Subnet(),
NIC: nicID2,
},
})
stats := s.Stats().IP
invalidAddressStat := test.invalidAddressStat(stats)
deliveredPacketsStat := stats.PacketsDelivered
if got := invalidAddressStat.Value(); got != 0 {
t.Fatalf("got invalidAddressStat.Value() = %d, want = 0", got)
}
if got := deliveredPacketsStat.Value(); got != 0 {
t.Fatalf("got deliveredPacketsStat.Value() = %d, want = 0", got)
}
test.rxICMP(e)
var expectedInvalidPackets uint64
if !test.shouldAccept {
expectedInvalidPackets = numPackets
}
if got := invalidAddressStat.Value(); got != expectedInvalidPackets {
t.Fatalf("got invalidAddressStat.Value() = %d, want = %d", got, expectedInvalidPackets)
}
if got, want := deliveredPacketsStat.Value(), numPackets-expectedInvalidPackets; got != want {
t.Fatalf("got deliveredPacketsStat.Value() = %d, want = %d", got, want)
}
})
}
}