d3e9ebe6287cbaaa01ed8d9ff1dc575e912d81fc
[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         char uri[MAXDNAME];
366
367         (void) state; /* unused */
368
369         memset(&dnsstate, 0, sizeof(struct __res_state));
370         rv = res_ninit(&dnsstate);
371         assert_int_equal(rv, 0);
372
373         rv = res_nquery(&dnsstate, "_vpn.cwrap.org", ns_c_in, ns_t_uri,
374                         answer, sizeof(answer));
375         assert_in_range(rv, 1, 100);
376
377         ns_initparse(answer, sizeof(answer), &handle);
378
379         /*
380          * The query must finish w/o an error, have one answer and the answer
381          * must be a parseable RR of type SRV and have the priority, weight,
382          * port and hostname as in the fake hosts file
383          */
384         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
385         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
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
389         rrdata = ns_rr_rdata(rr);
390         NS_GET16(prio, rrdata);
391         NS_GET16(weight, rrdata);
392
393         rv = ns_name_uncompress(ns_msg_base(handle),
394                                 ns_msg_end(handle),
395                                 rrdata,
396                                 uri, MAXDNAME);
397         assert_int_not_equal(rv, -1);
398
399         assert_int_equal(prio, 2);
400         assert_int_equal(weight, 5);
401         assert_string_equal(uri, "https://vpn.cwrap.org/VPN");
402 }
403
404 /*
405  * Test the case of a URI record query where the
406  * fake hosts file entry is minimal in the sense
407  * that it omits the priority and weight entries.
408  * The server then fills in some default values.
409  */
410 static void test_res_fake_uri_query_minimal(void **state)
411 {
412         int rv;
413         struct __res_state dnsstate;
414         unsigned char answer[ANSIZE];
415         ns_msg handle;
416         ns_rr rr;   /* expanded resource record */
417         const uint8_t *rrdata;
418         int prio;
419         int weight;
420         char uri[MAXDNAME];
421
422         (void) state; /* unused */
423
424         memset(&dnsstate, 0, sizeof(struct __res_state));
425         rv = res_ninit(&dnsstate);
426         assert_int_equal(rv, 0);
427
428         rv = res_nquery(&dnsstate, "_ftp.cwrap.org", ns_c_in, ns_t_uri,
429                         answer, sizeof(answer));
430         assert_in_range(rv, 1, 256);
431
432         ns_initparse(answer, sizeof(answer), &handle);
433
434         /*
435          * The query must finish w/o an error, have one answer and the answer
436          * must be a parseable RR of type SRV and have the priority, weight,
437          * port and hostname as in the fake hosts file
438          */
439         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
440         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
441         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
442         assert_int_equal(ns_rr_type(rr), ns_t_uri);
443
444         rrdata = ns_rr_rdata(rr);
445         NS_GET16(prio, rrdata);
446         NS_GET16(weight, rrdata);
447
448         rv = ns_name_uncompress(ns_msg_base(handle),
449                                 ns_msg_end(handle),
450                                 rrdata,
451                                 uri, MAXDNAME);
452         assert_int_not_equal(rv, -1);
453
454         assert_int_equal(prio, 1);
455         assert_int_equal(weight, 100);
456         assert_string_equal(uri, "ftp://ftp.cwrap.org/public");
457 }
458
459 static void test_res_fake_soa_query(void **state)
460 {
461         int rv;
462         struct __res_state dnsstate;
463         unsigned char answer[ANSIZE];
464         ns_msg handle;
465         ns_rr rr;   /* expanded resource record */
466         const uint8_t *rrdata;
467         char nameser[MAXDNAME];
468         char admin[MAXDNAME];
469         int serial;
470         int refresh;
471         int retry;
472         int expire;
473         int minimum;
474
475         (void) state; /* unused */
476
477         memset(&dnsstate, 0, sizeof(struct __res_state));
478         rv = res_ninit(&dnsstate);
479         assert_int_equal(rv, 0);
480
481         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
482                         answer, sizeof(answer));
483         assert_in_range(rv, 1, 100);
484
485         ns_initparse(answer, sizeof(answer), &handle);
486
487         /*
488          * The query must finish w/o an error, have one answer and the answer
489          * must be a parseable RR of type SOA and have the data as in the fake
490          * hosts file
491          */
492         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
493         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
494         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
495         assert_int_equal(ns_rr_type(rr), ns_t_soa);
496
497         rrdata = ns_rr_rdata(rr);
498
499         rv = ns_name_uncompress(ns_msg_base(handle),
500                                 ns_msg_end(handle),
501                                 rrdata,
502                                 nameser, MAXDNAME);
503         assert_int_not_equal(rv, -1);
504         rrdata += rv;
505
506         rv = ns_name_uncompress(ns_msg_base(handle),
507                                 ns_msg_end(handle),
508                                 rrdata,
509                                 admin, MAXDNAME);
510         assert_int_not_equal(rv, -1);
511         rrdata += rv;
512
513         NS_GET32(serial, rrdata);
514         NS_GET32(refresh, rrdata);
515         NS_GET32(retry, rrdata);
516         NS_GET32(expire, rrdata);
517         NS_GET32(minimum, rrdata);
518
519         assert_string_equal(nameser, "ns1.cwrap.org");
520         assert_string_equal(admin, "admin.cwrap.org");
521         assert_int_equal(serial, 2014100457);
522         assert_int_equal(refresh, 3600);
523         assert_int_equal(retry, 300);
524         assert_int_equal(expire, 1814400);
525         assert_int_equal(minimum, 600);
526 }
527
528 static void test_res_fake_cname_query(void **state)
529 {
530         int rv;
531         struct __res_state dnsstate;
532         unsigned char answer[ANSIZE];
533         ns_msg handle;
534         ns_rr rr;   /* expanded resource record */
535         const uint8_t *rrdata;
536         char cname[MAXDNAME];
537         char addr[INET_ADDRSTRLEN];
538
539         (void) state; /* unused */
540
541         memset(&dnsstate, 0, sizeof(struct __res_state));
542         rv = res_ninit(&dnsstate);
543         assert_int_equal(rv, 0);
544
545         rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname,
546                         answer, sizeof(answer));
547         assert_in_range(rv, 1, 256);
548
549         ns_initparse(answer, 256, &handle);
550         ns_initparse(answer, sizeof(answer), &handle);
551
552         /*
553          * The query must finish w/o an error, have one answer and the answer
554          * must be a parseable RR of type CNAME and have the cname as in the
555          * fake hosts file
556          */
557         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
558         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
559         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
560         assert_int_equal(ns_rr_type(rr), ns_t_cname);
561
562         rrdata = ns_rr_rdata(rr);
563
564         rv = ns_name_uncompress(ns_msg_base(handle),
565                                 ns_msg_end(handle),
566                                 rrdata,
567                                 cname, MAXDNAME);
568         assert_int_not_equal(rv, -1);
569
570         assert_string_equal(cname, "web.cwrap.org");
571
572         /* The CNAME points to an A record that's present in the additional
573          * section
574          */
575         assert_int_equal(ns_msg_count(handle, ns_s_ar), 2);
576
577         assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
578         assert_int_equal(ns_rr_type(rr), ns_t_cname);
579         assert_string_equal(ns_rr_name(rr), "web.cwrap.org");
580         rrdata = ns_rr_rdata(rr);
581
582         rv = ns_name_uncompress(ns_msg_base(handle),
583                                 ns_msg_end(handle),
584                                 rrdata,
585                                 cname, MAXDNAME);
586         assert_int_not_equal(rv, -1);
587
588         assert_string_equal(cname, "www.cwrap.org");
589
590         assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0);
591         assert_int_equal(ns_rr_type(rr), ns_t_a);
592         assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
593         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
594                         addr, sizeof(addr)));
595         assert_string_equal(addr, "127.0.0.22");
596 }
597
598 static void test_res_fake_a_via_cname(void **state)
599 {
600         int rv;
601         struct __res_state dnsstate;
602         unsigned char answer[ANSIZE];
603         ns_msg handle;
604         ns_rr rr;   /* expanded resource record */
605         const uint8_t *rrdata;
606         char cname[MAXDNAME];
607         char addr[INET_ADDRSTRLEN];
608
609         (void) state; /* unused */
610
611         memset(&dnsstate, 0, sizeof(struct __res_state));
612         rv = res_ninit(&dnsstate);
613         assert_int_equal(rv, 0);
614
615         /* Query for A record, but the key is a CNAME. The expected result is
616          * that the whole chain of CNAMEs will be included in the answer section
617          * along with the resulting A
618          */
619         rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a,
620                         answer, sizeof(answer));
621         assert_in_range(rv, 1, 256);
622
623         ns_initparse(answer, sizeof(answer), &handle);
624
625         /*
626          * The query must finish w/o an error, have three answers and the answers
627          * must be a parseable RR of type CNAME and have the cname as in the
628          * fake hosts file
629          */
630         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
631         assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
632
633         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
634         assert_int_equal(ns_rr_type(rr), ns_t_cname);
635
636         rrdata = ns_rr_rdata(rr);
637
638         rv = ns_name_uncompress(ns_msg_base(handle),
639                                 ns_msg_end(handle),
640                                 rrdata,
641                                 cname, MAXDNAME);
642         assert_int_not_equal(rv, -1);
643
644         assert_string_equal(cname, "web.cwrap.org");
645
646         assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
647         assert_int_equal(ns_rr_type(rr), ns_t_cname);
648
649         rrdata = ns_rr_rdata(rr);
650
651         rv = ns_name_uncompress(ns_msg_base(handle),
652                                 ns_msg_end(handle),
653                                 rrdata,
654                                 cname, MAXDNAME);
655         assert_int_not_equal(rv, -1);
656
657         assert_string_equal(cname, "www.cwrap.org");
658
659         assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
660         assert_int_equal(ns_rr_type(rr), ns_t_a);
661         assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
662         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
663                         addr, sizeof(addr)));
664         assert_string_equal(addr, "127.0.0.22");
665 }
666
667 static void test_res_fake_ptr_query(void **state)
668 {
669         int rv;
670         struct __res_state dnsstate;
671         unsigned char answer[ANSIZE];
672         const uint8_t *rrdata;
673         char ptrname[MAXDNAME];
674         ns_msg handle;
675         ns_rr rr;   /* expanded resource record */
676
677         (void) state; /* unused */
678
679         memset(&dnsstate, 0, sizeof(struct __res_state));
680         rv = res_ninit(&dnsstate);
681         assert_int_equal(rv, 0);
682
683         rv = res_nquery(&dnsstate, "22.0.0.127.in-addr.arpa", ns_c_in, ns_t_ptr,
684                         answer, sizeof(answer));
685         assert_in_range(rv, 1, 100);
686
687         ns_initparse(answer, sizeof(answer), &handle);
688
689         /*
690          * The query must finish w/o an error, have one answer and the answer
691          * must be a parseable RR of type PTR and have the name that our
692          * fake hosts file contains
693          */
694         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
695         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
696         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
697         assert_int_equal(ns_rr_type(rr), ns_t_ptr);
698
699         rrdata = ns_rr_rdata(rr);
700
701         rv = ns_name_uncompress(ns_msg_base(handle),
702                                 ns_msg_end(handle),
703                                 rrdata,
704                                 ptrname, MAXDNAME);
705         assert_int_not_equal(rv, -1);
706
707         assert_string_equal(ptrname, "www.cwrap.org");
708 }
709
710 int main(void)
711 {
712         int rc;
713
714         const struct CMUnitTest fake_tests[] = {
715                 cmocka_unit_test(test_res_fake_a_query),
716                 cmocka_unit_test(test_res_fake_a_query_case_insensitive),
717                 cmocka_unit_test(test_res_fake_a_query_trailing_dot),
718                 cmocka_unit_test(test_res_fake_a_query_notfound),
719                 cmocka_unit_test(test_res_fake_aaaa_query),
720                 cmocka_unit_test(test_res_fake_aaaa_query_notfound),
721                 cmocka_unit_test(test_res_fake_srv_query),
722                 cmocka_unit_test(test_res_fake_srv_query_minimal),
723                 cmocka_unit_test(test_res_fake_uri_query),
724                 cmocka_unit_test(test_res_fake_uri_query_minimal),
725                 cmocka_unit_test(test_res_fake_soa_query),
726                 cmocka_unit_test(test_res_fake_cname_query),
727                 cmocka_unit_test(test_res_fake_a_via_cname),
728                 cmocka_unit_test(test_res_fake_ptr_query),
729         };
730
731         rc = cmocka_run_group_tests(fake_tests, NULL, NULL);
732
733         return rc;
734 }