420d32b63d378b0ab9c63cbe48ad07ce4abeaabf
[resolv_wrapper.git] / tests / test_dns_fake.c
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
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
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
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
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
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
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
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  */
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
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  */
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
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
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
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
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
717 static void test_res_fake_txt_query(void **state)
718 {
719         int rv;
720         struct __res_state dnsstate;
721         unsigned char answer[ANSIZE];
722         ns_msg handle;
723         ns_rr rr;   /* expanded resource record */
724         const uint8_t *rrdata;
725
726         (void) state; /* unused */
727
728         memset(&dnsstate, 0, sizeof(struct __res_state));
729         rv = res_ninit(&dnsstate);
730         assert_int_equal(rv, 0);
731
732         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_txt,
733                         answer, sizeof(answer));
734         assert_in_range(rv, 1, 256);
735
736         ns_initparse(answer, sizeof(answer), &handle);
737
738         /*
739          * The query must finish w/o an error, have one answer and the answer
740          * must be a parseable RR of type TXT
741          */
742         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
743         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
744         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
745         assert_int_equal(ns_rr_type(rr), ns_t_txt);
746
747         rrdata = ns_rr_rdata(rr);
748         assert_string_equal(rrdata, "v=spf1 mx");
749 }
750
751 int main(void)
752 {
753         int rc;
754
755         const struct CMUnitTest fake_tests[] = {
756                 cmocka_unit_test(test_res_fake_a_query),
757                 cmocka_unit_test(test_res_fake_a_query_case_insensitive),
758                 cmocka_unit_test(test_res_fake_a_query_trailing_dot),
759                 cmocka_unit_test(test_res_fake_a_query_notfound),
760                 cmocka_unit_test(test_res_fake_aaaa_query),
761                 cmocka_unit_test(test_res_fake_aaaa_query_notfound),
762                 cmocka_unit_test(test_res_fake_srv_query),
763                 cmocka_unit_test(test_res_fake_srv_query_minimal),
764                 cmocka_unit_test(test_res_fake_uri_query),
765                 cmocka_unit_test(test_res_fake_uri_query_minimal),
766                 cmocka_unit_test(test_res_fake_soa_query),
767                 cmocka_unit_test(test_res_fake_cname_query),
768                 cmocka_unit_test(test_res_fake_a_via_cname),
769                 cmocka_unit_test(test_res_fake_ptr_query),
770                 cmocka_unit_test(test_res_fake_txt_query),
771         };
772
773         rc = cmocka_run_group_tests(fake_tests, NULL, NULL);
774
775         return rc;
776 }