"README.rst" did not exist on "e2492b10d0199b71f9d8ffbf925beec69026d006"
ipraw_test.go 7.94 KB
Newer Older
1 2 3 4
// 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.

5 6
// +build !plan9

7 8 9 10
package net

import (
	"bytes"
Mikio Hara's avatar
Mikio Hara committed
11
	"errors"
12
	"os"
13
	"reflect"
14
	"testing"
15
	"time"
16 17
)

18 19 20 21 22 23 24 25 26 27 28 29 30 31
var resolveIPAddrTests = []struct {
	net     string
	litAddr string
	addr    *IPAddr
	err     error
}{
	{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
	{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
	{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},

	{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
	{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
	{"ip6:icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},

32 33 34
	{"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior
	{"", "::1", &IPAddr{IP: ParseIP("::1")}, nil},           // Go 1.0 behavior

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
	{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
	{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
	{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
}

func TestResolveIPAddr(t *testing.T) {
	for _, tt := range resolveIPAddrTests {
		addr, err := ResolveIPAddr(tt.net, tt.litAddr)
		if err != tt.err {
			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
		}
		if !reflect.DeepEqual(addr, tt.addr) {
			t.Fatalf("got %#v; expected %#v", addr, tt.addr)
		}
	}
}

Mikio Hara's avatar
Mikio Hara committed
52
var icmpEchoTests = []struct {
53 54 55 56
	net   string
	laddr string
	raddr string
}{
Mikio Hara's avatar
Mikio Hara committed
57 58
	{"ip4:icmp", "0.0.0.0", "127.0.0.1"},
	{"ip6:ipv6-icmp", "::", "::1"},
59 60
}

Mikio Hara's avatar
Mikio Hara committed
61
func TestConnICMPEcho(t *testing.T) {
62
	if os.Getuid() != 0 {
Dave Cheney's avatar
Dave Cheney committed
63
		t.Skip("skipping test; must be root")
64 65
	}

Mikio Hara's avatar
Mikio Hara committed
66 67 68 69 70 71
	for i, tt := range icmpEchoTests {
		net, _, err := parseNetwork(tt.net)
		if err != nil {
			t.Fatalf("parseNetwork failed: %v", err)
		}
		if net == "ip6" && !supportsIPv6 {
72
			continue
73 74
		}

Mikio Hara's avatar
Mikio Hara committed
75 76 77 78 79 80
		c, err := Dial(tt.net, tt.raddr)
		if err != nil {
			t.Fatalf("Dial failed: %v", err)
		}
		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
		defer c.Close()
81

Mikio Hara's avatar
Mikio Hara committed
82 83 84 85 86 87 88 89 90 91 92 93
		typ := icmpv4EchoRequest
		if net == "ip6" {
			typ = icmpv6EchoRequest
		}
		xid, xseq := os.Getpid()&0xffff, i+1
		b, err := (&icmpMessage{
			Type: typ, Code: 0,
			Body: &icmpEcho{
				ID: xid, Seq: xseq,
				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
			},
		}).Marshal()
94
		if err != nil {
Mikio Hara's avatar
Mikio Hara committed
95
			t.Fatalf("icmpMessage.Marshal failed: %v", err)
96
		}
Mikio Hara's avatar
Mikio Hara committed
97 98 99 100 101 102 103 104 105 106 107 108 109
		if _, err := c.Write(b); err != nil {
			t.Fatalf("Conn.Write failed: %v", err)
		}
		var m *icmpMessage
		for {
			if _, err := c.Read(b); err != nil {
				t.Fatalf("Conn.Read failed: %v", err)
			}
			if net == "ip4" {
				b = ipv4Payload(b)
			}
			if m, err = parseICMPMessage(b); err != nil {
				t.Fatalf("parseICMPMessage failed: %v", err)
Mikio Hara's avatar
Mikio Hara committed
110
			}
Mikio Hara's avatar
Mikio Hara committed
111 112
			switch m.Type {
			case icmpv4EchoRequest, icmpv6EchoRequest:
Mikio Hara's avatar
Mikio Hara committed
113 114
				continue
			}
Mikio Hara's avatar
Mikio Hara committed
115
			break
116
		}
Mikio Hara's avatar
Mikio Hara committed
117 118 119 120 121 122 123
		switch p := m.Body.(type) {
		case *icmpEcho:
			if p.ID != xid || p.Seq != xseq {
				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
			}
		default:
			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
124 125 126 127
		}
	}
}

Mikio Hara's avatar
Mikio Hara committed
128 129 130
func TestPacketConnICMPEcho(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("skipping test; must be root")
131 132
	}

Mikio Hara's avatar
Mikio Hara committed
133 134
	for i, tt := range icmpEchoTests {
		net, _, err := parseNetwork(tt.net)
135
		if err != nil {
Mikio Hara's avatar
Mikio Hara committed
136
			t.Fatalf("parseNetwork failed: %v", err)
137
		}
Mikio Hara's avatar
Mikio Hara committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
		if net == "ip6" && !supportsIPv6 {
			continue
		}

		c, err := ListenPacket(tt.net, tt.laddr)
		if err != nil {
			t.Fatalf("ListenPacket failed: %v", err)
		}
		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
		defer c.Close()

		ra, err := ResolveIPAddr(tt.net, tt.raddr)
		if err != nil {
			t.Fatalf("ResolveIPAddr failed: %v", err)
		}
		typ := icmpv4EchoRequest
		if net == "ip6" {
			typ = icmpv6EchoRequest
		}
		xid, xseq := os.Getpid()&0xffff, i+1
		b, err := (&icmpMessage{
			Type: typ, Code: 0,
			Body: &icmpEcho{
				ID: xid, Seq: xseq,
				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
			},
		}).Marshal()
		if err != nil {
			t.Fatalf("icmpMessage.Marshal failed: %v", err)
		}
		if _, err := c.WriteTo(b, ra); err != nil {
			t.Fatalf("PacketConn.WriteTo failed: %v", err)
		}
		var m *icmpMessage
		for {
			if _, _, err := c.ReadFrom(b); err != nil {
				t.Fatalf("PacketConn.ReadFrom failed: %v", err)
Mikio Hara's avatar
Mikio Hara committed
175
			}
Mikio Hara's avatar
Mikio Hara committed
176 177 178 179 180 181 182 183 184
			// TODO: fix issue 3944
			//if net == "ip4" {
			//	b = ipv4Payload(b)
			//}
			if m, err = parseICMPMessage(b); err != nil {
				t.Fatalf("parseICMPMessage failed: %v", err)
			}
			switch m.Type {
			case icmpv4EchoRequest, icmpv6EchoRequest:
Mikio Hara's avatar
Mikio Hara committed
185 186
				continue
			}
Mikio Hara's avatar
Mikio Hara committed
187 188 189 190 191 192 193 194 195
			break
		}
		switch p := m.Body.(type) {
		case *icmpEcho:
			if p.ID != xid || p.Seq != xseq {
				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
			}
		default:
			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
196
		}
197
	}
Mikio Hara's avatar
Mikio Hara committed
198
}
199

Mikio Hara's avatar
Mikio Hara committed
200 201 202
func ipv4Payload(b []byte) []byte {
	if len(b) < 20 {
		return b
203
	}
Mikio Hara's avatar
Mikio Hara committed
204 205
	hdrlen := int(b[0]&0x0f) << 2
	return b[hdrlen:]
206 207 208
}

const (
Mikio Hara's avatar
Mikio Hara committed
209 210 211 212
	icmpv4EchoRequest = 8
	icmpv4EchoReply   = 0
	icmpv6EchoRequest = 128
	icmpv6EchoReply   = 129
213 214
)

Mikio Hara's avatar
Mikio Hara committed
215 216 217 218 219 220
// icmpMessage represents an ICMP message.
type icmpMessage struct {
	Type     int             // type
	Code     int             // code
	Checksum int             // checksum
	Body     icmpMessageBody // body
221 222
}

Mikio Hara's avatar
Mikio Hara committed
223 224 225 226 227
// icmpMessageBody represents an ICMP message body.
type icmpMessageBody interface {
	Len() int
	Marshal() ([]byte, error)
}
228

Mikio Hara's avatar
Mikio Hara committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
// Marshal returns the binary enconding of the ICMP echo request or
// reply message m.
func (m *icmpMessage) Marshal() ([]byte, error) {
	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
	if m.Body != nil && m.Body.Len() != 0 {
		mb, err := m.Body.Marshal()
		if err != nil {
			return nil, err
		}
		b = append(b, mb...)
	}
	switch m.Type {
	case icmpv6EchoRequest, icmpv6EchoReply:
		return b, nil
	}
	csumcv := len(b) - 1 // checksum coverage
245
	s := uint32(0)
Mikio Hara's avatar
Mikio Hara committed
246
	for i := 0; i < csumcv; i += 2 {
247 248
		s += uint32(b[i+1])<<8 | uint32(b[i])
	}
Mikio Hara's avatar
Mikio Hara committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
	if csumcv&1 == 0 {
		s += uint32(b[csumcv])
	}
	s = s>>16 + s&0xffff
	s = s + s>>16
	// Place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero.
	b[2] ^= byte(^s & 0xff)
	b[3] ^= byte(^s >> 8)
	return b, nil
}

// parseICMPMessage parses b as an ICMP message.
func parseICMPMessage(b []byte) (*icmpMessage, error) {
	msglen := len(b)
	if msglen < 4 {
		return nil, errors.New("message too short")
	}
	m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
	if msglen > 4 {
		var err error
		switch m.Type {
		case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
			m.Body, err = parseICMPEcho(b[4:])
			if err != nil {
				return nil, err
			}
		}
277
	}
Mikio Hara's avatar
Mikio Hara committed
278 279
	return m, nil
}
280

Mikio Hara's avatar
Mikio Hara committed
281 282 283 284 285
// imcpEcho represenets an ICMP echo request or reply message body.
type icmpEcho struct {
	ID   int    // identifier
	Seq  int    // sequence number
	Data []byte // data
286 287
}

Mikio Hara's avatar
Mikio Hara committed
288 289 290 291 292
func (p *icmpEcho) Len() int {
	if p == nil {
		return 0
	}
	return 4 + len(p.Data)
293 294
}

Mikio Hara's avatar
Mikio Hara committed
295 296 297 298 299 300 301 302
// Marshal returns the binary enconding of the ICMP echo request or
// reply message body p.
func (p *icmpEcho) Marshal() ([]byte, error) {
	b := make([]byte, 4+len(p.Data))
	b[0], b[1] = byte(p.ID>>8), byte(p.ID&0xff)
	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
	copy(b[4:], p.Data)
	return b, nil
303 304
}

Mikio Hara's avatar
Mikio Hara committed
305 306 307 308 309 310 311 312 313 314
// parseICMPEcho parses b as an ICMP echo request or reply message
// body.
func parseICMPEcho(b []byte) (*icmpEcho, error) {
	bodylen := len(b)
	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
	if bodylen > 4 {
		p.Data = make([]byte, bodylen-4)
		copy(p.Data, b[4:])
	}
	return p, nil
315
}
316 317 318 319 320 321 322 323 324 325 326 327

var ipConnLocalNameTests = []struct {
	net   string
	laddr *IPAddr
}{
	{"ip4:icmp", &IPAddr{IP: IPv4(127, 0, 0, 1)}},
	{"ip4:icmp", &IPAddr{}},
	{"ip4:icmp", nil},
}

func TestIPConnLocalName(t *testing.T) {
	if os.Getuid() != 0 {
Dave Cheney's avatar
Dave Cheney committed
328
		t.Skip("skipping test; must be root")
329 330 331 332 333
	}

	for _, tt := range ipConnLocalNameTests {
		c, err := ListenIP(tt.net, tt.laddr)
		if err != nil {
Mikio Hara's avatar
Mikio Hara committed
334
			t.Fatalf("ListenIP failed: %v", err)
335 336
		}
		defer c.Close()
Mikio Hara's avatar
Mikio Hara committed
337 338
		if la := c.LocalAddr(); la == nil {
			t.Fatal("IPConn.LocalAddr failed")
339 340 341
		}
	}
}