github.com/containerd/nerdctl@v1.7.7/pkg/resolvconf/resolvconf_linux_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // originally from https://github.com/moby/moby/blob/6014c1e29dc34dffa77fb5749cc3281c1b4854ac/libnetwork/resolvconf/resolvconf_linux_test.go 18 package resolvconf 19 20 import ( 21 "bytes" 22 "os" 23 "testing" 24 ) 25 26 func TestGet(t *testing.T) { 27 resolvConfUtils, err := Get() 28 if err != nil { 29 t.Fatal(err) 30 } 31 resolvConfSystem, err := os.ReadFile("/run/systemd/resolve/resolv.conf") 32 if err != nil { 33 t.Fatal(err) 34 } 35 if string(resolvConfUtils.Content) != string(resolvConfSystem) { 36 t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.") 37 } 38 hashSystem, err := hashData(bytes.NewReader(resolvConfSystem)) 39 if err != nil { 40 t.Fatal(err) 41 } 42 if resolvConfUtils.Hash != hashSystem { 43 t.Fatalf("/etc/resolv.conf and GetResolvConf have different hashes.") 44 } 45 } 46 47 func TestGetNameservers(t *testing.T) { 48 for resolv, result := range map[string][]string{` 49 nameserver 1.2.3.4 50 nameserver 40.3.200.10 51 search example.com`: {"1.2.3.4", "40.3.200.10"}, 52 `search example.com`: {}, 53 `nameserver 1.2.3.4 54 search example.com 55 nameserver 4.30.20.100`: {"1.2.3.4", "4.30.20.100"}, 56 ``: {}, 57 ` nameserver 1.2.3.4 `: {"1.2.3.4"}, 58 `search example.com 59 nameserver 1.2.3.4 60 #nameserver 4.3.2.1`: {"1.2.3.4"}, 61 `search example.com 62 nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"}, 63 } { 64 test := GetNameservers([]byte(resolv), IP) 65 if !strSlicesEqual(test, result) { 66 t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) 67 } 68 } 69 } 70 71 func TestGetNameserversAsCIDR(t *testing.T) { 72 for resolv, result := range map[string][]string{` 73 nameserver 1.2.3.4 74 nameserver 40.3.200.10 75 search example.com`: {"1.2.3.4/32", "40.3.200.10/32"}, 76 `search example.com`: {}, 77 `nameserver 1.2.3.4 78 search example.com 79 nameserver 4.30.20.100`: {"1.2.3.4/32", "4.30.20.100/32"}, 80 ``: {}, 81 ` nameserver 1.2.3.4 `: {"1.2.3.4/32"}, 82 `search example.com 83 nameserver 1.2.3.4 84 #nameserver 4.3.2.1`: {"1.2.3.4/32"}, 85 `search example.com 86 nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4/32"}, 87 } { 88 test := GetNameserversAsCIDR([]byte(resolv)) 89 if !strSlicesEqual(test, result) { 90 t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) 91 } 92 } 93 } 94 95 func TestGetSearchDomains(t *testing.T) { 96 for resolv, result := range map[string][]string{ 97 `search example.com`: {"example.com"}, 98 `search example.com # ignored`: {"example.com"}, 99 ` search example.com `: {"example.com"}, 100 ` search example.com # ignored`: {"example.com"}, 101 `search foo.example.com example.com`: {"foo.example.com", "example.com"}, 102 ` search foo.example.com example.com `: {"foo.example.com", "example.com"}, 103 ` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"}, 104 ``: {}, 105 `# ignored`: {}, 106 `nameserver 1.2.3.4 107 search foo.example.com example.com`: {"foo.example.com", "example.com"}, 108 `nameserver 1.2.3.4 109 search dup1.example.com dup2.example.com 110 search foo.example.com example.com`: {"foo.example.com", "example.com"}, 111 `nameserver 1.2.3.4 112 search foo.example.com example.com 113 nameserver 4.30.20.100`: {"foo.example.com", "example.com"}, 114 } { 115 test := GetSearchDomains([]byte(resolv)) 116 if !strSlicesEqual(test, result) { 117 t.Fatalf("Wrong search domain string {%s} should be %v. Input: %s", test, result, resolv) 118 } 119 } 120 } 121 122 func TestGetOptions(t *testing.T) { 123 for resolv, result := range map[string][]string{ 124 `options opt1`: {"opt1"}, 125 `options opt1 # ignored`: {"opt1"}, 126 ` options opt1 `: {"opt1"}, 127 ` options opt1 # ignored`: {"opt1"}, 128 `options opt1 opt2 opt3`: {"opt1", "opt2", "opt3"}, 129 `options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"}, 130 ` options opt1 opt2 opt3 `: {"opt1", "opt2", "opt3"}, 131 ` options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"}, 132 ``: {}, 133 `# ignored`: {}, 134 `nameserver 1.2.3.4`: {}, 135 `nameserver 1.2.3.4 136 options opt1 opt2 opt3`: {"opt1", "opt2", "opt3"}, 137 `nameserver 1.2.3.4 138 options opt1 opt2 139 options opt3 opt4`: {"opt3", "opt4"}, 140 } { 141 test := GetOptions([]byte(resolv)) 142 if !strSlicesEqual(test, result) { 143 t.Fatalf("Wrong options string {%s} should be %v. Input: %s", test, result, resolv) 144 } 145 } 146 } 147 148 func strSlicesEqual(a, b []string) bool { 149 if len(a) != len(b) { 150 return false 151 } 152 153 for i, v := range a { 154 if v != b[i] { 155 return false 156 } 157 } 158 159 return true 160 } 161 162 func TestBuild(t *testing.T) { 163 file, err := os.CreateTemp("", "") 164 if err != nil { 165 t.Fatal(err) 166 } 167 defer os.Remove(file.Name()) 168 169 _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"}) 170 if err != nil { 171 t.Fatal(err) 172 } 173 174 content, err := os.ReadFile(file.Name()) 175 if err != nil { 176 t.Fatal(err) 177 } 178 179 if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) { 180 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 181 } 182 } 183 184 func TestBuildWithZeroLengthDomainSearch(t *testing.T) { 185 file, err := os.CreateTemp("", "") 186 if err != nil { 187 t.Fatal(err) 188 } 189 defer os.Remove(file.Name()) 190 191 _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"}) 192 if err != nil { 193 t.Fatal(err) 194 } 195 196 content, err := os.ReadFile(file.Name()) 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) { 202 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 203 } 204 if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) { 205 t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content) 206 } 207 } 208 209 func TestBuildWithNoOptions(t *testing.T) { 210 file, err := os.CreateTemp("", "") 211 if err != nil { 212 t.Fatal(err) 213 } 214 defer os.Remove(file.Name()) 215 216 _, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{}) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 content, err := os.ReadFile(file.Name()) 222 if err != nil { 223 t.Fatal(err) 224 } 225 226 if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) { 227 t.Fatalf("Expected to find '%s' got '%s'", expected, content) 228 } 229 if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) { 230 t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content) 231 } 232 } 233 234 func TestFilterResolvDns(t *testing.T) { 235 ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n" 236 237 if result, _ := FilterResolvDNS([]byte(ns0), false); result != nil { 238 if ns0 != string(result.Content) { 239 t.Fatalf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 240 } 241 } 242 243 ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n" 244 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 245 if ns0 != string(result.Content) { 246 t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 247 } 248 } 249 250 ns1 = "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n" 251 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 252 if ns0 != string(result.Content) { 253 t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 254 } 255 } 256 257 ns1 = "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n" 258 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 259 if ns0 != string(result.Content) { 260 t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 261 } 262 } 263 264 ns1 = "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n" 265 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 266 if ns0 != string(result.Content) { 267 t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 268 } 269 } 270 271 ns1 = "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1" 272 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 273 if ns0 != string(result.Content) { 274 t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 275 } 276 } 277 278 // with IPv6 disabled (false param), the IPv6 nameserver should be removed 279 ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1" 280 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 281 if ns0 != string(result.Content) { 282 t.Fatalf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 283 } 284 } 285 286 // with IPv6 disabled (false param), the IPv6 link-local nameserver with zone ID should be removed 287 ns1 = "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21\n" 288 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 289 if ns0 != string(result.Content) { 290 t.Fatalf("Failed Localhost+IPv6 off: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 291 } 292 } 293 294 // with IPv6 enabled, the IPv6 nameserver should be preserved 295 ns0 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\n" 296 ns1 = "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1" 297 if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil { 298 if ns0 != string(result.Content) { 299 t.Fatalf("Failed Localhost+IPv6 on: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 300 } 301 } 302 303 // with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added 304 ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844" 305 ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1" 306 if result, _ := FilterResolvDNS([]byte(ns1), true); result != nil { 307 if ns0 != string(result.Content) { 308 t.Fatalf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 309 } 310 } 311 312 // with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added 313 ns0 = "\nnameserver 8.8.8.8\nnameserver 8.8.4.4" 314 ns1 = "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1" 315 if result, _ := FilterResolvDNS([]byte(ns1), false); result != nil { 316 if ns0 != string(result.Content) { 317 t.Fatalf("Failed no Localhost+IPv6 enabled: expected \n<%s> got \n<%s>", ns0, string(result.Content)) 318 } 319 } 320 }