|
@@ -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)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|