1package dns
2
3import (
4	"io/ioutil"
5	"os"
6	"path/filepath"
7	"strings"
8	"testing"
9)
10
11const normal string = `
12# Comment
13domain somedomain.com
14nameserver 10.28.10.2
15nameserver 11.28.10.1
16`
17
18const missingNewline string = `
19domain somedomain.com
20nameserver 10.28.10.2
21nameserver 11.28.10.1` // <- NOTE: NO newline.
22
23func testConfig(t *testing.T, data string) {
24	cc, err := ClientConfigFromReader(strings.NewReader(data))
25	if err != nil {
26		t.Errorf("error parsing resolv.conf: %v", err)
27	}
28	if l := len(cc.Servers); l != 2 {
29		t.Errorf("incorrect number of nameservers detected: %d", l)
30	}
31	if l := len(cc.Search); l != 1 {
32		t.Errorf("domain directive not parsed correctly: %v", cc.Search)
33	} else {
34		if cc.Search[0] != "somedomain.com" {
35			t.Errorf("domain is unexpected: %v", cc.Search[0])
36		}
37	}
38}
39
40func TestNameserver(t *testing.T)          { testConfig(t, normal) }
41func TestMissingFinalNewLine(t *testing.T) { testConfig(t, missingNewline) }
42
43func TestNdots(t *testing.T) {
44	ndotsVariants := map[string]int{
45		"options ndots:0":  0,
46		"options ndots:1":  1,
47		"options ndots:15": 15,
48		"options ndots:16": 15,
49		"options ndots:-1": 0,
50		"":                 1,
51	}
52
53	for data := range ndotsVariants {
54		cc, err := ClientConfigFromReader(strings.NewReader(data))
55		if err != nil {
56			t.Errorf("error parsing resolv.conf: %v", err)
57		}
58		if cc.Ndots != ndotsVariants[data] {
59			t.Errorf("Ndots not properly parsed: (Expected: %d / Was: %d)", ndotsVariants[data], cc.Ndots)
60		}
61	}
62}
63
64func TestClientConfigFromReaderAttempts(t *testing.T) {
65	testCases := []struct {
66		data     string
67		expected int
68	}{
69		{data: "options attempts:0", expected: 1},
70		{data: "options attempts:1", expected: 1},
71		{data: "options attempts:15", expected: 15},
72		{data: "options attempts:16", expected: 16},
73		{data: "options attempts:-1", expected: 1},
74		{data: "options attempt:", expected: 2},
75	}
76
77	for _, test := range testCases {
78		test := test
79		t.Run(strings.Replace(test.data, ":", " ", -1), func(t *testing.T) {
80			t.Parallel()
81
82			cc, err := ClientConfigFromReader(strings.NewReader(test.data))
83			if err != nil {
84				t.Errorf("error parsing resolv.conf: %v", err)
85			}
86			if cc.Attempts != test.expected {
87				t.Errorf("A attempts not properly parsed: (Expected: %d / Was: %d)", test.expected, cc.Attempts)
88			}
89		})
90	}
91}
92
93func TestReadFromFile(t *testing.T) {
94	tempDir, err := ioutil.TempDir("", "")
95	if err != nil {
96		t.Fatalf("tempDir: %v", err)
97	}
98	defer os.RemoveAll(tempDir)
99
100	path := filepath.Join(tempDir, "resolv.conf")
101	if err := ioutil.WriteFile(path, []byte(normal), 0644); err != nil {
102		t.Fatalf("writeFile: %v", err)
103	}
104	cc, err := ClientConfigFromFile(path)
105	if err != nil {
106		t.Errorf("error parsing resolv.conf: %v", err)
107	}
108	if l := len(cc.Servers); l != 2 {
109		t.Errorf("incorrect number of nameservers detected: %d", l)
110	}
111	if l := len(cc.Search); l != 1 {
112		t.Errorf("domain directive not parsed correctly: %v", cc.Search)
113	} else {
114		if cc.Search[0] != "somedomain.com" {
115			t.Errorf("domain is unexpected: %v", cc.Search[0])
116		}
117	}
118}
119
120func TestNameListNdots1(t *testing.T) {
121	cfg := ClientConfig{
122		Ndots: 1,
123	}
124	// fqdn should be only result returned
125	names := cfg.NameList("miek.nl.")
126	if len(names) != 1 {
127		t.Errorf("NameList returned != 1 names: %v", names)
128	} else if names[0] != "miek.nl." {
129		t.Errorf("NameList didn't return sent fqdn domain: %v", names[0])
130	}
131
132	cfg.Search = []string{
133		"test",
134	}
135	// Sent domain has NDots and search
136	names = cfg.NameList("miek.nl")
137	if len(names) != 2 {
138		t.Errorf("NameList returned != 2 names: %v", names)
139	} else if names[0] != "miek.nl." {
140		t.Errorf("NameList didn't return sent domain first: %v", names[0])
141	} else if names[1] != "miek.nl.test." {
142		t.Errorf("NameList didn't return search last: %v", names[1])
143	}
144}
145func TestNameListNdots2(t *testing.T) {
146	cfg := ClientConfig{
147		Ndots: 2,
148	}
149
150	// Sent domain has less than NDots and search
151	cfg.Search = []string{
152		"test",
153	}
154	names := cfg.NameList("miek.nl")
155
156	if len(names) != 2 {
157		t.Errorf("NameList returned != 2 names: %v", names)
158	} else if names[0] != "miek.nl.test." {
159		t.Errorf("NameList didn't return search first: %v", names[0])
160	} else if names[1] != "miek.nl." {
161		t.Errorf("NameList didn't return sent domain last: %v", names[1])
162	}
163}
164
165func TestNameListNdots0(t *testing.T) {
166	cfg := ClientConfig{
167		Ndots: 0,
168	}
169	cfg.Search = []string{
170		"test",
171	}
172	// Sent domain has less than NDots and search
173	names := cfg.NameList("miek")
174	if len(names) != 2 {
175		t.Errorf("NameList returned != 2 names: %v", names)
176	} else if names[0] != "miek." {
177		t.Errorf("NameList didn't return search first: %v", names[0])
178	} else if names[1] != "miek.test." {
179		t.Errorf("NameList didn't return sent domain last: %v", names[1])
180	}
181}
182