1// Copyright 2012 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
5package ipv4
6
7import (
8	"bytes"
9	"encoding/binary"
10	"net"
11	"reflect"
12	"runtime"
13	"strings"
14	"testing"
15
16	"golang.org/x/net/internal/socket"
17)
18
19type headerTest struct {
20	wireHeaderFromKernel          []byte
21	wireHeaderToKernel            []byte
22	wireHeaderFromTradBSDKernel   []byte
23	wireHeaderToTradBSDKernel     []byte
24	wireHeaderFromFreeBSD10Kernel []byte
25	wireHeaderToFreeBSD10Kernel   []byte
26	*Header
27}
28
29var headerLittleEndianTests = []headerTest{
30	// TODO(mikio): Add platform dependent wire header formats when
31	// we support new platforms.
32	{
33		wireHeaderFromKernel: []byte{
34			0x45, 0x01, 0xbe, 0xef,
35			0xca, 0xfe, 0x45, 0xdc,
36			0xff, 0x01, 0xde, 0xad,
37			172, 16, 254, 254,
38			192, 168, 0, 1,
39		},
40		wireHeaderToKernel: []byte{
41			0x45, 0x01, 0xbe, 0xef,
42			0xca, 0xfe, 0x45, 0xdc,
43			0xff, 0x01, 0xde, 0xad,
44			172, 16, 254, 254,
45			192, 168, 0, 1,
46		},
47		wireHeaderFromTradBSDKernel: []byte{
48			0x45, 0x01, 0xdb, 0xbe,
49			0xca, 0xfe, 0xdc, 0x45,
50			0xff, 0x01, 0xde, 0xad,
51			172, 16, 254, 254,
52			192, 168, 0, 1,
53		},
54		wireHeaderToTradBSDKernel: []byte{
55			0x45, 0x01, 0xef, 0xbe,
56			0xca, 0xfe, 0xdc, 0x45,
57			0xff, 0x01, 0xde, 0xad,
58			172, 16, 254, 254,
59			192, 168, 0, 1,
60		},
61		wireHeaderFromFreeBSD10Kernel: []byte{
62			0x45, 0x01, 0xef, 0xbe,
63			0xca, 0xfe, 0xdc, 0x45,
64			0xff, 0x01, 0xde, 0xad,
65			172, 16, 254, 254,
66			192, 168, 0, 1,
67		},
68		wireHeaderToFreeBSD10Kernel: []byte{
69			0x45, 0x01, 0xef, 0xbe,
70			0xca, 0xfe, 0xdc, 0x45,
71			0xff, 0x01, 0xde, 0xad,
72			172, 16, 254, 254,
73			192, 168, 0, 1,
74		},
75		Header: &Header{
76			Version:  Version,
77			Len:      HeaderLen,
78			TOS:      1,
79			TotalLen: 0xbeef,
80			ID:       0xcafe,
81			Flags:    DontFragment,
82			FragOff:  1500,
83			TTL:      255,
84			Protocol: 1,
85			Checksum: 0xdead,
86			Src:      net.IPv4(172, 16, 254, 254),
87			Dst:      net.IPv4(192, 168, 0, 1),
88		},
89	},
90
91	// with option headers
92	{
93		wireHeaderFromKernel: []byte{
94			0x46, 0x01, 0xbe, 0xf3,
95			0xca, 0xfe, 0x45, 0xdc,
96			0xff, 0x01, 0xde, 0xad,
97			172, 16, 254, 254,
98			192, 168, 0, 1,
99			0xff, 0xfe, 0xfe, 0xff,
100		},
101		wireHeaderToKernel: []byte{
102			0x46, 0x01, 0xbe, 0xf3,
103			0xca, 0xfe, 0x45, 0xdc,
104			0xff, 0x01, 0xde, 0xad,
105			172, 16, 254, 254,
106			192, 168, 0, 1,
107			0xff, 0xfe, 0xfe, 0xff,
108		},
109		wireHeaderFromTradBSDKernel: []byte{
110			0x46, 0x01, 0xdb, 0xbe,
111			0xca, 0xfe, 0xdc, 0x45,
112			0xff, 0x01, 0xde, 0xad,
113			172, 16, 254, 254,
114			192, 168, 0, 1,
115			0xff, 0xfe, 0xfe, 0xff,
116		},
117		wireHeaderToTradBSDKernel: []byte{
118			0x46, 0x01, 0xf3, 0xbe,
119			0xca, 0xfe, 0xdc, 0x45,
120			0xff, 0x01, 0xde, 0xad,
121			172, 16, 254, 254,
122			192, 168, 0, 1,
123			0xff, 0xfe, 0xfe, 0xff,
124		},
125		wireHeaderFromFreeBSD10Kernel: []byte{
126			0x46, 0x01, 0xf3, 0xbe,
127			0xca, 0xfe, 0xdc, 0x45,
128			0xff, 0x01, 0xde, 0xad,
129			172, 16, 254, 254,
130			192, 168, 0, 1,
131			0xff, 0xfe, 0xfe, 0xff,
132		},
133		wireHeaderToFreeBSD10Kernel: []byte{
134			0x46, 0x01, 0xf3, 0xbe,
135			0xca, 0xfe, 0xdc, 0x45,
136			0xff, 0x01, 0xde, 0xad,
137			172, 16, 254, 254,
138			192, 168, 0, 1,
139			0xff, 0xfe, 0xfe, 0xff,
140		},
141		Header: &Header{
142			Version:  Version,
143			Len:      HeaderLen + 4,
144			TOS:      1,
145			TotalLen: 0xbef3,
146			ID:       0xcafe,
147			Flags:    DontFragment,
148			FragOff:  1500,
149			TTL:      255,
150			Protocol: 1,
151			Checksum: 0xdead,
152			Src:      net.IPv4(172, 16, 254, 254),
153			Dst:      net.IPv4(192, 168, 0, 1),
154			Options:  []byte{0xff, 0xfe, 0xfe, 0xff},
155		},
156	},
157}
158
159func TestMarshalHeader(t *testing.T) {
160	for i, tt := range []struct {
161		h   *Header
162		err error
163	}{
164		{nil, errNilHeader},
165		{&Header{Len: HeaderLen - 1}, errHeaderTooShort},
166	} {
167		if _, err := tt.h.Marshal(); err != tt.err {
168			t.Errorf("#%d: got %v; want %v", i, err, tt.err)
169		}
170	}
171
172	if socket.NativeEndian != binary.LittleEndian {
173		t.Skip("no test for non-little endian machine yet")
174	}
175	for _, tt := range headerLittleEndianTests {
176		b, err := tt.Header.Marshal()
177		if err != nil {
178			t.Fatal(err)
179		}
180		var wh []byte
181		switch runtime.GOOS {
182		case "darwin", "ios", "dragonfly", "netbsd":
183			wh = tt.wireHeaderToTradBSDKernel
184		case "freebsd":
185			switch {
186			case freebsdVersion < 1000000:
187				wh = tt.wireHeaderToTradBSDKernel
188			case 1000000 <= freebsdVersion && freebsdVersion < 1100000:
189				wh = tt.wireHeaderToFreeBSD10Kernel
190			default:
191				wh = tt.wireHeaderToKernel
192			}
193		default:
194			wh = tt.wireHeaderToKernel
195		}
196		if !bytes.Equal(b, wh) {
197			t.Fatalf("got %#v; want %#v", b, wh)
198		}
199	}
200}
201
202func TestParseHeader(t *testing.T) {
203	for i, tt := range []struct {
204		h   *Header
205		wh  []byte
206		err error
207	}{
208		{nil, nil, errNilHeader},
209		{&Header{}, nil, errNilHeader},
210		{&Header{}, make([]byte, HeaderLen-1), errHeaderTooShort},
211		{&Header{}, []byte{
212			0x46, 0x00, 0x00, 0x00,
213			0x00, 0x00, 0x00, 0x00,
214			0x00, 0x00, 0x00, 0x00,
215			0x00, 0x00, 0x00, 0x00,
216			0x00, 0x00, 0x00, 0x00,
217		}, errExtHeaderTooShort},
218	} {
219		if err := tt.h.Parse(tt.wh); err != tt.err {
220			t.Fatalf("#%d: got %v; want %v", i, err, tt.err)
221		}
222	}
223
224	if socket.NativeEndian != binary.LittleEndian {
225		t.Skip("no test for big endian machine yet")
226	}
227	for _, tt := range headerLittleEndianTests {
228		var wh []byte
229		switch runtime.GOOS {
230		case "darwin", "ios", "dragonfly", "netbsd":
231			wh = tt.wireHeaderFromTradBSDKernel
232		case "freebsd":
233			switch {
234			case freebsdVersion < 1000000:
235				wh = tt.wireHeaderFromTradBSDKernel
236			case 1000000 <= freebsdVersion && freebsdVersion < 1100000:
237				wh = tt.wireHeaderFromFreeBSD10Kernel
238			default:
239				wh = tt.wireHeaderFromKernel
240			}
241		default:
242			wh = tt.wireHeaderFromKernel
243		}
244		h, err := ParseHeader(wh)
245		if err != nil {
246			t.Fatal(err)
247		}
248		if err := h.Parse(wh); err != nil {
249			t.Fatal(err)
250		}
251		if !reflect.DeepEqual(h, tt.Header) {
252			t.Fatalf("got %#v; want %#v", h, tt.Header)
253		}
254		s := h.String()
255		if strings.Contains(s, ",") {
256			t.Fatalf("should be space-separated values: %s", s)
257		}
258	}
259}
260