Commit 621fff36 authored by Mikio Hara's avatar Mikio Hara

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/10090Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent ad9eb390
......@@ -6,10 +6,12 @@ package icmp_test
import (
"errors"
"fmt"
"net"
"os"
"runtime"
"testing"
"time"
"golang.org/x/net/icmp"
"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")
}
var pingGoogleTests = []struct {
type pingTest struct {
network, address string
protocol int
mtype icmp.Type
}{
}
var nonPrivilegedPingTests = []pingTest{
{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
{"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() {
t.Skip("to avoid external network")
t.Skip("avoid external network")
}
switch runtime.GOOS {
case "darwin":
......@@ -73,61 +75,92 @@ func TestPingGoogle(t *testing.T) {
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)
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)
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)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment