Line data Source code
1 : /*
2 : SSSD
3 :
4 : Async resolver tests
5 :
6 : Authors:
7 : Martin Nagy <mnagy@redhat.com>
8 : Jakub Hrozek <jhrozek@redhat.com>
9 :
10 : Copyright (C) Red Hat, Inc 2009
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include <stdlib.h>
27 : #include <check.h>
28 : #include <string.h>
29 : #include <talloc.h>
30 : #include <tevent.h>
31 : #include <popt.h>
32 : #include <arpa/inet.h>
33 :
34 : #include "tests/common.h"
35 : #include "util/util.h"
36 : #include "tests/common_check.h"
37 :
38 : /* Interface under test */
39 : #include "resolv/async_resolv.h"
40 :
41 : #define RESOLV_DEFAULT_TIMEOUT 6
42 :
43 : static int use_net_test;
44 : static char *txt_host;
45 : static char *srv_host;
46 :
47 : struct resolv_test_ctx {
48 : struct tevent_context *ev;
49 : struct resolv_ctx *resolv;
50 :
51 : enum {
52 : TESTING_HOSTNAME,
53 : TESTING_TXT,
54 : TESTING_SRV,
55 : } tested_function;
56 :
57 : int error;
58 : bool done;
59 : };
60 :
61 5 : static int setup_resolv_test(int timeout, struct resolv_test_ctx **ctx)
62 : {
63 : struct resolv_test_ctx *test_ctx;
64 : int ret;
65 :
66 5 : test_ctx = talloc_zero(global_talloc_context, struct resolv_test_ctx);
67 5 : if (test_ctx == NULL) {
68 0 : fail("Could not allocate memory for test context");
69 : return ENOMEM;
70 : }
71 :
72 5 : test_ctx->ev = tevent_context_init(test_ctx);
73 5 : if (test_ctx->ev == NULL) {
74 0 : fail("Could not init tevent context");
75 : talloc_free(test_ctx);
76 : return EFAULT;
77 : }
78 :
79 5 : ret = resolv_init(test_ctx, test_ctx->ev, timeout, &test_ctx->resolv);
80 5 : if (ret != EOK) {
81 0 : fail("Could not init resolv context");
82 : talloc_free(test_ctx);
83 : return ret;
84 : }
85 :
86 5 : *ctx = test_ctx;
87 5 : return EOK;
88 : }
89 :
90 3 : static int test_loop(struct resolv_test_ctx *data)
91 : {
92 19 : while (!data->done)
93 13 : tevent_loop_once(data->ev);
94 :
95 3 : return data->error;
96 : }
97 :
98 : struct resolv_hostent *
99 2 : test_create_rhostent(TALLOC_CTX *mem_ctx,
100 : const char *hostname, const char *address)
101 : {
102 : struct resolv_hostent *rhostent;
103 : int ret;
104 : int family;
105 :
106 2 : rhostent = talloc_zero(mem_ctx, struct resolv_hostent);
107 2 : if (!rhostent) {
108 0 : return NULL;
109 : }
110 :
111 2 : rhostent->name = talloc_strdup(rhostent, hostname);
112 2 : rhostent->addr_list = talloc_array(rhostent, struct resolv_addr *, 2);
113 4 : if (!rhostent->name ||
114 2 : !rhostent->addr_list) {
115 : goto fail;
116 : }
117 :
118 2 : rhostent->addr_list[0] = talloc_zero(rhostent->addr_list,
119 : struct resolv_addr);
120 2 : if (!rhostent->addr_list[0]) {
121 0 : goto fail;
122 : }
123 2 : rhostent->addr_list[0]->ipaddr = talloc_array(rhostent->addr_list[0],
124 : uint8_t,
125 : sizeof(struct in6_addr));
126 2 : if (!rhostent->addr_list[0]->ipaddr) {
127 0 : goto fail;
128 : }
129 :
130 2 : family = AF_INET;
131 2 : ret = inet_pton(family, address,
132 2 : rhostent->addr_list[0]->ipaddr);
133 2 : if (ret != 1) {
134 1 : family = AF_INET6;
135 1 : ret = inet_pton(family, address,
136 1 : rhostent->addr_list[0]->ipaddr);
137 1 : if (ret != 1) {
138 0 : goto fail;
139 : }
140 : }
141 :
142 2 : rhostent->addr_list[0]->ttl = RESOLV_DEFAULT_TTL;
143 2 : rhostent->addr_list[1] = NULL;
144 2 : rhostent->family = family;
145 2 : rhostent->aliases = NULL;
146 :
147 2 : return rhostent;
148 :
149 : fail:
150 0 : talloc_free(rhostent);
151 0 : return NULL;
152 : }
153 :
154 1 : START_TEST(test_copy_hostent)
155 : {
156 : void *ctx;
157 : struct resolv_hostent *rhe;
158 :
159 1 : char name[] = "foo.example.com";
160 1 : char alias_1[] = "bar.example.com";
161 1 : char alias_2[] = "baz.example.com";
162 1 : char *aliases[] = { alias_1, alias_2, NULL };
163 1 : struct in_addr addr_1 = { 1234 };
164 1 : struct in_addr addr_2 = { 5678 };
165 1 : int ttl_1 = 12;
166 1 : int ttl_2 = 34;
167 1 : char *addr_list[] = { (char *) &addr_2, (char *) &addr_1, NULL };
168 1 : struct hostent he = {
169 : name, aliases, AF_INET,
170 : sizeof(addr_1), addr_list
171 : };
172 1 : struct ares_addrttl attl[] = { { addr_1, ttl_1 }, { addr_2, ttl_2 } };
173 :
174 1 : ctx = talloc_new(global_talloc_context);
175 1 : fail_if(ctx == NULL);
176 :
177 1 : ck_leaks_push(ctx);
178 :
179 1 : rhe = resolv_copy_hostent_ares(ctx, &he, AF_INET, &attl, 2);
180 :
181 1 : fail_if(rhe == NULL);
182 1 : fail_if(strcmp(rhe->name, name));
183 1 : fail_if(strcmp(rhe->aliases[0], alias_1));
184 1 : fail_if(strcmp(rhe->aliases[1], alias_2));
185 1 : fail_if(rhe->aliases[2] != NULL);
186 1 : fail_if(rhe->family != AF_INET);
187 1 : fail_if(memcmp(rhe->addr_list[0]->ipaddr, &addr_1, sizeof(addr_1)));
188 1 : fail_if(rhe->addr_list[0]->ttl != ttl_1);
189 1 : fail_if(memcmp(rhe->addr_list[1]->ipaddr, &addr_2, sizeof(addr_2)));
190 1 : fail_if(rhe->addr_list[1]->ttl != ttl_2);
191 1 : fail_if(rhe->addr_list[2] != NULL);
192 :
193 1 : talloc_zfree(rhe);
194 :
195 1 : rhe = resolv_copy_hostent(ctx, &he);
196 1 : fail_if(rhe == NULL);
197 1 : fail_if(strcmp(rhe->name, name));
198 1 : fail_if(strcmp(rhe->aliases[0], alias_1));
199 1 : fail_if(strcmp(rhe->aliases[1], alias_2));
200 1 : fail_if(rhe->aliases[2] != NULL);
201 1 : fail_if(rhe->family != AF_INET);
202 1 : fail_if(memcmp(rhe->addr_list[0]->ipaddr, &addr_2, sizeof(addr_1)));
203 1 : fail_if(rhe->addr_list[0]->ttl != RESOLV_DEFAULT_TTL);
204 1 : fail_if(memcmp(rhe->addr_list[1]->ipaddr, &addr_1, sizeof(addr_2)));
205 1 : fail_if(rhe->addr_list[1]->ttl != RESOLV_DEFAULT_TTL);
206 1 : fail_if(rhe->addr_list[2] != NULL);
207 :
208 1 : talloc_free(rhe);
209 :
210 1 : ck_leaks_pop(ctx);
211 : }
212 1 : END_TEST
213 :
214 1 : START_TEST(test_address_to_string)
215 : {
216 : void *ctx;
217 : struct resolv_hostent *rhe;
218 : char *str_addr;
219 : char *ptr_addr;
220 :
221 1 : ctx = talloc_new(global_talloc_context);
222 1 : fail_if(ctx == NULL);
223 1 : ck_leaks_push(ctx);
224 :
225 1 : rhe = test_create_rhostent(ctx, "www.example.com", "1.2.3.4");
226 1 : fail_if(rhe == NULL);
227 :
228 1 : str_addr = resolv_get_string_address_index(ctx, rhe, 0);
229 1 : fail_if(str_addr == NULL);
230 1 : fail_unless(strcmp(str_addr, "1.2.3.4") == 0, "Unexpected address\n");
231 1 : talloc_free(str_addr);
232 :
233 1 : ptr_addr = resolv_get_string_ptr_address(ctx, rhe->family,
234 1 : rhe->addr_list[0]->ipaddr);
235 1 : fail_if(ptr_addr == NULL);
236 1 : fail_unless(strcmp(ptr_addr, "4.3.2.1.in-addr.arpa.") == 0, "Unexpected PTR address\n");
237 1 : talloc_free(ptr_addr);
238 :
239 1 : talloc_free(rhe);
240 :
241 1 : rhe = test_create_rhostent(ctx, "www6.example.com", "2607:f8b0:400c:c03::6a");
242 1 : fail_if(rhe == NULL);
243 :
244 1 : str_addr = resolv_get_string_address_index(ctx, rhe, 0);
245 1 : fail_if(str_addr == NULL);
246 1 : fail_unless(strcmp(str_addr, "2607:f8b0:400c:c03::6a") == 0, "Unexpected address\n");
247 1 : talloc_free(str_addr);
248 :
249 1 : ptr_addr = resolv_get_string_ptr_address(ctx, rhe->family,
250 1 : rhe->addr_list[0]->ipaddr);
251 1 : fail_if(ptr_addr == NULL);
252 1 : fail_unless(strcmp(ptr_addr,
253 : "a.6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.3.0.c.0.c.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa.") == 0, "Unexpected PTR address\n");
254 1 : talloc_free(ptr_addr);
255 :
256 1 : talloc_free(rhe);
257 1 : ck_leaks_pop(ctx);
258 : }
259 1 : END_TEST
260 :
261 1 : static void test_ip_addr(struct tevent_req *req)
262 : {
263 : int recv_status;
264 : int status;
265 : struct resolv_hostent *rhostent;
266 : int i;
267 1 : struct resolv_test_ctx *test_ctx = tevent_req_callback_data(req,
268 : struct resolv_test_ctx);
269 :
270 1 : test_ctx->done = true;
271 :
272 1 : recv_status = resolv_gethostbyname_recv(req, test_ctx,
273 : &status, NULL, &rhostent);
274 1 : talloc_zfree(req);
275 1 : if (recv_status != EOK) {
276 0 : DEBUG(SSSDBG_OP_FAILURE,
277 : "resolv_gethostbyname_recv failed: %d\n", recv_status);
278 0 : test_ctx->error = recv_status;
279 0 : return;
280 : }
281 1 : DEBUG(SSSDBG_TRACE_LIBS, "resolv_gethostbyname_recv status: %d\n", status);
282 :
283 1 : test_ctx->error = ENOENT;
284 2 : for (i = 0; rhostent->addr_list[i]; i++) {
285 : char addr_buf[256];
286 1 : inet_ntop(rhostent->family,
287 1 : rhostent->addr_list[i]->ipaddr,
288 : addr_buf, sizeof(addr_buf));
289 :
290 1 : if (strcmp(addr_buf, "127.0.0.1") == 0) {
291 1 : test_ctx->error = EOK;
292 : }
293 : }
294 1 : talloc_free(rhostent);
295 : }
296 :
297 1 : START_TEST(test_resolv_ip_addr)
298 : {
299 : struct resolv_test_ctx *test_ctx;
300 1 : int ret = EOK;
301 : struct tevent_req *req;
302 1 : const char *hostname = "127.0.0.1";
303 :
304 1 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
305 1 : if (ret != EOK) {
306 0 : fail("Could not set up test");
307 : return;
308 : }
309 :
310 1 : ck_leaks_push(test_ctx);
311 1 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
312 1 : test_ctx->resolv, hostname, IPV4_ONLY,
313 : default_host_dbs);
314 1 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
315 1 : if (req == NULL) {
316 0 : ret = ENOMEM;
317 : }
318 :
319 1 : if (ret == EOK) {
320 1 : tevent_req_set_callback(req, test_ip_addr, test_ctx);
321 1 : ret = test_loop(test_ctx);
322 : }
323 :
324 1 : ck_leaks_pop(test_ctx);
325 1 : fail_unless(ret == EOK);
326 :
327 1 : talloc_zfree(test_ctx);
328 : }
329 1 : END_TEST
330 :
331 0 : static void test_localhost(struct tevent_req *req)
332 : {
333 : int recv_status;
334 : int status;
335 : struct resolv_hostent *rhostent;
336 : int i;
337 0 : struct resolv_test_ctx *test_ctx = tevent_req_callback_data(req,
338 : struct resolv_test_ctx);
339 :
340 0 : test_ctx->done = true;
341 :
342 0 : recv_status = resolv_gethostbyname_recv(req, test_ctx,
343 : &status, NULL, &rhostent);
344 0 : talloc_zfree(req);
345 0 : if (recv_status != EOK) {
346 0 : DEBUG(SSSDBG_OP_FAILURE,
347 : "resolv_gethostbyname_recv failed: %d\n", recv_status);
348 0 : test_ctx->error = recv_status;
349 0 : return;
350 : }
351 0 : DEBUG(SSSDBG_TRACE_LIBS, "resolv_gethostbyname_recv status: %d\n", status);
352 :
353 0 : test_ctx->error = ENOENT;
354 0 : for (i = 0; rhostent->addr_list[i]; i++) {
355 : char addr_buf[256];
356 0 : inet_ntop(rhostent->family, rhostent->addr_list[i]->ipaddr,
357 : addr_buf, sizeof(addr_buf));
358 :
359 : /* test that localhost resolves to 127.0.0.1 or ::1 */
360 0 : if (strcmp(addr_buf, "127.0.0.1") == 0 || strcmp(addr_buf, "::1") == 0) {
361 0 : test_ctx->error = EOK;
362 : }
363 : }
364 0 : talloc_free(rhostent);
365 : }
366 :
367 0 : START_TEST(test_resolv_localhost)
368 : {
369 : struct resolv_test_ctx *test_ctx;
370 0 : int ret = EOK;
371 : struct tevent_req *req;
372 0 : const char *hostname = "localhost.localdomain";
373 :
374 0 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
375 0 : if (ret != EOK) {
376 0 : fail("Could not set up test");
377 : return;
378 : }
379 :
380 0 : ck_leaks_push(test_ctx);
381 0 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
382 0 : test_ctx->resolv, hostname, IPV4_FIRST,
383 : default_host_dbs);
384 0 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
385 0 : if (req == NULL) {
386 0 : ret = ENOMEM;
387 : }
388 :
389 0 : if (ret == EOK) {
390 0 : tevent_req_set_callback(req, test_localhost, test_ctx);
391 0 : ret = test_loop(test_ctx);
392 : }
393 :
394 0 : ck_leaks_pop(test_ctx);
395 0 : fail_unless(ret == EOK);
396 :
397 0 : talloc_zfree(test_ctx);
398 : }
399 0 : END_TEST
400 :
401 0 : static void test_negative(struct tevent_req *req)
402 : {
403 : int recv_status;
404 : int status;
405 : struct resolv_hostent *hostent;
406 : struct resolv_test_ctx *test_ctx;
407 :
408 0 : test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
409 0 : test_ctx->done = true;
410 :
411 0 : recv_status = resolv_gethostbyname_recv(req, test_ctx,
412 : &status, NULL, &hostent);
413 0 : talloc_zfree(req);
414 0 : if (recv_status == EOK) {
415 0 : DEBUG(SSSDBG_TRACE_LIBS,
416 : "resolv_gethostbyname_recv succeeded in a negative test\n");
417 0 : return;
418 : }
419 :
420 0 : test_ctx->error = status;
421 0 : DEBUG(SSSDBG_OP_FAILURE,
422 : "resolv_gethostbyname_recv status: %d: %s\n", status, resolv_strerror(status));
423 : }
424 :
425 0 : START_TEST(test_resolv_negative)
426 : {
427 0 : int ret = EOK;
428 : struct tevent_req *req;
429 0 : const char *hostname = "sssd.foo";
430 : struct resolv_test_ctx *test_ctx;
431 :
432 0 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
433 0 : if (ret != EOK) {
434 0 : fail("Could not set up test");
435 : return;
436 : }
437 :
438 0 : ck_leaks_push(test_ctx);
439 0 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
440 0 : test_ctx->resolv, hostname, IPV4_FIRST,
441 : default_host_dbs);
442 0 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
443 0 : if (req == NULL) {
444 0 : ret = ENOMEM;
445 : }
446 :
447 0 : if (ret == EOK) {
448 0 : tevent_req_set_callback(req, test_negative, test_ctx);
449 0 : ret = test_loop(test_ctx);
450 : }
451 :
452 0 : ck_leaks_pop(test_ctx);
453 :
454 0 : fail_unless(ret != EOK);
455 0 : fail_unless(test_ctx->error == ARES_ENOTFOUND);
456 0 : talloc_zfree(test_ctx);
457 : }
458 0 : END_TEST
459 :
460 0 : static void test_internet(struct tevent_req *req)
461 : {
462 : int recv_status;
463 : int status;
464 : struct resolv_test_ctx *test_ctx;
465 : void *tmp_ctx;
466 0 : struct resolv_hostent *rhostent = NULL;
467 0 : struct ares_txt_reply *txt_replies = NULL, *txtptr;
468 0 : struct ares_srv_reply *srv_replies = NULL, *srvptr;
469 : int i;
470 :
471 0 : test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
472 :
473 0 : test_ctx->done = true;
474 :
475 0 : tmp_ctx = talloc_new(test_ctx);
476 0 : ck_leaks_push(tmp_ctx);
477 :
478 0 : switch (test_ctx->tested_function) {
479 : case TESTING_HOSTNAME:
480 0 : recv_status = resolv_gethostbyname_recv(req, tmp_ctx,
481 : &status, NULL, &rhostent);
482 0 : test_ctx->error = (rhostent->name == NULL) ? ENOENT : EOK;
483 0 : if (test_ctx->error == EOK) {
484 : char addr_buf[256];
485 0 : for (i=0; rhostent->addr_list[i]; i++) {
486 0 : inet_ntop(rhostent->family,
487 0 : rhostent->addr_list[i]->ipaddr,
488 : addr_buf, sizeof(addr_buf));
489 0 : DEBUG(SSSDBG_OP_FAILURE, "Found address %s with TTL %d\n",
490 : addr_buf, rhostent->addr_list[i]->ttl);
491 : }
492 : }
493 0 : break;
494 : case TESTING_TXT:
495 0 : recv_status = resolv_gettxt_recv(tmp_ctx, req, &status, NULL,
496 : &txt_replies);
497 0 : test_ctx->error = (txt_replies == NULL) ? ENOENT : EOK;
498 0 : for (txtptr = txt_replies; txtptr != NULL; txtptr = txtptr->next) {
499 0 : DEBUG(SSSDBG_OP_FAILURE, "TXT Record: %s\n", txtptr->txt);
500 : }
501 0 : break;
502 : case TESTING_SRV:
503 0 : recv_status = resolv_getsrv_recv(tmp_ctx, req, &status, NULL,
504 : &srv_replies, NULL);
505 0 : test_ctx->error = (srv_replies == NULL) ? ENOENT : EOK;
506 0 : for (srvptr = srv_replies; srvptr != NULL; srvptr = srvptr->next) {
507 0 : DEBUG(SSSDBG_OP_FAILURE,
508 : "SRV Record: %d %d %d %s\n", srvptr->weight,
509 : srvptr->priority, srvptr->port,
510 : srvptr->host);
511 : }
512 0 : break;
513 : default:
514 0 : recv_status = EINVAL;
515 0 : break;
516 : }
517 0 : talloc_zfree(req);
518 0 : fail_if(recv_status != EOK, "The recv function failed: %d", recv_status);
519 0 : DEBUG(SSSDBG_TRACE_LIBS, "recv status: %d\n", status);
520 :
521 0 : if (rhostent != NULL) {
522 0 : talloc_free(rhostent);
523 0 : } else if (txt_replies != NULL) {
524 0 : talloc_free(txt_replies);
525 0 : } else if (srv_replies != NULL) {
526 0 : talloc_free(srv_replies);
527 : }
528 0 : ck_leaks_pop(tmp_ctx);
529 0 : }
530 :
531 0 : START_TEST(test_resolv_internet)
532 : {
533 0 : int ret = EOK;
534 : struct tevent_req *req;
535 0 : const char *hostname = "redhat.com";
536 : struct resolv_test_ctx *test_ctx;
537 :
538 0 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
539 0 : if (ret != EOK) {
540 0 : fail("Could not set up test");
541 : return;
542 : }
543 0 : test_ctx->tested_function = TESTING_HOSTNAME;
544 :
545 0 : ck_leaks_push(test_ctx);
546 0 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
547 0 : test_ctx->resolv, hostname, IPV4_FIRST,
548 : default_host_dbs);
549 0 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
550 0 : if (req == NULL) {
551 0 : ret = ENOMEM;
552 : }
553 :
554 0 : if (ret == EOK) {
555 0 : tevent_req_set_callback(req, test_internet, test_ctx);
556 0 : ret = test_loop(test_ctx);
557 : }
558 :
559 0 : fail_unless(ret == EOK);
560 0 : ck_leaks_pop(test_ctx);
561 0 : talloc_zfree(test_ctx);
562 : }
563 0 : END_TEST
564 :
565 0 : START_TEST(test_resolv_internet_txt)
566 : {
567 : int ret;
568 : struct tevent_req *req;
569 : struct resolv_test_ctx *test_ctx;
570 :
571 0 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
572 0 : fail_if(ret != EOK, "Could not set up test");
573 0 : test_ctx->tested_function = TESTING_TXT;
574 :
575 0 : ck_leaks_push(test_ctx);
576 :
577 0 : req = resolv_gettxt_send(test_ctx, test_ctx->ev, test_ctx->resolv, txt_host);
578 0 : fail_if(req == NULL, "Function resolv_gettxt_send failed");
579 :
580 0 : tevent_req_set_callback(req, test_internet, test_ctx);
581 0 : ret = test_loop(test_ctx);
582 0 : fail_unless(ret == EOK);
583 :
584 0 : ck_leaks_pop(test_ctx);
585 :
586 0 : talloc_zfree(test_ctx);
587 : }
588 0 : END_TEST
589 :
590 0 : START_TEST(test_resolv_internet_srv)
591 : {
592 : int ret;
593 : struct tevent_req *req;
594 : struct resolv_test_ctx *test_ctx;
595 :
596 0 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
597 0 : fail_if(ret != EOK, "Could not set up test");
598 0 : test_ctx->tested_function = TESTING_SRV;
599 :
600 0 : ck_leaks_push(test_ctx);
601 :
602 0 : req = resolv_getsrv_send(test_ctx, test_ctx->ev, test_ctx->resolv, srv_host);
603 0 : fail_if(req == NULL, "Function resolv_getsrv_send failed");
604 :
605 0 : tevent_req_set_callback(req, test_internet, test_ctx);
606 0 : ret = test_loop(test_ctx);
607 0 : fail_unless(ret == EOK);
608 :
609 0 : ck_leaks_pop(test_ctx);
610 :
611 0 : talloc_zfree(test_ctx);
612 : }
613 0 : END_TEST
614 :
615 1 : static void resolv_free_context(struct tevent_context *ev,
616 : struct tevent_timer *te,
617 : struct timeval t, void *ptr)
618 : {
619 1 : struct resolv_ctx *rctx = talloc_get_type(ptr, struct resolv_ctx);
620 1 : DEBUG(SSSDBG_TRACE_LIBS, "freeing the context\n");
621 :
622 1 : talloc_free(rctx);
623 1 : }
624 :
625 2 : static void resolv_free_done(struct tevent_context *ev,
626 : struct tevent_timer *te,
627 : struct timeval t, void *ptr)
628 : {
629 2 : struct resolv_test_ctx *tctx = talloc_get_type(ptr, struct resolv_test_ctx);
630 2 : DEBUG(SSSDBG_TRACE_LIBS, "marking test as done\n");
631 :
632 2 : tctx->error = EOK;
633 2 : tctx->done = true;
634 2 : }
635 :
636 1 : START_TEST(test_resolv_free_context)
637 : {
638 1 : int ret = EOK;
639 : struct tevent_req *req;
640 1 : const char *hostname = "redhat.com";
641 : struct resolv_test_ctx *test_ctx;
642 : struct tevent_timer *free_timer, *terminate_timer;
643 : struct timeval free_tv, terminate_tv;
644 :
645 1 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
646 1 : if (ret != EOK) {
647 0 : fail("Could not set up test");
648 : return;
649 : }
650 :
651 1 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
652 1 : test_ctx->resolv, hostname, IPV4_FIRST,
653 : default_host_dbs);
654 1 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
655 1 : if (req == NULL) {
656 0 : fail("Error calling resolv_gethostbyname_send");
657 : goto done;
658 : }
659 :
660 1 : gettimeofday(&free_tv, NULL);
661 1 : free_tv.tv_sec += 1;
662 1 : free_tv.tv_usec = 0;
663 1 : terminate_tv.tv_sec = free_tv.tv_sec + 1;
664 1 : terminate_tv.tv_usec = 0;
665 :
666 1 : free_timer = tevent_add_timer(test_ctx->ev, test_ctx, free_tv, resolv_free_context, test_ctx->resolv);
667 1 : if (free_timer == NULL) {
668 0 : fail("Error calling tevent_add_timer");
669 : goto done;
670 : }
671 :
672 1 : terminate_timer = tevent_add_timer(test_ctx->ev, test_ctx, terminate_tv, resolv_free_done, test_ctx);
673 1 : if (terminate_timer == NULL) {
674 0 : fail("Error calling tevent_add_timer");
675 : goto done;
676 : }
677 :
678 1 : ret = test_loop(test_ctx);
679 1 : fail_unless(ret == EOK);
680 :
681 : done:
682 1 : talloc_zfree(test_ctx);
683 : }
684 1 : END_TEST
685 :
686 1 : static void resolv_free_req(struct tevent_context *ev,
687 : struct tevent_timer *te,
688 : struct timeval t, void *ptr)
689 : {
690 1 : struct tevent_req *req = talloc_get_type(ptr, struct tevent_req);
691 1 : DEBUG(SSSDBG_TRACE_LIBS, "freeing the request\n");
692 :
693 1 : talloc_free(req);
694 1 : }
695 :
696 1 : START_TEST(test_resolv_sort_srv_reply)
697 : {
698 : int ret;
699 1 : struct ares_srv_reply *replies = NULL;
700 1 : struct ares_srv_reply *r, *prev = NULL;
701 : struct resolv_test_ctx *test_ctx;
702 1 : int num_replies = 3;
703 : int i;
704 :
705 1 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
706 1 : if (ret != EOK) {
707 0 : fail("Could not set up test");
708 : return;
709 : }
710 :
711 1 : ck_leaks_push(test_ctx);
712 :
713 : /* prepare linked list with reversed values */
714 4 : for (i = 0; i<num_replies; i++) {
715 3 : r = talloc_zero(test_ctx, struct ares_srv_reply);
716 3 : fail_if(r == NULL);
717 3 : r->priority = num_replies-i;
718 3 : r->weight = i;
719 :
720 3 : if (!replies) {
721 1 : replies = r;
722 1 : prev = r;
723 : } else {
724 2 : prev->next = r;
725 2 : prev = prev->next;
726 : }
727 : }
728 :
729 : /* do the sort */
730 1 : ret = resolv_sort_srv_reply(&replies);
731 1 : fail_if(ret != EOK);
732 :
733 : /* check if the list is sorted */
734 1 : prev = NULL;
735 4 : for (i = 1, r = replies; r; r=r->next, i++) {
736 3 : talloc_zfree(prev);
737 3 : prev = r;
738 3 : fail_unless(r->priority == i);
739 : }
740 1 : talloc_zfree(prev);
741 :
742 : /* check if the list is complete */
743 1 : fail_unless(i-1 == num_replies);
744 :
745 : /* test if the weighting algorithm runs..not much do
746 : * deterministically test here since it is based on
747 : * random weight-selection */
748 1 : replies = NULL;
749 4 : for (i = 0; i<num_replies; i++) {
750 3 : r = talloc_zero(test_ctx, struct ares_srv_reply);
751 3 : fail_if(r == NULL);
752 3 : r->priority = i % 2 + 1;
753 3 : r->weight = i;
754 :
755 3 : if (!replies) {
756 1 : replies = r;
757 1 : prev = r;
758 : } else {
759 2 : prev->next = r;
760 2 : prev = prev->next;
761 : }
762 : }
763 :
764 : /* do the sort */
765 1 : ret = resolv_sort_srv_reply(&replies);
766 1 : fail_if(ret != EOK);
767 :
768 : /* clean up */
769 1 : prev = NULL;
770 4 : for (r = replies; r; r=r->next) {
771 3 : talloc_zfree(prev);
772 3 : prev = r;
773 : }
774 1 : talloc_zfree(prev);
775 :
776 :
777 : /* check for leaks */
778 1 : ck_leaks_pop(test_ctx);
779 1 : talloc_zfree(test_ctx);
780 : }
781 1 : END_TEST
782 :
783 1 : START_TEST(test_resolv_sort_srv_reply_zero_weight)
784 : {
785 : int ret;
786 1 : struct ares_srv_reply *replies = NULL;
787 1 : struct ares_srv_reply *r, *prev = NULL;
788 : struct resolv_test_ctx *test_ctx;
789 1 : int num_replies = 6;
790 : int i;
791 :
792 1 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
793 1 : if (ret != EOK) {
794 0 : fail("Could not set up test");
795 : return;
796 : }
797 :
798 1 : ck_leaks_push(test_ctx);
799 :
800 : /* prepare linked list */
801 7 : for (i = 0; i < num_replies; i++) {
802 6 : r = talloc_zero(test_ctx, struct ares_srv_reply);
803 6 : fail_if(r == NULL);
804 :
805 6 : r->priority = 20;
806 6 : r->priority = i <= 3 ? 10 : r->priority;
807 6 : r->priority = i <= 1 ? 0 : r->priority;
808 6 : r->weight = 0;
809 :
810 6 : if (replies == NULL) {
811 1 : replies = r;
812 1 : prev = r;
813 : } else {
814 5 : prev->next = r;
815 5 : prev = prev->next;
816 : }
817 : }
818 :
819 : /* do the sort */
820 1 : ret = resolv_sort_srv_reply(&replies);
821 1 : fail_if(ret != EOK);
822 :
823 : /* check if the list contains all values and is sorted */
824 7 : for (i = 0, r = replies; r != NULL; r = r->next, i++) {
825 6 : if (r->next != NULL) {
826 5 : fail_unless(r->priority <= r->next->priority);
827 : }
828 : }
829 1 : fail_unless(i == num_replies);
830 :
831 : /* clean up */
832 1 : prev = NULL;
833 7 : for (r = replies; r != NULL; r=r->next) {
834 6 : talloc_zfree(prev);
835 6 : prev = r;
836 : }
837 1 : talloc_zfree(prev);
838 :
839 :
840 : /* check for leaks */
841 1 : ck_leaks_pop(test_ctx);
842 1 : talloc_zfree(test_ctx);
843 : }
844 1 : END_TEST
845 :
846 1 : START_TEST(test_resolv_free_req)
847 : {
848 1 : int ret = EOK;
849 : struct tevent_req *req;
850 1 : const char *hostname = "redhat.com";
851 : struct resolv_test_ctx *test_ctx;
852 : struct tevent_timer *free_timer, *terminate_timer;
853 : struct timeval free_tv, terminate_tv;
854 :
855 1 : ret = setup_resolv_test(RESOLV_DEFAULT_TIMEOUT, &test_ctx);
856 1 : if (ret != EOK) {
857 0 : fail("Could not set up test");
858 : return;
859 : }
860 :
861 1 : ck_leaks_push(test_ctx);
862 1 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
863 1 : test_ctx->resolv, hostname, IPV4_FIRST,
864 : default_host_dbs);
865 1 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
866 1 : if (req == NULL) {
867 0 : fail("Error calling resolv_gethostbyname_send");
868 : goto done;
869 : }
870 :
871 1 : gettimeofday(&free_tv, NULL);
872 1 : free_tv.tv_sec += 1;
873 1 : free_tv.tv_usec = 0;
874 : /* Give enought time for c-ares request to terminate */
875 1 : terminate_tv.tv_sec = free_tv.tv_sec + 6;
876 1 : terminate_tv.tv_usec = 0;
877 :
878 1 : free_timer = tevent_add_timer(test_ctx->ev, test_ctx, free_tv, resolv_free_req, req);
879 1 : if (free_timer == NULL) {
880 0 : fail("Error calling tevent_add_timer");
881 : goto done;
882 : }
883 :
884 1 : terminate_timer = tevent_add_timer(test_ctx->ev, test_ctx, terminate_tv, resolv_free_done, test_ctx);
885 1 : if (terminate_timer == NULL) {
886 0 : fail("Error calling tevent_add_timer");
887 : goto done;
888 : }
889 :
890 1 : ret = test_loop(test_ctx);
891 1 : ck_leaks_pop(test_ctx);
892 1 : fail_unless(ret == EOK);
893 :
894 : done:
895 1 : talloc_zfree(test_ctx);
896 : }
897 1 : END_TEST
898 :
899 0 : static void test_timeout(struct tevent_req *req)
900 : {
901 : int recv_status;
902 : int status;
903 : struct resolv_test_ctx *test_ctx;
904 : TALLOC_CTX *tmp_ctx;
905 0 : struct resolv_hostent *rhostent = NULL;
906 :
907 0 : test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
908 :
909 0 : test_ctx->done = true;
910 :
911 0 : tmp_ctx = talloc_new(test_ctx);
912 0 : ck_leaks_push(tmp_ctx);
913 :
914 0 : fail_unless(test_ctx->tested_function == TESTING_HOSTNAME);
915 0 : recv_status = resolv_gethostbyname_recv(req, tmp_ctx,
916 : &status, NULL, &rhostent);
917 0 : talloc_zfree(req);
918 0 : fail_unless(recv_status == ETIMEDOUT);
919 0 : fail_unless(status == ARES_ETIMEOUT);
920 0 : ck_leaks_pop(tmp_ctx);
921 0 : talloc_free(tmp_ctx);
922 0 : }
923 :
924 0 : START_TEST(test_resolv_timeout)
925 : {
926 : struct resolv_test_ctx *test_ctx;
927 : errno_t ret;
928 : struct tevent_req *req;
929 0 : const char *hostname = "redhat.com";
930 :
931 0 : ret = setup_resolv_test(0, &test_ctx);
932 0 : if (ret != EOK) {
933 0 : fail("Could not set up test");
934 : return;
935 : }
936 :
937 0 : test_ctx->tested_function = TESTING_HOSTNAME;
938 :
939 0 : req = resolv_gethostbyname_send(test_ctx, test_ctx->ev,
940 0 : test_ctx->resolv, hostname, IPV4_FIRST,
941 : default_host_dbs);
942 0 : DEBUG(SSSDBG_TRACE_LIBS, "Sent resolv_gethostbyname\n");
943 0 : if (req == NULL) {
944 0 : ret = ENOMEM;
945 : }
946 :
947 0 : if (ret == EOK) {
948 0 : tevent_req_set_callback(req, test_timeout, test_ctx);
949 0 : ret = test_loop(test_ctx);
950 : }
951 :
952 0 : fail_unless(ret == EOK);
953 0 : talloc_zfree(test_ctx);
954 : }
955 0 : END_TEST
956 :
957 1 : Suite *create_resolv_suite(void)
958 : {
959 1 : Suite *s = suite_create("resolv");
960 :
961 1 : TCase *tc_resolv = tcase_create("RESOLV Tests");
962 1 : tcase_set_timeout(tc_resolv, 8);
963 :
964 1 : tcase_add_checked_fixture(tc_resolv, ck_leak_check_setup, ck_leak_check_teardown);
965 : /* Do some testing */
966 1 : tcase_add_test(tc_resolv, test_copy_hostent);
967 1 : tcase_add_test(tc_resolv, test_address_to_string);
968 1 : tcase_add_test(tc_resolv, test_resolv_ip_addr);
969 1 : tcase_add_test(tc_resolv, test_resolv_sort_srv_reply);
970 1 : tcase_add_test(tc_resolv, test_resolv_sort_srv_reply_zero_weight);
971 1 : if (use_net_test) {
972 0 : tcase_add_test(tc_resolv, test_resolv_internet);
973 0 : tcase_add_test(tc_resolv, test_resolv_negative);
974 0 : tcase_add_test(tc_resolv, test_resolv_localhost);
975 0 : tcase_add_test(tc_resolv, test_resolv_timeout);
976 0 : if (txt_host != NULL) {
977 0 : tcase_add_test(tc_resolv, test_resolv_internet_txt);
978 : }
979 0 : if (srv_host != NULL) {
980 0 : tcase_add_test(tc_resolv, test_resolv_internet_srv);
981 : }
982 : }
983 1 : tcase_add_test(tc_resolv, test_resolv_free_context);
984 1 : tcase_add_test(tc_resolv, test_resolv_free_req);
985 :
986 : /* Add all test cases to the test suite */
987 1 : suite_add_tcase(s, tc_resolv);
988 :
989 1 : return s;
990 : }
991 :
992 1 : int main(int argc, const char *argv[])
993 : {
994 : int opt;
995 : poptContext pc;
996 : int failure_count;
997 : Suite *resolv_suite;
998 : SRunner *sr;
999 1 : int debug = 0;
1000 :
1001 1 : struct poptOption long_options[] = {
1002 : POPT_AUTOHELP
1003 : { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
1004 : { "use-net-test", 'n', POPT_ARG_NONE, 0, 'n', "Run tests that need an active internet connection", NULL },
1005 : { "txt-host", 't', POPT_ARG_STRING, 0, 't', "Specify the host used for TXT record testing", NULL },
1006 : { "srv-host", 's', POPT_ARG_STRING, 0, 's', "Specify the host used for SRV record testing", NULL },
1007 : POPT_TABLEEND
1008 : };
1009 :
1010 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
1011 1 : debug_level = SSSDBG_INVALID;
1012 :
1013 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
1014 1 : while((opt = poptGetNextOpt(pc)) != -1) {
1015 0 : switch(opt) {
1016 : case 'n':
1017 0 : use_net_test = 1;
1018 0 : break;
1019 : case 't':
1020 0 : txt_host = poptGetOptArg(pc);
1021 0 : break;
1022 : case 's':
1023 0 : srv_host = poptGetOptArg(pc);
1024 0 : break;
1025 : default:
1026 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
1027 : poptBadOption(pc, 0), poptStrerror(opt));
1028 0 : poptPrintUsage(pc, stderr, 0);
1029 0 : return 1;
1030 : }
1031 : }
1032 1 : poptFreeContext(pc);
1033 :
1034 1 : DEBUG_CLI_INIT(debug);
1035 :
1036 1 : if (!use_net_test) {
1037 1 : printf("Network tests disabled. Rerun with the \"-n\" "
1038 : "option to run the full suite of tests\n");
1039 : }
1040 :
1041 1 : tests_set_cwd();
1042 :
1043 1 : resolv_suite = create_resolv_suite();
1044 1 : sr = srunner_create(resolv_suite);
1045 : /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */
1046 1 : srunner_run_all(sr, CK_ENV);
1047 1 : failure_count = srunner_ntests_failed(sr);
1048 1 : srunner_free(sr);
1049 1 : return (failure_count==0 ? EXIT_SUCCESS : EXIT_FAILURE);
1050 : }
1051 :
|