1
2
3
4
5
6
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
21
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
27 p[1] = 0
28 p[2] = 0
29 p[3] = 0
30 p[4] = uint8(id >> 8)
31 p[5] = uint8(id & 0xff)
32 p[6] = uint8(seq >> 8)
33 p[7] = uint8(seq & 0xff)
34
35
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
48
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
63 var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
64
65
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 }