2 * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@posteo.se>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the author nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 #include <netinet/in.h>
47 #include <arpa/nameser.h>
48 #include <arpa/inet.h>
53 static void test_res_fake_a_query(void **state)
56 struct __res_state dnsstate;
57 unsigned char answer[ANSIZE];
58 char addr[INET_ADDRSTRLEN];
60 ns_rr rr; /* expanded resource record */
62 (void) state; /* unused */
64 memset(&dnsstate, 0, sizeof(struct __res_state));
65 rv = res_ninit(&dnsstate);
66 assert_int_equal(rv, 0);
68 rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a,
69 answer, sizeof(answer));
70 assert_in_range(rv, 1, 100);
72 ns_initparse(answer, sizeof(answer), &handle);
73 /* The query must finish w/o an error, have one answer and the answer
74 * must be a parseable RR of type A and have the address that our
75 * fake hosts file contains
77 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
78 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
79 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
80 assert_int_equal(ns_rr_type(rr), ns_t_a);
81 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
83 assert_string_equal(addr, "127.0.0.21");
86 static void test_res_fake_a_query_case_insensitive(void **state)
89 struct __res_state dnsstate;
90 unsigned char answer[ANSIZE];
91 char addr[INET_ADDRSTRLEN];
93 ns_rr rr; /* expanded resource record */
95 (void) state; /* unused */
97 memset(&dnsstate, 0, sizeof(struct __res_state));
98 rv = res_ninit(&dnsstate);
99 assert_int_equal(rv, 0);
101 rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a,
102 answer, sizeof(answer));
103 assert_in_range(rv, 1, 100);
105 ns_initparse(answer, sizeof(answer), &handle);
106 /* The query must finish w/o an error, have one answer and the answer
107 * must be a parseable RR of type A and have the address that our
108 * fake hosts file contains. Case does not matter.
110 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
111 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
112 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
113 assert_int_equal(ns_rr_type(rr), ns_t_a);
114 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
115 addr, sizeof(addr)));
116 assert_string_equal(addr, "127.0.0.21");
118 res_nclose(&dnsstate);
121 static void test_res_fake_a_query_trailing_dot(void **state)
124 struct __res_state dnsstate;
125 unsigned char answer[ANSIZE];
126 char addr[INET_ADDRSTRLEN];
128 ns_rr rr; /* expanded resource record */
130 (void) state; /* unused */
132 memset(&dnsstate, 0, sizeof(struct __res_state));
133 rv = res_ninit(&dnsstate);
134 assert_int_equal(rv, 0);
136 rv = res_nquery(&dnsstate, "cwrap.org.", ns_c_in, ns_t_a,
138 assert_in_range(rv, 1, 100);
140 ns_initparse(answer, 256, &handle);
141 /* The query must finish w/o an error, have one answer and the answer
142 * must be a parseable RR of type A and have the address that our
143 * fake hosts file contains
145 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
146 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
147 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
148 assert_int_equal(ns_rr_type(rr), ns_t_a);
149 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, 256));
150 assert_string_equal(addr, "127.0.0.21");
152 res_nclose(&dnsstate);
155 static void test_res_fake_a_query_notfound(void **state)
158 struct __res_state dnsstate;
159 unsigned char answer[ANSIZE];
162 (void) state; /* unused */
164 memset(&dnsstate, 0, sizeof(struct __res_state));
165 rv = res_ninit(&dnsstate);
166 assert_int_equal(rv, 0);
168 rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a,
169 answer, sizeof(answer));
170 assert_in_range(rv, 1, 100);
172 ns_initparse(answer, sizeof(answer), &handle);
173 /* The query must finish w/o an error and have no answer */
174 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
175 assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
178 static void test_res_fake_aaaa_query(void **state)
181 struct __res_state dnsstate;
182 unsigned char answer[ANSIZE];
183 char addr[INET6_ADDRSTRLEN];
185 ns_rr rr; /* expanded resource record */
187 (void) state; /* unused */
189 memset(&dnsstate, 0, sizeof(struct __res_state));
190 rv = res_ninit(&dnsstate);
191 assert_int_equal(rv, 0);
193 rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa,
194 answer, sizeof(answer));
195 assert_in_range(rv, 1, 100);
197 ns_initparse(answer, sizeof(answer), &handle);
198 /* The query must finish w/o an error, have one answer and the answer
199 * must be a parseable RR of type AAAA and have the address that our
200 * fake hosts file contains
202 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
203 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
204 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
205 assert_int_equal(ns_rr_type(rr), ns_t_aaaa);
206 assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr),
207 addr, sizeof(addr)));
208 assert_string_equal(addr, "2a00:1450:4013:c01::63");
211 static void test_res_fake_aaaa_query_notfound(void **state)
214 struct __res_state dnsstate;
215 unsigned char answer[ANSIZE];
218 (void) state; /* unused */
220 memset(&dnsstate, 0, sizeof(struct __res_state));
221 rv = res_ninit(&dnsstate);
222 assert_int_equal(rv, 0);
224 rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa,
225 answer, sizeof(answer));
226 assert_in_range(rv, 1, 100);
228 ns_initparse(answer, sizeof(answer), &handle);
229 /* The query must finish w/o an error and have no answer */
230 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
231 assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
234 static void test_res_fake_srv_query(void **state)
237 struct __res_state dnsstate;
238 unsigned char answer[ANSIZE];
240 ns_rr rr; /* expanded resource record */
241 const uint8_t *rrdata;
245 char hostname[MAXDNAME];
247 (void) state; /* unused */
249 memset(&dnsstate, 0, sizeof(struct __res_state));
250 rv = res_ninit(&dnsstate);
251 assert_int_equal(rv, 0);
253 rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
254 answer, sizeof(answer));
255 assert_in_range(rv, 1, 100);
257 ns_initparse(answer, sizeof(answer), &handle);
260 * The query must finish w/o an error, have one answer and the answer
261 * must be a parseable RR of type SRV and have the priority, weight,
262 * port and hostname as in the fake hosts file
264 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
265 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
266 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
267 assert_int_equal(ns_rr_type(rr), ns_t_srv);
269 rrdata = ns_rr_rdata(rr);
270 NS_GET16(prio, rrdata);
271 NS_GET16(weight, rrdata);
272 NS_GET16(port, rrdata);
274 rv = ns_name_uncompress(ns_msg_base(handle),
278 assert_int_not_equal(rv, -1);
280 assert_int_equal(prio, 1);
281 assert_int_equal(weight, 5);
282 assert_int_equal(port, 389);
283 assert_string_equal(hostname, "ldap.cwrap.org");
287 * Test the case of a SRV record query where the
288 * fake hosts file entry is minimal in the sense
289 * that it omits the priority and weight entries.
290 * The server then fills in some default values.
292 static void test_res_fake_srv_query_minimal(void **state)
295 struct __res_state dnsstate;
296 unsigned char answer[ANSIZE];
298 ns_rr rr; /* expanded resource record */
299 const uint8_t *rrdata;
303 char hostname[MAXDNAME];
304 char addr[INET_ADDRSTRLEN];
306 (void) state; /* unused */
308 memset(&dnsstate, 0, sizeof(struct __res_state));
309 rv = res_ninit(&dnsstate);
310 assert_int_equal(rv, 0);
312 rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
313 answer, sizeof(answer));
314 assert_in_range(rv, 1, 256);
316 ns_initparse(answer, sizeof(answer), &handle);
319 * The query must finish w/o an error, have one answer and the answer
320 * must be a parseable RR of type SRV and have the priority, weight,
321 * port and hostname as in the fake hosts file
323 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
324 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
325 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
326 assert_int_equal(ns_rr_type(rr), ns_t_srv);
328 rrdata = ns_rr_rdata(rr);
329 NS_GET16(prio, rrdata);
330 NS_GET16(weight, rrdata);
331 NS_GET16(port, rrdata);
333 rv = ns_name_uncompress(ns_msg_base(handle),
337 assert_int_not_equal(rv, -1);
339 assert_int_equal(prio, 1);
340 assert_int_equal(weight, 100);
341 assert_int_equal(port, 88);
342 assert_string_equal(hostname, "krb5.cwrap.org");
344 /* The additional section contains the A record of krb5.cwrap.org */
345 assert_int_equal(ns_msg_count(handle, ns_s_ar), 1);
346 assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
347 assert_int_equal(ns_rr_type(rr), ns_t_a);
348 assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org");
349 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
350 addr, sizeof(addr)));
351 assert_string_equal(addr, "127.0.0.23");
354 static void test_res_fake_soa_query(void **state)
357 struct __res_state dnsstate;
358 unsigned char answer[ANSIZE];
360 ns_rr rr; /* expanded resource record */
361 const uint8_t *rrdata;
362 char nameser[MAXDNAME];
363 char admin[MAXDNAME];
370 (void) state; /* unused */
372 memset(&dnsstate, 0, sizeof(struct __res_state));
373 rv = res_ninit(&dnsstate);
374 assert_int_equal(rv, 0);
376 rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
377 answer, sizeof(answer));
378 assert_in_range(rv, 1, 100);
380 ns_initparse(answer, sizeof(answer), &handle);
383 * The query must finish w/o an error, have one answer and the answer
384 * must be a parseable RR of type SOA and have the data as in the fake
387 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
388 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
389 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
390 assert_int_equal(ns_rr_type(rr), ns_t_soa);
392 rrdata = ns_rr_rdata(rr);
394 rv = ns_name_uncompress(ns_msg_base(handle),
398 assert_int_not_equal(rv, -1);
401 rv = ns_name_uncompress(ns_msg_base(handle),
405 assert_int_not_equal(rv, -1);
408 NS_GET32(serial, rrdata);
409 NS_GET32(refresh, rrdata);
410 NS_GET32(retry, rrdata);
411 NS_GET32(expire, rrdata);
412 NS_GET32(minimum, rrdata);
414 assert_string_equal(nameser, "ns1.cwrap.org");
415 assert_string_equal(admin, "admin.cwrap.org");
416 assert_int_equal(serial, 2014100457);
417 assert_int_equal(refresh, 3600);
418 assert_int_equal(retry, 300);
419 assert_int_equal(expire, 1814400);
420 assert_int_equal(minimum, 600);
423 static void test_res_fake_cname_query(void **state)
426 struct __res_state dnsstate;
427 unsigned char answer[ANSIZE];
429 ns_rr rr; /* expanded resource record */
430 const uint8_t *rrdata;
431 char cname[MAXDNAME];
432 char addr[INET_ADDRSTRLEN];
434 (void) state; /* unused */
436 memset(&dnsstate, 0, sizeof(struct __res_state));
437 rv = res_ninit(&dnsstate);
438 assert_int_equal(rv, 0);
440 rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname,
441 answer, sizeof(answer));
442 assert_in_range(rv, 1, 256);
444 ns_initparse(answer, 256, &handle);
445 ns_initparse(answer, sizeof(answer), &handle);
448 * The query must finish w/o an error, have one answer and the answer
449 * must be a parseable RR of type CNAME and have the cname as in the
452 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
453 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
454 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
455 assert_int_equal(ns_rr_type(rr), ns_t_cname);
457 rrdata = ns_rr_rdata(rr);
459 rv = ns_name_uncompress(ns_msg_base(handle),
463 assert_int_not_equal(rv, -1);
465 assert_string_equal(cname, "web.cwrap.org");
467 /* The CNAME points to an A record that's present in the additional
470 assert_int_equal(ns_msg_count(handle, ns_s_ar), 2);
472 assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
473 assert_int_equal(ns_rr_type(rr), ns_t_cname);
474 assert_string_equal(ns_rr_name(rr), "web.cwrap.org");
475 rrdata = ns_rr_rdata(rr);
477 rv = ns_name_uncompress(ns_msg_base(handle),
481 assert_int_not_equal(rv, -1);
483 assert_string_equal(cname, "www.cwrap.org");
485 assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0);
486 assert_int_equal(ns_rr_type(rr), ns_t_a);
487 assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
488 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
489 addr, sizeof(addr)));
490 assert_string_equal(addr, "127.0.0.22");
493 static void test_res_fake_a_via_cname(void **state)
496 struct __res_state dnsstate;
497 unsigned char answer[ANSIZE];
499 ns_rr rr; /* expanded resource record */
500 const uint8_t *rrdata;
501 char cname[MAXDNAME];
502 char addr[INET_ADDRSTRLEN];
504 (void) state; /* unused */
506 memset(&dnsstate, 0, sizeof(struct __res_state));
507 rv = res_ninit(&dnsstate);
508 assert_int_equal(rv, 0);
510 /* Query for A record, but the key is a CNAME. The expected result is
511 * that the whole chain of CNAMEs will be included in the answer section
512 * along with the resulting A
514 rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a,
515 answer, sizeof(answer));
516 assert_in_range(rv, 1, 256);
518 ns_initparse(answer, sizeof(answer), &handle);
521 * The query must finish w/o an error, have three answers and the answers
522 * must be a parseable RR of type CNAME and have the cname as in the
525 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
526 assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
528 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
529 assert_int_equal(ns_rr_type(rr), ns_t_cname);
531 rrdata = ns_rr_rdata(rr);
533 rv = ns_name_uncompress(ns_msg_base(handle),
537 assert_int_not_equal(rv, -1);
539 assert_string_equal(cname, "web.cwrap.org");
541 assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
542 assert_int_equal(ns_rr_type(rr), ns_t_cname);
544 rrdata = ns_rr_rdata(rr);
546 rv = ns_name_uncompress(ns_msg_base(handle),
550 assert_int_not_equal(rv, -1);
552 assert_string_equal(cname, "www.cwrap.org");
554 assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
555 assert_int_equal(ns_rr_type(rr), ns_t_a);
556 assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
557 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
558 addr, sizeof(addr)));
559 assert_string_equal(addr, "127.0.0.22");
566 const struct CMUnitTest fake_tests[] = {
567 cmocka_unit_test(test_res_fake_a_query),
568 cmocka_unit_test(test_res_fake_a_query_case_insensitive),
569 cmocka_unit_test(test_res_fake_a_query_trailing_dot),
570 cmocka_unit_test(test_res_fake_a_query_notfound),
571 cmocka_unit_test(test_res_fake_aaaa_query),
572 cmocka_unit_test(test_res_fake_aaaa_query_notfound),
573 cmocka_unit_test(test_res_fake_srv_query),
574 cmocka_unit_test(test_res_fake_srv_query_minimal),
575 cmocka_unit_test(test_res_fake_soa_query),
576 cmocka_unit_test(test_res_fake_cname_query),
577 cmocka_unit_test(test_res_fake_a_via_cname),
580 rc = cmocka_run_group_tests(fake_tests, NULL, NULL);