1 /*
2 * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@posteo.se>
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33
34 #include <stdarg.h>
35 #include <stddef.h>
36 #include <setjmp.h>
37 #include <cmocka.h>
38
39 #include "config.h"
40
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <stdio.h>
45
46 #include <netinet/in.h>
47 #include <arpa/nameser.h>
48 #include <arpa/inet.h>
49 #include <resolv.h>
50
51 #define ANSIZE 256
52 #define ns_t_uri 256
53
test_res_fake_a_query(void ** state)54 static void test_res_fake_a_query(void **state)
55 {
56 int rv;
57 struct __res_state dnsstate;
58 unsigned char answer[ANSIZE];
59 char addr[INET_ADDRSTRLEN];
60 ns_msg handle;
61 ns_rr rr; /* expanded resource record */
62
63 (void) state; /* unused */
64
65 memset(&dnsstate, 0, sizeof(struct __res_state));
66 rv = res_ninit(&dnsstate);
67 assert_int_equal(rv, 0);
68
69 rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a,
70 answer, sizeof(answer));
71 assert_in_range(rv, 1, 100);
72
73 ns_initparse(answer, sizeof(answer), &handle);
74 /* The query must finish w/o an error, have one answer and the answer
75 * must be a parseable RR of type A and have the address that our
76 * fake hosts file contains
77 */
78 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
79 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
80 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
81 assert_int_equal(ns_rr_type(rr), ns_t_a);
82 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
83 addr, sizeof(addr)));
84 assert_string_equal(addr, "127.0.0.21");
85 }
86
test_res_fake_a_query_case_insensitive(void ** state)87 static void test_res_fake_a_query_case_insensitive(void **state)
88 {
89 int rv;
90 struct __res_state dnsstate;
91 unsigned char answer[ANSIZE];
92 char addr[INET_ADDRSTRLEN];
93 ns_msg handle;
94 ns_rr rr; /* expanded resource record */
95
96 (void) state; /* unused */
97
98 memset(&dnsstate, 0, sizeof(struct __res_state));
99 rv = res_ninit(&dnsstate);
100 assert_int_equal(rv, 0);
101
102 rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a,
103 answer, sizeof(answer));
104 assert_in_range(rv, 1, 100);
105
106 ns_initparse(answer, sizeof(answer), &handle);
107 /* The query must finish w/o an error, have one answer and the answer
108 * must be a parseable RR of type A and have the address that our
109 * fake hosts file contains. Case does not matter.
110 */
111 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
112 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
113 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
114 assert_int_equal(ns_rr_type(rr), ns_t_a);
115 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
116 addr, sizeof(addr)));
117 assert_string_equal(addr, "127.0.0.21");
118
119 res_nclose(&dnsstate);
120 }
121
test_res_fake_a_query_trailing_dot(void ** state)122 static void test_res_fake_a_query_trailing_dot(void **state)
123 {
124 int rv;
125 struct __res_state dnsstate;
126 unsigned char answer[ANSIZE];
127 char addr[INET_ADDRSTRLEN];
128 ns_msg handle;
129 ns_rr rr; /* expanded resource record */
130
131 (void) state; /* unused */
132
133 memset(&dnsstate, 0, sizeof(struct __res_state));
134 rv = res_ninit(&dnsstate);
135 assert_int_equal(rv, 0);
136
137 rv = res_nquery(&dnsstate, "cwrap.org.", ns_c_in, ns_t_a,
138 answer, ANSIZE);
139 assert_in_range(rv, 1, 100);
140
141 ns_initparse(answer, 256, &handle);
142 /* The query must finish w/o an error, have one answer and the answer
143 * must be a parseable RR of type A and have the address that our
144 * fake hosts file contains
145 */
146 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
147 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
148 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
149 assert_int_equal(ns_rr_type(rr), ns_t_a);
150 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, 256));
151 assert_string_equal(addr, "127.0.0.21");
152
153 res_nclose(&dnsstate);
154 }
155
test_res_fake_a_query_notfound(void ** state)156 static void test_res_fake_a_query_notfound(void **state)
157 {
158 int rv;
159 struct __res_state dnsstate;
160 unsigned char answer[ANSIZE];
161 ns_msg handle;
162
163 (void) state; /* unused */
164
165 memset(&dnsstate, 0, sizeof(struct __res_state));
166 rv = res_ninit(&dnsstate);
167 assert_int_equal(rv, 0);
168
169 rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a,
170 answer, sizeof(answer));
171 assert_in_range(rv, 1, 100);
172
173 ns_initparse(answer, sizeof(answer), &handle);
174 /* The query must finish w/o an error and have no answer */
175 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
176 assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
177 }
178
test_res_fake_aaaa_query(void ** state)179 static void test_res_fake_aaaa_query(void **state)
180 {
181 int rv;
182 struct __res_state dnsstate;
183 unsigned char answer[ANSIZE];
184 char addr[INET6_ADDRSTRLEN];
185 ns_msg handle;
186 ns_rr rr; /* expanded resource record */
187
188 (void) state; /* unused */
189
190 memset(&dnsstate, 0, sizeof(struct __res_state));
191 rv = res_ninit(&dnsstate);
192 assert_int_equal(rv, 0);
193
194 rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa,
195 answer, sizeof(answer));
196 assert_in_range(rv, 1, 100);
197
198 ns_initparse(answer, sizeof(answer), &handle);
199 /* The query must finish w/o an error, have one answer and the answer
200 * must be a parseable RR of type AAAA and have the address that our
201 * fake hosts file contains
202 */
203 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
204 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
205 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
206 assert_int_equal(ns_rr_type(rr), ns_t_aaaa);
207 assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr),
208 addr, sizeof(addr)));
209 assert_string_equal(addr, "2a00:1450:4013:c01::63");
210 }
211
test_res_fake_aaaa_query_notfound(void ** state)212 static void test_res_fake_aaaa_query_notfound(void **state)
213 {
214 int rv;
215 struct __res_state dnsstate;
216 unsigned char answer[ANSIZE];
217 ns_msg handle;
218
219 (void) state; /* unused */
220
221 memset(&dnsstate, 0, sizeof(struct __res_state));
222 rv = res_ninit(&dnsstate);
223 assert_int_equal(rv, 0);
224
225 rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa,
226 answer, sizeof(answer));
227 assert_in_range(rv, 1, 100);
228
229 ns_initparse(answer, sizeof(answer), &handle);
230 /* The query must finish w/o an error and have no answer */
231 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
232 assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
233 }
234
test_res_fake_srv_query(void ** state)235 static void test_res_fake_srv_query(void **state)
236 {
237 int rv;
238 struct __res_state dnsstate;
239 unsigned char answer[ANSIZE];
240 ns_msg handle;
241 ns_rr rr; /* expanded resource record */
242 const uint8_t *rrdata;
243 int prio;
244 int weight;
245 int port;
246 char hostname[MAXDNAME];
247
248 (void) state; /* unused */
249
250 memset(&dnsstate, 0, sizeof(struct __res_state));
251 rv = res_ninit(&dnsstate);
252 assert_int_equal(rv, 0);
253
254 rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
255 answer, sizeof(answer));
256 assert_in_range(rv, 1, 100);
257
258 ns_initparse(answer, sizeof(answer), &handle);
259
260 /*
261 * The query must finish w/o an error, have one answer and the answer
262 * must be a parseable RR of type SRV and have the priority, weight,
263 * port and hostname as in the fake hosts file
264 */
265 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
266 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
267 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
268 assert_int_equal(ns_rr_type(rr), ns_t_srv);
269
270 rrdata = ns_rr_rdata(rr);
271 NS_GET16(prio, rrdata);
272 NS_GET16(weight, rrdata);
273 NS_GET16(port, rrdata);
274
275 rv = ns_name_uncompress(ns_msg_base(handle),
276 ns_msg_end(handle),
277 rrdata,
278 hostname, MAXDNAME);
279 assert_int_not_equal(rv, -1);
280
281 assert_int_equal(prio, 1);
282 assert_int_equal(weight, 5);
283 assert_int_equal(port, 389);
284 assert_string_equal(hostname, "ldap.cwrap.org");
285 }
286
287 /*
288 * Test the case of a SRV record query where the
289 * fake hosts file entry is minimal in the sense
290 * that it omits the priority and weight entries.
291 * The server then fills in some default values.
292 */
test_res_fake_srv_query_minimal(void ** state)293 static void test_res_fake_srv_query_minimal(void **state)
294 {
295 int rv;
296 struct __res_state dnsstate;
297 unsigned char answer[ANSIZE];
298 ns_msg handle;
299 ns_rr rr; /* expanded resource record */
300 const uint8_t *rrdata;
301 int prio;
302 int weight;
303 int port;
304 char hostname[MAXDNAME];
305 char addr[INET_ADDRSTRLEN];
306
307 (void) state; /* unused */
308
309 memset(&dnsstate, 0, sizeof(struct __res_state));
310 rv = res_ninit(&dnsstate);
311 assert_int_equal(rv, 0);
312
313 rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
314 answer, sizeof(answer));
315 assert_in_range(rv, 1, 256);
316
317 ns_initparse(answer, sizeof(answer), &handle);
318
319 /*
320 * The query must finish w/o an error, have one answer and the answer
321 * must be a parseable RR of type SRV and have the priority, weight,
322 * port and hostname as in the fake hosts file
323 */
324 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
325 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
326 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
327 assert_int_equal(ns_rr_type(rr), ns_t_srv);
328
329 rrdata = ns_rr_rdata(rr);
330 NS_GET16(prio, rrdata);
331 NS_GET16(weight, rrdata);
332 NS_GET16(port, rrdata);
333
334 rv = ns_name_uncompress(ns_msg_base(handle),
335 ns_msg_end(handle),
336 rrdata,
337 hostname, MAXDNAME);
338 assert_int_not_equal(rv, -1);
339
340 assert_int_equal(prio, 1);
341 assert_int_equal(weight, 100);
342 assert_int_equal(port, 88);
343 assert_string_equal(hostname, "krb5.cwrap.org");
344
345 /* The additional section contains the A record of krb5.cwrap.org */
346 assert_int_equal(ns_msg_count(handle, ns_s_ar), 1);
347 assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
348 assert_int_equal(ns_rr_type(rr), ns_t_a);
349 assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org");
350 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
351 addr, sizeof(addr)));
352 assert_string_equal(addr, "127.0.0.23");
353 }
354
test_res_fake_uri_query(void ** state)355 static void test_res_fake_uri_query(void **state)
356 {
357 int rv;
358 struct __res_state dnsstate;
359 unsigned char answer[ANSIZE];
360 ns_msg handle;
361 ns_rr rr; /* expanded resource record */
362 const uint8_t *rrdata;
363 int prio;
364 int weight;
365
366 (void) state; /* unused */
367
368 memset(&dnsstate, 0, sizeof(struct __res_state));
369 rv = res_ninit(&dnsstate);
370 assert_int_equal(rv, 0);
371
372 rv = res_nquery(&dnsstate, "_vpn.cwrap.org", ns_c_in, ns_t_uri,
373 answer, sizeof(answer));
374 assert_in_range(rv, 1, ANSIZE);
375
376 ns_initparse(answer, sizeof(answer), &handle);
377
378 /*
379 * The query must finish w/o an error, have three answers and they must be
380 * a parseable RR of type URI and have the priority, weight, and URI string
381 * as in the hosts file.
382 */
383 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
384 assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
385
386 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
387 assert_int_equal(ns_rr_type(rr), ns_t_uri);
388 rrdata = ns_rr_rdata(rr);
389 NS_GET16(prio, rrdata);
390 NS_GET16(weight, rrdata);
391
392 assert_int_equal(prio, 2);
393 assert_int_equal(weight, 5);
394 assert_string_equal(rrdata, "https://vpn.cwrap.org/VPN");
395
396 assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
397 assert_int_equal(ns_rr_type(rr), ns_t_uri);
398 rrdata = ns_rr_rdata(rr);
399 NS_GET16(prio, rrdata);
400 NS_GET16(weight, rrdata);
401
402 assert_int_equal(prio, 2);
403 assert_int_equal(weight, 10);
404 assert_string_equal(rrdata, "https://vpn2.cwrap.org/VPN");
405
406 assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
407 assert_int_equal(ns_rr_type(rr), ns_t_uri);
408 rrdata = ns_rr_rdata(rr);
409 NS_GET16(prio, rrdata);
410 NS_GET16(weight, rrdata);
411
412 assert_int_equal(prio, 2);
413 assert_int_equal(weight, 20);
414 assert_string_equal(rrdata, "https://vpn3.cwrap.org/VPN");
415
416 }
417
418 /*
419 * Test the case of a URI record query where the
420 * fake hosts file entry is minimal in the sense
421 * that it omits the priority and weight entries.
422 * The server then fills in some default values.
423 */
test_res_fake_uri_query_minimal(void ** state)424 static void test_res_fake_uri_query_minimal(void **state)
425 {
426 int rv;
427 struct __res_state dnsstate;
428 unsigned char answer[ANSIZE];
429 ns_msg handle;
430 ns_rr rr; /* expanded resource record */
431 const uint8_t *rrdata;
432 int prio;
433 int weight;
434
435 (void) state; /* unused */
436
437 memset(&dnsstate, 0, sizeof(struct __res_state));
438 rv = res_ninit(&dnsstate);
439 assert_int_equal(rv, 0);
440
441 rv = res_nquery(&dnsstate, "_ftp.cwrap.org", ns_c_in, ns_t_uri,
442 answer, sizeof(answer));
443 assert_in_range(rv, 1, 256);
444
445 ns_initparse(answer, sizeof(answer), &handle);
446
447 /*
448 * The query must finish w/o an error, have one answer and the answer
449 * must be a parseable RR of type URI and have the priority, weight, and
450 * URI string as in the fake hosts file
451 */
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_uri);
456
457 rrdata = ns_rr_rdata(rr);
458 NS_GET16(prio, rrdata);
459 NS_GET16(weight, rrdata);
460
461 assert_int_equal(prio, 1);
462 assert_int_equal(weight, 100);
463 assert_string_equal(rrdata, "ftp://ftp.cwrap.org/public");
464 }
465
test_res_fake_soa_query(void ** state)466 static void test_res_fake_soa_query(void **state)
467 {
468 int rv;
469 struct __res_state dnsstate;
470 unsigned char answer[ANSIZE];
471 ns_msg handle;
472 ns_rr rr; /* expanded resource record */
473 const uint8_t *rrdata;
474 char nameser[MAXDNAME];
475 char admin[MAXDNAME];
476 int serial;
477 int refresh;
478 int retry;
479 int expire;
480 int minimum;
481
482 (void) state; /* unused */
483
484 memset(&dnsstate, 0, sizeof(struct __res_state));
485 rv = res_ninit(&dnsstate);
486 assert_int_equal(rv, 0);
487
488 rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
489 answer, sizeof(answer));
490 assert_in_range(rv, 1, 100);
491
492 ns_initparse(answer, sizeof(answer), &handle);
493
494 /*
495 * The query must finish w/o an error, have one answer and the answer
496 * must be a parseable RR of type SOA and have the data as in the fake
497 * hosts file
498 */
499 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
500 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
501 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
502 assert_int_equal(ns_rr_type(rr), ns_t_soa);
503
504 rrdata = ns_rr_rdata(rr);
505
506 rv = ns_name_uncompress(ns_msg_base(handle),
507 ns_msg_end(handle),
508 rrdata,
509 nameser, MAXDNAME);
510 assert_int_not_equal(rv, -1);
511 rrdata += rv;
512
513 rv = ns_name_uncompress(ns_msg_base(handle),
514 ns_msg_end(handle),
515 rrdata,
516 admin, MAXDNAME);
517 assert_int_not_equal(rv, -1);
518 rrdata += rv;
519
520 NS_GET32(serial, rrdata);
521 NS_GET32(refresh, rrdata);
522 NS_GET32(retry, rrdata);
523 NS_GET32(expire, rrdata);
524 NS_GET32(minimum, rrdata);
525
526 assert_string_equal(nameser, "ns1.cwrap.org");
527 assert_string_equal(admin, "admin.cwrap.org");
528 assert_int_equal(serial, 2014100457);
529 assert_int_equal(refresh, 3600);
530 assert_int_equal(retry, 300);
531 assert_int_equal(expire, 1814400);
532 assert_int_equal(minimum, 600);
533 }
534
test_res_fake_cname_query(void ** state)535 static void test_res_fake_cname_query(void **state)
536 {
537 int rv;
538 struct __res_state dnsstate;
539 unsigned char answer[ANSIZE];
540 ns_msg handle;
541 ns_rr rr; /* expanded resource record */
542 const uint8_t *rrdata;
543 char cname[MAXDNAME];
544 char addr[INET_ADDRSTRLEN];
545
546 (void) state; /* unused */
547
548 memset(&dnsstate, 0, sizeof(struct __res_state));
549 rv = res_ninit(&dnsstate);
550 assert_int_equal(rv, 0);
551
552 rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname,
553 answer, sizeof(answer));
554 assert_in_range(rv, 1, 256);
555
556 ns_initparse(answer, 256, &handle);
557 ns_initparse(answer, sizeof(answer), &handle);
558
559 /*
560 * The query must finish w/o an error, have one answer and the answer
561 * must be a parseable RR of type CNAME and have the cname as in the
562 * fake hosts file
563 */
564 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
565 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
566 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
567 assert_int_equal(ns_rr_type(rr), ns_t_cname);
568
569 rrdata = ns_rr_rdata(rr);
570
571 rv = ns_name_uncompress(ns_msg_base(handle),
572 ns_msg_end(handle),
573 rrdata,
574 cname, MAXDNAME);
575 assert_int_not_equal(rv, -1);
576
577 assert_string_equal(cname, "web.cwrap.org");
578
579 /* The CNAME points to an A record that's present in the additional
580 * section
581 */
582 assert_int_equal(ns_msg_count(handle, ns_s_ar), 2);
583
584 assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
585 assert_int_equal(ns_rr_type(rr), ns_t_cname);
586 assert_string_equal(ns_rr_name(rr), "web.cwrap.org");
587 rrdata = ns_rr_rdata(rr);
588
589 rv = ns_name_uncompress(ns_msg_base(handle),
590 ns_msg_end(handle),
591 rrdata,
592 cname, MAXDNAME);
593 assert_int_not_equal(rv, -1);
594
595 assert_string_equal(cname, "www.cwrap.org");
596
597 assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0);
598 assert_int_equal(ns_rr_type(rr), ns_t_a);
599 assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
600 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
601 addr, sizeof(addr)));
602 assert_string_equal(addr, "127.0.0.22");
603 }
604
test_res_fake_a_via_cname(void ** state)605 static void test_res_fake_a_via_cname(void **state)
606 {
607 int rv;
608 struct __res_state dnsstate;
609 unsigned char answer[ANSIZE];
610 ns_msg handle;
611 ns_rr rr; /* expanded resource record */
612 const uint8_t *rrdata;
613 char cname[MAXDNAME];
614 char addr[INET_ADDRSTRLEN];
615
616 (void) state; /* unused */
617
618 memset(&dnsstate, 0, sizeof(struct __res_state));
619 rv = res_ninit(&dnsstate);
620 assert_int_equal(rv, 0);
621
622 /* Query for A record, but the key is a CNAME. The expected result is
623 * that the whole chain of CNAMEs will be included in the answer section
624 * along with the resulting A
625 */
626 rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a,
627 answer, sizeof(answer));
628 assert_in_range(rv, 1, 256);
629
630 ns_initparse(answer, sizeof(answer), &handle);
631
632 /*
633 * The query must finish w/o an error, have three answers and the answers
634 * must be a parseable RR of type CNAME and have the cname as in the
635 * fake hosts file
636 */
637 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
638 assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
639
640 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
641 assert_int_equal(ns_rr_type(rr), ns_t_cname);
642
643 rrdata = ns_rr_rdata(rr);
644
645 rv = ns_name_uncompress(ns_msg_base(handle),
646 ns_msg_end(handle),
647 rrdata,
648 cname, MAXDNAME);
649 assert_int_not_equal(rv, -1);
650
651 assert_string_equal(cname, "web.cwrap.org");
652
653 assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
654 assert_int_equal(ns_rr_type(rr), ns_t_cname);
655
656 rrdata = ns_rr_rdata(rr);
657
658 rv = ns_name_uncompress(ns_msg_base(handle),
659 ns_msg_end(handle),
660 rrdata,
661 cname, MAXDNAME);
662 assert_int_not_equal(rv, -1);
663
664 assert_string_equal(cname, "www.cwrap.org");
665
666 assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
667 assert_int_equal(ns_rr_type(rr), ns_t_a);
668 assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
669 assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
670 addr, sizeof(addr)));
671 assert_string_equal(addr, "127.0.0.22");
672 }
673
test_res_fake_ptr_query(void ** state)674 static void test_res_fake_ptr_query(void **state)
675 {
676 int rv;
677 struct __res_state dnsstate;
678 unsigned char answer[ANSIZE];
679 const uint8_t *rrdata;
680 char ptrname[MAXDNAME];
681 ns_msg handle;
682 ns_rr rr; /* expanded resource record */
683
684 (void) state; /* unused */
685
686 memset(&dnsstate, 0, sizeof(struct __res_state));
687 rv = res_ninit(&dnsstate);
688 assert_int_equal(rv, 0);
689
690 rv = res_nquery(&dnsstate, "22.0.0.127.in-addr.arpa", ns_c_in, ns_t_ptr,
691 answer, sizeof(answer));
692 assert_in_range(rv, 1, 100);
693
694 ns_initparse(answer, sizeof(answer), &handle);
695
696 /*
697 * The query must finish w/o an error, have one answer and the answer
698 * must be a parseable RR of type PTR and have the name that our
699 * fake hosts file contains
700 */
701 assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
702 assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
703 assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
704 assert_int_equal(ns_rr_type(rr), ns_t_ptr);
705
706 rrdata = ns_rr_rdata(rr);
707
708 rv = ns_name_uncompress(ns_msg_base(handle),
709 ns_msg_end(handle),
710 rrdata,
711 ptrname, MAXDNAME);
712 assert_int_not_equal(rv, -1);
713
714 assert_string_equal(ptrname, "www.cwrap.org");
715 }
716
main(void)717 int main(void)
718 {
719 int rc;
720
721 const struct CMUnitTest fake_tests[] = {
722 cmocka_unit_test(test_res_fake_a_query),
723 cmocka_unit_test(test_res_fake_a_query_case_insensitive),
724 cmocka_unit_test(test_res_fake_a_query_trailing_dot),
725 cmocka_unit_test(test_res_fake_a_query_notfound),
726 cmocka_unit_test(test_res_fake_aaaa_query),
727 cmocka_unit_test(test_res_fake_aaaa_query_notfound),
728 cmocka_unit_test(test_res_fake_srv_query),
729 cmocka_unit_test(test_res_fake_srv_query_minimal),
730 cmocka_unit_test(test_res_fake_uri_query),
731 cmocka_unit_test(test_res_fake_uri_query_minimal),
732 cmocka_unit_test(test_res_fake_soa_query),
733 cmocka_unit_test(test_res_fake_cname_query),
734 cmocka_unit_test(test_res_fake_a_via_cname),
735 cmocka_unit_test(test_res_fake_ptr_query),
736 };
737
738 rc = cmocka_run_group_tests(fake_tests, NULL, NULL);
739
740 return rc;
741 }
742