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 type diagTest struct {
25 network, address string
30 func TestDiag(t *testing.T) {
32 t.Skip("avoid external network")
35 t.Run("Ping/NonPrivileged", func(t *testing.T) {
39 t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
41 t.Logf("not supported on %s", runtime.GOOS)
44 for i, dt := range []diagTest{
46 "udp4", "0.0.0.0", iana.ProtocolICMP,
48 Type: ipv4.ICMPTypeEcho, Code: 0,
50 ID: os.Getpid() & 0xffff,
51 Data: []byte("HELLO-R-U-THERE"),
57 "udp6", "::", iana.ProtocolIPv6ICMP,
59 Type: ipv6.ICMPTypeEchoRequest, Code: 0,
61 ID: os.Getpid() & 0xffff,
62 Data: []byte("HELLO-R-U-THERE"),
67 if err := doDiag(dt, i); err != nil {
72 t.Run("Ping/Privileged", func(t *testing.T) {
73 if m, ok := nettest.SupportsRawIPSocket(); !ok {
76 for i, dt := range []diagTest{
78 "ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
80 Type: ipv4.ICMPTypeEcho, Code: 0,
82 ID: os.Getpid() & 0xffff,
83 Data: []byte("HELLO-R-U-THERE"),
89 "ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
91 Type: ipv6.ICMPTypeEchoRequest, Code: 0,
93 ID: os.Getpid() & 0xffff,
94 Data: []byte("HELLO-R-U-THERE"),
99 if err := doDiag(dt, i); err != nil {
104 t.Run("Probe/Privileged", func(t *testing.T) {
105 if m, ok := nettest.SupportsRawIPSocket(); !ok {
108 for i, dt := range []diagTest{
110 "ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
112 Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
113 Body: &icmp.ExtendedEchoRequest{
114 ID: os.Getpid() & 0xffff,
116 Extensions: []icmp.Extension{
117 &icmp.InterfaceIdent{
119 Name: "doesnotexist",
127 "ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
129 Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
130 Body: &icmp.ExtendedEchoRequest{
131 ID: os.Getpid() & 0xffff,
133 Extensions: []icmp.Extension{
134 &icmp.InterfaceIdent{
136 Name: "doesnotexist",
143 if err := doDiag(dt, i); err != nil {
150 func doDiag(dt diagTest, seq int) error {
151 c, err := icmp.ListenPacket(dt.network, dt.address)
157 dst, err := googleAddr(c, dt.protocol)
162 if dt.network != "udp6" && dt.protocol == iana.ProtocolIPv6ICMP {
163 var f ipv6.ICMPFilter
165 f.Accept(ipv6.ICMPTypeDestinationUnreachable)
166 f.Accept(ipv6.ICMPTypePacketTooBig)
167 f.Accept(ipv6.ICMPTypeTimeExceeded)
168 f.Accept(ipv6.ICMPTypeParameterProblem)
169 f.Accept(ipv6.ICMPTypeEchoReply)
170 f.Accept(ipv6.ICMPTypeExtendedEchoReply)
171 if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
176 switch m := dt.m.Body.(type) {
178 m.Seq = 1 << uint(seq)
179 case *icmp.ExtendedEchoRequest:
180 m.Seq = 1 << uint(seq)
182 wb, err := dt.m.Marshal(nil)
186 if n, err := c.WriteTo(wb, dst); err != nil {
188 } else if n != len(wb) {
189 return fmt.Errorf("got %v; want %v", n, len(wb))
192 rb := make([]byte, 1500)
193 if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
196 n, peer, err := c.ReadFrom(rb)
200 rm, err := icmp.ParseMessage(dt.protocol, rb[:n])
205 case dt.m.Type == ipv4.ICMPTypeEcho && rm.Type == ipv4.ICMPTypeEchoReply:
207 case dt.m.Type == ipv6.ICMPTypeEchoRequest && rm.Type == ipv6.ICMPTypeEchoReply:
209 case dt.m.Type == ipv4.ICMPTypeExtendedEchoRequest && rm.Type == ipv4.ICMPTypeExtendedEchoReply:
211 case dt.m.Type == ipv6.ICMPTypeExtendedEchoRequest && rm.Type == ipv6.ICMPTypeExtendedEchoReply:
214 return fmt.Errorf("got %+v from %v; want echo reply or extended echo reply", rm, peer)
218 func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
219 host := "ipv4.google.com"
220 if protocol == iana.ProtocolIPv6ICMP {
221 host = "ipv6.google.com"
223 ips, err := net.LookupIP(host)
227 netaddr := func(ip net.IP) (net.Addr, error) {
228 switch c.LocalAddr().(type) {
230 return &net.UDPAddr{IP: ip}, nil
232 return &net.IPAddr{IP: ip}, nil
234 return nil, errors.New("neither UDPAddr nor IPAddr")
238 return netaddr(ips[0])
240 return nil, errors.New("no A or AAAA record")
243 func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
245 t.Skip("avoid external network")
247 switch runtime.GOOS {
250 t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
252 t.Skipf("not supported on %s", runtime.GOOS)
255 network, address := "udp4", "127.0.0.1"
256 if !nettest.SupportsIPv4() {
257 network, address = "udp6", "::1"
260 var wg sync.WaitGroup
262 for i := 0; i < N; i++ {
265 c, err := icmp.ListenPacket(network, address)