The Go Programming Language

Source file src/pkg/net/ipraw_test.go

     1	// Copyright 2009 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.
     4	
     5	// TODO(cw): ListenPacket test, Read() test, ipv6 test &
     6	// Dial()/Listen() level tests
     7	
     8	package net
     9	
    10	import (
    11		"bytes"
    12		"flag"
    13		"os"
    14		"testing"
    15	)
    16	
    17	const ICMP_ECHO_REQUEST = 8
    18	const ICMP_ECHO_REPLY = 0
    19	
    20	// returns a suitable 'ping request' packet, with id & seq and a
    21	// payload length of pktlen
    22	func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
    23		p := make([]byte, pktlen)
    24		copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))
    25	
    26		p[0] = ICMP_ECHO_REQUEST // type
    27		p[1] = 0                 // code
    28		p[2] = 0                 // cksum
    29		p[3] = 0                 // cksum
    30		p[4] = uint8(id >> 8)    // id
    31		p[5] = uint8(id & 0xff)  // id
    32		p[6] = uint8(seq >> 8)   // sequence
    33		p[7] = uint8(seq & 0xff) // sequence
    34	
    35		// calculate icmp checksum
    36		cklen := len(p)
    37		s := uint32(0)
    38		for i := 0; i < (cklen - 1); i += 2 {
    39			s += uint32(p[i+1])<<8 | uint32(p[i])
    40		}
    41		if cklen&1 == 1 {
    42			s += uint32(p[cklen-1])
    43		}
    44		s = (s >> 16) + (s & 0xffff)
    45		s = s + (s >> 16)
    46	
    47		// place checksum back in header; using ^= avoids the
    48		// assumption the checksum bytes are zero
    49		p[2] ^= uint8(^s & 0xff)
    50		p[3] ^= uint8(^s >> 8)
    51	
    52		return p
    53	}
    54	
    55	func parsePingReply(p []byte) (id, seq int) {
    56		id = int(p[4])<<8 | int(p[5])
    57		seq = int(p[6])<<8 | int(p[7])
    58		return
    59	}
    60	
    61	var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
    62	// 127.0.0.1 because this is an IPv4-specific test.
    63	var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
    64	
    65	// test (raw) IP socket using ICMP
    66	func TestICMP(t *testing.T) {
    67		if os.Getuid() != 0 {
    68			t.Logf("test disabled; must be root")
    69			return
    70		}
    71	
    72		var (
    73			laddr *IPAddr
    74			err   os.Error
    75		)
    76		if *srchost != "" {
    77			laddr, err = ResolveIPAddr("ip4", *srchost)
    78			if err != nil {
    79				t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
    80			}
    81		}
    82	
    83		raddr, err := ResolveIPAddr("ip4", *dsthost)
    84		if err != nil {
    85			t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
    86		}
    87	
    88		c, err := ListenIP("ip4:icmp", laddr)
    89		if err != nil {
    90			t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
    91		}
    92	
    93		sendid := os.Getpid() & 0xffff
    94		const sendseq = 61455
    95		const pingpktlen = 128
    96		sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))
    97	
    98		n, err := c.WriteToIP(sendpkt, raddr)
    99		if err != nil || n != pingpktlen {
   100			t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
   101		}
   102	
   103		c.SetTimeout(100e6)
   104		resp := make([]byte, 1024)
   105		for {
   106			n, from, err := c.ReadFrom(resp)
   107			if err != nil {
   108				t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
   109			}
   110			if resp[0] != ICMP_ECHO_REPLY {
   111				continue
   112			}
   113			rcvid, rcvseq := parsePingReply(resp)
   114			if rcvid != sendid || rcvseq != sendseq {
   115				t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
   116			}
   117			return
   118		}
   119		t.Fatalf("saw no ping return")
   120	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.