1 // Copyright 2013 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 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package net 8 9 import ( 10 "errors" 11 "os" 12 "reflect" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 var dnsReadConfigTests = []struct { 19 name string 20 want *dnsConfig 21 }{ 22 { 23 name: "testdata/resolv.conf", 24 want: &dnsConfig{ 25 servers: []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"}, 26 search: []string{"localdomain."}, 27 ndots: 5, 28 timeout: 10 * time.Second, 29 attempts: 3, 30 rotate: true, 31 unknownOpt: true, // the "options attempts 3" line 32 }, 33 }, 34 { 35 name: "testdata/domain-resolv.conf", 36 want: &dnsConfig{ 37 servers: []string{"8.8.8.8:53"}, 38 search: []string{"localdomain."}, 39 ndots: 1, 40 timeout: 5 * time.Second, 41 attempts: 2, 42 }, 43 }, 44 { 45 name: "testdata/search-resolv.conf", 46 want: &dnsConfig{ 47 servers: []string{"8.8.8.8:53"}, 48 search: []string{"test.", "invalid."}, 49 ndots: 1, 50 timeout: 5 * time.Second, 51 attempts: 2, 52 }, 53 }, 54 { 55 name: "testdata/empty-resolv.conf", 56 want: &dnsConfig{ 57 servers: defaultNS, 58 ndots: 1, 59 timeout: 5 * time.Second, 60 attempts: 2, 61 search: []string{"domain.local."}, 62 }, 63 }, 64 { 65 name: "testdata/invalid-ndots-resolv.conf", 66 want: &dnsConfig{ 67 servers: defaultNS, 68 ndots: 0, 69 timeout: 5 * time.Second, 70 attempts: 2, 71 search: []string{"domain.local."}, 72 }, 73 }, 74 { 75 name: "testdata/large-ndots-resolv.conf", 76 want: &dnsConfig{ 77 servers: defaultNS, 78 ndots: 15, 79 timeout: 5 * time.Second, 80 attempts: 2, 81 search: []string{"domain.local."}, 82 }, 83 }, 84 { 85 name: "testdata/negative-ndots-resolv.conf", 86 want: &dnsConfig{ 87 servers: defaultNS, 88 ndots: 0, 89 timeout: 5 * time.Second, 90 attempts: 2, 91 search: []string{"domain.local."}, 92 }, 93 }, 94 { 95 name: "testdata/openbsd-resolv.conf", 96 want: &dnsConfig{ 97 ndots: 1, 98 timeout: 5 * time.Second, 99 attempts: 2, 100 lookup: []string{"file", "bind"}, 101 servers: []string{"169.254.169.254:53", "10.240.0.1:53"}, 102 search: []string{"c.symbolic-datum-552.internal."}, 103 }, 104 }, 105 { 106 name: "testdata/single-request-resolv.conf", 107 want: &dnsConfig{ 108 servers: defaultNS, 109 ndots: 1, 110 singleRequest: true, 111 timeout: 5 * time.Second, 112 attempts: 2, 113 search: []string{"domain.local."}, 114 }, 115 }, 116 { 117 name: "testdata/single-request-reopen-resolv.conf", 118 want: &dnsConfig{ 119 servers: defaultNS, 120 ndots: 1, 121 singleRequest: true, 122 timeout: 5 * time.Second, 123 attempts: 2, 124 search: []string{"domain.local."}, 125 }, 126 }, 127 { 128 name: "testdata/linux-use-vc-resolv.conf", 129 want: &dnsConfig{ 130 servers: defaultNS, 131 ndots: 1, 132 useTCP: true, 133 timeout: 5 * time.Second, 134 attempts: 2, 135 search: []string{"domain.local."}, 136 }, 137 }, 138 { 139 name: "testdata/freebsd-usevc-resolv.conf", 140 want: &dnsConfig{ 141 servers: defaultNS, 142 ndots: 1, 143 useTCP: true, 144 timeout: 5 * time.Second, 145 attempts: 2, 146 search: []string{"domain.local."}, 147 }, 148 }, 149 { 150 name: "testdata/openbsd-tcp-resolv.conf", 151 want: &dnsConfig{ 152 servers: defaultNS, 153 ndots: 1, 154 useTCP: true, 155 timeout: 5 * time.Second, 156 attempts: 2, 157 search: []string{"domain.local."}, 158 }, 159 }, 160 } 161 162 func TestDNSReadConfig(t *testing.T) { 163 origGetHostname := getHostname 164 defer func() { getHostname = origGetHostname }() 165 getHostname = func() (string, error) { return "host.domain.local", nil } 166 167 for _, tt := range dnsReadConfigTests { 168 conf := dnsReadConfig(tt.name) 169 if conf.err != nil { 170 t.Fatal(conf.err) 171 } 172 conf.mtime = time.Time{} 173 if !reflect.DeepEqual(conf, tt.want) { 174 t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want) 175 } 176 } 177 } 178 179 func TestDNSReadMissingFile(t *testing.T) { 180 origGetHostname := getHostname 181 defer func() { getHostname = origGetHostname }() 182 getHostname = func() (string, error) { return "host.domain.local", nil } 183 184 conf := dnsReadConfig("a-nonexistent-file") 185 if !os.IsNotExist(conf.err) { 186 t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist) 187 } 188 conf.err = nil 189 want := &dnsConfig{ 190 servers: defaultNS, 191 ndots: 1, 192 timeout: 5 * time.Second, 193 attempts: 2, 194 search: []string{"domain.local."}, 195 } 196 if !reflect.DeepEqual(conf, want) { 197 t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want) 198 } 199 } 200 201 var dnsDefaultSearchTests = []struct { 202 name string 203 err error 204 want []string 205 }{ 206 { 207 name: "host.long.domain.local", 208 want: []string{"long.domain.local."}, 209 }, 210 { 211 name: "host.local", 212 want: []string{"local."}, 213 }, 214 { 215 name: "host", 216 want: nil, 217 }, 218 { 219 name: "host.domain.local", 220 err: errors.New("errored"), 221 want: nil, 222 }, 223 { 224 // ensures we don't return []string{""} 225 // which causes duplicate lookups 226 name: "foo.", 227 want: nil, 228 }, 229 } 230 231 func TestDNSDefaultSearch(t *testing.T) { 232 origGetHostname := getHostname 233 defer func() { getHostname = origGetHostname }() 234 235 for _, tt := range dnsDefaultSearchTests { 236 getHostname = func() (string, error) { return tt.name, tt.err } 237 got := dnsDefaultSearch() 238 if !reflect.DeepEqual(got, tt.want) { 239 t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want) 240 } 241 } 242 } 243 244 func TestDNSNameLength(t *testing.T) { 245 origGetHostname := getHostname 246 defer func() { getHostname = origGetHostname }() 247 getHostname = func() (string, error) { return "host.domain.local", nil } 248 249 var char63 = "" 250 for i := 0; i < 63; i++ { 251 char63 += "a" 252 } 253 longDomain := strings.Repeat(char63+".", 5) + "example" 254 255 for _, tt := range dnsReadConfigTests { 256 conf := dnsReadConfig(tt.name) 257 if conf.err != nil { 258 t.Fatal(conf.err) 259 } 260 261 var shortestSuffix int 262 for _, suffix := range tt.want.search { 263 if shortestSuffix == 0 || len(suffix) < shortestSuffix { 264 shortestSuffix = len(suffix) 265 } 266 } 267 268 // Test a name that will be maximally long when prefixing the shortest 269 // suffix (accounting for the intervening dot). 270 longName := longDomain[len(longDomain)-254+1+shortestSuffix:] 271 if longName[0] == '.' || longName[1] == '.' { 272 longName = "aa." + longName[3:] 273 } 274 for _, fqdn := range conf.nameList(longName) { 275 if len(fqdn) > 254 { 276 t.Errorf("got %d; want less than or equal to 254", len(fqdn)) 277 } 278 } 279 280 // Now test a name that's too long for suffixing. 281 unsuffixable := "a." + longName[1:] 282 unsuffixableResults := conf.nameList(unsuffixable) 283 if len(unsuffixableResults) != 1 { 284 t.Errorf("suffixed names %v; want []", unsuffixableResults[1:]) 285 } 286 287 // Now test a name that's too long for DNS. 288 tooLong := "a." + longDomain 289 tooLongResults := conf.nameList(tooLong) 290 if tooLongResults != nil { 291 t.Errorf("suffixed names %v; want nil", tooLongResults) 292 } 293 } 294 } 295
View as plain text