Add support for ping sockets

PiperOrigin-RevId: 195049322
Change-Id: I09f6dd58cf10a2e50e53d17d2823d540102913c5
This commit is contained in:
Ian Gudger
2018-05-01 22:51:41 -07:00
committed by Shentubot
parent 65df955168
commit eb5414ee29
15 changed files with 914 additions and 331 deletions
+1
View File
@@ -50,6 +50,7 @@ go_library(
"//pkg/syserror",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/network/ipv6",
"//pkg/tcpip/stack",
+11 -8
View File
@@ -23,6 +23,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/socket"
"gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4"
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv6"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/tcp"
@@ -37,8 +38,8 @@ type provider struct {
netProto tcpip.NetworkProtocolNumber
}
// GetTransportProtocol figures out transport protocol. Currently only TCP and
// UDP are supported.
// GetTransportProtocol figures out transport protocol. Currently only TCP,
// UDP, and ICMP are supported.
func GetTransportProtocol(stype unix.SockType, protocol int) (tcpip.TransportProtocolNumber, *syserr.Error) {
switch stype {
case linux.SOCK_STREAM:
@@ -48,14 +49,16 @@ func GetTransportProtocol(stype unix.SockType, protocol int) (tcpip.TransportPro
return tcp.ProtocolNumber, nil
case linux.SOCK_DGRAM:
if protocol != 0 && protocol != syscall.IPPROTO_UDP {
return 0, syserr.ErrInvalidArgument
switch protocol {
case 0, syscall.IPPROTO_UDP:
return udp.ProtocolNumber, nil
case syscall.IPPROTO_ICMP:
return header.ICMPv4ProtocolNumber, nil
case syscall.IPPROTO_ICMPV6:
return header.ICMPv6ProtocolNumber, nil
}
return udp.ProtocolNumber, nil
default:
return 0, syserr.ErrInvalidArgument
}
return 0, syserr.ErrInvalidArgument
}
// Socket creates a new socket object for the AF_INET or AF_INET6 family.
+1 -1
View File
@@ -791,7 +791,7 @@ func recvFrom(t *kernel.Task, fd kdefs.FD, bufPtr usermem.Addr, bufLen uint64, f
}
// Reject flags that we don't handle yet.
if flags & ^(linux.MSG_DONTWAIT|linux.MSG_NOSIGNAL|linux.MSG_PEEK|linux.MSG_TRUNC) != 0 {
if flags & ^(linux.MSG_DONTWAIT|linux.MSG_NOSIGNAL|linux.MSG_PEEK|linux.MSG_TRUNC|linux.MSG_CONFIRM) != 0 {
return 0, syscall.EINVAL
}
+1
View File
@@ -30,5 +30,6 @@ go_test(
"//pkg/tcpip/link/sniffer",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/stack",
"//pkg/tcpip/transport/ping",
],
)
+2 -1
View File
@@ -16,6 +16,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/arp"
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/ping"
)
const (
@@ -32,7 +33,7 @@ type testContext struct {
}
func newTestContext(t *testing.T) *testContext {
s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, arp.ProtocolName}, []string{ipv4.PingProtocolName})
s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName, arp.ProtocolName}, []string{ping.ProtocolName4})
const defaultMTU = 65536
id, linkEP := channel.New(256, defaultMTU, stackLinkAddr)
+1 -16
View File
@@ -1,6 +1,6 @@
package(licenses = ["notice"]) # BSD
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "ipv4",
@@ -19,20 +19,5 @@ go_library(
"//pkg/tcpip/network/fragmentation",
"//pkg/tcpip/network/hash",
"//pkg/tcpip/stack",
"//pkg/waiter",
],
)
go_test(
name = "ipv4_test",
size = "small",
srcs = ["icmp_test.go"],
deps = [
":ipv4",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/link/channel",
"//pkg/tcpip/link/sniffer",
"//pkg/tcpip/stack",
],
)
+11 -179
View File
@@ -5,26 +5,14 @@
package ipv4
import (
"context"
"encoding/binary"
"time"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
// PingProtocolName is a pseudo transport protocol used to handle ping replies.
// Use it when constructing a stack that intends to use ipv4.Ping.
const PingProtocolName = "icmpv4ping"
// pingProtocolNumber is a fake transport protocol used to
// deliver incoming ICMP echo replies. The ICMP identifier
// number is used as a port number for multiplexing.
const pingProtocolNumber tcpip.TransportProtocolNumber = 256 + 11
// handleControl handles the case when an ICMP packet contains the headers of
// the original packet that caused the ICMP one to be sent. This information is
// used to find out which transport endpoint must be notified about the ICMP
@@ -78,7 +66,10 @@ func (e *endpoint) handleICMP(r *stack.Route, vv *buffer.VectorisedView) {
}
case header.ICMPv4EchoReply:
e.dispatcher.DeliverTransportPacket(r, pingProtocolNumber, vv)
if len(v) < header.ICMPv4EchoMinimumSize {
return
}
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, vv)
case header.ICMPv4DstUnreachable:
if len(v) < header.ICMPv4DstUnreachableMinimumSize {
@@ -104,179 +95,20 @@ type echoRequest struct {
func (e *endpoint) echoReplier() {
for req := range e.echoRequests {
sendICMPv4(&req.r, header.ICMPv4EchoReply, 0, req.v)
sendPing4(&req.r, 0, req.v)
req.r.Release()
}
}
func sendICMPv4(r *stack.Route, typ header.ICMPv4Type, code byte, data buffer.View) *tcpip.Error {
hdr := buffer.NewPrependable(header.ICMPv4MinimumSize + int(r.MaxHeaderLength()))
func sendPing4(r *stack.Route, code byte, data buffer.View) *tcpip.Error {
hdr := buffer.NewPrependable(header.ICMPv4EchoMinimumSize + int(r.MaxHeaderLength()))
icmpv4 := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
icmpv4.SetType(typ)
icmpv4 := header.ICMPv4(hdr.Prepend(header.ICMPv4EchoMinimumSize))
icmpv4.SetType(header.ICMPv4EchoReply)
icmpv4.SetCode(code)
copy(icmpv4[header.ICMPv4MinimumSize:], data)
data = data[header.ICMPv4EchoMinimumSize-header.ICMPv4MinimumSize:]
icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data, 0)))
return r.WritePacket(&hdr, data, header.ICMPv4ProtocolNumber)
}
// A Pinger can send echo requests to an address.
type Pinger struct {
Stack *stack.Stack
NICID tcpip.NICID
Addr tcpip.Address
LocalAddr tcpip.Address // optional
Wait time.Duration // if zero, defaults to 1 second
Count uint16 // if zero, defaults to MaxUint16
}
// Ping sends echo requests to an ICMPv4 endpoint.
// Responses are streamed to the channel ch.
func (p *Pinger) Ping(ctx context.Context, ch chan<- PingReply) *tcpip.Error {
count := p.Count
if count == 0 {
count = 1<<16 - 1
}
wait := p.Wait
if wait == 0 {
wait = 1 * time.Second
}
r, err := p.Stack.FindRoute(p.NICID, p.LocalAddr, p.Addr, ProtocolNumber)
if err != nil {
return err
}
netProtos := []tcpip.NetworkProtocolNumber{ProtocolNumber}
ep := &pingEndpoint{
stack: p.Stack,
pktCh: make(chan buffer.View, 1),
}
id := stack.TransportEndpointID{
LocalAddress: r.LocalAddress,
RemoteAddress: p.Addr,
}
_, err = p.Stack.PickEphemeralPort(func(port uint16) (bool, *tcpip.Error) {
id.LocalPort = port
err := p.Stack.RegisterTransportEndpoint(p.NICID, netProtos, pingProtocolNumber, id, ep)
switch err {
case nil:
return true, nil
case tcpip.ErrPortInUse:
return false, nil
default:
return false, err
}
})
if err != nil {
return err
}
defer p.Stack.UnregisterTransportEndpoint(p.NICID, netProtos, pingProtocolNumber, id)
v := buffer.NewView(4)
binary.BigEndian.PutUint16(v[0:], id.LocalPort)
start := time.Now()
done := make(chan struct{})
go func(count int) {
loop:
for ; count > 0; count-- {
select {
case v := <-ep.pktCh:
seq := binary.BigEndian.Uint16(v[header.ICMPv4MinimumSize+2:])
ch <- PingReply{
Duration: time.Since(start) - time.Duration(seq)*wait,
SeqNumber: seq,
}
case <-ctx.Done():
break loop
}
}
close(done)
}(int(count))
defer func() { <-done }()
t := time.NewTicker(wait)
defer t.Stop()
for seq := uint16(0); seq < count; seq++ {
select {
case <-t.C:
case <-ctx.Done():
return nil
}
binary.BigEndian.PutUint16(v[2:], seq)
sent := time.Now()
if err := sendICMPv4(&r, header.ICMPv4Echo, 0, v); err != nil {
ch <- PingReply{
Error: err,
Duration: time.Since(sent),
SeqNumber: seq,
}
}
}
return nil
}
// PingReply summarizes an ICMP echo reply.
type PingReply struct {
Error *tcpip.Error // reports any errors sending a ping request
Duration time.Duration
SeqNumber uint16
}
type pingProtocol struct{}
func (*pingProtocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
return nil, tcpip.ErrNotSupported // endpoints are created directly
}
func (*pingProtocol) Number() tcpip.TransportProtocolNumber { return pingProtocolNumber }
func (*pingProtocol) MinimumPacketSize() int { return header.ICMPv4EchoMinimumSize }
func (*pingProtocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error) {
ident := binary.BigEndian.Uint16(v[4:])
return 0, ident, nil
}
func (*pingProtocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *buffer.VectorisedView) bool {
return true
}
// SetOption implements TransportProtocol.SetOption.
func (p *pingProtocol) SetOption(option interface{}) *tcpip.Error {
return tcpip.ErrUnknownProtocolOption
}
// Option implements TransportProtocol.Option.
func (p *pingProtocol) Option(option interface{}) *tcpip.Error {
return tcpip.ErrUnknownProtocolOption
}
func init() {
stack.RegisterTransportProtocolFactory(PingProtocolName, func() stack.TransportProtocol {
return &pingProtocol{}
})
}
type pingEndpoint struct {
stack *stack.Stack
pktCh chan buffer.View
}
func (e *pingEndpoint) Close() {
close(e.pktCh)
}
func (e *pingEndpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv *buffer.VectorisedView) {
select {
case e.pktCh <- vv.ToView():
default:
}
}
// HandleControlPacket implements stack.TransportEndpoint.HandleControlPacket.
func (e *pingEndpoint) HandleControlPacket(id stack.TransportEndpointID, typ stack.ControlType, extra uint32, vv *buffer.VectorisedView) {
}
-124
View File
@@ -1,124 +0,0 @@
// Copyright 2016 The Netstack Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ipv4_test
import (
"context"
"testing"
"time"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/link/channel"
"gvisor.googlesource.com/gvisor/pkg/tcpip/link/sniffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
)
const stackAddr = "\x0a\x00\x00\x01"
type testContext struct {
t *testing.T
linkEP *channel.Endpoint
s *stack.Stack
}
func newTestContext(t *testing.T) *testContext {
s := stack.New(&tcpip.StdClock{}, []string{ipv4.ProtocolName}, []string{ipv4.PingProtocolName})
const defaultMTU = 65536
id, linkEP := channel.New(256, defaultMTU, "")
if testing.Verbose() {
id = sniffer.New(id)
}
if err := s.CreateNIC(1, id); err != nil {
t.Fatalf("CreateNIC failed: %v", err)
}
if err := s.AddAddress(1, ipv4.ProtocolNumber, stackAddr); err != nil {
t.Fatalf("AddAddress failed: %v", err)
}
s.SetRouteTable([]tcpip.Route{{
Destination: "\x00\x00\x00\x00",
Mask: "\x00\x00\x00\x00",
Gateway: "",
NIC: 1,
}})
return &testContext{
t: t,
s: s,
linkEP: linkEP,
}
}
func (c *testContext) cleanup() {
close(c.linkEP.C)
}
func (c *testContext) loopback() {
go func() {
for pkt := range c.linkEP.C {
v := make(buffer.View, len(pkt.Header)+len(pkt.Payload))
copy(v, pkt.Header)
copy(v[len(pkt.Header):], pkt.Payload)
vv := v.ToVectorisedView([1]buffer.View{})
c.linkEP.Inject(pkt.Proto, &vv)
}
}()
}
func TestEcho(t *testing.T) {
c := newTestContext(t)
defer c.cleanup()
c.loopback()
ch := make(chan ipv4.PingReply, 1)
p := ipv4.Pinger{
Stack: c.s,
NICID: 1,
Addr: stackAddr,
Wait: 10 * time.Millisecond,
Count: 1, // one ping only
}
if err := p.Ping(context.Background(), ch); err != nil {
t.Fatalf("icmp.Ping failed: %v", err)
}
ping := <-ch
if ping.Error != nil {
t.Errorf("bad ping response: %v", ping.Error)
}
}
func TestEchoSequence(t *testing.T) {
c := newTestContext(t)
defer c.cleanup()
c.loopback()
const numPings = 3
ch := make(chan ipv4.PingReply, numPings)
p := ipv4.Pinger{
Stack: c.s,
NICID: 1,
Addr: stackAddr,
Wait: 10 * time.Millisecond,
Count: numPings,
}
if err := p.Ping(context.Background(), ch); err != nil {
t.Fatalf("icmp.Ping failed: %v", err)
}
for i := uint16(0); i < numPings; i++ {
ping := <-ch
if ping.Error != nil {
t.Errorf("i=%d bad ping response: %v", i, ping.Error)
}
if ping.SeqNumber != i {
t.Errorf("SeqNumber=%d, want %d", ping.SeqNumber, i)
}
}
}
+50
View File
@@ -0,0 +1,50 @@
package(licenses = ["notice"]) # BSD
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//tools/go_generics:defs.bzl", "go_template_instance")
load("//tools/go_stateify:defs.bzl", "go_stateify")
go_stateify(
name = "ping_state",
srcs = [
"endpoint.go",
"endpoint_state.go",
"ping_packet_list.go",
],
out = "ping_state.go",
imports = ["gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"],
package = "ping",
)
go_template_instance(
name = "ping_packet_list",
out = "ping_packet_list.go",
package = "ping",
prefix = "pingPacket",
template = "//pkg/ilist:generic_list",
types = {
"Linker": "*pingPacket",
},
)
go_library(
name = "ping",
srcs = [
"endpoint.go",
"endpoint_state.go",
"ping_packet_list.go",
"ping_state.go",
"protocol.go",
],
importpath = "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/ping",
visibility = ["//visibility:public"],
deps = [
"//pkg/sleep",
"//pkg/state",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
"//pkg/tcpip/stack",
"//pkg/waiter",
],
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,61 @@
// Copyright 2016 The Netstack Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ping
import (
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
)
// saveData saves pingPacket.data field.
func (p *pingPacket) saveData() buffer.VectorisedView {
// We cannot save p.data directly as p.data.views may alias to p.views,
// which is not allowed by state framework (in-struct pointer).
return p.data.Clone(nil)
}
// loadData loads pingPacket.data field.
func (p *pingPacket) loadData(data buffer.VectorisedView) {
// NOTE: We cannot do the p.data = data.Clone(p.views[:]) optimization
// here because data.views is not guaranteed to be loaded by now. Plus,
// data.views will be allocated anyway so there really is little point
// of utilizing p.views for data.views.
p.data = data
}
// beforeSave is invoked by stateify.
func (e *endpoint) beforeSave() {
// Stop incoming packets from being handled (and mutate endpoint state).
e.rcvMu.Lock()
}
// afterLoad is invoked by stateify.
func (e *endpoint) afterLoad() {
e.stack = stack.StackFromEnv
if e.state != stateBound && e.state != stateConnected {
return
}
var err *tcpip.Error
if e.state == stateConnected {
e.route, err = e.stack.FindRoute(e.regNICID, e.bindAddr, e.id.RemoteAddress, e.netProto)
if err != nil {
panic(*err)
}
e.id.LocalAddress = e.route.LocalAddress
} else if len(e.id.LocalAddress) != 0 { // stateBound
if e.stack.CheckLocalAddress(e.regNICID, e.netProto, e.id.LocalAddress) == 0 {
panic(tcpip.ErrBadLocalAddress)
}
}
e.id, err = e.registerWithStack(e.regNICID, []tcpip.NetworkProtocolNumber{e.netProto}, e.id)
if err != nil {
panic(*err)
}
}
+106
View File
@@ -0,0 +1,106 @@
// Copyright 2016 The Netstack Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ping contains the implementation of the ICMP and IPv6-ICMP transport
// protocols for use in ping. To use it in the networking stack, this package
// must be added to the project, and
// activated on the stack by passing ping.ProtocolName (or "ping") and/or
// ping.ProtocolName6 (or "ping6") as one of the transport protocols when
// calling stack.New(). Then endpoints can be created by passing
// ping.ProtocolNumber or ping.ProtocolNumber6 as the transport protocol number
// when calling Stack.NewEndpoint().
package ping
import (
"encoding/binary"
"fmt"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
const (
// ProtocolName4 is the string representation of the ping protocol name.
ProtocolName4 = "ping4"
// ProtocolNumber4 is the ICMP protocol number.
ProtocolNumber4 = header.ICMPv4ProtocolNumber
// ProtocolName6 is the string representation of the ping protocol name.
ProtocolName6 = "ping6"
// ProtocolNumber6 is the IPv6-ICMP protocol number.
ProtocolNumber6 = header.ICMPv6ProtocolNumber
)
type protocol struct {
number tcpip.TransportProtocolNumber
}
// Number returns the ICMP protocol number.
func (p *protocol) Number() tcpip.TransportProtocolNumber {
return p.number
}
func (p *protocol) netProto() tcpip.NetworkProtocolNumber {
switch p.number {
case ProtocolNumber4:
return header.IPv4ProtocolNumber
case ProtocolNumber6:
return header.IPv6ProtocolNumber
}
panic(fmt.Sprint("unknown protocol number: ", p.number))
}
// NewEndpoint creates a new ping endpoint.
func (p *protocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
if netProto != p.netProto() {
return nil, tcpip.ErrUnknownProtocol
}
return newEndpoint(stack, netProto, waiterQueue), nil
}
// MinimumPacketSize returns the minimum valid ping packet size.
func (p *protocol) MinimumPacketSize() int {
switch p.number {
case ProtocolNumber4:
return header.ICMPv4EchoMinimumSize
case ProtocolNumber6:
return header.ICMPv6EchoMinimumSize
}
panic(fmt.Sprint("unknown protocol number: ", p.number))
}
// ParsePorts returns the source and destination ports stored in the given udp
// packet.
func (*protocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error) {
return 0, binary.BigEndian.Uint16(v[header.ICMPv4MinimumSize:]), nil
}
// HandleUnknownDestinationPacket handles packets targeted at this protocol but
// that don't match any existing endpoint.
func (p *protocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *buffer.VectorisedView) bool {
return true
}
// SetOption implements TransportProtocol.SetOption.
func (p *protocol) SetOption(option interface{}) *tcpip.Error {
return tcpip.ErrUnknownProtocolOption
}
// Option implements TransportProtocol.Option.
func (p *protocol) Option(option interface{}) *tcpip.Error {
return tcpip.ErrUnknownProtocolOption
}
func init() {
stack.RegisterTransportProtocolFactory(ProtocolName4, func() stack.TransportProtocol {
return &protocol{ProtocolNumber4}
})
// TODO: Support IPv6.
}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
// saveData saves udpPacket.data field.
func (u *udpPacket) saveData() buffer.VectorisedView {
// We canoot save u.data directly as u.data.views may alias to u.views,
// We cannot save u.data directly as u.data.views may alias to u.views,
// which is not allowed by state framework (in-struct pointer).
return u.data.Clone(nil)
}
+1
View File
@@ -64,6 +64,7 @@ go_library(
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/network/ipv6",
"//pkg/tcpip/stack",
"//pkg/tcpip/transport/ping",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/udp",
"//pkg/urpc",
+2 -1
View File
@@ -43,6 +43,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv4"
"gvisor.googlesource.com/gvisor/pkg/tcpip/network/ipv6"
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/ping"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/tcp"
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/udp"
"gvisor.googlesource.com/gvisor/runsc/boot/filter"
@@ -346,7 +347,7 @@ func newEmptyNetworkStack(conf *Config, clock tcpip.Clock) inet.Stack {
case NetworkNone, NetworkSandbox:
// NetworkNone sets up loopback using netstack.
netProtos := []string{ipv4.ProtocolName, ipv6.ProtocolName, arp.ProtocolName}
protoNames := []string{tcp.ProtocolName, udp.ProtocolName}
protoNames := []string{tcp.ProtocolName, udp.ProtocolName, ping.ProtocolName4}
return &epsocket.Stack{stack.New(clock, netProtos, protoNames)}
default: