github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/icmp/ping_test.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package icmp_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"os"
    12  	"runtime"
    13  	"testing"
    14  	"time"
    15  
    16  	"golang.org/x/net/icmp"
    17  	"golang.org/x/net/internal/iana"
    18  	"golang.org/x/net/internal/nettest"
    19  	"golang.org/x/net/ipv4"
    20  	"golang.org/x/net/ipv6"
    21  )
    22  
    23  func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
    24  	const host = "www.google.com"
    25  	ips, err := net.LookupIP(host)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	netaddr := func(ip net.IP) (net.Addr, error) {
    30  		switch c.LocalAddr().(type) {
    31  		case *net.UDPAddr:
    32  			return &net.UDPAddr{IP: ip}, nil
    33  		case *net.IPAddr:
    34  			return &net.IPAddr{IP: ip}, nil
    35  		default:
    36  			return nil, errors.New("neither UDPAddr nor IPAddr")
    37  		}
    38  	}
    39  	for _, ip := range ips {
    40  		switch protocol {
    41  		case iana.ProtocolICMP:
    42  			if ip.To4() != nil {
    43  				return netaddr(ip)
    44  			}
    45  		case iana.ProtocolIPv6ICMP:
    46  			if ip.To16() != nil && ip.To4() == nil {
    47  				return netaddr(ip)
    48  			}
    49  		}
    50  	}
    51  	return nil, errors.New("no A or AAAA record")
    52  }
    53  
    54  type pingTest struct {
    55  	network, address string
    56  	protocol         int
    57  	mtype            icmp.Type
    58  }
    59  
    60  var nonPrivilegedPingTests = []pingTest{
    61  	{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
    62  
    63  	{"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
    64  }
    65  
    66  func TestNonPrivilegedPing(t *testing.T) {
    67  	if testing.Short() {
    68  		t.Skip("avoid external network")
    69  	}
    70  	switch runtime.GOOS {
    71  	case "darwin":
    72  	case "linux":
    73  		t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
    74  	default:
    75  		t.Skipf("not supported on %s", runtime.GOOS)
    76  	}
    77  
    78  	for i, tt := range nonPrivilegedPingTests {
    79  		if err := doPing(tt, i); err != nil {
    80  			t.Error(err)
    81  		}
    82  	}
    83  }
    84  
    85  var privilegedPingTests = []pingTest{
    86  	{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
    87  
    88  	{"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
    89  }
    90  
    91  func TestPrivilegedPing(t *testing.T) {
    92  	if testing.Short() {
    93  		t.Skip("avoid external network")
    94  	}
    95  	if m, ok := nettest.SupportsRawIPSocket(); !ok {
    96  		t.Skip(m)
    97  	}
    98  
    99  	for i, tt := range privilegedPingTests {
   100  		if err := doPing(tt, i); err != nil {
   101  			t.Error(err)
   102  		}
   103  	}
   104  }
   105  
   106  func doPing(tt pingTest, seq int) error {
   107  	c, err := icmp.ListenPacket(tt.network, tt.address)
   108  	if err != nil {
   109  		return err
   110  	}
   111  	defer c.Close()
   112  
   113  	dst, err := googleAddr(c, tt.protocol)
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	if tt.network != "udp6" && tt.protocol == iana.ProtocolIPv6ICMP {
   119  		var f ipv6.ICMPFilter
   120  		f.SetAll(true)
   121  		f.Accept(ipv6.ICMPTypeDestinationUnreachable)
   122  		f.Accept(ipv6.ICMPTypePacketTooBig)
   123  		f.Accept(ipv6.ICMPTypeTimeExceeded)
   124  		f.Accept(ipv6.ICMPTypeParameterProblem)
   125  		f.Accept(ipv6.ICMPTypeEchoReply)
   126  		if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
   127  			return err
   128  		}
   129  	}
   130  
   131  	wm := icmp.Message{
   132  		Type: tt.mtype, Code: 0,
   133  		Body: &icmp.Echo{
   134  			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
   135  			Data: []byte("HELLO-R-U-THERE"),
   136  		},
   137  	}
   138  	wb, err := wm.Marshal(nil)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	if n, err := c.WriteTo(wb, dst); err != nil {
   143  		return err
   144  	} else if n != len(wb) {
   145  		return fmt.Errorf("got %v; want %v", n, len(wb))
   146  	}
   147  
   148  	rb := make([]byte, 1500)
   149  	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
   150  		return err
   151  	}
   152  	n, peer, err := c.ReadFrom(rb)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
   157  	if err != nil {
   158  		return err
   159  	}
   160  	switch rm.Type {
   161  	case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
   162  		return nil
   163  	default:
   164  		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
   165  	}
   166  }