github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/resolvconf/resolvconf_unix_test.go (about) 1 //go:build !windows 2 3 package resolvconf 4 5 import ( 6 "bytes" 7 "os" 8 "strings" 9 "testing" 10 11 "github.com/opencontainers/go-digest" 12 "gotest.tools/v3/assert" 13 is "gotest.tools/v3/assert/cmp" 14 ) 15 16 func TestGet(t *testing.T) { 17 actual, err := Get() 18 if err != nil { 19 t.Fatal(err) 20 } 21 expected, err := os.ReadFile(Path()) 22 if err != nil { 23 t.Fatal(err) 24 } 25 if !bytes.Equal(actual.Content, expected) { 26 t.Errorf("%s and GetResolvConf have different content.", Path()) 27 } 28 hash := digest.FromBytes(expected) 29 if !bytes.Equal(actual.Hash, []byte(hash)) { 30 t.Errorf("%s and GetResolvConf have different hashes.", Path()) 31 } 32 } 33 34 func TestGetNameservers(t *testing.T) { 35 for _, tc := range []struct { 36 input string 37 result []string 38 }{ 39 { 40 input: ``, 41 }, 42 { 43 input: `search example.com`, 44 }, 45 { 46 input: ` nameserver 1.2.3.4 `, 47 result: []string{"1.2.3.4"}, 48 }, 49 { 50 input: ` 51 nameserver 1.2.3.4 52 nameserver 40.3.200.10 53 search example.com`, 54 result: []string{"1.2.3.4", "40.3.200.10"}, 55 }, 56 { 57 input: `nameserver 1.2.3.4 58 search example.com 59 nameserver 4.30.20.100`, 60 result: []string{"1.2.3.4", "4.30.20.100"}, 61 }, 62 { 63 input: `search example.com 64 nameserver 1.2.3.4 65 #nameserver 4.3.2.1`, 66 result: []string{"1.2.3.4"}, 67 }, 68 { 69 input: `search example.com 70 nameserver 1.2.3.4 # not 4.3.2.1`, 71 result: []string{"1.2.3.4"}, 72 }, 73 } { 74 test := GetNameservers([]byte(tc.input), IP) 75 if !strSlicesEqual(test, tc.result) { 76 t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input) 77 } 78 } 79 } 80 81 func TestGetNameserversAsCIDR(t *testing.T) { 82 for _, tc := range []struct { 83 input string 84 result []string 85 }{ 86 { 87 input: ``, 88 }, 89 { 90 input: `search example.com`, 91 }, 92 { 93 input: ` nameserver 1.2.3.4 `, 94 result: []string{"1.2.3.4/32"}, 95 }, 96 { 97 input: ` 98 nameserver 1.2.3.4 99 nameserver 40.3.200.10 100 search example.com`, 101 result: []string{"1.2.3.4/32", "40.3.200.10/32"}, 102 }, 103 { 104 input: `nameserver 1.2.3.4 105 search example.com 106 nameserver 4.30.20.100`, 107 result: []string{"1.2.3.4/32", "4.30.20.100/32"}, 108 }, 109 { 110 input: `search example.com 111 nameserver 1.2.3.4 112 #nameserver 4.3.2.1`, 113 result: []string{"1.2.3.4/32"}, 114 }, 115 { 116 input: `search example.com 117 nameserver 1.2.3.4 # not 4.3.2.1`, 118 result: []string{"1.2.3.4/32"}, 119 }, 120 { 121 input: `nameserver fd6f:c490:ec68::1`, 122 result: []string{"fd6f:c490:ec68::1/128"}, 123 }, 124 { 125 input: `nameserver fe80::1234%eth0`, 126 result: []string{"fe80::1234/128"}, 127 }, 128 } { 129 test := GetNameserversAsCIDR([]byte(tc.input)) 130 if !strSlicesEqual(test, tc.result) { 131 t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input) 132 } 133 } 134 } 135 136 func TestGetSearchDomains(t *testing.T) { 137 for _, tc := range []struct { 138 input string 139 result []string 140 }{ 141 { 142 input: ``, 143 }, 144 { 145 input: `# ignored`, 146 }, 147 { 148 input: `search example.com`, 149 result: []string{"example.com"}, 150 }, 151 { 152 input: `search example.com # ignored`, 153 result: []string{"example.com"}, 154 }, 155 { 156 input: ` search example.com `, 157 result: []string{"example.com"}, 158 }, 159 { 160 input: ` search example.com # ignored`, 161 result: []string{"example.com"}, 162 }, 163 { 164 input: `search foo.example.com example.com`, 165 result: []string{"foo.example.com", "example.com"}, 166 }, 167 { 168 input: ` search foo.example.com example.com `, 169 result: []string{"foo.example.com", "example.com"}, 170 }, 171 { 172 input: ` search foo.example.com example.com # ignored`, 173 result: []string{"foo.example.com", "example.com"}, 174 }, 175 { 176 input: `nameserver 1.2.3.4 177 search foo.example.com example.com`, 178 result: []string{"foo.example.com", "example.com"}, 179 }, 180 { 181 input: `nameserver 1.2.3.4 182 search dup1.example.com dup2.example.com 183 search foo.example.com example.com`, 184 result: []string{"foo.example.com", "example.com"}, 185 }, 186 { 187 input: `nameserver 1.2.3.4 188 search foo.example.com example.com 189 nameserver 4.30.20.100`, 190 result: []string{"foo.example.com", "example.com"}, 191 }, 192 { 193 input: `domain an.example`, 194 result: []string{"an.example"}, 195 }, 196 } { 197 test := GetSearchDomains([]byte(tc.input)) 198 if !strSlicesEqual(test, tc.result) { 199 t.Errorf("Wrong search domain string {%s} should be %v. Input: %s", test, tc.result, tc.input) 200 } 201 } 202 } 203 204 func TestGetOptions(t *testing.T) { 205 for _, tc := range []struct { 206 input string 207 result []string 208 }{ 209 { 210 input: ``, 211 }, 212 { 213 input: `# ignored`, 214 }, 215 { 216 input: `nameserver 1.2.3.4`, 217 }, 218 { 219 input: `options opt1`, 220 result: []string{"opt1"}, 221 }, 222 { 223 input: `options opt1 # ignored`, 224 result: []string{"opt1"}, 225 }, 226 { 227 input: ` options opt1 `, 228 result: []string{"opt1"}, 229 }, 230 { 231 input: ` options opt1 # ignored`, 232 result: []string{"opt1"}, 233 }, 234 { 235 input: `options opt1 opt2 opt3`, 236 result: []string{"opt1", "opt2", "opt3"}, 237 }, 238 { 239 input: `options opt1 opt2 opt3 # ignored`, 240 result: []string{"opt1", "opt2", "opt3"}, 241 }, 242 { 243 input: ` options opt1 opt2 opt3 `, 244 result: []string{"opt1", "opt2", "opt3"}, 245 }, 246 { 247 input: ` options opt1 opt2 opt3 # ignored`, 248 result: []string{"opt1", "opt2", "opt3"}, 249 }, 250 { 251 input: `nameserver 1.2.3.4 252 options opt1 opt2 opt3`, 253 result: []string{"opt1", "opt2", "opt3"}, 254 }, 255 { 256 input: `nameserver 1.2.3.4 257 options opt1 opt2 258 options opt3 opt4`, 259 result: []string{"opt3", "opt4"}, 260 }, 261 } { 262 test := GetOptions([]byte(tc.input)) 263 if !strSlicesEqual(test, tc.result) { 264 t.Errorf("Wrong options string {%s} should be %v. Input: %s", test, tc.result, tc.input) 265 } 266 } 267 } 268 269 func strSlicesEqual(a, b []string) bool { 270 if len(a) != len(b) { 271 return false 272 } 273 274 for i, v := range a { 275 if v != b[i] { 276 return false 277 } 278 } 279 280 return true 281 } 282 283 func TestBuild(t *testing.T) { 284 tmpDir := t.TempDir() 285 file, err := os.CreateTemp(tmpDir, "") 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"}) 291 if err != nil { 292 t.Fatal(err) 293 } 294 295 const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n" 296 if !bytes.Equal(f.Content, []byte(expected)) { 297 t.Errorf("Expected to find '%s' got '%s'", expected, f.Content) 298 } 299 content, err := os.ReadFile(file.Name()) 300 if err != nil { 301 t.Fatal(err) 302 } 303 if !bytes.Equal(content, []byte(expected)) { 304 t.Errorf("Expected to find '%s' got '%s'", expected, content) 305 } 306 } 307 308 func TestBuildWithZeroLengthDomainSearch(t *testing.T) { 309 tmpDir := t.TempDir() 310 file, err := os.CreateTemp(tmpDir, "") 311 if err != nil { 312 t.Fatal(err) 313 } 314 315 f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"}) 316 if err != nil { 317 t.Fatal(err) 318 } 319 320 const expected = "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n" 321 if !bytes.Equal(f.Content, []byte(expected)) { 322 t.Errorf("Expected to find '%s' got '%s'", expected, f.Content) 323 } 324 content, err := os.ReadFile(file.Name()) 325 if err != nil { 326 t.Fatal(err) 327 } 328 if !bytes.Equal(content, []byte(expected)) { 329 t.Errorf("Expected to find '%s' got '%s'", expected, content) 330 } 331 } 332 333 func TestBuildWithNoOptions(t *testing.T) { 334 tmpDir := t.TempDir() 335 file, err := os.CreateTemp(tmpDir, "") 336 if err != nil { 337 t.Fatal(err) 338 } 339 340 f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{}) 341 if err != nil { 342 t.Fatal(err) 343 } 344 345 const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n" 346 if !bytes.Equal(f.Content, []byte(expected)) { 347 t.Errorf("Expected to find '%s' got '%s'", expected, f.Content) 348 } 349 content, err := os.ReadFile(file.Name()) 350 if err != nil { 351 t.Fatal(err) 352 } 353 if !bytes.Equal(content, []byte(expected)) { 354 t.Errorf("Expected to find '%s' got '%s'", expected, content) 355 } 356 } 357 358 func TestFilterResolvDNS(t *testing.T) { 359 testcases := []struct { 360 name string 361 input string 362 ipv6Enabled bool 363 expOut string 364 }{ 365 { 366 name: "No localhost", 367 input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\n", 368 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 369 }, 370 { 371 name: "Localhost last", 372 input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n", 373 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 374 }, 375 { 376 name: "Localhost middle", 377 input: "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n", 378 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 379 }, 380 { 381 name: "Localhost first", 382 input: "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n", 383 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 384 }, 385 { 386 name: "IPv6 Localhost", 387 input: "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n", 388 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 389 }, 390 { 391 name: "Two IPv6 Localhosts", 392 input: "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1", 393 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 394 }, 395 { 396 name: "IPv6 disabled", 397 input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1", 398 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 399 }, 400 { 401 name: "IPv6 link-local disabled", 402 input: "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21", 403 expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", 404 }, 405 { 406 name: "IPv6 enabled", 407 input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1\n", 408 ipv6Enabled: true, 409 expOut: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21", 410 }, 411 { 412 // with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added 413 name: "localhost only IPv6", 414 input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1", 415 ipv6Enabled: true, 416 expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844", 417 }, 418 { 419 // with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added 420 name: "localhost only no IPv6", 421 input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1", 422 expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4", 423 }, 424 } 425 426 for _, tc := range testcases { 427 t.Run(tc.name, func(t *testing.T) { 428 f, err := FilterResolvDNS([]byte(tc.input), tc.ipv6Enabled) 429 assert.Check(t, is.Nil(err)) 430 out := strings.TrimSpace(string(f.Content)) 431 assert.Check(t, is.Equal(out, tc.expOut)) 432 }) 433 } 434 }