diff options
author | Ghanan Gowripalan <ghanan@google.com> | 2021-03-17 11:10:04 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-03-17 11:12:06 -0700 |
commit | 4065604e1b6b767754a8ce939add6fdd91616a24 (patch) | |
tree | 26a69dbba3ab962d8350b3750561547382d021c7 /pkg/tcpip/tests | |
parent | 3dd7ad13b4586791cdc1c1efdef90760a7deff8e (diff) |
Drop loopback traffic from outside of the stack
Loopback traffic should be stack-local but gVisor has some clients
that depend on the ability to receive loopback traffic that originated
from outside of the stack. Because of this, we guard this change behind
IP protocol options.
Test: integration_test.TestExternalLoopbackTraffic
PiperOrigin-RevId: 363461242
Diffstat (limited to 'pkg/tcpip/tests')
-rw-r--r-- | pkg/tcpip/tests/integration/BUILD | 2 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/loopback_test.go | 261 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/multicast_broadcast_test.go | 148 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/route_test.go | 132 | ||||
-rw-r--r-- | pkg/tcpip/tests/utils/BUILD | 3 | ||||
-rw-r--r-- | pkg/tcpip/tests/utils/utils.go | 60 |
6 files changed, 449 insertions, 157 deletions
diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD index 58aabe547..3cc8c36f1 100644 --- a/pkg/tcpip/tests/integration/BUILD +++ b/pkg/tcpip/tests/integration/BUILD @@ -72,11 +72,13 @@ go_test( "//pkg/tcpip/buffer", "//pkg/tcpip/checker", "//pkg/tcpip/header", + "//pkg/tcpip/link/channel", "//pkg/tcpip/link/loopback", "//pkg/tcpip/network/ipv4", "//pkg/tcpip/network/ipv6", "//pkg/tcpip/stack", "//pkg/tcpip/tests/utils", + "//pkg/tcpip/transport/icmp", "//pkg/tcpip/transport/tcp", "//pkg/tcpip/transport/udp", "//pkg/waiter", diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go index 80afc2825..0a9ea1aa8 100644 --- a/pkg/tcpip/tests/integration/loopback_test.go +++ b/pkg/tcpip/tests/integration/loopback_test.go @@ -24,11 +24,13 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/buffer" "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/transport/icmp" "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "gvisor.dev/gvisor/pkg/waiter" @@ -502,3 +504,262 @@ func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) { }) } } + +func TestExternalLoopbackTraffic(t *testing.T) { + const ( + nicID1 = 1 + nicID2 = 2 + + ipv4Loopback = tcpip.Address("\x7f\x00\x00\x01") + + numPackets = 1 + ) + + loopbackSourcedICMPv4 := func(e *channel.Endpoint) { + utils.RxICMPv4EchoRequest(e, ipv4Loopback, utils.Ipv4Addr.Address) + } + + loopbackSourcedICMPv6 := func(e *channel.Endpoint) { + utils.RxICMPv6EchoRequest(e, header.IPv6Loopback, utils.Ipv6Addr.Address) + } + + loopbackDestinedICMPv4 := func(e *channel.Endpoint) { + utils.RxICMPv4EchoRequest(e, utils.RemoteIPv4Addr, ipv4Loopback) + } + + loopbackDestinedICMPv6 := func(e *channel.Endpoint) { + utils.RxICMPv6EchoRequest(e, utils.RemoteIPv6Addr, header.IPv6Loopback) + } + + invalidSrcAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter { + return s.InvalidSourceAddressesReceived + } + + invalidDestAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter { + return s.InvalidDestinationAddressesReceived + } + + tests := []struct { + name string + dropExternalLoopback bool + forwarding bool + rxICMP func(*channel.Endpoint) + invalidAddressStat func(tcpip.IPStats) *tcpip.StatCounter + shouldAccept bool + }{ + { + name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: false, + rxICMP: loopbackSourcedICMPv4, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: true, + }, + { + name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: false, + rxICMP: loopbackSourcedICMPv4, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: false, + }, + { + name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: true, + rxICMP: loopbackSourcedICMPv4, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: true, + }, + { + name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: true, + rxICMP: loopbackSourcedICMPv4, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: false, + }, + { + name: "IPv4 external loopback destined traffic without forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: false, + rxICMP: loopbackDestinedICMPv4, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: false, + }, + { + name: "IPv4 external loopback destined traffic without forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: false, + rxICMP: loopbackDestinedICMPv4, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: false, + }, + { + name: "IPv4 external loopback destined traffic with forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: true, + rxICMP: loopbackDestinedICMPv4, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: true, + }, + { + name: "IPv4 external loopback destined traffic with forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: true, + rxICMP: loopbackDestinedICMPv4, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: false, + }, + + { + name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: false, + rxICMP: loopbackSourcedICMPv6, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: true, + }, + { + name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: false, + rxICMP: loopbackSourcedICMPv6, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: false, + }, + { + name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: true, + rxICMP: loopbackSourcedICMPv6, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: true, + }, + { + name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: true, + rxICMP: loopbackSourcedICMPv6, + invalidAddressStat: invalidSrcAddrStat, + shouldAccept: false, + }, + { + name: "IPv6 external loopback destined traffic without forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: false, + rxICMP: loopbackDestinedICMPv6, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: false, + }, + { + name: "IPv6 external loopback destined traffic without forwarding and drop external loopback enabled", + dropExternalLoopback: true, + forwarding: false, + rxICMP: loopbackDestinedICMPv6, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: false, + }, + { + name: "IPv6 external loopback destined traffic with forwarding and drop external loopback disabled", + dropExternalLoopback: false, + forwarding: true, + rxICMP: loopbackDestinedICMPv6, + invalidAddressStat: invalidDestAddrStat, + shouldAccept: true, + }, + { + name: "IPv6 external loopback destined traffic with forwarding and drop external loopback enabled", + dropExternalLoopback: true, + 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{ + DropExternalLoopbackTraffic: test.dropExternalLoopback, + }), + ipv6.NewProtocolWithOptions(ipv6.Options{ + DropExternalLoopbackTraffic: test.dropExternalLoopback, + }), + }, + TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6}, + }) + e := channel.New(1, header.IPv6MinimumMTU, "") + if err := s.CreateNIC(nicID1, e); err != nil { + t.Fatalf("CreateNIC(%d, _): %s", nicID1, err) + } + if err := s.AddAddressWithPrefix(nicID1, ipv4.ProtocolNumber, utils.Ipv4Addr); err != nil { + t.Fatalf("AddAddressWithPrefix(%d, %d, %s): %s", nicID1, ipv4.ProtocolNumber, utils.Ipv4Addr, err) + } + if err := s.AddAddressWithPrefix(nicID1, ipv6.ProtocolNumber, utils.Ipv6Addr); err != nil { + t.Fatalf("AddAddressWithPrefix(%d, %d, %s): %s", nicID1, ipv6.ProtocolNumber, utils.Ipv6Addr, err) + } + + if err := s.CreateNIC(nicID2, loopback.New()); err != nil { + t.Fatalf("CreateNIC(%d, _): %s", nicID2, err) + } + if err := s.AddAddress(nicID2, ipv4.ProtocolNumber, ipv4Loopback); err != nil { + t.Fatalf("AddAddress(%d, %d, %s): %s", nicID2, ipv4.ProtocolNumber, ipv4Loopback, err) + } + if err := s.AddAddress(nicID2, ipv6.ProtocolNumber, header.IPv6Loopback); err != nil { + t.Fatalf("AddAddress(%d, %d, %s): %s", nicID2, ipv6.ProtocolNumber, header.IPv6Loopback, err) + } + + if test.forwarding { + if err := s.SetForwarding(ipv4.ProtocolNumber, true); err != nil { + t.Fatalf("SetForwarding(%d, true): %s", ipv4.ProtocolNumber, err) + } + if err := s.SetForwarding(ipv6.ProtocolNumber, true); err != nil { + t.Fatalf("SetForwarding(%d, true): %s", ipv6.ProtocolNumber, err) + } + } + + s.SetRouteTable([]tcpip.Route{ + tcpip.Route{ + Destination: header.IPv4EmptySubnet, + NIC: nicID1, + }, + tcpip.Route{ + Destination: header.IPv6EmptySubnet, + NIC: nicID1, + }, + tcpip.Route{ + Destination: ipv4Loopback.WithPrefix().Subnet(), + NIC: nicID2, + }, + tcpip.Route{ + 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) + } + }) + } +} diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go index 29266a4fc..77f4a88ec 100644 --- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go +++ b/pkg/tcpip/tests/integration/multicast_broadcast_test.go @@ -45,82 +45,61 @@ const ( func TestPingMulticastBroadcast(t *testing.T) { const nicID = 1 - rxIPv4ICMP := func(e *channel.Endpoint, dst tcpip.Address) { - totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize - hdr := buffer.NewPrependable(totalLen) - pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) - pkt.SetType(header.ICMPv4Echo) - pkt.SetCode(0) - pkt.SetChecksum(0) - pkt.SetChecksum(^header.Checksum(pkt, 0)) - ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) - ip.Encode(&header.IPv4Fields{ - TotalLength: uint16(totalLen), - Protocol: uint8(icmp.ProtocolNumber4), - TTL: ttl, - SrcAddr: utils.RemoteIPv4Addr, - DstAddr: dst, - }) - ip.SetChecksum(^ip.CalculateChecksum()) - - e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Data: hdr.View().ToVectorisedView(), - })) - } - - rxIPv6ICMP := func(e *channel.Endpoint, dst tcpip.Address) { - totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize - hdr := buffer.NewPrependable(totalLen) - pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize)) - pkt.SetType(header.ICMPv6EchoRequest) - pkt.SetCode(0) - pkt.SetChecksum(0) - pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ - Header: pkt, - Src: utils.RemoteIPv6Addr, - Dst: dst, - })) - ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) - ip.Encode(&header.IPv6Fields{ - PayloadLength: header.ICMPv6MinimumSize, - TransportProtocol: icmp.ProtocolNumber6, - HopLimit: ttl, - SrcAddr: utils.RemoteIPv6Addr, - DstAddr: dst, - }) - - e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Data: hdr.View().ToVectorisedView(), - })) - } - tests := []struct { - name string - dstAddr tcpip.Address + name string + protoNum tcpip.NetworkProtocolNumber + rxICMP func(*channel.Endpoint, tcpip.Address, tcpip.Address) + srcAddr tcpip.Address + dstAddr tcpip.Address + expectedSrc tcpip.Address }{ { - name: "IPv4 unicast", - dstAddr: utils.Ipv4Addr.Address, + name: "IPv4 unicast", + protoNum: header.IPv4ProtocolNumber, + dstAddr: utils.Ipv4Addr.Address, + srcAddr: utils.RemoteIPv4Addr, + rxICMP: utils.RxICMPv4EchoRequest, + expectedSrc: utils.Ipv4Addr.Address, }, { - name: "IPv4 directed broadcast", - dstAddr: utils.Ipv4SubnetBcast, + name: "IPv4 directed broadcast", + protoNum: header.IPv4ProtocolNumber, + rxICMP: utils.RxICMPv4EchoRequest, + srcAddr: utils.RemoteIPv4Addr, + dstAddr: utils.Ipv4SubnetBcast, + expectedSrc: utils.Ipv4Addr.Address, }, { - name: "IPv4 broadcast", - dstAddr: header.IPv4Broadcast, + name: "IPv4 broadcast", + protoNum: header.IPv4ProtocolNumber, + rxICMP: utils.RxICMPv4EchoRequest, + srcAddr: utils.RemoteIPv4Addr, + dstAddr: header.IPv4Broadcast, + expectedSrc: utils.Ipv4Addr.Address, }, { - name: "IPv4 all-systems multicast", - dstAddr: header.IPv4AllSystems, + name: "IPv4 all-systems multicast", + protoNum: header.IPv4ProtocolNumber, + rxICMP: utils.RxICMPv4EchoRequest, + srcAddr: utils.RemoteIPv4Addr, + dstAddr: header.IPv4AllSystems, + expectedSrc: utils.Ipv4Addr.Address, }, { - name: "IPv6 unicast", - dstAddr: utils.Ipv6Addr.Address, + name: "IPv6 unicast", + protoNum: header.IPv6ProtocolNumber, + rxICMP: utils.RxICMPv6EchoRequest, + srcAddr: utils.RemoteIPv6Addr, + dstAddr: utils.Ipv6Addr.Address, + expectedSrc: utils.Ipv6Addr.Address, }, { - name: "IPv6 all-nodes multicast", - dstAddr: header.IPv6AllNodesMulticastAddress, + name: "IPv6 all-nodes multicast", + protoNum: header.IPv6ProtocolNumber, + rxICMP: utils.RxICMPv6EchoRequest, + srcAddr: utils.RemoteIPv6Addr, + dstAddr: header.IPv6AllNodesMulticastAddress, + expectedSrc: utils.Ipv6Addr.Address, }, } @@ -157,44 +136,29 @@ func TestPingMulticastBroadcast(t *testing.T) { }, }) - var rxICMP func(*channel.Endpoint, tcpip.Address) - var expectedSrc tcpip.Address - var expectedDst tcpip.Address - var protoNum tcpip.NetworkProtocolNumber - switch l := len(test.dstAddr); l { - case header.IPv4AddressSize: - rxICMP = rxIPv4ICMP - expectedSrc = utils.Ipv4Addr.Address - expectedDst = utils.RemoteIPv4Addr - protoNum = header.IPv4ProtocolNumber - case header.IPv6AddressSize: - rxICMP = rxIPv6ICMP - expectedSrc = utils.Ipv6Addr.Address - expectedDst = utils.RemoteIPv6Addr - protoNum = header.IPv6ProtocolNumber - default: - t.Fatalf("got unexpected address length = %d bytes", l) - } - - rxICMP(e, test.dstAddr) + test.rxICMP(e, test.srcAddr, test.dstAddr) pkt, ok := e.Read() if !ok { t.Fatal("expected ICMP response") } - if pkt.Route.LocalAddress != expectedSrc { - t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", pkt.Route.LocalAddress, expectedSrc) + if pkt.Route.LocalAddress != test.expectedSrc { + t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", pkt.Route.LocalAddress, test.expectedSrc) } - if pkt.Route.RemoteAddress != expectedDst { - t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", pkt.Route.RemoteAddress, expectedDst) + // The destination of the response packet should be the source of the + // original packet. + if pkt.Route.RemoteAddress != test.srcAddr { + t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", pkt.Route.RemoteAddress, test.srcAddr) } - src, dst := s.NetworkProtocolInstance(protoNum).ParseAddresses(stack.PayloadSince(pkt.Pkt.NetworkHeader())) - if src != expectedSrc { - t.Errorf("got pkt source = %s, want = %s", src, expectedSrc) + src, dst := s.NetworkProtocolInstance(test.protoNum).ParseAddresses(stack.PayloadSince(pkt.Pkt.NetworkHeader())) + if src != test.expectedSrc { + t.Errorf("got pkt source = %s, want = %s", src, test.expectedSrc) } - if dst != expectedDst { - t.Errorf("got pkt destination = %s, want = %s", dst, expectedDst) + // The destination of the response packet should be the source of the + // original packet. + if dst != test.srcAddr { + t.Errorf("got pkt destination = %s, want = %s", dst, test.srcAddr) } }) } diff --git a/pkg/tcpip/tests/integration/route_test.go b/pkg/tcpip/tests/integration/route_test.go index 4455f6dd7..568a982bb 100644 --- a/pkg/tcpip/tests/integration/route_test.go +++ b/pkg/tcpip/tests/integration/route_test.go @@ -16,6 +16,7 @@ package route_test import ( "bytes" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -161,78 +162,79 @@ func TestLocalPing(t *testing.T) { 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{icmp.NewProtocol4, icmp.NewProtocol6}, - HandleLocal: true, - }) - e := test.linkEndpoint() - if err := s.CreateNIC(nicID, e); err != nil { - t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) - } + for _, dropExternalLoopback := range []bool{true, false} { + t.Run(fmt.Sprintf("DropExternalLoopback=%t", dropExternalLoopback), func(t *testing.T) { + s := stack.New(stack.Options{ + NetworkProtocols: []stack.NetworkProtocolFactory{ + ipv4.NewProtocolWithOptions(ipv4.Options{ + DropExternalLoopbackTraffic: dropExternalLoopback, + }), + ipv6.NewProtocolWithOptions(ipv6.Options{ + DropExternalLoopbackTraffic: dropExternalLoopback, + }), + }, + TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6}, + HandleLocal: true, + }) + e := test.linkEndpoint() + if err := s.CreateNIC(nicID, e); err != nil { + t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) + } - if len(test.localAddr) != 0 { - if err := s.AddAddress(nicID, test.netProto, test.localAddr); err != nil { - t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, test.netProto, test.localAddr, err) - } - } + if len(test.localAddr) != 0 { + if err := s.AddAddress(nicID, test.netProto, test.localAddr); err != nil { + t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, test.netProto, test.localAddr, err) + } + } - var wq waiter.Queue - we, ch := waiter.NewChannelEntry(nil) - wq.EventRegister(&we, waiter.EventIn) - ep, err := s.NewEndpoint(test.transProto, test.netProto, &wq) - if err != nil { - t.Fatalf("s.NewEndpoint(%d, %d, _): %s", test.transProto, test.netProto, err) - } - defer ep.Close() - - connAddr := tcpip.FullAddress{Addr: test.localAddr} - { - err := ep.Connect(connAddr) - if diff := cmp.Diff(test.expectedConnectErr, err); diff != "" { - t.Fatalf("unexpected error from ep.Connect(%#v), (-want, +got):\n%s", connAddr, diff) - } - } + var wq waiter.Queue + we, ch := waiter.NewChannelEntry(nil) + wq.EventRegister(&we, waiter.EventIn) + ep, err := s.NewEndpoint(test.transProto, test.netProto, &wq) + if err != nil { + t.Fatalf("s.NewEndpoint(%d, %d, _): %s", test.transProto, test.netProto, err) + } + defer ep.Close() - if test.expectedConnectErr != nil { - return - } + connAddr := tcpip.FullAddress{Addr: test.localAddr} + if err := ep.Connect(connAddr); err != test.expectedConnectErr { + t.Fatalf("got ep.Connect(%#v) = %s, want = %s", connAddr, err, test.expectedConnectErr) + } - payload := test.icmpBuf(t) - var r bytes.Reader - r.Reset(payload) - var wOpts tcpip.WriteOptions - if n, err := ep.Write(&r, wOpts); err != nil { - t.Fatalf("ep.Write(%#v, %#v): %s", payload, wOpts, err) - } else if n != int64(len(payload)) { - t.Fatalf("got ep.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", payload, wOpts, n, len(payload)) - } + if test.expectedConnectErr != nil { + return + } - // Wait for the endpoint to become readable. - <-ch + var r bytes.Reader + payload := test.icmpBuf(t) + r.Reset(payload) + var wOpts tcpip.WriteOptions + if n, err := ep.Write(&r, wOpts); err != nil { + t.Fatalf("ep.Write(%#v, %#v): %s", payload, wOpts, err) + } else if n != int64(len(payload)) { + t.Fatalf("got ep.Write(%#v, %#v) = (%d, _, nil), want = (%d, _, nil)", payload, wOpts, n, len(payload)) + } - var buf bytes.Buffer - opts := tcpip.ReadOptions{NeedRemoteAddr: true} - res, err := ep.Read(&buf, opts) - if err != nil { - t.Fatalf("ep.Read(_, %#v): %s", opts, err) - } - if diff := cmp.Diff(tcpip.ReadResult{ - Count: buf.Len(), - Total: buf.Len(), - RemoteAddr: tcpip.FullAddress{Addr: test.localAddr}, - }, res, checker.IgnoreCmpPath( - "ControlMessages", - "RemoteAddr.NIC", - "RemoteAddr.Port", - )); diff != "" { - t.Errorf("ep.Read: unexpected result (-want +got):\n%s", diff) - } - if diff := cmp.Diff(buf.Bytes()[icmpDataOffset:], []byte(payload[icmpDataOffset:])); diff != "" { - t.Errorf("received data mismatch (-want +got):\n%s", diff) - } + // Wait for the endpoint to become readable. + <-ch - test.checkLinkEndpoint(t, e) + var w bytes.Buffer + rr, err := ep.Read(&w, tcpip.ReadOptions{ + NeedRemoteAddr: true, + }) + if err != nil { + t.Fatalf("ep.Read(...): %s", err) + } + if diff := cmp.Diff(buffer.View(w.Bytes()[icmpDataOffset:]), payload[icmpDataOffset:]); diff != "" { + t.Errorf("received data mismatch (-want +got):\n%s", diff) + } + if rr.RemoteAddr.Addr != test.localAddr { + t.Errorf("got addr.Addr = %s, want = %s", rr.RemoteAddr.Addr, test.localAddr) + } + + test.checkLinkEndpoint(t, e) + }) + } }) } } diff --git a/pkg/tcpip/tests/utils/BUILD b/pkg/tcpip/tests/utils/BUILD index 433004148..a9699a367 100644 --- a/pkg/tcpip/tests/utils/BUILD +++ b/pkg/tcpip/tests/utils/BUILD @@ -8,12 +8,15 @@ go_library( visibility = ["//pkg/tcpip/tests:__subpackages__"], deps = [ "//pkg/tcpip", + "//pkg/tcpip/buffer", "//pkg/tcpip/header", + "//pkg/tcpip/link/channel", "//pkg/tcpip/link/ethernet", "//pkg/tcpip/link/nested", "//pkg/tcpip/link/pipe", "//pkg/tcpip/network/ipv4", "//pkg/tcpip/network/ipv6", "//pkg/tcpip/stack", + "//pkg/tcpip/transport/icmp", ], ) diff --git a/pkg/tcpip/tests/utils/utils.go b/pkg/tcpip/tests/utils/utils.go index f414a2234..d1c9f3a94 100644 --- a/pkg/tcpip/tests/utils/utils.go +++ b/pkg/tcpip/tests/utils/utils.go @@ -20,13 +20,16 @@ import ( "testing" "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/buffer" "gvisor.dev/gvisor/pkg/tcpip/header" + "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" "gvisor.dev/gvisor/pkg/tcpip/link/nested" "gvisor.dev/gvisor/pkg/tcpip/link/pipe" "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/transport/icmp" ) // Common NIC IDs used by tests. @@ -45,6 +48,10 @@ const ( LinkAddr4 = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09") ) +const ( + ttl = 255 +) + // Common IP addresses used by tests. var ( Ipv4Addr = tcpip.AddressWithPrefix{ @@ -312,3 +319,56 @@ func SetupRoutedStacks(t *testing.T, host1Stack, routerStack, host2Stack *stack. }, }) } + +// RxICMPv4EchoRequest constructs and injects an ICMPv4 echo request packet on +// the provided endpoint. +func RxICMPv4EchoRequest(e *channel.Endpoint, src, dst tcpip.Address) { + totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize + hdr := buffer.NewPrependable(totalLen) + pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) + pkt.SetType(header.ICMPv4Echo) + pkt.SetCode(header.ICMPv4UnusedCode) + pkt.SetChecksum(0) + pkt.SetChecksum(^header.Checksum(pkt, 0)) + ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize)) + ip.Encode(&header.IPv4Fields{ + TotalLength: uint16(totalLen), + Protocol: uint8(icmp.ProtocolNumber4), + TTL: ttl, + SrcAddr: src, + DstAddr: dst, + }) + ip.SetChecksum(^ip.CalculateChecksum()) + + e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ + Data: hdr.View().ToVectorisedView(), + })) +} + +// RxICMPv6EchoRequest constructs and injects an ICMPv6 echo request packet on +// the provided endpoint. +func RxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address) { + totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize + hdr := buffer.NewPrependable(totalLen) + pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize)) + pkt.SetType(header.ICMPv6EchoRequest) + pkt.SetCode(header.ICMPv6UnusedCode) + pkt.SetChecksum(0) + pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ + Header: pkt, + Src: src, + Dst: dst, + })) + ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) + ip.Encode(&header.IPv6Fields{ + PayloadLength: header.ICMPv6MinimumSize, + TransportProtocol: icmp.ProtocolNumber6, + HopLimit: ttl, + SrcAddr: src, + DstAddr: dst, + }) + + e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ + Data: hdr.View().ToVectorisedView(), + })) +} |