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.
17 "golang.org/x/net/icmp"
18 "golang.org/x/net/internal/iana"
19 "golang.org/x/net/internal/nettest"
20 "golang.org/x/net/ipv4"
21 "golang.org/x/net/ipv6"
24 func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
25 const host = "www.google.com"
26 ips, err := net.LookupIP(host)
30 netaddr := func(ip net.IP) (net.Addr, error) {
31 switch c.LocalAddr().(type) {
33 return &net.UDPAddr{IP: ip}, nil
35 return &net.IPAddr{IP: ip}, nil
37 return nil, errors.New("neither UDPAddr nor IPAddr")
40 for _, ip := range ips {
42 case iana.ProtocolICMP:
46 case iana.ProtocolIPv6ICMP:
47 if ip.To16() != nil && ip.To4() == nil {
52 return nil, errors.New("no A or AAAA record")
55 type pingTest struct {
56 network, address string
61 var nonPrivilegedPingTests = []pingTest{
62 {"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
64 {"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
67 func TestNonPrivilegedPing(t *testing.T) {
69 t.Skip("avoid external network")
74 t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
76 t.Skipf("not supported on %s", runtime.GOOS)
79 for i, tt := range nonPrivilegedPingTests {
80 if err := doPing(tt, i); err != nil {
86 var privilegedPingTests = []pingTest{
87 {"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
89 {"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
92 func TestPrivilegedPing(t *testing.T) {
94 t.Skip("avoid external network")
96 if m, ok := nettest.SupportsRawIPSocket(); !ok {
100 for i, tt := range privilegedPingTests {
101 if err := doPing(tt, i); err != nil {
107 func doPing(tt pingTest, seq int) error {
108 c, err := icmp.ListenPacket(tt.network, tt.address)
114 dst, err := googleAddr(c, tt.protocol)
119 if tt.network != "udp6" && tt.protocol == iana.ProtocolIPv6ICMP {
120 var f ipv6.ICMPFilter
122 f.Accept(ipv6.ICMPTypeDestinationUnreachable)
123 f.Accept(ipv6.ICMPTypePacketTooBig)
124 f.Accept(ipv6.ICMPTypeTimeExceeded)
125 f.Accept(ipv6.ICMPTypeParameterProblem)
126 f.Accept(ipv6.ICMPTypeEchoReply)
127 if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
133 Type: tt.mtype, Code: 0,
135 ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
136 Data: []byte("HELLO-R-U-THERE"),
139 wb, err := wm.Marshal(nil)
143 if n, err := c.WriteTo(wb, dst); err != nil {
145 } else if n != len(wb) {
146 return fmt.Errorf("got %v; want %v", n, len(wb))
149 rb := make([]byte, 1500)
150 if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
153 n, peer, err := c.ReadFrom(rb)
157 rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
162 case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
165 return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
169 func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
171 t.Skip("avoid external network")
173 switch runtime.GOOS {
176 t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
178 t.Skipf("not supported on %s", runtime.GOOS)
181 network, address := "udp4", "127.0.0.1"
182 if !nettest.SupportsIPv4() {
183 network, address = "udp6", "::1"
186 var wg sync.WaitGroup
188 for i := 0; i < N; i++ {
191 c, err := icmp.ListenPacket(network, address)