1// Copyright 2009 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	"reflect"
9	"strings"
10	"testing"
11)
12
13type staticHostEntry struct {
14	in  string
15	out []string
16}
17
18var lookupStaticHostTests = []struct {
19	name string
20	ents []staticHostEntry
21}{
22	{
23		"testdata/hosts",
24		[]staticHostEntry{
25			{"odin", []string{"127.0.0.2", "127.0.0.3", "::2"}},
26			{"thor", []string{"127.1.1.1"}},
27			{"ullr", []string{"127.1.1.2"}},
28			{"ullrhost", []string{"127.1.1.2"}},
29			{"localhost", []string{"fe80::1%lo0"}},
30		},
31	},
32	{
33		"testdata/singleline-hosts", // see golang.org/issue/6646
34		[]staticHostEntry{
35			{"odin", []string{"127.0.0.2"}},
36		},
37	},
38	{
39		"testdata/ipv4-hosts",
40		[]staticHostEntry{
41			{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
42			{"localhost.localdomain", []string{"127.0.0.3"}},
43		},
44	},
45	{
46		"testdata/ipv6-hosts", // see golang.org/issue/8996
47		[]staticHostEntry{
48			{"localhost", []string{"::1", "fe80::1", "fe80::2%lo0", "fe80::3%lo0"}},
49			{"localhost.localdomain", []string{"fe80::3%lo0"}},
50		},
51	},
52	{
53		"testdata/case-hosts", // see golang.org/issue/12806
54		[]staticHostEntry{
55			{"PreserveMe", []string{"127.0.0.1", "::1"}},
56			{"PreserveMe.local", []string{"127.0.0.1", "::1"}},
57		},
58	},
59}
60
61func TestLookupStaticHost(t *testing.T) {
62	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
63
64	for _, tt := range lookupStaticHostTests {
65		hostsFilePath = tt.name
66		for _, ent := range tt.ents {
67			testStaticHost(t, tt.name, ent)
68		}
69	}
70}
71
72func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
73	ins := []string{ent.in, absDomainName(ent.in), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
74	for _, in := range ins {
75		addrs, _ := lookupStaticHost(in)
76		if !reflect.DeepEqual(addrs, ent.out) {
77			t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
78		}
79	}
80}
81
82var lookupStaticAddrTests = []struct {
83	name string
84	ents []staticHostEntry
85}{
86	{
87		"testdata/hosts",
88		[]staticHostEntry{
89			{"255.255.255.255", []string{"broadcasthost"}},
90			{"127.0.0.2", []string{"odin"}},
91			{"127.0.0.3", []string{"odin"}},
92			{"::2", []string{"odin"}},
93			{"127.1.1.1", []string{"thor"}},
94			{"127.1.1.2", []string{"ullr", "ullrhost"}},
95			{"fe80::1%lo0", []string{"localhost"}},
96		},
97	},
98	{
99		"testdata/singleline-hosts", // see golang.org/issue/6646
100		[]staticHostEntry{
101			{"127.0.0.2", []string{"odin"}},
102		},
103	},
104	{
105		"testdata/ipv4-hosts",
106		[]staticHostEntry{
107			{"127.0.0.1", []string{"localhost"}},
108			{"127.0.0.2", []string{"localhost"}},
109			{"127.0.0.3", []string{"localhost", "localhost.localdomain"}},
110		},
111	},
112	{
113		"testdata/ipv6-hosts", // see golang.org/issue/8996
114		[]staticHostEntry{
115			{"::1", []string{"localhost"}},
116			{"fe80::1", []string{"localhost"}},
117			{"fe80::2%lo0", []string{"localhost"}},
118			{"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}},
119		},
120	},
121	{
122		"testdata/case-hosts", // see golang.org/issue/12806
123		[]staticHostEntry{
124			{"127.0.0.1", []string{"PreserveMe", "PreserveMe.local"}},
125			{"::1", []string{"PreserveMe", "PreserveMe.local"}},
126		},
127	},
128}
129
130func TestLookupStaticAddr(t *testing.T) {
131	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
132
133	for _, tt := range lookupStaticAddrTests {
134		hostsFilePath = tt.name
135		for _, ent := range tt.ents {
136			testStaticAddr(t, tt.name, ent)
137		}
138	}
139}
140
141func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) {
142	hosts := lookupStaticAddr(ent.in)
143	for i := range ent.out {
144		ent.out[i] = absDomainName(ent.out[i])
145	}
146	if !reflect.DeepEqual(hosts, ent.out) {
147		t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out)
148	}
149}
150
151func TestHostCacheModification(t *testing.T) {
152	// Ensure that programs can't modify the internals of the host cache.
153	// See https://golang.org/issues/14212.
154	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
155
156	hostsFilePath = "testdata/ipv4-hosts"
157	ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
158	testStaticHost(t, hostsFilePath, ent)
159	// Modify the addresses return by lookupStaticHost.
160	addrs, _ := lookupStaticHost(ent.in)
161	for i := range addrs {
162		addrs[i] += "junk"
163	}
164	testStaticHost(t, hostsFilePath, ent)
165
166	hostsFilePath = "testdata/ipv6-hosts"
167	ent = staticHostEntry{"::1", []string{"localhost"}}
168	testStaticAddr(t, hostsFilePath, ent)
169	// Modify the hosts return by lookupStaticAddr.
170	hosts := lookupStaticAddr(ent.in)
171	for i := range hosts {
172		hosts[i] += "junk"
173	}
174	testStaticAddr(t, hostsFilePath, ent)
175}
176
177var lookupStaticHostAliasesTest = []struct {
178	lookup, res string
179}{
180	// 127.0.0.1
181	{"test", "test"},
182	// 127.0.0.2
183	{"test2.example.com", "test2.example.com"},
184	{"2.test", "test2.example.com"},
185	// 127.0.0.3
186	{"test3.example.com", "3.test"},
187	{"3.test", "3.test"},
188	// 127.0.0.4
189	{"example.com", "example.com"},
190	// 127.0.0.5
191	{"test5.example.com", "test4.example.com"},
192	{"5.test", "test4.example.com"},
193	{"4.test", "test4.example.com"},
194	{"test4.example.com", "test4.example.com"},
195}
196
197func TestLookupStaticHostAliases(t *testing.T) {
198	defer func(orig string) { hostsFilePath = orig }(hostsFilePath)
199
200	hostsFilePath = "testdata/aliases"
201	for _, ent := range lookupStaticHostAliasesTest {
202		testLookupStaticHostAliases(t, ent.lookup, absDomainName(ent.res))
203	}
204}
205
206func testLookupStaticHostAliases(t *testing.T, lookup, lookupRes string) {
207	ins := []string{lookup, absDomainName(lookup), strings.ToLower(lookup), strings.ToUpper(lookup)}
208	for _, in := range ins {
209		_, res := lookupStaticHost(in)
210		if res != lookupRes {
211			t.Errorf("lookupStaticHost(%v): got %v, want %v", in, res, lookupRes)
212		}
213	}
214}
215