mirror of
https://github.com/golang/go
synced 2024-10-05 08:21:22 -06:00
2ddcad96d7
This CL will help to make an adaptive address family selection possible when an any address family, vague network string such as "ip", "tcp" or "udp" is passed to Dial and Listen API. Fixes #1769. R=bradfitz, rsc CC=golang-dev https://golang.org/cl/4438066
122 lines
3.0 KiB
Go
122 lines
3.0 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
// TODO(cw): ListenPacket test, Read() test, ipv6 test &
|
|
// Dial()/Listen() level tests
|
|
|
|
package net
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
const ICMP_ECHO_REQUEST = 8
|
|
const ICMP_ECHO_REPLY = 0
|
|
|
|
// returns a suitable 'ping request' packet, with id & seq and a
|
|
// payload length of pktlen
|
|
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
|
|
p := make([]byte, pktlen)
|
|
copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
|
|
|
|
p[0] = ICMP_ECHO_REQUEST // type
|
|
p[1] = 0 // code
|
|
p[2] = 0 // cksum
|
|
p[3] = 0 // cksum
|
|
p[4] = uint8(id >> 8) // id
|
|
p[5] = uint8(id & 0xff) // id
|
|
p[6] = uint8(seq >> 8) // sequence
|
|
p[7] = uint8(seq & 0xff) // sequence
|
|
|
|
// calculate icmp checksum
|
|
cklen := len(p)
|
|
s := uint32(0)
|
|
for i := 0; i < (cklen - 1); i += 2 {
|
|
s += uint32(p[i+1])<<8 | uint32(p[i])
|
|
}
|
|
if cklen&1 == 1 {
|
|
s += uint32(p[cklen-1])
|
|
}
|
|
s = (s >> 16) + (s & 0xffff)
|
|
s = s + (s >> 16)
|
|
|
|
// place checksum back in header; using ^= avoids the
|
|
// assumption the checksum bytes are zero
|
|
p[2] ^= uint8(^s & 0xff)
|
|
p[3] ^= uint8(^s >> 8)
|
|
|
|
return p
|
|
}
|
|
|
|
func parsePingReply(p []byte) (id, seq int) {
|
|
id = int(p[4])<<8 | int(p[5])
|
|
seq = int(p[6])<<8 | int(p[7])
|
|
return
|
|
}
|
|
|
|
var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
|
|
// 127.0.0.1 because this is an IPv4-specific test.
|
|
var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
|
|
|
|
// test (raw) IP socket using ICMP
|
|
func TestICMP(t *testing.T) {
|
|
if os.Getuid() != 0 {
|
|
t.Logf("test disabled; must be root")
|
|
return
|
|
}
|
|
|
|
var (
|
|
laddr *IPAddr
|
|
err os.Error
|
|
)
|
|
if *srchost != "" {
|
|
laddr, err = ResolveIPAddr("ip4", *srchost)
|
|
if err != nil {
|
|
t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
|
|
}
|
|
}
|
|
|
|
raddr, err := ResolveIPAddr("ip4", *dsthost)
|
|
if err != nil {
|
|
t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
|
|
}
|
|
|
|
c, err := ListenIP("ip4:icmp", laddr)
|
|
if err != nil {
|
|
t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
|
|
}
|
|
|
|
sendid := os.Getpid() & 0xffff
|
|
const sendseq = 61455
|
|
const pingpktlen = 128
|
|
sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
|
|
|
|
n, err := c.WriteToIP(sendpkt, raddr)
|
|
if err != nil || n != pingpktlen {
|
|
t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
|
|
}
|
|
|
|
c.SetTimeout(100e6)
|
|
resp := make([]byte, 1024)
|
|
for {
|
|
n, from, err := c.ReadFrom(resp)
|
|
if err != nil {
|
|
t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
|
|
}
|
|
if resp[0] != ICMP_ECHO_REPLY {
|
|
continue
|
|
}
|
|
rcvid, rcvseq := parsePingReply(resp)
|
|
if rcvid != sendid || rcvseq != sendseq {
|
|
t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
|
|
}
|
|
return
|
|
}
|
|
t.Fatalf("saw no ping return")
|
|
}
|