Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2013 Red Hat
6 :
7 : SSSD tests: Dynamic DNS tests
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <talloc.h>
24 : #include <tevent.h>
25 : #include <errno.h>
26 : #include <popt.h>
27 : #include <unistd.h>
28 : #include <sys/types.h>
29 : #include <ifaddrs.h>
30 : #include <arpa/inet.h>
31 :
32 : /* In order to access opaque types */
33 : #include "providers/dp_dyndns.c"
34 :
35 : #include "tests/cmocka/common_mock.h"
36 : #include "tests/cmocka/common_mock_be.h"
37 : #include "src/providers/dp_dyndns.h"
38 :
39 : #define TESTS_PATH "tp_" BASE_FILE_STEM
40 : #define TEST_CONF_DB "test_dyndns_conf.ldb"
41 : #define TEST_DOM_NAME "dyndns_test"
42 : #define TEST_ID_PROVIDER "ldap"
43 :
44 : enum mock_nsupdate_states {
45 : MOCK_NSUPDATE_OK,
46 : MOCK_NSUPDATE_ERR,
47 : MOCK_NSUPDATE_TIMEOUT,
48 : };
49 :
50 : static TALLOC_CTX *global_mock_context = NULL;
51 :
52 : struct dyndns_test_ctx {
53 : struct sss_test_ctx *tctx;
54 :
55 : struct be_ctx *be_ctx;
56 : struct be_nsupdate_ctx *update_ctx;
57 :
58 : enum mock_nsupdate_states state;
59 : int child_status;
60 : int child_retval;
61 : };
62 :
63 : static struct dyndns_test_ctx *dyndns_test_ctx;
64 :
65 0 : void __wrap_execv(const char *path, char *const argv[])
66 : {
67 : int err;
68 :
69 0 : switch (dyndns_test_ctx->state) {
70 : case MOCK_NSUPDATE_OK:
71 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate success test case\n");
72 0 : err = 0;
73 0 : usleep(50000); /* 50 miliseconds */
74 0 : break;
75 : case MOCK_NSUPDATE_ERR:
76 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate error test case\n");
77 0 : err = 1;
78 0 : break;
79 : case MOCK_NSUPDATE_TIMEOUT:
80 0 : DEBUG(SSSDBG_FUNC_DATA, "nsupdate timeout test case\n");
81 0 : err = 2;
82 0 : sleep(3);
83 0 : break;
84 : default:
85 0 : DEBUG(SSSDBG_CRIT_FAILURE, "unknown test case\n");
86 0 : err = 255;
87 0 : break;
88 : }
89 :
90 0 : DEBUG(SSSDBG_TRACE_LIBS, "Child exiting with status %d\n", err);
91 0 : _exit(err);
92 : }
93 :
94 17 : int __wrap_getifaddrs(struct ifaddrs **_ifap)
95 : {
96 17 : struct ifaddrs *ifap = NULL;
97 17 : struct ifaddrs *ifap_prev = NULL;
98 17 : struct ifaddrs *ifap_head = NULL;
99 : char *name;
100 : char *straddr;
101 : int ad_family;
102 : struct sockaddr_in *sa;
103 : void *dst;
104 :
105 92 : while ((name = sss_mock_ptr_type(char *)) != NULL) {
106 58 : straddr = sss_mock_ptr_type(char *);
107 58 : if (straddr == NULL) {
108 0 : errno = EINVAL;
109 0 : goto fail;
110 : }
111 58 : ad_family = sss_mock_type(int);
112 :
113 58 : ifap = talloc_zero(global_mock_context, struct ifaddrs);
114 58 : if (ifap == NULL) {
115 0 : errno = ENOMEM; /* getifaddrs sets errno, too */
116 0 : goto fail;
117 : }
118 :
119 58 : if (ifap_prev) {
120 41 : ifap_prev->ifa_next = ifap;
121 : } else {
122 17 : ifap_head = ifap;
123 : }
124 58 : ifap_prev = ifap;
125 :
126 58 : ifap->ifa_name = talloc_strdup(ifap, name);
127 58 : if (ifap->ifa_name == NULL) {
128 0 : errno = ENOMEM;
129 0 : goto fail;
130 : }
131 :
132 : /* Do not alocate directly on ifap->ifa_addr to
133 : * avoid alignment warnings */
134 58 : if (ad_family == AF_INET) {
135 30 : sa = talloc(ifap, struct sockaddr_in);
136 28 : } else if (ad_family == AF_INET6) {
137 28 : sa = (struct sockaddr_in *) talloc(ifap, struct sockaddr_in6);
138 : } else {
139 0 : errno = EINVAL;
140 0 : goto fail;
141 : }
142 :
143 58 : if (sa == NULL) {
144 0 : errno = ENOMEM;
145 0 : goto fail;
146 : }
147 :
148 58 : sa->sin_family = ad_family;
149 :
150 58 : if (ad_family == AF_INET) {
151 30 : dst = &sa->sin_addr;
152 28 : } else if (ad_family == AF_INET6) {
153 28 : dst = &((struct sockaddr_in6 *)sa)->sin6_addr;
154 : } else {
155 0 : errno = EINVAL;
156 0 : goto fail;
157 : }
158 :
159 : /* convert straddr into ifa_addr */
160 58 : if (inet_pton(ad_family, straddr, dst) != 1) {
161 0 : goto fail;
162 : }
163 :
164 58 : ifap->ifa_addr = (struct sockaddr *) sa;
165 : }
166 :
167 17 : *_ifap = ifap_head;
168 17 : return 0;
169 :
170 : fail:
171 0 : talloc_free(ifap);
172 0 : return -1;
173 : }
174 :
175 17 : void __wrap_freeifaddrs(struct ifaddrs *ifap)
176 : {
177 17 : talloc_free(ifap);
178 17 : }
179 :
180 3 : static void dyndns_test_done(struct tevent_req *req)
181 : {
182 3 : struct dyndns_test_ctx *ctx =
183 3 : tevent_req_callback_data(req, struct dyndns_test_ctx);
184 :
185 3 : ctx->child_retval = -1;
186 3 : ctx->tctx->error = be_nsupdate_recv(req, &ctx->child_status);
187 3 : talloc_zfree(req);
188 :
189 3 : ctx->tctx->done = true;
190 3 : }
191 :
192 75 : void will_return_getifaddrs(const char *ifname, const char *straddr,
193 : int af_family)
194 : {
195 75 : will_return(__wrap_getifaddrs, ifname);
196 75 : if (ifname) {
197 58 : will_return(__wrap_getifaddrs, straddr);
198 : }
199 75 : if (straddr) {
200 58 : will_return(__wrap_getifaddrs, af_family);
201 : }
202 75 : }
203 :
204 1 : void dyndns_test_sss_iface_addr_get_misc(void **state)
205 : {
206 : struct sss_iface_addr addrs[3];
207 : struct sockaddr_storage ss[3];
208 :
209 1 : addrs[0].prev = NULL;
210 1 : addrs[0].next = &addrs[1];
211 1 : addrs[0].addr = &ss[0];
212 1 : addrs[1].prev = &addrs[0];
213 1 : addrs[1].next = &addrs[2];
214 1 : addrs[1].addr = &ss[1];
215 1 : addrs[2].prev = &addrs[1];
216 1 : addrs[2].next = NULL;
217 1 : addrs[2].addr = &ss[2];
218 :
219 1 : assert_ptr_equal(sss_iface_addr_get_address(NULL), NULL);
220 1 : assert_ptr_equal(sss_iface_addr_get_address(&addrs[0]), &ss[0]);
221 1 : assert_ptr_equal(sss_iface_addr_get_address(&addrs[1]), &ss[1]);
222 1 : assert_ptr_equal(sss_iface_addr_get_address(&addrs[2]), &ss[2]);
223 :
224 1 : assert_ptr_equal(sss_iface_addr_get_next(NULL), NULL);
225 1 : assert_ptr_equal(sss_iface_addr_get_next(&addrs[0]), &addrs[1]);
226 1 : assert_ptr_equal(sss_iface_addr_get_next(&addrs[1]), &addrs[2]);
227 1 : assert_ptr_equal(sss_iface_addr_get_next(&addrs[2]), NULL);
228 1 : }
229 :
230 1 : void dyndns_test_get_ifaddr(void **state)
231 : {
232 : errno_t ret;
233 : struct sss_iface_addr *addrlist;
234 : char straddr[128];
235 :
236 1 : check_leaks_push(dyndns_test_ctx);
237 1 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
238 1 : will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
239 1 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
240 1 : ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
241 1 : assert_int_equal(ret, EOK);
242 :
243 : /* There must be only one address with the correct value */
244 1 : assert_non_null(addrlist);
245 1 : assert_non_null(addrlist->addr);
246 1 : assert_null(addrlist->next);
247 1 : assert_null(addrlist->prev);
248 :
249 1 : assert_non_null(inet_ntop(AF_INET,
250 : &((struct sockaddr_in *) addrlist->addr)->sin_addr,
251 : straddr, INET_ADDRSTRLEN));
252 1 : assert_string_equal(straddr, "192.168.0.1");
253 :
254 1 : talloc_free(addrlist);
255 :
256 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
257 1 : }
258 :
259 1 : void dyndns_test_get_multi_ifaddr(void **state)
260 : {
261 : errno_t ret;
262 : struct sss_iface_addr *addrlist;
263 : struct sss_iface_addr *sss_if_addr;
264 : char straddr[128];
265 :
266 1 : check_leaks_push(dyndns_test_ctx);
267 1 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
268 1 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
269 1 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
270 1 : ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
271 1 : assert_int_equal(ret, EOK);
272 :
273 1 : sss_if_addr = addrlist;
274 1 : assert_non_null(sss_if_addr);
275 1 : assert_non_null(sss_if_addr->addr);
276 1 : assert_non_null(sss_if_addr->next);
277 1 : assert_null(sss_if_addr->prev);
278 :
279 1 : assert_non_null(inet_ntop(AF_INET,
280 : &((struct sockaddr_in *) sss_if_addr->addr)->sin_addr,
281 : straddr, INET_ADDRSTRLEN));
282 : /* ip addresses are returned in different order */
283 1 : assert_string_equal(straddr, "192.168.0.1");
284 :
285 1 : sss_if_addr = addrlist->next;
286 1 : assert_non_null(sss_if_addr);
287 1 : assert_non_null(sss_if_addr->addr);
288 1 : assert_null(sss_if_addr->next);
289 1 : assert_non_null(sss_if_addr->prev);
290 :
291 1 : assert_non_null(inet_ntop(AF_INET,
292 : &((struct sockaddr_in *) sss_if_addr->addr)->sin_addr,
293 : straddr, INET_ADDRSTRLEN));
294 : /* ip addresses are returned in different order */
295 1 : assert_string_equal(straddr, "192.168.0.2");
296 :
297 1 : talloc_free(addrlist);
298 :
299 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
300 1 : }
301 :
302 1 : void dyndns_test_get_ifaddr_enoent(void **state)
303 : {
304 : errno_t ret;
305 1 : struct sss_iface_addr *addrlist = NULL;
306 :
307 1 : check_leaks_push(dyndns_test_ctx);
308 1 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
309 1 : will_return_getifaddrs("eth1", "192.168.0.2", AF_INET);
310 1 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
311 1 : ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface",
312 : &addrlist);
313 1 : assert_int_equal(ret, ENOENT);
314 1 : talloc_free(addrlist);
315 :
316 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
317 1 : }
318 :
319 1 : void dyndns_test_addr_list_as_str_list(void **state)
320 : {
321 : int i;
322 : char **output;
323 : errno_t ret;
324 : struct sss_iface_addr *addrlist;
325 : struct {
326 : const char* addr;
327 : int af;
328 1 : } input[] = {
329 : {"2001:cdba::555", AF_INET6},
330 : {"192.168.0.1", AF_INET},
331 : {"192.168.0.2", AF_INET},
332 : {"2001:cdba::444", AF_INET6}
333 : };
334 1 : int size = 4;
335 :
336 1 : check_leaks_push(dyndns_test_ctx);
337 :
338 5 : for (i = 0; i < size; i++) {
339 4 : will_return_getifaddrs("eth0", input[i].addr, input[i].af);
340 : }
341 1 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
342 :
343 1 : ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist);
344 1 : assert_int_equal(ret, EOK);
345 :
346 1 : ret = sss_iface_addr_list_as_str_list(dyndns_test_ctx, addrlist, &output);
347 1 : assert_int_equal(ret, EOK);
348 5 : for (i = 0; i < size; i++) {
349 : /* addresses are returned in reversed order */
350 4 : assert_int_equal(strcmp(input[i].addr, output[size - 1 - i]), 0);
351 : }
352 :
353 1 : talloc_free(addrlist);
354 1 : talloc_free(output);
355 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
356 1 : }
357 :
358 1 : void dyndns_test_create_fwd_msg(void **state)
359 : {
360 : errno_t ret;
361 : char *msg;
362 : struct sss_iface_addr *addrlist;
363 : int i;
364 :
365 1 : check_leaks_push(dyndns_test_ctx);
366 :
367 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
368 3 : for (i = 0; i < 2; i++) {
369 2 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
370 2 : will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
371 2 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
372 2 : will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
373 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
374 : }
375 :
376 : struct sockaddr_in sin;
377 1 : memset(&sin, 0, sizeof (sin));
378 1 : sin.sin_family = AF_INET;
379 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
380 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
381 : (struct sockaddr *) &sin,
382 : &addrlist);
383 1 : assert_int_equal(ret, EOK);
384 :
385 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
386 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
387 : addrlist, &msg);
388 1 : assert_int_equal(ret, EOK);
389 :
390 1 : assert_string_equal(msg,
391 : "\nupdate delete bran_stark. in A\n"
392 : "update add bran_stark. 1234 in A 192.168.0.2\n"
393 : "send\n"
394 : "update delete bran_stark. in AAAA\n"
395 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
396 : "send\n");
397 1 : talloc_zfree(msg);
398 :
399 : /* fallback case realm and server */
400 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", "Winterfell",
401 : "bran_stark",
402 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
403 : addrlist, &msg);
404 1 : assert_int_equal(ret, EOK);
405 :
406 1 : assert_string_equal(msg,
407 : "server Winterfell\n"
408 : "realm North\n"
409 : "update delete bran_stark. in A\n"
410 : "update add bran_stark. 1234 in A 192.168.0.2\n"
411 : "send\n"
412 : "update delete bran_stark. in AAAA\n"
413 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
414 : "send\n");
415 1 : talloc_zfree(msg);
416 :
417 : /* just realm */
418 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, "North", NULL,
419 : "bran_stark",
420 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
421 : addrlist, &msg);
422 1 : assert_int_equal(ret, EOK);
423 :
424 1 : assert_string_equal(msg,
425 : "realm North\n"
426 : "update delete bran_stark. in A\n"
427 : "update add bran_stark. 1234 in A 192.168.0.2\n"
428 : "send\n"
429 : "update delete bran_stark. in AAAA\n"
430 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
431 : "send\n");
432 1 : talloc_zfree(msg);
433 :
434 : /* just server */
435 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, "Winterfell",
436 : "bran_stark",
437 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
438 : addrlist, &msg);
439 1 : assert_int_equal(ret, EOK);
440 :
441 1 : assert_string_equal(msg,
442 : "server Winterfell\n"
443 : "\n"
444 : "update delete bran_stark. in A\n"
445 : "update add bran_stark. 1234 in A 192.168.0.2\n"
446 : "send\n"
447 : "update delete bran_stark. in AAAA\n"
448 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
449 : "send\n");
450 1 : talloc_zfree(msg);
451 :
452 : /* remove just A */
453 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
454 : 1234, DYNDNS_REMOVE_A,
455 : addrlist, &msg);
456 1 : assert_int_equal(ret, EOK);
457 :
458 1 : assert_string_equal(msg,
459 : "\nupdate delete bran_stark. in A\n"
460 : "update add bran_stark. 1234 in A 192.168.0.2\n"
461 : "send\n"
462 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
463 : "send\n");
464 1 : talloc_zfree(msg);
465 :
466 : /* remove just AAAA */
467 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
468 : 1234, DYNDNS_REMOVE_AAAA,
469 : addrlist, &msg);
470 1 : assert_int_equal(ret, EOK);
471 :
472 1 : assert_string_equal(msg,
473 : "\nupdate add bran_stark. 1234 in A 192.168.0.2\n"
474 : "send\n"
475 : "update delete bran_stark. in AAAA\n"
476 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
477 : "send\n");
478 1 : talloc_zfree(msg);
479 :
480 1 : talloc_free(addrlist);
481 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
482 1 : }
483 :
484 1 : void dyndns_test_create_fwd_msg_mult(void **state)
485 : {
486 : errno_t ret;
487 : char *msg;
488 : struct sss_iface_addr *addrlist;
489 : int i;
490 :
491 1 : check_leaks_push(dyndns_test_ctx);
492 :
493 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
494 3 : for (i = 0; i < 2; i++) {
495 2 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
496 2 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
497 2 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
498 2 : will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
499 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
500 : }
501 :
502 : struct sockaddr_in sin;
503 1 : memset(&sin, 0, sizeof (sin));
504 1 : sin.sin_family = AF_INET;
505 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
506 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
507 : (struct sockaddr *) &sin,
508 : &addrlist);
509 1 : assert_int_equal(ret, EOK);
510 :
511 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
512 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
513 : addrlist, &msg);
514 1 : assert_int_equal(ret, EOK);
515 :
516 1 : assert_string_equal(msg,
517 : "\nupdate delete bran_stark. in A\n"
518 : "update add bran_stark. 1234 in A 192.168.0.1\n"
519 : "update add bran_stark. 1234 in A 192.168.0.2\n"
520 : "send\n"
521 : "update delete bran_stark. in AAAA\n"
522 : "update add bran_stark. 1234 in AAAA 2001:cdba::444\n"
523 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
524 : "send\n");
525 1 : talloc_zfree(msg);
526 :
527 1 : talloc_free(addrlist);
528 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
529 1 : }
530 :
531 1 : void dyndns_test_create_fwd_msg_A(void **state)
532 : {
533 : errno_t ret;
534 : char *msg;
535 : struct sss_iface_addr *addrlist;
536 : int i;
537 :
538 1 : check_leaks_push(dyndns_test_ctx);
539 :
540 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
541 3 : for (i = 0; i < 2; i++) {
542 2 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
543 2 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
544 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
545 : }
546 :
547 : struct sockaddr_in sin;
548 1 : memset(&sin, 0, sizeof (sin));
549 1 : sin.sin_family = AF_INET;
550 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
551 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
552 : (struct sockaddr *) &sin,
553 : &addrlist);
554 1 : assert_int_equal(ret, EOK);
555 :
556 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
557 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
558 : addrlist, &msg);
559 1 : assert_int_equal(ret, EOK);
560 :
561 1 : assert_string_equal(msg,
562 : "\nupdate delete bran_stark. in A\n"
563 : "update add bran_stark. 1234 in A 192.168.0.1\n"
564 : "update add bran_stark. 1234 in A 192.168.0.2\n"
565 : "send\n"
566 : "update delete bran_stark. in AAAA\n"
567 : "send\n");
568 1 : talloc_zfree(msg);
569 :
570 1 : talloc_free(addrlist);
571 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
572 1 : }
573 :
574 1 : void dyndns_test_create_fwd_msg_AAAA(void **state)
575 : {
576 : errno_t ret;
577 : char *msg;
578 : struct sss_iface_addr *addrlist;
579 : int i;
580 :
581 1 : check_leaks_push(dyndns_test_ctx);
582 :
583 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
584 3 : for (i = 0; i < 2; i++) {
585 2 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
586 2 : will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
587 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
588 : }
589 :
590 : struct sockaddr_in6 sin;
591 1 : memset(&sin, 0, sizeof (sin));
592 1 : sin.sin6_family = AF_INET6;
593 1 : ret = inet_pton(AF_INET6, "2001:cdba::555", &sin.sin6_addr.s6_addr);
594 1 : assert_int_equal(ret, 1);
595 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
596 : (struct sockaddr *) &sin,
597 : &addrlist);
598 1 : assert_int_equal(ret, EOK);
599 :
600 1 : ret = be_nsupdate_create_fwd_msg(dyndns_test_ctx, NULL, NULL, "bran_stark",
601 : 1234, DYNDNS_REMOVE_A | DYNDNS_REMOVE_AAAA,
602 : addrlist, &msg);
603 1 : assert_int_equal(ret, EOK);
604 :
605 1 : assert_string_equal(msg,
606 : "\nupdate delete bran_stark. in A\n"
607 : "send\n"
608 : "update delete bran_stark. in AAAA\n"
609 : "update add bran_stark. 1234 in AAAA 2001:cdba::444\n"
610 : "update add bran_stark. 1234 in AAAA 2001:cdba::555\n"
611 : "send\n");
612 1 : talloc_zfree(msg);
613 :
614 1 : talloc_free(addrlist);
615 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
616 1 : }
617 :
618 1 : void dyndns_test_dualstack(void **state)
619 : {
620 : errno_t ret;
621 : struct sss_iface_addr *addrlist;
622 : struct sss_iface_addr *sss_if_addrs;
623 : char straddr[128];
624 : int i;
625 :
626 1 : check_leaks_push(dyndns_test_ctx);
627 :
628 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
629 3 : for (i = 0; i < 2; i++) {
630 2 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
631 2 : will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
632 2 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
633 2 : will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
634 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
635 : }
636 :
637 : struct sockaddr_in sin;
638 1 : memset(&sin, 0, sizeof (sin));
639 1 : sin.sin_family = AF_INET;
640 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
641 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
642 : (struct sockaddr *) &sin,
643 : &addrlist);
644 1 : assert_int_equal(ret, EOK);
645 :
646 1 : sss_if_addrs = addrlist;
647 1 : assert_non_null(sss_if_addrs);
648 1 : assert_non_null(sss_if_addrs->addr);
649 1 : assert_non_null(sss_if_addrs->next);
650 1 : assert_null(sss_if_addrs->prev);
651 :
652 1 : assert_non_null(inet_ntop(AF_INET6,
653 : &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
654 : straddr, INET6_ADDRSTRLEN));
655 : /* ip addresses are returned in different order */
656 1 : assert_string_equal(straddr, "2001:cdba::555");
657 :
658 1 : sss_if_addrs = addrlist->next;
659 1 : assert_non_null(sss_if_addrs);
660 1 : assert_non_null(sss_if_addrs->addr);
661 1 : assert_null(sss_if_addrs->next);
662 1 : assert_non_null(sss_if_addrs->prev);
663 :
664 1 : assert_non_null(inet_ntop(AF_INET,
665 : &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
666 : straddr, INET_ADDRSTRLEN));
667 : /* ip addresses are returned in different order */
668 1 : assert_string_equal(straddr, "192.168.0.2");
669 :
670 1 : talloc_free(addrlist);
671 :
672 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
673 1 : }
674 :
675 1 : void dyndns_test_dualstack_multiple_addresses(void **state)
676 : {
677 : errno_t ret;
678 : struct sss_iface_addr *addrlist;
679 : struct sss_iface_addr *sss_if_addrs;
680 : char straddr[128];
681 : int i;
682 :
683 1 : check_leaks_push(dyndns_test_ctx);
684 :
685 : /* getifaddrs is called twice in sss_get_dualstack_addresses() */
686 3 : for (i = 0; i < 2; i++) {
687 2 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
688 2 : will_return_getifaddrs("eth0", "192.168.0.1", AF_INET);
689 : /* loopback - invalid for dns (should be skipped) */
690 2 : will_return_getifaddrs("eth0", "::1", AF_INET6);
691 : /* linklocal - invalid for dns (should be skipped) */
692 2 : will_return_getifaddrs("eth0", "fe80::5054:ff:fe4a:65ae", AF_INET6);
693 2 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
694 2 : will_return_getifaddrs("eth0", "2001:cdba::444", AF_INET6);
695 2 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
696 : }
697 :
698 : struct sockaddr_in sin;
699 1 : memset(&sin, 0, sizeof (sin));
700 1 : sin.sin_family = AF_INET;
701 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.2");
702 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
703 : (struct sockaddr *) &sin,
704 : &addrlist);
705 1 : assert_int_equal(ret, EOK);
706 :
707 1 : sss_if_addrs = addrlist;
708 1 : assert_non_null(sss_if_addrs);
709 1 : assert_non_null(sss_if_addrs->addr);
710 1 : assert_non_null(sss_if_addrs->next);
711 1 : assert_null(sss_if_addrs->prev);
712 :
713 1 : assert_non_null(inet_ntop(AF_INET6,
714 : &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
715 : straddr, INET6_ADDRSTRLEN));
716 : /* ip addresses are returned in different order */
717 1 : assert_string_equal(straddr, "2001:cdba::444");
718 :
719 1 : sss_if_addrs = sss_if_addrs->next;
720 1 : assert_non_null(sss_if_addrs);
721 1 : assert_non_null(sss_if_addrs->addr);
722 1 : assert_non_null(sss_if_addrs->prev);
723 1 : assert_non_null(sss_if_addrs->next);
724 :
725 1 : assert_non_null(inet_ntop(AF_INET6,
726 : &((struct sockaddr_in6 *) sss_if_addrs->addr)->sin6_addr,
727 : straddr, INET6_ADDRSTRLEN));
728 : /* ip addresses are returned in different order */
729 1 : assert_string_equal(straddr, "2001:cdba::555");
730 :
731 1 : sss_if_addrs = sss_if_addrs->next;
732 1 : assert_non_null(sss_if_addrs);
733 1 : assert_non_null(sss_if_addrs->addr);
734 1 : assert_non_null(sss_if_addrs->next);
735 1 : assert_non_null(sss_if_addrs->prev);
736 :
737 1 : assert_non_null(inet_ntop(AF_INET,
738 : &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
739 : straddr, INET_ADDRSTRLEN));
740 : /* ip addresses are returned in different order */
741 1 : assert_string_equal(straddr, "192.168.0.1");
742 :
743 1 : sss_if_addrs = sss_if_addrs->next;
744 1 : assert_non_null(sss_if_addrs);
745 1 : assert_non_null(sss_if_addrs->addr);
746 1 : assert_null(sss_if_addrs->next);
747 1 : assert_non_null(sss_if_addrs->prev);
748 :
749 1 : assert_non_null(inet_ntop(AF_INET,
750 : &((struct sockaddr_in *) sss_if_addrs->addr)->sin_addr,
751 : straddr, INET_ADDRSTRLEN));
752 : /* ip addresses are returned in different order */
753 1 : assert_string_equal(straddr, "192.168.0.2");
754 :
755 1 : talloc_free(addrlist);
756 :
757 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
758 1 : }
759 :
760 1 : void dyndns_test_dualstack_no_iface(void **state)
761 : {
762 : errno_t ret;
763 : struct sss_iface_addr *addrlist;
764 :
765 1 : check_leaks_push(dyndns_test_ctx);
766 :
767 1 : will_return_getifaddrs("eth0", "192.168.0.2", AF_INET);
768 1 : will_return_getifaddrs("eth1", "192.168.0.1", AF_INET);
769 1 : will_return_getifaddrs("eth0", "2001:cdba::555", AF_INET6);
770 1 : will_return_getifaddrs("eth1", "2001:cdba::444", AF_INET6);
771 1 : will_return_getifaddrs(NULL, NULL, 0); /* sentinel */
772 :
773 : struct sockaddr_in sin;
774 1 : memset(&sin, 0, sizeof (sin));
775 1 : sin.sin_family = AF_INET;
776 1 : sin.sin_addr.s_addr = inet_addr ("192.168.0.3");
777 1 : ret = sss_get_dualstack_addresses(dyndns_test_ctx,
778 : (struct sockaddr *) &sin,
779 : &addrlist);
780 1 : assert_int_equal(ret, ENOENT);
781 :
782 1 : assert_true(check_leaks_pop(dyndns_test_ctx) == true);
783 1 : }
784 :
785 1 : void dyndns_test_ok(void **state)
786 : {
787 : struct tevent_req *req;
788 : errno_t ret;
789 : TALLOC_CTX *tmp_ctx;
790 :
791 1 : tmp_ctx = talloc_new(global_talloc_context);
792 1 : assert_non_null(tmp_ctx);
793 1 : check_leaks_push(tmp_ctx);
794 :
795 1 : dyndns_test_ctx->state = MOCK_NSUPDATE_OK;
796 :
797 1 : req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
798 : BE_NSUPDATE_AUTH_GSS_TSIG,
799 : discard_const("test message"), false);
800 1 : assert_non_null(req);
801 1 : tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
802 :
803 : /* Wait until the test finishes with EOK */
804 1 : ret = test_ev_loop(dyndns_test_ctx->tctx);
805 1 : DEBUG(SSSDBG_TRACE_LIBS,
806 : "Child request returned [%d]: %s\n", ret, strerror(ret));
807 1 : assert_int_equal(ret, EOK);
808 :
809 1 : assert_true(WIFEXITED(dyndns_test_ctx->child_status));
810 1 : assert_int_equal(WEXITSTATUS(dyndns_test_ctx->child_status), 0);
811 :
812 1 : assert_true(check_leaks_pop(tmp_ctx) == true);
813 1 : talloc_free(tmp_ctx);
814 1 : }
815 :
816 1 : void dyndns_test_error(void **state)
817 : {
818 : struct tevent_req *req;
819 : errno_t ret;
820 : TALLOC_CTX *tmp_ctx;
821 :
822 1 : tmp_ctx = talloc_new(global_talloc_context);
823 1 : assert_non_null(tmp_ctx);
824 1 : check_leaks_push(tmp_ctx);
825 :
826 1 : dyndns_test_ctx->state = MOCK_NSUPDATE_ERR;
827 :
828 1 : req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
829 : BE_NSUPDATE_AUTH_GSS_TSIG,
830 : discard_const("test message"), false);
831 1 : assert_non_null(req);
832 1 : tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
833 :
834 : /* Wait until the test finishes with EIO (child error) */
835 1 : ret = test_ev_loop(dyndns_test_ctx->tctx);
836 1 : DEBUG(SSSDBG_TRACE_LIBS,
837 : "Child request returned [%d]: %s\n", ret, strerror(ret));
838 1 : assert_int_equal(ret, ERR_DYNDNS_FAILED);
839 :
840 1 : assert_true(WIFEXITED(dyndns_test_ctx->child_status));
841 1 : assert_int_equal(WEXITSTATUS(dyndns_test_ctx->child_status), 1);
842 :
843 1 : assert_true(check_leaks_pop(tmp_ctx) == true);
844 1 : talloc_free(tmp_ctx);
845 1 : }
846 :
847 1 : void dyndns_test_timeout(void **state)
848 : {
849 : struct tevent_req *req;
850 : errno_t ret;
851 : TALLOC_CTX *tmp_ctx;
852 :
853 1 : tmp_ctx = talloc_new(global_talloc_context);
854 1 : assert_non_null(tmp_ctx);
855 1 : check_leaks_push(tmp_ctx);
856 :
857 1 : dyndns_test_ctx->state = MOCK_NSUPDATE_TIMEOUT;
858 :
859 1 : req = be_nsupdate_send(tmp_ctx, dyndns_test_ctx->tctx->ev,
860 : BE_NSUPDATE_AUTH_GSS_TSIG,
861 : discard_const("test message"), false);
862 1 : assert_non_null(req);
863 1 : tevent_req_set_callback(req, dyndns_test_done, dyndns_test_ctx);
864 :
865 : /* Wait until the test finishes with EIO (child error) */
866 1 : ret = test_ev_loop(dyndns_test_ctx->tctx);
867 :
868 : /* The event queue may not be empty. We need to make sure that all events
869 : * are processed. Unfortunately, tevent_loop_wait() contains a bug that
870 : * prevents exiting the loop even if there are no remaining events, thus
871 : * we have to use tevent_loop_once().
872 : *
873 : * FIXME: use tevent_loop_wait() when the bug is fixed
874 : * https://bugzilla.samba.org/show_bug.cgi?id=10012
875 : */
876 1 : tevent_loop_once(dyndns_test_ctx->tctx->ev); /* SIGCHLD handler */
877 1 : tevent_loop_once(dyndns_test_ctx->tctx->ev); /* nsupdate_child_handler */
878 :
879 1 : DEBUG(SSSDBG_TRACE_LIBS,
880 : "Child request returned [%d]: %s\n", ret, strerror(ret));
881 1 : assert_int_equal(ret, ERR_DYNDNS_TIMEOUT);
882 :
883 1 : assert_true(check_leaks_pop(tmp_ctx) == true);
884 1 : talloc_free(tmp_ctx);
885 1 : }
886 :
887 2 : void dyndns_test_timer(void *pvt)
888 : {
889 2 : struct dyndns_test_ctx *ctx = talloc_get_type(pvt, struct dyndns_test_ctx);
890 : static int ncalls = 0;
891 :
892 2 : ncalls++;
893 2 : if (ncalls == 1) {
894 1 : be_nsupdate_timer_schedule(ctx->tctx->ev, ctx->update_ctx);
895 1 : } else if (ncalls == 2) {
896 1 : ctx->tctx->done = true;
897 : }
898 2 : ctx->tctx->error = ERR_OK;
899 2 : }
900 :
901 1 : void dyndns_test_interval(void **state)
902 : {
903 : errno_t ret;
904 : TALLOC_CTX *tmp_ctx;
905 :
906 1 : tmp_ctx = talloc_new(global_talloc_context);
907 1 : assert_non_null(tmp_ctx);
908 1 : check_leaks_push(tmp_ctx);
909 :
910 1 : ret = be_nsupdate_init(tmp_ctx, dyndns_test_ctx->be_ctx, NULL,
911 1 : &dyndns_test_ctx->update_ctx);
912 1 : assert_int_equal(ret, EOK);
913 :
914 2 : ret = be_nsupdate_init_timer(dyndns_test_ctx->update_ctx,
915 1 : dyndns_test_ctx->be_ctx->ev,
916 : dyndns_test_timer, dyndns_test_ctx);
917 1 : assert_int_equal(ret, EOK);
918 :
919 : /* Wait until the timer hits */
920 1 : ret = test_ev_loop(dyndns_test_ctx->tctx);
921 1 : DEBUG(SSSDBG_TRACE_LIBS,
922 : "Child request returned [%d]: %s\n", ret, strerror(ret));
923 1 : assert_int_equal(ret, ERR_OK);
924 :
925 1 : talloc_free(dyndns_test_ctx->update_ctx);
926 1 : assert_true(check_leaks_pop(tmp_ctx) == true);
927 1 : talloc_free(tmp_ctx);
928 1 : }
929 :
930 : /* Testsuite setup and teardown */
931 8 : static int dyndns_test_setup(void **state)
932 : {
933 8 : struct sss_test_conf_param params[] = {
934 : { "dyndns_update", "true" },
935 : { "dyndns_refresh_interval", "2" },
936 : { NULL, NULL }, /* Sentinel */
937 : };
938 :
939 8 : assert_true(leak_check_setup());
940 8 : global_mock_context = talloc_new(global_talloc_context);
941 8 : assert_non_null(global_mock_context);
942 :
943 8 : dyndns_test_ctx = talloc_zero(global_talloc_context, struct dyndns_test_ctx);
944 8 : assert_non_null(dyndns_test_ctx);
945 :
946 8 : dyndns_test_ctx->tctx = create_dom_test_ctx(dyndns_test_ctx, TESTS_PATH,
947 : TEST_CONF_DB, TEST_DOM_NAME,
948 : TEST_ID_PROVIDER, params);
949 8 : assert_non_null(dyndns_test_ctx->tctx);
950 :
951 8 : dyndns_test_ctx->be_ctx = mock_be_ctx(dyndns_test_ctx, dyndns_test_ctx->tctx);
952 8 : assert_non_null(dyndns_test_ctx->be_ctx);
953 :
954 8 : return 0;
955 : }
956 :
957 8 : static int dyndns_test_simple_setup(void **state)
958 : {
959 8 : assert_true(leak_check_setup());
960 8 : global_mock_context = talloc_new(global_talloc_context);
961 8 : assert_non_null(global_mock_context);
962 :
963 8 : dyndns_test_ctx = talloc_zero(global_talloc_context, struct dyndns_test_ctx);
964 8 : assert_non_null(dyndns_test_ctx);
965 8 : return 0;
966 : }
967 :
968 16 : static int dyndns_test_teardown(void **state)
969 : {
970 16 : talloc_free(dyndns_test_ctx);
971 16 : talloc_free(global_mock_context);
972 16 : assert_true(leak_check_teardown());
973 16 : return 0;
974 : }
975 :
976 1 : int main(int argc, const char *argv[])
977 : {
978 : int rv;
979 1 : int no_cleanup = 0;
980 : poptContext pc;
981 : int opt;
982 7 : struct poptOption long_options[] = {
983 : POPT_AUTOHELP
984 5 : SSSD_DEBUG_OPTS
985 : {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0,
986 1 : _("Do not delete the test database after a test run"), NULL },
987 : POPT_TABLEEND
988 : };
989 :
990 1 : const struct CMUnitTest tests[] = {
991 : /* Utility functions unit test */
992 : cmocka_unit_test_setup_teardown(dyndns_test_sss_iface_addr_get_misc,
993 : dyndns_test_simple_setup,
994 : dyndns_test_teardown),
995 : cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr,
996 : dyndns_test_simple_setup,
997 : dyndns_test_teardown),
998 : cmocka_unit_test_setup_teardown(dyndns_test_get_multi_ifaddr,
999 : dyndns_test_simple_setup,
1000 : dyndns_test_teardown),
1001 : cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent,
1002 : dyndns_test_simple_setup,
1003 : dyndns_test_teardown),
1004 : cmocka_unit_test_setup_teardown(dyndns_test_addr_list_as_str_list,
1005 : dyndns_test_simple_setup,
1006 : dyndns_test_teardown),
1007 :
1008 : /* Dynamic DNS update unit tests*/
1009 : cmocka_unit_test_setup_teardown(dyndns_test_ok,
1010 : dyndns_test_setup,
1011 : dyndns_test_teardown),
1012 : cmocka_unit_test_setup_teardown(dyndns_test_error,
1013 : dyndns_test_setup,
1014 : dyndns_test_teardown),
1015 : cmocka_unit_test_setup_teardown(dyndns_test_timeout,
1016 : dyndns_test_setup,
1017 : dyndns_test_teardown),
1018 : cmocka_unit_test_setup_teardown(dyndns_test_interval,
1019 : dyndns_test_setup,
1020 : dyndns_test_teardown),
1021 :
1022 : /* Dynamic DNS dualstack unit tests*/
1023 : cmocka_unit_test_setup_teardown(dyndns_test_dualstack,
1024 : dyndns_test_simple_setup,
1025 : dyndns_test_teardown),
1026 : cmocka_unit_test_setup_teardown(dyndns_test_dualstack_multiple_addresses,
1027 : dyndns_test_simple_setup,
1028 : dyndns_test_teardown),
1029 : cmocka_unit_test_setup_teardown(dyndns_test_dualstack_no_iface,
1030 : dyndns_test_simple_setup,
1031 : dyndns_test_teardown),
1032 :
1033 : /* Messages for nsupdate */
1034 : cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg,
1035 : dyndns_test_setup,
1036 : dyndns_test_teardown),
1037 : cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_mult,
1038 : dyndns_test_setup,
1039 : dyndns_test_teardown),
1040 : cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_A,
1041 : dyndns_test_setup,
1042 : dyndns_test_teardown),
1043 : cmocka_unit_test_setup_teardown(dyndns_test_create_fwd_msg_AAAA,
1044 : dyndns_test_setup,
1045 : dyndns_test_teardown),
1046 : };
1047 :
1048 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
1049 1 : debug_level = SSSDBG_INVALID;
1050 :
1051 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
1052 1 : while((opt = poptGetNextOpt(pc)) != -1) {
1053 : switch(opt) {
1054 : default:
1055 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
1056 : poptBadOption(pc, 0), poptStrerror(opt));
1057 0 : poptPrintUsage(pc, stderr, 0);
1058 0 : return 1;
1059 : }
1060 : }
1061 1 : poptFreeContext(pc);
1062 :
1063 1 : DEBUG_CLI_INIT(debug_level);
1064 :
1065 : /* Even though normally the tests should clean up after themselves
1066 : * they might not after a failed run. Remove the old db to be sure */
1067 1 : tests_set_cwd();
1068 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
1069 1 : test_dom_suite_setup(TESTS_PATH);
1070 :
1071 1 : rv = cmocka_run_group_tests(tests, NULL, NULL);
1072 1 : if (rv == 0 && !no_cleanup) {
1073 1 : test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
1074 : }
1075 1 : return rv;
1076 : }
|