tests: Fix memory overrun
[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, sizeof(answer), &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, sizeof(addr)));
151
152         assert_string_equal(addr, "127.0.0.21");
153
154         res_nclose(&dnsstate);
155 }
156
157 static void test_res_fake_a_query_notfound(void **state)
158 {
159         int rv;
160         struct __res_state dnsstate;
161         unsigned char answer[ANSIZE];
162         ns_msg handle;
163
164         (void) state; /* unused */
165
166         memset(&dnsstate, 0, sizeof(struct __res_state));
167         rv = res_ninit(&dnsstate);
168         assert_int_equal(rv, 0);
169
170         rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a,
171                         answer, sizeof(answer));
172         assert_in_range(rv, 1, 100);
173
174         ns_initparse(answer, sizeof(answer), &handle);
175         /* The query must finish w/o an error and have no answer */
176         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
177         assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
178 }
179
180 static void test_res_fake_aaaa_query(void **state)
181 {
182         int rv;
183         struct __res_state dnsstate;
184         unsigned char answer[ANSIZE];
185         char addr[INET6_ADDRSTRLEN];
186         ns_msg handle;
187         ns_rr rr;   /* expanded resource record */
188
189         (void) state; /* unused */
190
191         memset(&dnsstate, 0, sizeof(struct __res_state));
192         rv = res_ninit(&dnsstate);
193         assert_int_equal(rv, 0);
194
195         rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa,
196                         answer, sizeof(answer));
197         assert_in_range(rv, 1, 100);
198
199         ns_initparse(answer, sizeof(answer), &handle);
200         /* The query must finish w/o an error, have one answer and the answer
201          * must be a parseable RR of type AAAA and have the address that our
202          * fake hosts file contains
203          */
204         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
205         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
206         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
207         assert_int_equal(ns_rr_type(rr), ns_t_aaaa);
208         assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr),
209                         addr, sizeof(addr)));
210         assert_string_equal(addr, "2a00:1450:4013:c01::63");
211 }
212
213 static void test_res_fake_aaaa_query_notfound(void **state)
214 {
215         int rv;
216         struct __res_state dnsstate;
217         unsigned char answer[ANSIZE];
218         ns_msg handle;
219
220         (void) state; /* unused */
221
222         memset(&dnsstate, 0, sizeof(struct __res_state));
223         rv = res_ninit(&dnsstate);
224         assert_int_equal(rv, 0);
225
226         rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa,
227                         answer, sizeof(answer));
228         assert_in_range(rv, 1, 100);
229
230         ns_initparse(answer, sizeof(answer), &handle);
231         /* The query must finish w/o an error and have no answer */
232         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
233         assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
234 }
235
236 static void test_res_fake_srv_query(void **state)
237 {
238         int rv;
239         struct __res_state dnsstate;
240         unsigned char answer[ANSIZE];
241         ns_msg handle;
242         ns_rr rr;   /* expanded resource record */
243         const uint8_t *rrdata;
244         int prio;
245         int weight;
246         int port;
247         char hostname[MAXDNAME];
248
249         (void) state; /* unused */
250
251         memset(&dnsstate, 0, sizeof(struct __res_state));
252         rv = res_ninit(&dnsstate);
253         assert_int_equal(rv, 0);
254
255         rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
256                         answer, sizeof(answer));
257         assert_in_range(rv, 1, 100);
258
259         ns_initparse(answer, sizeof(answer), &handle);
260
261         /*
262          * The query must finish w/o an error, have one answer and the answer
263          * must be a parseable RR of type SRV and have the priority, weight,
264          * port and hostname as in the fake hosts file
265          */
266         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
267         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
268         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
269         assert_int_equal(ns_rr_type(rr), ns_t_srv);
270
271         rrdata = ns_rr_rdata(rr);
272         NS_GET16(prio, rrdata);
273         NS_GET16(weight, rrdata);
274         NS_GET16(port, rrdata);
275
276         rv = ns_name_uncompress(ns_msg_base(handle),
277                                 ns_msg_end(handle),
278                                 rrdata,
279                                 hostname, MAXDNAME);
280         assert_int_not_equal(rv, -1);
281
282         assert_int_equal(prio, 1);
283         assert_int_equal(weight, 5);
284         assert_int_equal(port, 389);
285         assert_string_equal(hostname, "ldap.cwrap.org");
286 }
287
288 /*
289  * Test the case of a SRV record query where the
290  * fake hosts file entry is minimal in the sense
291  * that it omits the priority and weight entries.
292  * The server then fills in some default values.
293  */
294 static void test_res_fake_srv_query_minimal(void **state)
295 {
296         int rv;
297         struct __res_state dnsstate;
298         unsigned char answer[ANSIZE];
299         ns_msg handle;
300         ns_rr rr;   /* expanded resource record */
301         const uint8_t *rrdata;
302         int prio;
303         int weight;
304         int port;
305         char hostname[MAXDNAME];
306         char addr[INET_ADDRSTRLEN];
307
308         (void) state; /* unused */
309
310         memset(&dnsstate, 0, sizeof(struct __res_state));
311         rv = res_ninit(&dnsstate);
312         assert_int_equal(rv, 0);
313
314         rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
315                         answer, sizeof(answer));
316         assert_in_range(rv, 1, 256);
317
318         ns_initparse(answer, sizeof(answer), &handle);
319
320         /*
321          * The query must finish w/o an error, have one answer and the answer
322          * must be a parseable RR of type SRV and have the priority, weight,
323          * port and hostname as in the fake hosts file
324          */
325         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
326         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
327         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
328         assert_int_equal(ns_rr_type(rr), ns_t_srv);
329
330         rrdata = ns_rr_rdata(rr);
331         NS_GET16(prio, rrdata);
332         NS_GET16(weight, rrdata);
333         NS_GET16(port, rrdata);
334
335         rv = ns_name_uncompress(ns_msg_base(handle),
336                                 ns_msg_end(handle),
337                                 rrdata,
338                                 hostname, MAXDNAME);
339         assert_int_not_equal(rv, -1);
340
341         assert_int_equal(prio, 1);
342         assert_int_equal(weight, 100);
343         assert_int_equal(port, 88);
344         assert_string_equal(hostname, "krb5.cwrap.org");
345
346         /* The additional section contains the A record of krb5.cwrap.org */
347         assert_int_equal(ns_msg_count(handle, ns_s_ar), 1);
348         assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
349         assert_int_equal(ns_rr_type(rr), ns_t_a);
350         assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org");
351         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
352                         addr, sizeof(addr)));
353         assert_string_equal(addr, "127.0.0.23");
354 }
355
356 static void test_res_fake_uri_query(void **state)
357 {
358         int rv;
359         struct __res_state dnsstate;
360         unsigned char answer[ANSIZE];
361         ns_msg handle;
362         ns_rr rr;   /* expanded resource record */
363         const uint8_t *rrdata;
364         int prio;
365         int weight;
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, ANSIZE);
376
377         ns_initparse(answer, sizeof(answer), &handle);
378
379         /*
380          * The query must finish w/o an error, have three answers and they must be
381          * a parseable RR of type URI and have the priority, weight, and URI string
382          * as in the 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), 3);
386
387         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
388         assert_int_equal(ns_rr_type(rr), ns_t_uri);
389         rrdata = ns_rr_rdata(rr);
390         NS_GET16(prio, rrdata);
391         NS_GET16(weight, rrdata);
392
393         assert_int_equal(prio, 2);
394         assert_int_equal(weight, 5);
395         assert_string_equal(rrdata, "https://vpn.cwrap.org/VPN");
396
397         assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
398         assert_int_equal(ns_rr_type(rr), ns_t_uri);
399         rrdata = ns_rr_rdata(rr);
400         NS_GET16(prio, rrdata);
401         NS_GET16(weight, rrdata);
402
403         assert_int_equal(prio, 2);
404         assert_int_equal(weight, 10);
405         assert_string_equal(rrdata, "https://vpn2.cwrap.org/VPN");
406
407         assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
408         assert_int_equal(ns_rr_type(rr), ns_t_uri);
409         rrdata = ns_rr_rdata(rr);
410         NS_GET16(prio, rrdata);
411         NS_GET16(weight, rrdata);
412
413         assert_int_equal(prio, 2);
414         assert_int_equal(weight, 20);
415         assert_string_equal(rrdata, "https://vpn3.cwrap.org/VPN");
416
417 }
418
419 /*
420  * Test the case of a URI record query where the
421  * fake hosts file entry is minimal in the sense
422  * that it omits the priority and weight entries.
423  * The server then fills in some default values.
424  */
425 static void test_res_fake_uri_query_minimal(void **state)
426 {
427         int rv;
428         struct __res_state dnsstate;
429         unsigned char answer[ANSIZE];
430         ns_msg handle;
431         ns_rr rr;   /* expanded resource record */
432         const uint8_t *rrdata;
433         int prio;
434         int weight;
435
436         (void) state; /* unused */
437
438         memset(&dnsstate, 0, sizeof(struct __res_state));
439         rv = res_ninit(&dnsstate);
440         assert_int_equal(rv, 0);
441
442         rv = res_nquery(&dnsstate, "_ftp.cwrap.org", ns_c_in, ns_t_uri,
443                         answer, sizeof(answer));
444         assert_in_range(rv, 1, 256);
445
446         ns_initparse(answer, sizeof(answer), &handle);
447
448         /*
449          * The query must finish w/o an error, have one answer and the answer
450          * must be a parseable RR of type URI and have the priority, weight, and
451          * URI string as in the fake hosts file
452          */
453         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
454         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
455         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
456         assert_int_equal(ns_rr_type(rr), ns_t_uri);
457
458         rrdata = ns_rr_rdata(rr);
459         NS_GET16(prio, rrdata);
460         NS_GET16(weight, rrdata);
461
462         assert_int_equal(prio, 1);
463         assert_int_equal(weight, 100);
464         assert_string_equal(rrdata, "ftp://ftp.cwrap.org/public");
465 }
466
467 static void test_res_fake_soa_query(void **state)
468 {
469         int rv;
470         struct __res_state dnsstate;
471         unsigned char answer[ANSIZE];
472         ns_msg handle;
473         ns_rr rr;   /* expanded resource record */
474         const uint8_t *rrdata;
475         char nameser[MAXDNAME];
476         char admin[MAXDNAME];
477         int serial;
478         int refresh;
479         int retry;
480         int expire;
481         int minimum;
482
483         (void) state; /* unused */
484
485         memset(&dnsstate, 0, sizeof(struct __res_state));
486         rv = res_ninit(&dnsstate);
487         assert_int_equal(rv, 0);
488
489         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
490                         answer, sizeof(answer));
491         assert_in_range(rv, 1, 100);
492
493         ns_initparse(answer, sizeof(answer), &handle);
494
495         /*
496          * The query must finish w/o an error, have one answer and the answer
497          * must be a parseable RR of type SOA and have the data as in the fake
498          * hosts file
499          */
500         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
501         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
502         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
503         assert_int_equal(ns_rr_type(rr), ns_t_soa);
504
505         rrdata = ns_rr_rdata(rr);
506
507         rv = ns_name_uncompress(ns_msg_base(handle),
508                                 ns_msg_end(handle),
509                                 rrdata,
510                                 nameser, MAXDNAME);
511         assert_int_not_equal(rv, -1);
512         rrdata += rv;
513
514         rv = ns_name_uncompress(ns_msg_base(handle),
515                                 ns_msg_end(handle),
516                                 rrdata,
517                                 admin, MAXDNAME);
518         assert_int_not_equal(rv, -1);
519         rrdata += rv;
520
521         NS_GET32(serial, rrdata);
522         NS_GET32(refresh, rrdata);
523         NS_GET32(retry, rrdata);
524         NS_GET32(expire, rrdata);
525         NS_GET32(minimum, rrdata);
526
527         assert_string_equal(nameser, "ns1.cwrap.org");
528         assert_string_equal(admin, "admin.cwrap.org");
529         assert_int_equal(serial, 2014100457);
530         assert_int_equal(refresh, 3600);
531         assert_int_equal(retry, 300);
532         assert_int_equal(expire, 1814400);
533         assert_int_equal(minimum, 600);
534 }
535
536 static void test_res_fake_cname_query(void **state)
537 {
538         int rv;
539         struct __res_state dnsstate;
540         unsigned char answer[ANSIZE];
541         ns_msg handle;
542         ns_rr rr;   /* expanded resource record */
543         const uint8_t *rrdata;
544         char cname[MAXDNAME];
545         char addr[INET_ADDRSTRLEN];
546
547         (void) state; /* unused */
548
549         memset(&dnsstate, 0, sizeof(struct __res_state));
550         rv = res_ninit(&dnsstate);
551         assert_int_equal(rv, 0);
552
553         rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname,
554                         answer, sizeof(answer));
555         assert_in_range(rv, 1, 256);
556
557         ns_initparse(answer, 256, &handle);
558         ns_initparse(answer, sizeof(answer), &handle);
559
560         /*
561          * The query must finish w/o an error, have one answer and the answer
562          * must be a parseable RR of type CNAME and have the cname as in the
563          * fake hosts file
564          */
565         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
566         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
567         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
568         assert_int_equal(ns_rr_type(rr), ns_t_cname);
569
570         rrdata = ns_rr_rdata(rr);
571
572         rv = ns_name_uncompress(ns_msg_base(handle),
573                                 ns_msg_end(handle),
574                                 rrdata,
575                                 cname, MAXDNAME);
576         assert_int_not_equal(rv, -1);
577
578         assert_string_equal(cname, "web.cwrap.org");
579
580         /* The CNAME points to an A record that's present in the additional
581          * section
582          */
583         assert_int_equal(ns_msg_count(handle, ns_s_ar), 2);
584
585         assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
586         assert_int_equal(ns_rr_type(rr), ns_t_cname);
587         assert_string_equal(ns_rr_name(rr), "web.cwrap.org");
588         rrdata = ns_rr_rdata(rr);
589
590         rv = ns_name_uncompress(ns_msg_base(handle),
591                                 ns_msg_end(handle),
592                                 rrdata,
593                                 cname, MAXDNAME);
594         assert_int_not_equal(rv, -1);
595
596         assert_string_equal(cname, "www.cwrap.org");
597
598         assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0);
599         assert_int_equal(ns_rr_type(rr), ns_t_a);
600         assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
601         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
602                         addr, sizeof(addr)));
603         assert_string_equal(addr, "127.0.0.22");
604 }
605
606 static void test_res_fake_a_via_cname(void **state)
607 {
608         int rv;
609         struct __res_state dnsstate;
610         unsigned char answer[ANSIZE];
611         ns_msg handle;
612         ns_rr rr;   /* expanded resource record */
613         const uint8_t *rrdata;
614         char cname[MAXDNAME];
615         char addr[INET_ADDRSTRLEN];
616
617         (void) state; /* unused */
618
619         memset(&dnsstate, 0, sizeof(struct __res_state));
620         rv = res_ninit(&dnsstate);
621         assert_int_equal(rv, 0);
622
623         /* Query for A record, but the key is a CNAME. The expected result is
624          * that the whole chain of CNAMEs will be included in the answer section
625          * along with the resulting A
626          */
627         rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a,
628                         answer, sizeof(answer));
629         assert_in_range(rv, 1, 256);
630
631         ns_initparse(answer, sizeof(answer), &handle);
632
633         /*
634          * The query must finish w/o an error, have three answers and the answers
635          * must be a parseable RR of type CNAME and have the cname as in the
636          * fake hosts file
637          */
638         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
639         assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
640
641         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
642         assert_int_equal(ns_rr_type(rr), ns_t_cname);
643
644         rrdata = ns_rr_rdata(rr);
645
646         rv = ns_name_uncompress(ns_msg_base(handle),
647                                 ns_msg_end(handle),
648                                 rrdata,
649                                 cname, MAXDNAME);
650         assert_int_not_equal(rv, -1);
651
652         assert_string_equal(cname, "web.cwrap.org");
653
654         assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
655         assert_int_equal(ns_rr_type(rr), ns_t_cname);
656
657         rrdata = ns_rr_rdata(rr);
658
659         rv = ns_name_uncompress(ns_msg_base(handle),
660                                 ns_msg_end(handle),
661                                 rrdata,
662                                 cname, MAXDNAME);
663         assert_int_not_equal(rv, -1);
664
665         assert_string_equal(cname, "www.cwrap.org");
666
667         assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
668         assert_int_equal(ns_rr_type(rr), ns_t_a);
669         assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
670         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
671                         addr, sizeof(addr)));
672         assert_string_equal(addr, "127.0.0.22");
673 }
674
675 static void test_res_fake_ptr_query(void **state)
676 {
677         int rv;
678         struct __res_state dnsstate;
679         unsigned char answer[ANSIZE];
680         const uint8_t *rrdata;
681         char ptrname[MAXDNAME];
682         ns_msg handle;
683         ns_rr rr;   /* expanded resource record */
684
685         (void) state; /* unused */
686
687         memset(&dnsstate, 0, sizeof(struct __res_state));
688         rv = res_ninit(&dnsstate);
689         assert_int_equal(rv, 0);
690
691         rv = res_nquery(&dnsstate, "22.0.0.127.in-addr.arpa", ns_c_in, ns_t_ptr,
692                         answer, sizeof(answer));
693         assert_in_range(rv, 1, 100);
694
695         ns_initparse(answer, sizeof(answer), &handle);
696
697         /*
698          * The query must finish w/o an error, have one answer and the answer
699          * must be a parseable RR of type PTR and have the name that our
700          * fake hosts file contains
701          */
702         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
703         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
704         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
705         assert_int_equal(ns_rr_type(rr), ns_t_ptr);
706
707         rrdata = ns_rr_rdata(rr);
708
709         rv = ns_name_uncompress(ns_msg_base(handle),
710                                 ns_msg_end(handle),
711                                 rrdata,
712                                 ptrname, MAXDNAME);
713         assert_int_not_equal(rv, -1);
714
715         assert_string_equal(ptrname, "www.cwrap.org");
716 }
717
718 static void test_res_fake_txt_query(void **state)
719 {
720         int rv;
721         struct __res_state dnsstate;
722         unsigned char answer[ANSIZE];
723         ns_msg handle;
724         ns_rr rr;   /* expanded resource record */
725         const uint8_t *rrdata;
726
727         (void) state; /* unused */
728
729         memset(&dnsstate, 0, sizeof(struct __res_state));
730         rv = res_ninit(&dnsstate);
731         assert_int_equal(rv, 0);
732
733         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_txt,
734                         answer, sizeof(answer));
735         assert_in_range(rv, 1, 256);
736
737         ns_initparse(answer, sizeof(answer), &handle);
738
739         /*
740          * The query must finish w/o an error, have one answer and the answer
741          * must be a parseable RR of type TXT
742          */
743         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
744         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
745         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
746         assert_int_equal(ns_rr_type(rr), ns_t_txt);
747
748         rrdata = ns_rr_rdata(rr);
749         assert_string_equal(rrdata, "v=spf1 mx");
750 }
751
752 int main(void)
753 {
754         int rc;
755
756         const struct CMUnitTest fake_tests[] = {
757                 cmocka_unit_test(test_res_fake_a_query),
758                 cmocka_unit_test(test_res_fake_a_query_case_insensitive),
759                 cmocka_unit_test(test_res_fake_a_query_trailing_dot),
760                 cmocka_unit_test(test_res_fake_a_query_notfound),
761                 cmocka_unit_test(test_res_fake_aaaa_query),
762                 cmocka_unit_test(test_res_fake_aaaa_query_notfound),
763                 cmocka_unit_test(test_res_fake_srv_query),
764                 cmocka_unit_test(test_res_fake_srv_query_minimal),
765                 cmocka_unit_test(test_res_fake_uri_query),
766                 cmocka_unit_test(test_res_fake_uri_query_minimal),
767                 cmocka_unit_test(test_res_fake_soa_query),
768                 cmocka_unit_test(test_res_fake_cname_query),
769                 cmocka_unit_test(test_res_fake_a_via_cname),
770                 cmocka_unit_test(test_res_fake_ptr_query),
771                 cmocka_unit_test(test_res_fake_txt_query),
772         };
773
774         rc = cmocka_run_group_tests(fake_tests, NULL, NULL);
775
776         return rc;
777 }