tests: Use the right array size in tests.
[obnox/cwrap/resolv_wrapper.git] / tests / test_dns_fake.c
1 /*
2  * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@gmail.com>
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
53 static void test_res_fake_a_query(void **state)
54 {
55         int rv;
56         struct __res_state dnsstate;
57         unsigned char answer[ANSIZE];
58         char addr[INET_ADDRSTRLEN];
59         ns_msg handle;
60         ns_rr rr;   /* expanded resource record */
61
62         (void) state; /* unused */
63
64         memset(&dnsstate, 0, sizeof(struct __res_state));
65         rv = res_ninit(&dnsstate);
66         assert_int_equal(rv, 0);
67
68         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a,
69                         answer, sizeof(answer));
70         assert_int_not_equal(rv, -1);
71
72         ns_initparse(answer, sizeof(answer), &handle);
73         /* The query must finish w/o an error, have one answer and the answer
74          * must be a parseable RR of type A and have the address that our
75          * fake hosts file contains
76          */
77         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
78         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
79         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
80         assert_int_equal(ns_rr_type(rr), ns_t_a);
81         assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
82                         addr, sizeof(addr)));
83         assert_string_equal(addr, "127.0.0.21");
84 }
85
86 static void test_res_fake_a_query_notfound(void **state)
87 {
88         int rv;
89         struct __res_state dnsstate;
90         unsigned char answer[ANSIZE];
91         ns_msg handle;
92
93         (void) state; /* unused */
94
95         memset(&dnsstate, 0, sizeof(struct __res_state));
96         rv = res_ninit(&dnsstate);
97         assert_int_equal(rv, 0);
98
99         rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a,
100                         answer, sizeof(answer));
101         assert_int_not_equal(rv, -1);
102
103         ns_initparse(answer, sizeof(answer), &handle);
104         /* The query must finish w/o an error and have no answer */
105         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
106         assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
107 }
108
109 static void test_res_fake_aaaa_query(void **state)
110 {
111         int rv;
112         struct __res_state dnsstate;
113         unsigned char answer[ANSIZE];
114         char addr[INET6_ADDRSTRLEN];
115         ns_msg handle;
116         ns_rr rr;   /* expanded resource record */
117
118         (void) state; /* unused */
119
120         memset(&dnsstate, 0, sizeof(struct __res_state));
121         rv = res_ninit(&dnsstate);
122         assert_int_equal(rv, 0);
123
124         rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa,
125                         answer, sizeof(answer));
126         assert_int_not_equal(rv, -1);
127
128         ns_initparse(answer, sizeof(answer), &handle);
129         /* The query must finish w/o an error, have one answer and the answer
130          * must be a parseable RR of type AAAA and have the address that our
131          * fake hosts file contains
132          */
133         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
134         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
135         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
136         assert_int_equal(ns_rr_type(rr), ns_t_aaaa);
137         assert_non_null(inet_ntop(AF_INET6, ns_rr_rdata(rr),
138                         addr, sizeof(addr)));
139         assert_string_equal(addr, "2a00:1450:4013:c01::63");
140 }
141
142 static void test_res_fake_aaaa_query_notfound(void **state)
143 {
144         int rv;
145         struct __res_state dnsstate;
146         unsigned char answer[ANSIZE];
147         ns_msg handle;
148
149         (void) state; /* unused */
150
151         memset(&dnsstate, 0, sizeof(struct __res_state));
152         rv = res_ninit(&dnsstate);
153         assert_int_equal(rv, 0);
154
155         rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa,
156                         answer, sizeof(answer));
157         assert_int_not_equal(rv, -1);
158
159         ns_initparse(answer, sizeof(answer), &handle);
160         /* The query must finish w/o an error and have no answer */
161         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
162         assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
163 }
164
165 static void test_res_fake_srv_query(void **state)
166 {
167         int rv;
168         struct __res_state dnsstate;
169         unsigned char answer[ANSIZE];
170         ns_msg handle;
171         ns_rr rr;   /* expanded resource record */
172         const uint8_t *rrdata;
173         int prio;
174         int weight;
175         int port;
176         char hostname[MAXDNAME];
177
178         (void) state; /* unused */
179
180         memset(&dnsstate, 0, sizeof(struct __res_state));
181         rv = res_ninit(&dnsstate);
182         assert_int_equal(rv, 0);
183
184         rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
185                         answer, sizeof(answer));
186         assert_int_not_equal(rv, -1);
187
188         ns_initparse(answer, sizeof(answer), &handle);
189
190         /*
191          * The query must finish w/o an error, have one answer and the answer
192          * must be a parseable RR of type SRV and have the priority, weight,
193          * port and hostname as in the fake hosts file
194          */
195         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
196         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
197         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
198         assert_int_equal(ns_rr_type(rr), ns_t_srv);
199
200         rrdata = ns_rr_rdata(rr);
201         NS_GET16(prio, rrdata);
202         NS_GET16(weight, rrdata);
203         NS_GET16(port, rrdata);
204
205         rv = ns_name_uncompress(ns_msg_base(handle),
206                                 ns_msg_end(handle),
207                                 rrdata,
208                                 hostname, MAXDNAME);
209         assert_int_not_equal(rv, -1);
210
211         assert_int_equal(prio, 1);
212         assert_int_equal(weight, 5);
213         assert_int_equal(port, 389);
214         assert_string_equal(hostname, "ldap.cwrap.org");
215 }
216
217 /*
218  * Test the case of a SRV record query where the
219  * fake hosts file entry is minimal in the sense
220  * that it omits the priority and weight entries.
221  * The server then fills in some default values.
222  */
223 static void test_res_fake_srv_query_minimal(void **state)
224 {
225         int rv;
226         struct __res_state dnsstate;
227         unsigned char answer[ANSIZE];
228         ns_msg handle;
229         ns_rr rr;   /* expanded resource record */
230         const uint8_t *rrdata;
231         int prio;
232         int weight;
233         int port;
234         char hostname[MAXDNAME];
235
236         (void) state; /* unused */
237
238         memset(&dnsstate, 0, sizeof(struct __res_state));
239         rv = res_ninit(&dnsstate);
240         assert_int_equal(rv, 0);
241
242         rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
243                         answer, sizeof(answer));
244         assert_int_not_equal(rv, -1);
245
246         ns_initparse(answer, sizeof(answer), &handle);
247
248         /*
249          * The query must finish w/o an error, have one answer and the answer
250          * must be a parseable RR of type SRV and have the priority, weight,
251          * port and hostname as in the fake hosts file
252          */
253         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
254         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
255         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
256         assert_int_equal(ns_rr_type(rr), ns_t_srv);
257
258         rrdata = ns_rr_rdata(rr);
259         NS_GET16(prio, rrdata);
260         NS_GET16(weight, rrdata);
261         NS_GET16(port, rrdata);
262
263         rv = ns_name_uncompress(ns_msg_base(handle),
264                                 ns_msg_end(handle),
265                                 rrdata,
266                                 hostname, MAXDNAME);
267         assert_int_not_equal(rv, -1);
268
269         assert_int_equal(prio, 1);
270         assert_int_equal(weight, 100);
271         assert_int_equal(port, 88);
272         assert_string_equal(hostname, "krb5.cwrap.org");
273 }
274
275 static void test_res_fake_soa_query(void **state)
276 {
277         int rv;
278         struct __res_state dnsstate;
279         unsigned char answer[ANSIZE];
280         ns_msg handle;
281         ns_rr rr;   /* expanded resource record */
282         const uint8_t *rrdata;
283         char nameser[MAXDNAME];
284         char admin[MAXDNAME];
285         int serial;
286         int refresh;
287         int retry;
288         int expire;
289         int minimum;
290
291         (void) state; /* unused */
292
293         memset(&dnsstate, 0, sizeof(struct __res_state));
294         rv = res_ninit(&dnsstate);
295         assert_int_equal(rv, 0);
296
297         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
298                         answer, sizeof(answer));
299         assert_int_not_equal(rv, -1);
300
301         ns_initparse(answer, sizeof(answer), &handle);
302
303         /*
304          * The query must finish w/o an error, have one answer and the answer
305          * must be a parseable RR of type SOA and have the data as in the fake
306          * hosts file
307          */
308         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
309         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
310         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
311         assert_int_equal(ns_rr_type(rr), ns_t_soa);
312
313         rrdata = ns_rr_rdata(rr);
314
315         rv = ns_name_uncompress(ns_msg_base(handle),
316                                 ns_msg_end(handle),
317                                 rrdata,
318                                 nameser, MAXDNAME);
319         assert_int_not_equal(rv, -1);
320         rrdata += rv;
321
322         rv = ns_name_uncompress(ns_msg_base(handle),
323                                 ns_msg_end(handle),
324                                 rrdata,
325                                 admin, MAXDNAME);
326         assert_int_not_equal(rv, -1);
327         rrdata += rv;
328
329         NS_GET32(serial, rrdata);
330         NS_GET32(refresh, rrdata);
331         NS_GET32(retry, rrdata);
332         NS_GET32(expire, rrdata);
333         NS_GET32(minimum, rrdata);
334
335         assert_string_equal(nameser, "ns1.cwrap.org");
336         assert_string_equal(admin, "admin.cwrap.org");
337         assert_int_equal(serial, 2014100457);
338         assert_int_equal(refresh, 3600);
339         assert_int_equal(retry, 300);
340         assert_int_equal(expire, 1814400);
341         assert_int_equal(minimum, 600);
342 }
343
344 static void test_res_fake_cname_query(void **state)
345 {
346         int rv;
347         struct __res_state dnsstate;
348         unsigned char answer[ANSIZE];
349         ns_msg handle;
350         ns_rr rr;   /* expanded resource record */
351         const uint8_t *rrdata;
352         char cname[MAXDNAME];
353
354         (void) state; /* unused */
355
356         memset(&dnsstate, 0, sizeof(struct __res_state));
357         rv = res_ninit(&dnsstate);
358         assert_int_equal(rv, 0);
359
360         rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_cname,
361                         answer, sizeof(answer));
362         assert_int_not_equal(rv, -1);
363
364         ns_initparse(answer, 256, &handle);
365         ns_initparse(answer, sizeof(answer), &handle);
366
367         /*
368          * The query must finish w/o an error, have one answer and the answer
369          * must be a parseable RR of type CNAME and have the cname as in the
370          * fake hosts file
371          */
372         assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
373         assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
374         assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
375         assert_int_equal(ns_rr_type(rr), ns_t_cname);
376
377         rrdata = ns_rr_rdata(rr);
378
379         rv = ns_name_uncompress(ns_msg_base(handle),
380                                 ns_msg_end(handle),
381                                 rrdata,
382                                 cname, MAXDNAME);
383         assert_int_not_equal(rv, -1);
384
385         assert_string_equal(cname, "therealcwrap.org");
386 }
387
388 int main(void)
389 {
390         int rc;
391
392         const UnitTest tests[] = {
393                 unit_test(test_res_fake_a_query),
394                 unit_test(test_res_fake_a_query_notfound),
395                 unit_test(test_res_fake_aaaa_query),
396                 unit_test(test_res_fake_aaaa_query_notfound),
397                 unit_test(test_res_fake_srv_query),
398                 unit_test(test_res_fake_srv_query_minimal),
399                 unit_test(test_res_fake_soa_query),
400                 unit_test(test_res_fake_cname_query),
401         };
402
403         rc = run_tests(tests);
404
405         return rc;
406 }