1 /* MIT License
2 *
3 * Copyright (c) The c-ares project and its contributors
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * SPDX-License-Identifier: MIT
25 */
26 #include "ares-test.h"
27
28 extern "C" {
29 #include "ares_private.h"
30 }
31
32 // library initialization is only needed for windows builds
33 #ifdef WIN32
34 #define EXPECTED_NONINIT ARES_ENOTINITIALIZED
35 #else
36 #define EXPECTED_NONINIT ARES_SUCCESS
37 #endif
38
39 namespace ares {
40 namespace test {
41
TEST(LibraryInit,Basic)42 TEST(LibraryInit, Basic) {
43 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
44 EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL));
45 EXPECT_EQ(ARES_SUCCESS, ares_library_initialized());
46 ares_library_cleanup();
47 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
48 }
49
TEST(LibraryInit,UnexpectedCleanup)50 TEST(LibraryInit, UnexpectedCleanup) {
51 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
52 ares_library_cleanup();
53 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
54 }
55
TEST(LibraryInit,Nested)56 TEST(LibraryInit, Nested) {
57 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
58 EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL));
59 EXPECT_EQ(ARES_SUCCESS, ares_library_initialized());
60 EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL));
61 EXPECT_EQ(ARES_SUCCESS, ares_library_initialized());
62 ares_library_cleanup();
63 EXPECT_EQ(ARES_SUCCESS, ares_library_initialized());
64 ares_library_cleanup();
65 EXPECT_EQ(EXPECTED_NONINIT, ares_library_initialized());
66 }
67
TEST(LibraryInit,BasicChannelInit)68 TEST(LibraryInit, BasicChannelInit) {
69 EXPECT_EQ(ARES_SUCCESS, ares_library_init(ARES_LIB_INIT_ALL));
70 ares_channel_t *channel = nullptr;
71 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
72 EXPECT_NE(nullptr, channel);
73 ares_destroy(channel);
74 ares_library_cleanup();
75 }
76
TEST_F(LibraryTest,OptionsChannelInit)77 TEST_F(LibraryTest, OptionsChannelInit) {
78 struct ares_options opts;
79 int optmask = 0;
80 memset(&opts, 0, sizeof(opts));
81 opts.flags = ARES_FLAG_USEVC | ARES_FLAG_PRIMARY;
82 optmask |= ARES_OPT_FLAGS;
83 opts.timeout = 2000;
84 optmask |= ARES_OPT_TIMEOUTMS;
85 opts.tries = 2;
86 optmask |= ARES_OPT_TRIES;
87 opts.ndots = 4;
88 optmask |= ARES_OPT_NDOTS;
89 opts.udp_port = 54;
90 optmask |= ARES_OPT_MAXTIMEOUTMS;
91 opts.maxtimeout = 10000;
92 optmask |= ARES_OPT_UDP_PORT;
93 opts.tcp_port = 54;
94 optmask |= ARES_OPT_TCP_PORT;
95 opts.socket_send_buffer_size = 514;
96 optmask |= ARES_OPT_SOCK_SNDBUF;
97 opts.socket_receive_buffer_size = 514;
98 optmask |= ARES_OPT_SOCK_RCVBUF;
99 opts.ednspsz = 1280;
100 optmask |= ARES_OPT_EDNSPSZ;
101 opts.nservers = 2;
102 opts.servers = (struct in_addr *)malloc((size_t)opts.nservers * sizeof(struct in_addr));
103 opts.servers[0].s_addr = htonl(0x01020304);
104 opts.servers[1].s_addr = htonl(0x02030405);
105 optmask |= ARES_OPT_SERVERS;
106 opts.ndomains = 2;
107 opts.domains = (char **)malloc((size_t)opts.ndomains * sizeof(char *));
108 opts.domains[0] = strdup("example.com");
109 opts.domains[1] = strdup("example2.com");
110 optmask |= ARES_OPT_DOMAINS;
111 opts.lookups = strdup("b");
112 optmask |= ARES_OPT_LOOKUPS;
113 optmask |= ARES_OPT_ROTATE;
114 opts.resolvconf_path = strdup("/etc/resolv.conf");
115 optmask |= ARES_OPT_RESOLVCONF;
116 opts.hosts_path = strdup("/etc/hosts");
117 optmask |= ARES_OPT_HOSTS_FILE;
118
119 ares_channel_t *channel = nullptr;
120 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
121 EXPECT_NE(nullptr, channel);
122
123 ares_channel_t *channel2 = nullptr;
124 EXPECT_EQ(ARES_SUCCESS, ares_dup(&channel2, channel));
125 EXPECT_NE(nullptr, channel2);
126
127 struct ares_options opts2;
128 int optmask2 = 0;
129 memset(&opts2, 0, sizeof(opts2));
130 EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel2, &opts2, &optmask2));
131
132 // Note that not all opts-settable fields are saved (e.g.
133 // ednspsz, socket_{send,receive}_buffer_size).
134 EXPECT_EQ(opts.flags, opts2.flags);
135 EXPECT_EQ(opts.timeout, opts2.timeout);
136 EXPECT_EQ(opts.tries, opts2.tries);
137 EXPECT_EQ(opts.ndots, opts2.ndots);
138 EXPECT_EQ(opts.maxtimeout, opts2.maxtimeout);
139 EXPECT_EQ(opts.udp_port, opts2.udp_port);
140 EXPECT_EQ(opts.tcp_port, opts2.tcp_port);
141 EXPECT_EQ(1, opts2.nservers); // Truncated by ARES_FLAG_PRIMARY
142 EXPECT_EQ(opts.servers[0].s_addr, opts2.servers[0].s_addr);
143 EXPECT_EQ(opts.ndomains, opts2.ndomains);
144 EXPECT_EQ(std::string(opts.domains[0]), std::string(opts2.domains[0]));
145 EXPECT_EQ(std::string(opts.domains[1]), std::string(opts2.domains[1]));
146 EXPECT_EQ(std::string(opts.lookups), std::string(opts2.lookups));
147 EXPECT_EQ(std::string(opts.resolvconf_path), std::string(opts2.resolvconf_path));
148 EXPECT_EQ(std::string(opts.hosts_path), std::string(opts2.hosts_path));
149
150 ares_destroy_options(&opts);
151 ares_destroy_options(&opts2);
152 ares_destroy(channel);
153 ares_destroy(channel2);
154 }
155
TEST_F(LibraryTest,ChannelAllocFail)156 TEST_F(LibraryTest, ChannelAllocFail) {
157 ares_channel_t *channel;
158 for (int ii = 1; ii <= 25; ii++) {
159 ClearFails();
160 SetAllocFail(ii);
161 channel = nullptr;
162 int rc = ares_init(&channel);
163 // The number of allocations depends on local environment, so don't expect ENOMEM.
164 if (rc == ARES_ENOMEM) {
165 EXPECT_EQ(nullptr, channel);
166 } else {
167 ares_destroy(channel);
168 }
169 }
170 }
171
TEST_F(LibraryTest,OptionsChannelAllocFail)172 TEST_F(LibraryTest, OptionsChannelAllocFail) {
173 struct ares_options opts;
174 int optmask = 0;
175 memset(&opts, 0, sizeof(opts));
176 opts.flags = ARES_FLAG_USEVC;
177 optmask |= ARES_OPT_FLAGS;
178 opts.timeout = 2;
179 optmask |= ARES_OPT_TIMEOUT;
180 opts.tries = 2;
181 optmask |= ARES_OPT_TRIES;
182 opts.ndots = 4;
183 optmask |= ARES_OPT_NDOTS;
184 opts.udp_port = 54;
185 optmask |= ARES_OPT_UDP_PORT;
186 opts.tcp_port = 54;
187 optmask |= ARES_OPT_TCP_PORT;
188 opts.socket_send_buffer_size = 514;
189 optmask |= ARES_OPT_SOCK_SNDBUF;
190 opts.socket_receive_buffer_size = 514;
191 optmask |= ARES_OPT_SOCK_RCVBUF;
192 opts.ednspsz = 1280;
193 optmask |= ARES_OPT_EDNSPSZ;
194 opts.nservers = 2;
195 opts.servers = (struct in_addr *)malloc((size_t)opts.nservers * sizeof(struct in_addr));
196 opts.servers[0].s_addr = htonl(0x01020304);
197 opts.servers[1].s_addr = htonl(0x02030405);
198 optmask |= ARES_OPT_SERVERS;
199 opts.ndomains = 2;
200 opts.domains = (char **)malloc((size_t)opts.ndomains * sizeof(char *));
201 opts.domains[0] = strdup("example.com");
202 opts.domains[1] = strdup("example2.com");
203 optmask |= ARES_OPT_DOMAINS;
204 opts.lookups = strdup("b");
205 optmask |= ARES_OPT_LOOKUPS;
206 optmask |= ARES_OPT_ROTATE;
207 opts.resolvconf_path = strdup("/etc/resolv.conf");
208 optmask |= ARES_OPT_RESOLVCONF;
209 opts.hosts_path = strdup("/etc/hosts");
210 optmask |= ARES_OPT_HOSTS_FILE;
211
212 ares_channel_t *channel = nullptr;
213 for (int ii = 1; ii <= 8; ii++) {
214 ClearFails();
215 SetAllocFail(ii);
216 int rc = ares_init_options(&channel, &opts, optmask);
217 if (rc == ARES_ENOMEM) {
218 EXPECT_EQ(nullptr, channel);
219 } else {
220 EXPECT_EQ(ARES_SUCCESS, rc);
221 ares_destroy(channel);
222 channel = nullptr;
223 }
224 }
225 ClearFails();
226
227 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
228 EXPECT_NE(nullptr, channel);
229
230 // Add some servers and a sortlist for flavour.
231 EXPECT_EQ(ARES_SUCCESS,
232 ares_set_servers_csv(channel, "1.2.3.4,0102:0304:0506:0708:0910:1112:1314:1516,2.3.4.5"));
233 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel, "1.2.3.4 2.3.4.5"));
234
235 ares_channel_t *channel2 = nullptr;
236 for (int ii = 1; ii <= 18; ii++) {
237 ClearFails();
238 SetAllocFail(ii);
239 EXPECT_EQ(ARES_ENOMEM, ares_dup(&channel2, channel)) << ii;
240 EXPECT_EQ(nullptr, channel2) << ii;
241 }
242
243 struct ares_options opts2;
244 int optmask2 = 0;
245 for (int ii = 1; ii <= 6; ii++) {
246 memset(&opts2, 0, sizeof(opts2));
247 ClearFails();
248 SetAllocFail(ii);
249 EXPECT_EQ(ARES_ENOMEM, ares_save_options(channel, &opts2, &optmask2)) << ii;
250 // May still have allocations even after ARES_ENOMEM return code.
251 ares_destroy_options(&opts2);
252 }
253 ares_destroy_options(&opts);
254 ares_destroy(channel);
255 }
256
TEST_F(LibraryTest,FailChannelInit)257 TEST_F(LibraryTest, FailChannelInit) {
258 EXPECT_EQ(ARES_SUCCESS,
259 ares_library_init_mem(ARES_LIB_INIT_ALL,
260 &LibraryTest::amalloc,
261 &LibraryTest::afree,
262 &LibraryTest::arealloc));
263 SetAllocFail(1);
264 ares_channel_t *channel = nullptr;
265 EXPECT_EQ(ARES_ENOMEM, ares_init(&channel));
266 EXPECT_EQ(nullptr, channel);
267 ares_library_cleanup();
268 }
269
270 #ifndef WIN32
TEST_F(LibraryTest,EnvInit)271 TEST_F(LibraryTest, EnvInit) {
272 ares_channel_t *channel = nullptr;
273 EnvValue v1("LOCALDOMAIN", "this.is.local");
274 EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2");
275 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
276 ares_destroy(channel);
277 }
278
TEST_F(LibraryTest,EnvInitModernOptions)279 TEST_F(LibraryTest, EnvInitModernOptions) {
280 ares_channel_t *channel = nullptr;
281 EnvValue v1("LOCALDOMAIN", "this.is.local");
282 EnvValue v2("RES_OPTIONS", "options debug retrans:2 ndots:3 attempts:4 timeout:5 rotate");
283 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
284
285 channel->optmask |= ARES_OPT_TRIES;
286 channel->optmask |= ARES_OPT_TIMEOUTMS;
287
288 struct ares_options opts;
289 memset(&opts, 0, sizeof(opts));
290 int optmask = 0;
291 EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &opts, &optmask));
292 EXPECT_EQ(5000, opts.timeout);
293 EXPECT_EQ(4, opts.tries);
294
295 ares_destroy(channel);
296 }
297
TEST_F(LibraryTest,EnvInitAllocFail)298 TEST_F(LibraryTest, EnvInitAllocFail) {
299 ares_channel_t *channel;
300 EnvValue v1("LOCALDOMAIN", "this.is.local");
301 EnvValue v2("RES_OPTIONS", "options debug ndots:3 retry:3 rotate retrans:2");
302 for (int ii = 1; ii <= 10; ii++) {
303 ClearFails();
304 SetAllocFail(ii);
305 channel = nullptr;
306 int rc = ares_init(&channel);
307 if (rc == ARES_SUCCESS) {
308 ares_destroy(channel);
309 } else {
310 EXPECT_EQ(ARES_ENOMEM, rc);
311 }
312 }
313 }
314 #endif
315
TEST_F(DefaultChannelTest,SetAddresses)316 TEST_F(DefaultChannelTest, SetAddresses) {
317 ares_set_local_ip4(channel_, 0x01020304);
318 byte addr6[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
319 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
320 ares_set_local_ip6(channel_, addr6);
321 ares_set_local_dev(channel_, "dummy");
322 }
323
TEST_F(DefaultChannelTest,SetSortlistFailures)324 TEST_F(DefaultChannelTest, SetSortlistFailures) {
325 EXPECT_EQ(ARES_ENODATA, ares_set_sortlist(nullptr, "1.2.3.4"));
326 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "111.111.111.111*/16"));
327 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "111.111.111.111/255.255.255.240*"));
328 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "1 0123456789012345"));
329 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "1 /01234567890123456789012345678901"));
330 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "xyzzy ; lwk"));
331 EXPECT_EQ(ARES_EBADSTR, ares_set_sortlist(channel_, "xyzzy ; 0x123"));
332 }
333
TEST_F(DefaultChannelTest,SetSortlistVariants)334 TEST_F(DefaultChannelTest, SetSortlistVariants) {
335 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4"));
336 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4 ; 2.3.4.5"));
337 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "1.2.3.4/26;1234::5678/126;4.5.6.7;5678::1234"));
338 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, " 1.2.3.4/26 1234::5678/126 4.5.6.7 5678::1234 "));
339 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "129.1.1.1"));
340 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "192.1.1.1"));
341 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "224.1.1.1"));
342 EXPECT_EQ(ARES_SUCCESS, ares_set_sortlist(channel_, "225.1.1.1"));
343 }
344
TEST_F(DefaultChannelTest,SetSortlistAllocFail)345 TEST_F(DefaultChannelTest, SetSortlistAllocFail) {
346 for (int ii = 1; ii <= 3; ii++) {
347 ClearFails();
348 SetAllocFail(ii);
349 EXPECT_EQ(ARES_ENOMEM, ares_set_sortlist(channel_, "12.13.0.0/16 1234::5678/40 1.2.3.4")) << ii;
350 }
351 }
352
353 #ifdef USE_WINSOCK
TEST(Init,NoLibraryInit)354 TEST(Init, NoLibraryInit) {
355 ares_channel_t *channel = nullptr;
356 EXPECT_EQ(ARES_ENOTINITIALIZED, ares_init(&channel));
357 }
358 #endif
359
360 #ifdef HAVE_CONTAINER
361 // These tests rely on the ability of non-root users to create a chroot
362 // using Linux namespaces.
363
364
365 // The library uses a variety of information sources to initialize a channel,
366 // in particular to determine:
367 // - search: the search domains to use
368 // - servers: the name servers to use
369 // - lookup: whether to check files or DNS or both (e.g. "fb")
370 // - options: various resolver options
371 // - sortlist: the order of preference for IP addresses
372 //
373 // The first source from the following list is used:
374 // - init_by_options(): explicitly specified values in struct ares_options
375 // - init_by_environment(): values from the environment:
376 // - LOCALDOMAIN -> search (single value)
377 // - RES_OPTIONS -> options
378 // - init_by_resolv_conf(): values from various config files:
379 // - /etc/resolv.conf -> search, lookup, servers, sortlist, options
380 // - /etc/nsswitch.conf -> lookup
381 // - /etc/host.conf -> lookup
382 // - /etc/svc.conf -> lookup
383 // - init_by_defaults(): fallback values:
384 // - gethostname(3) -> domain
385 // - "fb" -> lookup
386
387 NameContentList filelist = {
388 {"/etc/resolv.conf", "nameserver 1.2.3.4\n"
389 "sortlist 1.2.3.4/16 2.3.4.5\n"
390 "search first.com second.com\n"},
391 {"/etc/hosts", "3.4.5.6 ahostname.com\n"},
392 {"/etc/nsswitch.conf", "hosts: files\n"}};
393 CONTAINED_TEST_F(LibraryTest, ContainerChannelInit,
394 "myhostname", "mydomainname.org", filelist) {
395 ares_channel_t *channel = nullptr;
396 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
397 std::string actual = GetNameServers(channel);
398 std::string expected = "1.2.3.4:53";
399 EXPECT_EQ(expected, actual);
400 EXPECT_EQ(2, channel->ndomains);
401 EXPECT_EQ(std::string("first.com"), std::string(channel->domains[0]));
402 EXPECT_EQ(std::string("second.com"), std::string(channel->domains[1]));
403
404 HostResult result;
405 ares_gethostbyname(channel, "ahostname.com", AF_INET, HostCallback, &result);
406 ProcessWork(channel, NoExtraFDs, nullptr);
407 EXPECT_TRUE(result.done_);
408 std::stringstream ss;
409 ss << result.host_;
410
411 EXPECT_EQ("{'ahostname.com' aliases=[] addrs=[3.4.5.6]}", ss.str());
412
413 ares_destroy(channel);
414 return HasFailure();
415 }
416
417 CONTAINED_TEST_F(LibraryTest, ContainerSortlistOptionInit,
418 "myhostname", "mydomainname.org", filelist) {
419 ares_channel_t *channel = nullptr;
420 struct ares_options opts;
421 memset(&opts, 0, sizeof(opts));
422 int optmask = 0;
423 optmask |= ARES_OPT_SORTLIST;
424 opts.nsort = 0;
425 // Explicitly specifying an empty sortlist in the options should override the
426 // environment.
427 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
428 EXPECT_EQ(0, channel->nsort);
429 EXPECT_EQ(nullptr, channel->sortlist);
430 EXPECT_EQ(ARES_OPT_SORTLIST, (channel->optmask & ARES_OPT_SORTLIST));
431
432 ares_destroy(channel);
433 return HasFailure();
434 }
435
436 NameContentList fullresolv = {
437 {"/etc/resolv.conf", " nameserver 1.2.3.4 \n"
438 "search first.com second.com\n"
439 "lookup bind\n"
440 "options debug ndots:5\n"
441 "sortlist 1.2.3.4/16 2.3.4.5\n"}};
442 CONTAINED_TEST_F(LibraryTest, ContainerFullResolvInit,
443 "myhostname", "mydomainname.org", fullresolv) {
444 ares_channel_t *channel = nullptr;
445 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
446
447 EXPECT_EQ(std::string("b"), std::string(channel->lookups));
448 EXPECT_EQ(5, channel->ndots);
449
450 ares_destroy(channel);
451 return HasFailure();
452 }
453
454 // Allow path for resolv.conf to be configurable
455 NameContentList myresolvconf = {
456 {"/tmp/myresolv.cnf", " nameserver 1.2.3.4 \n"
457 "search first.com second.com\n"
458 "lookup bind\n"
459 "options debug ndots:5\n"
460 "sortlist 1.2.3.4/16 2.3.4.5\n"}};
461 CONTAINED_TEST_F(LibraryTest, ContainerMyResolvConfInit,
462 "myhostname", "mydomain.org", myresolvconf) {
463 char filename[] = "/tmp/myresolv.cnf";
464 ares_channel_t *channel = nullptr;
465 struct ares_options options;
466 memset(&options, 0, sizeof(options));
467 options.resolvconf_path = strdup(filename);
468 int optmask = ARES_OPT_RESOLVCONF;
469 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &options, optmask));
470
471 optmask = 0;
472 free(options.resolvconf_path);
473 options.resolvconf_path = NULL;
474
475 EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &options, &optmask));
476 EXPECT_EQ(ARES_OPT_RESOLVCONF, (optmask & ARES_OPT_RESOLVCONF));
477 EXPECT_EQ(std::string(filename), std::string(options.resolvconf_path));
478
479 ares_destroy_options(&options);
480 ares_destroy(channel);
481 return HasFailure();
482 }
483
484 // Allow hosts path to be configurable
485 NameContentList myhosts = {
486 {"/tmp/hosts", "10.0.12.26 foobar\n"
487 "2001:A0:C::1A foobar\n"}};
488 CONTAINED_TEST_F(LibraryTest, ContainerMyHostsInit,
489 "myhostname", "mydomain.org", myhosts) {
490 char filename[] = "/tmp/hosts";
491 ares_channel_t *channel = nullptr;
492 struct ares_options options;
493
494 options.hosts_path = strdup(filename);
495 int optmask = ARES_OPT_HOSTS_FILE;
496 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &options, optmask));
497 memset(&options, 0, sizeof(options));
498 optmask = 0;
499 free(options.hosts_path);
500 options.hosts_path = NULL;
501
502 EXPECT_EQ(ARES_SUCCESS, ares_save_options(channel, &options, &optmask));
503 EXPECT_EQ(ARES_OPT_HOSTS_FILE, (optmask & ARES_OPT_HOSTS_FILE));
504 EXPECT_EQ(std::string(filename), std::string(options.hosts_path));
505
506 ares_destroy_options(&options);
507 ares_destroy(channel);
508 return HasFailure();
509 }
510
511 NameContentList svcconf = {
512 {"/etc/resolv.conf", "nameserver 1.2.3.4\n"
513 "search first.com second.com\n"},
514 {"/etc/svc.conf", "hosts= bind\n"}};
515 CONTAINED_TEST_F(LibraryTest, ContainerSvcConfInit,
516 "myhostname", "mydomainname.org", svcconf) {
517 ares_channel_t *channel = nullptr;
518 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
519
520 EXPECT_EQ(std::string("b"), std::string(channel->lookups));
521
522 ares_destroy(channel);
523 return HasFailure();
524 }
525
526 NameContentList malformedresolvconflookup = {
527 {"/etc/resolv.conf", "nameserver 1.2.3.4\n"
528 "lookup garbage\n"}}; // malformed line
529 CONTAINED_TEST_F(LibraryTest, ContainerMalformedResolvConfLookup,
530 "myhostname", "mydomainname.org", malformedresolvconflookup) {
531 ares_channel_t *channel = nullptr;
532 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
533
534 EXPECT_EQ(std::string("fb"), std::string(channel->lookups));
535
536 ares_destroy(channel);
537 return HasFailure();
538 }
539
540 // Failures when expected config filenames are inaccessible.
541 class MakeUnreadable {
542 public:
MakeUnreadable(const std::string & filename)543 explicit MakeUnreadable(const std::string& filename)
544 : filename_(filename) {
545 chmod(filename_.c_str(), 0000);
546 }
~MakeUnreadable()547 ~MakeUnreadable() { chmod(filename_.c_str(), 0644); }
548 private:
549 std::string filename_;
550 };
551
552 CONTAINED_TEST_F(LibraryTest, ContainerResolvConfNotReadable,
553 "myhostname", "mydomainname.org", filelist) {
554 ares_channel_t *channel = nullptr;
555 MakeUnreadable hide("/etc/resolv.conf");
556 // Unavailable /etc/resolv.conf falls back to defaults
557 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
558 return HasFailure();
559 }
560 CONTAINED_TEST_F(LibraryTest, ContainerNsswitchConfNotReadable,
561 "myhostname", "mydomainname.org", filelist) {
562 ares_channel_t *channel = nullptr;
563 // Unavailable /etc/nsswitch.conf falls back to defaults.
564 MakeUnreadable hide("/etc/nsswitch.conf");
565 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
566
567 EXPECT_EQ(std::string("fb"), std::string(channel->lookups));
568
569 ares_destroy(channel);
570 return HasFailure();
571 }
572
573 CONTAINED_TEST_F(LibraryTest, ContainerSvcConfNotReadable,
574 "myhostname", "mydomainname.org", svcconf) {
575 ares_channel_t *channel = nullptr;
576 // Unavailable /etc/svc.conf falls back to defaults.
577 MakeUnreadable hide("/etc/svc.conf");
578 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
579 ares_destroy(channel);
580 return HasFailure();
581 }
582
583 NameContentList rotateenv = {
584 {"/etc/resolv.conf", "nameserver 1.2.3.4\n"
585 "search first.com second.com\n"
586 "options rotate\n"}};
587 CONTAINED_TEST_F(LibraryTest, ContainerRotateInit,
588 "myhostname", "mydomainname.org", rotateenv) {
589 ares_channel_t *channel = nullptr;
590 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
591
592 EXPECT_EQ(ARES_TRUE, channel->rotate);
593
594 ares_destroy(channel);
595 return HasFailure();
596 }
597
598 CONTAINED_TEST_F(LibraryTest, ContainerRotateOverride,
599 "myhostname", "mydomainname.org", rotateenv) {
600 ares_channel_t *channel = nullptr;
601 struct ares_options opts;
602 memset(&opts, 0, sizeof(opts));
603 int optmask = ARES_OPT_NOROTATE;
604 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
605 optmask = 0;
606 ares_save_options(channel, &opts, &optmask);
607 EXPECT_EQ(ARES_OPT_NOROTATE, (optmask & ARES_OPT_NOROTATE));
608 ares_destroy_options(&opts);
609
610 ares_destroy(channel);
611 return HasFailure();
612 }
613
614 // Test that blacklisted IPv6 resolves are ignored. They're filtered from any
615 // source, so resolv.conf is as good as any.
616 NameContentList blacklistedIpv6 = {
617 {"/etc/resolv.conf", " nameserver 254.192.1.1\n" // 0xfe.0xc0.0x01.0x01
618 " nameserver fec0::dead\n" // Blacklisted
619 " nameserver ffc0::c001\n" // Not blacklisted
620 " domain first.com\n"},
621 {"/etc/nsswitch.conf", "hosts: files\n"}};
622 CONTAINED_TEST_F(LibraryTest, ContainerBlacklistedIpv6,
623 "myhostname", "mydomainname.org", blacklistedIpv6) {
624 ares_channel_t *channel = nullptr;
625 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
626 std::string actual = GetNameServers(channel);
627 std::string expected = "254.192.1.1:53,"
628 "[ffc0::c001]:53";
629 EXPECT_EQ(expected, actual);
630
631 EXPECT_EQ(1, channel->ndomains);
632 EXPECT_EQ(std::string("first.com"), std::string(channel->domains[0]));
633
634 ares_destroy(channel);
635 return HasFailure();
636 }
637
638 NameContentList multiresolv = {
639 {"/etc/resolv.conf", " nameserver 1::2 ; ;;\n"
640 " domain first.com\n"},
641 {"/etc/nsswitch.conf", "hosts: files\n"}};
642 CONTAINED_TEST_F(LibraryTest, ContainerMultiResolvInit,
643 "myhostname", "mydomainname.org", multiresolv) {
644 ares_channel_t *channel = nullptr;
645 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
646 std::string actual = GetNameServers(channel);
647 std::string expected = "[1::2]:53";
648 EXPECT_EQ(expected, actual);
649
650 EXPECT_EQ(1, channel->ndomains);
651 EXPECT_EQ(std::string("first.com"), std::string(channel->domains[0]));
652
653 ares_destroy(channel);
654 return HasFailure();
655 }
656
657 NameContentList systemdresolv = {
658 {"/etc/resolv.conf", "nameserver 1.2.3.4\n"
659 "domain first.com\n"},
660 {"/etc/nsswitch.conf", "hosts: junk resolve files\n"}};
661 CONTAINED_TEST_F(LibraryTest, ContainerSystemdResolvInit,
662 "myhostname", "mydomainname.org", systemdresolv) {
663 ares_channel_t *channel = nullptr;
664 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
665
666 EXPECT_EQ(std::string("bf"), std::string(channel->lookups));
667
668 ares_destroy(channel);
669 return HasFailure();
670 }
671
672 NameContentList empty = {}; // no files
673 CONTAINED_TEST_F(LibraryTest, ContainerEmptyInit,
674 "host.domain.org", "domain.org", empty) {
675 ares_channel_t *channel = nullptr;
676 EXPECT_EQ(ARES_SUCCESS, ares_init(&channel));
677 std::string actual = GetNameServers(channel);
678 std::string expected = "127.0.0.1:53";
679 EXPECT_EQ(expected, actual);
680
681 EXPECT_EQ(1, channel->ndomains);
682 EXPECT_EQ(std::string("domain.org"), std::string(channel->domains[0]));
683 EXPECT_EQ(std::string("fb"), std::string(channel->lookups));
684
685 ares_destroy(channel);
686 return HasFailure();
687 }
688
689 // Test that init fails if the flag to not use a default local named server is
690 // enabled and no other nameservers are available.
691 CONTAINED_TEST_F(LibraryTest, ContainerNoDfltSvrEmptyInit,
692 "myhostname", "mydomainname.org", empty) {
693 ares_channel_t *channel = nullptr;
694 struct ares_options opts;
695 memset(&opts, 0, sizeof(opts));
696 int optmask = ARES_OPT_FLAGS;
697 opts.flags = ARES_FLAG_NO_DFLT_SVR;
698 EXPECT_EQ(ARES_ENOSERVER, ares_init_options(&channel, &opts, optmask));
699
700 EXPECT_EQ(nullptr, channel);
701 return HasFailure();
702 }
703 // Test that init succeeds if the flag to not use a default local named server
704 // is enabled but other nameservers are available.
705 CONTAINED_TEST_F(LibraryTest, ContainerNoDfltSvrFullInit,
706 "myhostname", "mydomainname.org", filelist) {
707 ares_channel_t *channel = nullptr;
708 struct ares_options opts;
709 memset(&opts, 0, sizeof(opts));
710 int optmask = ARES_OPT_FLAGS;
711 opts.flags = ARES_FLAG_NO_DFLT_SVR;
712 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel, &opts, optmask));
713
714 std::string actual = GetNameServers(channel);
715 std::string expected = "1.2.3.4:53";
716 EXPECT_EQ(expected, actual);
717
718 ares_destroy(channel);
719 return HasFailure();
720 }
721
722 #endif
723
724 } // namespace test
725 } // namespace ares
726