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
5package net
6
7import (
8	"bytes"
9	"internal/syscall/windows"
10	"sort"
11	"testing"
12)
13
14func TestWindowsInterfaces(t *testing.T) {
15	aas, err := adapterAddresses()
16	if err != nil {
17		t.Fatal(err)
18	}
19	ift, err := Interfaces()
20	if err != nil {
21		t.Fatal(err)
22	}
23	for i, ifi := range ift {
24		aa := aas[i]
25		if len(ifi.HardwareAddr) != int(aa.PhysicalAddressLength) {
26			t.Errorf("got %d; want %d", len(ifi.HardwareAddr), aa.PhysicalAddressLength)
27		}
28		if ifi.MTU > 0x7fffffff {
29			t.Errorf("%s: got %d; want less than or equal to 1<<31 - 1", ifi.Name, ifi.MTU)
30		}
31		if ifi.Flags&FlagUp != 0 && aa.OperStatus != windows.IfOperStatusUp {
32			t.Errorf("%s: got %v; should not include FlagUp", ifi.Name, ifi.Flags)
33		}
34		if ifi.Flags&FlagLoopback != 0 && aa.IfType != windows.IF_TYPE_SOFTWARE_LOOPBACK {
35			t.Errorf("%s: got %v; should not include FlagLoopback", ifi.Name, ifi.Flags)
36		}
37		if _, _, err := addrPrefixTable(aa); err != nil {
38			t.Errorf("%s: %v", ifi.Name, err)
39		}
40	}
41}
42
43type byAddrLen []IPNet
44
45func (ps byAddrLen) Len() int { return len(ps) }
46
47func (ps byAddrLen) Less(i, j int) bool {
48	if n := bytes.Compare(ps[i].IP, ps[j].IP); n != 0 {
49		return n < 0
50	}
51	if n := bytes.Compare(ps[i].Mask, ps[j].Mask); n != 0 {
52		return n < 0
53	}
54	return false
55}
56
57func (ps byAddrLen) Swap(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
58
59var windowsAddrPrefixLenTests = []struct {
60	pfxs []IPNet
61	ip   IP
62	out  int
63}{
64	{
65		[]IPNet{
66			{IP: IPv4(172, 16, 0, 0), Mask: IPv4Mask(255, 255, 0, 0)},
67			{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)},
68			{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 128)},
69			{IP: IPv4(192, 168, 0, 0), Mask: IPv4Mask(255, 255, 255, 192)},
70		},
71		IPv4(192, 168, 0, 1),
72		26,
73	},
74	{
75		[]IPNet{
76			{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"))},
77			{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"))},
78			{IP: ParseIP("2001:db8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"))},
79		},
80		ParseIP("2001:db8::1"),
81		126,
82	},
83
84	// Fallback cases. It may happen on Windows XP or 2003 server.
85	{
86		[]IPNet{
87			{IP: IPv4(127, 0, 0, 0).To4(), Mask: IPv4Mask(255, 0, 0, 0)},
88			{IP: IPv4(10, 0, 0, 0).To4(), Mask: IPv4Mask(255, 0, 0, 0)},
89			{IP: IPv4(172, 16, 0, 0).To4(), Mask: IPv4Mask(255, 255, 0, 0)},
90			{IP: IPv4(192, 168, 255, 0), Mask: IPv4Mask(255, 255, 255, 0)},
91			{IP: IPv4zero, Mask: IPv4Mask(0, 0, 0, 0)},
92		},
93		IPv4(192, 168, 0, 1),
94		8 * IPv4len,
95	},
96	{
97		nil,
98		IPv4(192, 168, 0, 1),
99		8 * IPv4len,
100	},
101	{
102		[]IPNet{
103			{IP: IPv6loopback, Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))},
104			{IP: ParseIP("2001:db8:1::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"))},
105			{IP: ParseIP("2001:db8:2::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8"))},
106			{IP: ParseIP("2001:db8:3::"), Mask: IPMask(ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc"))},
107			{IP: IPv6unspecified, Mask: IPMask(ParseIP("::"))},
108		},
109		ParseIP("2001:db8::1"),
110		8 * IPv6len,
111	},
112	{
113		nil,
114		ParseIP("2001:db8::1"),
115		8 * IPv6len,
116	},
117}
118
119func TestWindowsAddrPrefixLen(t *testing.T) {
120	for i, tt := range windowsAddrPrefixLenTests {
121		sort.Sort(byAddrLen(tt.pfxs))
122		l := addrPrefixLen(tt.pfxs, tt.ip)
123		if l != tt.out {
124			t.Errorf("#%d: got %d; want %d", i, l, tt.out)
125		}
126		sort.Sort(sort.Reverse(byAddrLen(tt.pfxs)))
127		l = addrPrefixLen(tt.pfxs, tt.ip)
128		if l != tt.out {
129			t.Errorf("#%d: got %d; want %d", i, l, tt.out)
130		}
131	}
132}
133