• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 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//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6
7package net
8
9import (
10	"net/netip"
11	"reflect"
12	"testing"
13)
14
15func TestSortByRFC6724(t *testing.T) {
16	tests := []struct {
17		in      []IPAddr
18		srcs    []netip.Addr
19		want    []IPAddr
20		reverse bool // also test it starting backwards
21	}{
22		// Examples from RFC 6724 section 10.2:
23
24		// Prefer matching scope.
25		{
26			in: []IPAddr{
27				{IP: ParseIP("2001:db8:1::1")},
28				{IP: ParseIP("198.51.100.121")},
29			},
30			srcs: []netip.Addr{
31				netip.MustParseAddr("2001:db8:1::2"),
32				netip.MustParseAddr("169.254.13.78"),
33			},
34			want: []IPAddr{
35				{IP: ParseIP("2001:db8:1::1")},
36				{IP: ParseIP("198.51.100.121")},
37			},
38			reverse: true,
39		},
40
41		// Prefer matching scope.
42		{
43			in: []IPAddr{
44				{IP: ParseIP("2001:db8:1::1")},
45				{IP: ParseIP("198.51.100.121")},
46			},
47			srcs: []netip.Addr{
48				netip.MustParseAddr("fe80::1"),
49				netip.MustParseAddr("198.51.100.117"),
50			},
51			want: []IPAddr{
52				{IP: ParseIP("198.51.100.121")},
53				{IP: ParseIP("2001:db8:1::1")},
54			},
55			reverse: true,
56		},
57
58		// Prefer higher precedence.
59		{
60			in: []IPAddr{
61				{IP: ParseIP("2001:db8:1::1")},
62				{IP: ParseIP("10.1.2.3")},
63			},
64			srcs: []netip.Addr{
65				netip.MustParseAddr("2001:db8:1::2"),
66				netip.MustParseAddr("10.1.2.4"),
67			},
68			want: []IPAddr{
69				{IP: ParseIP("2001:db8:1::1")},
70				{IP: ParseIP("10.1.2.3")},
71			},
72			reverse: true,
73		},
74
75		// Prefer smaller scope.
76		{
77			in: []IPAddr{
78				{IP: ParseIP("2001:db8:1::1")},
79				{IP: ParseIP("fe80::1")},
80			},
81			srcs: []netip.Addr{
82				netip.MustParseAddr("2001:db8:1::2"),
83				netip.MustParseAddr("fe80::2"),
84			},
85			want: []IPAddr{
86				{IP: ParseIP("fe80::1")},
87				{IP: ParseIP("2001:db8:1::1")},
88			},
89			reverse: true,
90		},
91
92		// Issue 13283.  Having a 10/8 source address does not
93		// mean we should prefer 23/8 destination addresses.
94		{
95			in: []IPAddr{
96				{IP: ParseIP("54.83.193.112")},
97				{IP: ParseIP("184.72.238.214")},
98				{IP: ParseIP("23.23.172.185")},
99				{IP: ParseIP("75.101.148.21")},
100				{IP: ParseIP("23.23.134.56")},
101				{IP: ParseIP("23.21.50.150")},
102			},
103			srcs: []netip.Addr{
104				netip.MustParseAddr("10.2.3.4"),
105				netip.MustParseAddr("10.2.3.4"),
106				netip.MustParseAddr("10.2.3.4"),
107				netip.MustParseAddr("10.2.3.4"),
108				netip.MustParseAddr("10.2.3.4"),
109				netip.MustParseAddr("10.2.3.4"),
110			},
111			want: []IPAddr{
112				{IP: ParseIP("54.83.193.112")},
113				{IP: ParseIP("184.72.238.214")},
114				{IP: ParseIP("23.23.172.185")},
115				{IP: ParseIP("75.101.148.21")},
116				{IP: ParseIP("23.23.134.56")},
117				{IP: ParseIP("23.21.50.150")},
118			},
119			reverse: false,
120		},
121	}
122	for i, tt := range tests {
123		inCopy := make([]IPAddr, len(tt.in))
124		copy(inCopy, tt.in)
125		srcCopy := make([]netip.Addr, len(tt.in))
126		copy(srcCopy, tt.srcs)
127		sortByRFC6724withSrcs(inCopy, srcCopy)
128		if !reflect.DeepEqual(inCopy, tt.want) {
129			t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
130		}
131		if tt.reverse {
132			copy(inCopy, tt.in)
133			copy(srcCopy, tt.srcs)
134			for j := 0; j < len(inCopy)/2; j++ {
135				k := len(inCopy) - j - 1
136				inCopy[j], inCopy[k] = inCopy[k], inCopy[j]
137				srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j]
138			}
139			sortByRFC6724withSrcs(inCopy, srcCopy)
140			if !reflect.DeepEqual(inCopy, tt.want) {
141				t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
142			}
143		}
144
145	}
146
147}
148
149func TestRFC6724PolicyTableOrder(t *testing.T) {
150	for i := 0; i < len(rfc6724policyTable)-1; i++ {
151		if !(rfc6724policyTable[i].Prefix.Bits() >= rfc6724policyTable[i+1].Prefix.Bits()) {
152			t.Errorf("rfc6724policyTable item number %d sorted in wrong order = %d bits, next item = %d bits;", i, rfc6724policyTable[i].Prefix.Bits(), rfc6724policyTable[i+1].Prefix.Bits())
153		}
154	}
155}
156
157func TestRFC6724PolicyTableContent(t *testing.T) {
158	expectedRfc6724policyTable := policyTable{
159		{
160			Prefix:     netip.MustParsePrefix("::1/128"),
161			Precedence: 50,
162			Label:      0,
163		},
164		{
165			Prefix:     netip.MustParsePrefix("::ffff:0:0/96"),
166			Precedence: 35,
167			Label:      4,
168		},
169		{
170			Prefix:     netip.MustParsePrefix("::/96"),
171			Precedence: 1,
172			Label:      3,
173		},
174		{
175			Prefix:     netip.MustParsePrefix("2001::/32"),
176			Precedence: 5,
177			Label:      5,
178		},
179		{
180			Prefix:     netip.MustParsePrefix("2002::/16"),
181			Precedence: 30,
182			Label:      2,
183		},
184		{
185			Prefix:     netip.MustParsePrefix("3ffe::/16"),
186			Precedence: 1,
187			Label:      12,
188		},
189		{
190			Prefix:     netip.MustParsePrefix("fec0::/10"),
191			Precedence: 1,
192			Label:      11,
193		},
194		{
195			Prefix:     netip.MustParsePrefix("fc00::/7"),
196			Precedence: 3,
197			Label:      13,
198		},
199		{
200			Prefix:     netip.MustParsePrefix("::/0"),
201			Precedence: 40,
202			Label:      1,
203		},
204	}
205	if !reflect.DeepEqual(rfc6724policyTable, expectedRfc6724policyTable) {
206		t.Errorf("rfc6724policyTable has wrong contend = %v; want %v", rfc6724policyTable, expectedRfc6724policyTable)
207	}
208}
209
210func TestRFC6724PolicyTableClassify(t *testing.T) {
211	tests := []struct {
212		ip   netip.Addr
213		want policyTableEntry
214	}{
215		{
216			ip: netip.MustParseAddr("127.0.0.1"),
217			want: policyTableEntry{
218				Prefix:     netip.MustParsePrefix("::ffff:0:0/96"),
219				Precedence: 35,
220				Label:      4,
221			},
222		},
223		{
224			ip: netip.MustParseAddr("2601:645:8002:a500:986f:1db8:c836:bd65"),
225			want: policyTableEntry{
226				Prefix:     netip.MustParsePrefix("::/0"),
227				Precedence: 40,
228				Label:      1,
229			},
230		},
231		{
232			ip: netip.MustParseAddr("::1"),
233			want: policyTableEntry{
234				Prefix:     netip.MustParsePrefix("::1/128"),
235				Precedence: 50,
236				Label:      0,
237			},
238		},
239		{
240			ip: netip.MustParseAddr("2002::ab12"),
241			want: policyTableEntry{
242				Prefix:     netip.MustParsePrefix("2002::/16"),
243				Precedence: 30,
244				Label:      2,
245			},
246		},
247	}
248	for i, tt := range tests {
249		got := rfc6724policyTable.Classify(tt.ip)
250		if !reflect.DeepEqual(got, tt.want) {
251			t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want)
252		}
253	}
254}
255
256func TestRFC6724ClassifyScope(t *testing.T) {
257	tests := []struct {
258		ip   netip.Addr
259		want scope
260	}{
261		{netip.MustParseAddr("127.0.0.1"), scopeLinkLocal},   // rfc6724#section-3.2
262		{netip.MustParseAddr("::1"), scopeLinkLocal},         // rfc4007#section-4
263		{netip.MustParseAddr("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
264		{netip.MustParseAddr("fec0::1"), scopeSiteLocal},
265		{netip.MustParseAddr("8.8.8.8"), scopeGlobal},
266
267		{netip.MustParseAddr("ff02::"), scopeLinkLocal},  // IPv6 multicast
268		{netip.MustParseAddr("ff05::"), scopeSiteLocal},  // IPv6 multicast
269		{netip.MustParseAddr("ff04::"), scopeAdminLocal}, // IPv6 multicast
270		{netip.MustParseAddr("ff0e::"), scopeGlobal},     // IPv6 multicast
271
272		{netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 0, 0, 0}), scopeGlobal}, // IPv4 link-local multicast as 16 bytes
273		{netip.AddrFrom16([16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe0, 2, 2, 2}), scopeGlobal}, // IPv4 global multicast as 16 bytes
274		{netip.AddrFrom4([4]byte{0xe0, 0, 0, 0}), scopeGlobal},                                       // IPv4 link-local multicast as 4 bytes
275		{netip.AddrFrom4([4]byte{0xe0, 2, 2, 2}), scopeGlobal},                                       // IPv4 global multicast as 4 bytes
276	}
277	for i, tt := range tests {
278		got := classifyScope(tt.ip)
279		if got != tt.want {
280			t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want)
281		}
282	}
283}
284
285func TestRFC6724CommonPrefixLength(t *testing.T) {
286	tests := []struct {
287		a    netip.Addr
288		b    IP
289		want int
290	}{
291		{netip.MustParseAddr("fe80::1"), ParseIP("fe80::2"), 64},
292		{netip.MustParseAddr("fe81::1"), ParseIP("fe80::2"), 15},
293		{netip.MustParseAddr("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
294		{netip.AddrFrom4([4]byte{1, 2, 3, 4}), IP{1, 2, 3, 4}, 32},
295		{netip.AddrFrom4([4]byte{1, 2, 255, 255}), IP{1, 2, 0, 0}, 16},
296		{netip.AddrFrom4([4]byte{1, 2, 127, 255}), IP{1, 2, 0, 0}, 17},
297		{netip.AddrFrom4([4]byte{1, 2, 63, 255}), IP{1, 2, 0, 0}, 18},
298		{netip.AddrFrom4([4]byte{1, 2, 31, 255}), IP{1, 2, 0, 0}, 19},
299		{netip.AddrFrom4([4]byte{1, 2, 15, 255}), IP{1, 2, 0, 0}, 20},
300		{netip.AddrFrom4([4]byte{1, 2, 7, 255}), IP{1, 2, 0, 0}, 21},
301		{netip.AddrFrom4([4]byte{1, 2, 3, 255}), IP{1, 2, 0, 0}, 22},
302		{netip.AddrFrom4([4]byte{1, 2, 1, 255}), IP{1, 2, 0, 0}, 23},
303		{netip.AddrFrom4([4]byte{1, 2, 0, 255}), IP{1, 2, 0, 0}, 24},
304	}
305	for i, tt := range tests {
306		got := commonPrefixLen(tt.a, tt.b)
307		if got != tt.want {
308			t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want)
309		}
310	}
311
312}
313