Browse Source

icmp: more coverage to ping test

This change splits the existing ping test into non-privileged and
privileged tests to cover IPConn full stack test on behalf of the
standard library.

Updates golang/go#10730.

Change-Id: I5d2e00c0b42b857045414eb8e0efca393967742e
Reviewed-on: https://go-review.googlesource.com/10090
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Mikio Hara 10 years ago
parent
commit
621fff363a
1 changed files with 87 additions and 54 deletions
  1. 87 54
      icmp/ping_test.go

+ 87 - 54
icmp/ping_test.go

@@ -6,10 +6,12 @@ package icmp_test
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"fmt"
 	"net"
 	"net"
 	"os"
 	"os"
 	"runtime"
 	"runtime"
 	"testing"
 	"testing"
+	"time"
 
 
 	"golang.org/x/net/icmp"
 	"golang.org/x/net/icmp"
 	"golang.org/x/net/internal/iana"
 	"golang.org/x/net/internal/iana"
@@ -49,21 +51,21 @@ func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
 	return nil, errors.New("no A or AAAA record")
 	return nil, errors.New("no A or AAAA record")
 }
 }
 
 
-var pingGoogleTests = []struct {
+type pingTest struct {
 	network, address string
 	network, address string
 	protocol         int
 	protocol         int
 	mtype            icmp.Type
 	mtype            icmp.Type
-}{
+}
+
+var nonPrivilegedPingTests = []pingTest{
 	{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
 	{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
-	{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
 
 
 	{"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
 	{"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
-	{"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
 }
 }
 
 
-func TestPingGoogle(t *testing.T) {
+func TestNonPrivilegedPing(t *testing.T) {
 	if testing.Short() {
 	if testing.Short() {
-		t.Skip("to avoid external network")
+		t.Skip("avoid external network")
 	}
 	}
 	switch runtime.GOOS {
 	switch runtime.GOOS {
 	case "darwin":
 	case "darwin":
@@ -73,61 +75,92 @@ func TestPingGoogle(t *testing.T) {
 		t.Skipf("not supported on %s", runtime.GOOS)
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	}
 
 
-	m, ok := nettest.SupportsRawIPSocket()
-	for i, tt := range pingGoogleTests {
-		if tt.network[:2] == "ip" && !ok {
-			t.Log(m)
-			continue
-		}
-		c, err := icmp.ListenPacket(tt.network, tt.address)
-		if err != nil {
+	for i, tt := range nonPrivilegedPingTests {
+		if err := doPing(tt, i); err != nil {
 			t.Error(err)
 			t.Error(err)
-			continue
 		}
 		}
-		defer c.Close()
+	}
+}
 
 
-		dst, err := googleAddr(c, tt.protocol)
-		if err != nil {
-			t.Error(err)
-			continue
-		}
+var privilegedPingTests = []pingTest{
+	{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
 
 
-		wm := icmp.Message{
-			Type: tt.mtype, Code: 0,
-			Body: &icmp.Echo{
-				ID: os.Getpid() & 0xffff, Seq: 1 << uint(i),
-				Data: []byte("HELLO-R-U-THERE"),
-			},
-		}
-		wb, err := wm.Marshal(nil)
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-		if n, err := c.WriteTo(wb, dst); err != nil {
-			t.Error(err, dst)
-			continue
-		} else if n != len(wb) {
-			t.Errorf("got %v; want %v", n, len(wb))
-			continue
-		}
+	{"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
+}
 
 
-		rb := make([]byte, 1500)
-		n, peer, err := c.ReadFrom(rb)
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-		rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
-		if err != nil {
+func TestPrivilegedPing(t *testing.T) {
+	if testing.Short() {
+		t.Skip("avoid external network")
+	}
+	if m, ok := nettest.SupportsRawIPSocket(); !ok {
+		t.Skip(m)
+	}
+
+	for i, tt := range privilegedPingTests {
+		if err := doPing(tt, i); err != nil {
 			t.Error(err)
 			t.Error(err)
-			continue
 		}
 		}
-		switch rm.Type {
-		case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
-			t.Logf("got reflection from %v", peer)
-		default:
-			t.Errorf("got %+v; want echo reply", rm)
+	}
+}
+
+func doPing(tt pingTest, seq int) error {
+	c, err := icmp.ListenPacket(tt.network, tt.address)
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+
+	dst, err := googleAddr(c, tt.protocol)
+	if err != nil {
+		return err
+	}
+
+	if tt.protocol == iana.ProtocolIPv6ICMP {
+		var f ipv6.ICMPFilter
+		f.SetAll(true)
+		f.Accept(ipv6.ICMPTypeDestinationUnreachable)
+		f.Accept(ipv6.ICMPTypePacketTooBig)
+		f.Accept(ipv6.ICMPTypeTimeExceeded)
+		f.Accept(ipv6.ICMPTypeParameterProblem)
+		f.Accept(ipv6.ICMPTypeEchoReply)
+		if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
+			return err
 		}
 		}
 	}
 	}
+
+	wm := icmp.Message{
+		Type: tt.mtype, Code: 0,
+		Body: &icmp.Echo{
+			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
+			Data: []byte("HELLO-R-U-THERE"),
+		},
+	}
+	wb, err := wm.Marshal(nil)
+	if err != nil {
+		return err
+	}
+	if n, err := c.WriteTo(wb, dst); err != nil {
+		return err
+	} else if n != len(wb) {
+		return fmt.Errorf("got %v; want %v", n, len(wb))
+	}
+
+	rb := make([]byte, 1500)
+	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
+		return err
+	}
+	n, peer, err := c.ReadFrom(rb)
+	if err != nil {
+		return err
+	}
+	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
+	if err != nil {
+		return err
+	}
+	switch rm.Type {
+	case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
+		return nil
+	default:
+		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
+	}
 }
 }