]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/tests/nss/getaddrinfo_test.c
zfs: merge openzfs/zfs@043c6ee3b
[FreeBSD/FreeBSD.git] / lib / libc / tests / nss / getaddrinfo_test.c
1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33 #include <errno.h>
34 #include <netdb.h>
35 #include <resolv.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stringlist.h>
40 #include <unistd.h>
41
42 #include <atf-c.h>
43
44 #include "freebsd_test_suite/macros.h"
45 #include "testutil.h"
46
47 enum test_methods {
48         TEST_GETADDRINFO,
49         TEST_BUILD_SNAPSHOT
50 };
51
52 static struct addrinfo hints;
53 static enum test_methods method = TEST_GETADDRINFO;
54
55 DECLARE_TEST_DATA(addrinfo)
56 DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
57 DECLARE_2PASS_TEST(addrinfo)
58
59 static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
60 static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
61 static void dump_addrinfo(struct addrinfo *);
62
63 static void sdump_addrinfo(struct addrinfo *, char *, size_t);
64
65 IMPLEMENT_TEST_DATA(addrinfo)
66 IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
67 IMPLEMENT_2PASS_TEST(addrinfo)
68
69 static void
70 clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
71 {
72
73         ATF_REQUIRE(dest != NULL);
74         ATF_REQUIRE(src != NULL);
75
76         memcpy(dest, src, sizeof(struct addrinfo));
77         if (src->ai_canonname != NULL)
78                 dest->ai_canonname = strdup(src->ai_canonname);
79
80         if (src->ai_addr != NULL) {
81                 dest->ai_addr = malloc(src->ai_addrlen);
82                 ATF_REQUIRE(dest->ai_addr != NULL);
83                 memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
84         }
85
86         if (src->ai_next != NULL) {
87                 dest->ai_next = malloc(sizeof(struct addrinfo));
88                 ATF_REQUIRE(dest->ai_next != NULL);
89                 clone_addrinfo(dest->ai_next, src->ai_next);
90         }
91 }
92
93 static int
94 compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
95 {
96
97         if ((ai1 == NULL) || (ai2 == NULL))
98                 return (-1);
99
100         if (ai1->ai_flags != ai2->ai_flags ||
101             ai1->ai_family != ai2->ai_family ||
102             ai1->ai_socktype != ai2->ai_socktype ||
103             ai1->ai_protocol != ai2->ai_protocol ||
104             ai1->ai_addrlen != ai2->ai_addrlen ||
105             ((ai1->ai_addr == NULL || ai2->ai_addr == NULL) &&
106              ai1->ai_addr != ai2->ai_addr) ||
107             ((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) &&
108              ai1->ai_canonname != ai2->ai_canonname))
109                 return (-1);
110
111         if (ai1->ai_canonname != NULL &&
112             strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0)
113                 return (-1);
114
115         if (ai1->ai_addr != NULL &&
116             memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0)
117                 return (-1);
118
119         if (ai1->ai_next == NULL && ai2->ai_next == NULL)
120                 return (0);
121         else
122                 return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
123 }
124
125 static int
126 compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2,
127     void *mdata __unused)
128 {
129         int rv;
130
131         printf("testing equality of 2 addrinfo structures\n");
132
133         rv = compare_addrinfo_(ai1, ai2);
134
135         if (rv == 0)
136                 printf("equal\n");
137         else {
138                 dump_addrinfo(ai1);
139                 dump_addrinfo(ai2);
140                 printf("not equal\n");
141         }
142
143         return (rv);
144 }
145
146 static void
147 free_addrinfo(struct addrinfo *ai)
148 {
149         if (ai == NULL)
150                 return;
151
152         free(ai->ai_addr);
153         free(ai->ai_canonname);
154         free_addrinfo(ai->ai_next);
155 }
156
157 void
158 sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
159 {
160         int written, i;
161
162         written = snprintf(buffer, buflen, "%d %d %d %d %d ",
163                 ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
164                 ai->ai_addrlen);
165         buffer += written;
166         if (written > (int)buflen)
167                 return;
168         buflen -= written;
169
170         written = snprintf(buffer, buflen, "%s ",
171                 ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
172         buffer += written;
173         if (written > (int)buflen)
174                 return;
175         buflen -= written;
176
177         if (ai->ai_addr == NULL) {
178                 written = snprintf(buffer, buflen, "(null)");
179                 buffer += written;
180                 if (written > (int)buflen)
181                         return;
182                 buflen -= written;
183         } else {
184                 for (i = 0; i < (int)ai->ai_addrlen; i++) {
185                         written = snprintf(buffer, buflen,
186                             i + 1 != (int)ai->ai_addrlen ? "%d." : "%d",
187                             ((unsigned char *)ai->ai_addr)[i]);
188                         buffer += written;
189                         if (written > (int)buflen)
190                                 return;
191                         buflen -= written;
192
193                         if (buflen == 0)
194                                 return;
195                 }
196         }
197
198         if (ai->ai_next != NULL) {
199                 written = snprintf(buffer, buflen, ":");
200                 buffer += written;
201                 if (written > (int)buflen)
202                         return;
203                 buflen -= written;
204
205                 sdump_addrinfo(ai->ai_next, buffer, buflen);
206         }
207 }
208
209 void
210 dump_addrinfo(struct addrinfo *result)
211 {
212         if (result != NULL) {
213                 char buffer[2048];
214                 sdump_addrinfo(result, buffer, sizeof(buffer));
215                 printf("%s\n", buffer);
216         } else
217                 printf("(null)\n");
218 }
219
220 static int
221 addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
222 {
223         char *s, *ps, *ts;
224
225         ps = addr;
226         while ((s = strsep(&ps, ".")) != NULL) {
227                 if (len == 0)
228                         return (-1);
229
230                 *result = (unsigned char)strtol(s, &ts, 10);
231                 ++result;
232                 if (*ts != '\0')
233                         return (-1);
234
235                 --len;
236         }
237         if (len != 0)
238                 return (-1);
239         else
240                 return (0);
241 }
242
243 static int
244 addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
245 {
246         char *s, *ps, *ts;
247         int i, rv, *pi;
248
249         rv = 0;
250         i = 0;
251         ps = line;
252         memset(ai, 0, sizeof(struct addrinfo));
253         while ((s = strsep(&ps, " ")) != NULL) {
254                 switch (i) {
255                 case 0:
256                 case 1:
257                 case 2:
258                 case 3:
259                         pi = &ai->ai_flags + i;
260                         *pi = (int)strtol(s, &ts, 10);
261                         if (*ts != '\0')
262                                 goto fin;
263                         break;
264                 case 4:
265                         ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
266                         if (*ts != '\0')
267                                 goto fin;
268                         break;
269                 case 5:
270                         if (strcmp(s, "(null)") != 0) {
271                                 ai->ai_canonname = strdup(s);
272                                 ATF_REQUIRE(ai->ai_canonname != NULL);
273                         }
274                         break;
275                 case 6:
276                         if (strcmp(s, "(null)") != 0) {
277                                 ai->ai_addr = calloc(1, ai->ai_addrlen);
278                                 ATF_REQUIRE(ai->ai_addr != NULL);
279                                 rv = addrinfo_read_snapshot_addr(s,
280                                     (unsigned char *)ai->ai_addr,
281                                     ai->ai_addrlen);
282
283                                 if (rv != 0)
284                                         goto fin;
285                         }
286                         break;
287                 default:
288                         /* NOTE: should not be reachable */
289                         rv = -1;
290                         goto fin;
291                 }
292
293                 ++i;
294         }
295
296 fin:
297         if (i != 7 || rv != 0) {
298                 free_addrinfo(ai);
299                 ai = NULL;
300                 return (-1);
301         }
302
303         return (0);
304 }
305
306 static int
307 addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
308 {
309         struct addrinfo *ai2;
310         char *s, *ps;
311         int rv;
312
313         printf("1 line read from snapshot:\n%s\n", line);
314
315         rv = 0;
316         ps = line;
317
318         s = strsep(&ps, ":");
319         if (s == NULL)
320                 return (-1);
321
322         rv = addrinfo_read_snapshot_ai(ai, s);
323         if (rv != 0)
324                 return (-1);
325
326         ai2 = ai;
327         while ((s = strsep(&ps, ":")) != NULL) {
328                 ai2->ai_next = calloc(1, sizeof(struct addrinfo));
329                 ATF_REQUIRE(ai2->ai_next != NULL);
330
331                 rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
332                 if (rv != 0) {
333                         free_addrinfo(ai);
334                         ai = NULL;
335                         return (-1);
336                 }
337
338                 ai2 = ai2->ai_next;
339         }
340
341         return (0);
342 }
343
344 static int
345 addrinfo_test_correctness(struct addrinfo *ai, void *mdata __unused)
346 {
347
348         printf("testing correctness with the following data:\n");
349         dump_addrinfo(ai);
350
351         if (ai == NULL)
352                 goto errfin;
353
354         if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX))
355                 goto errfin;
356
357         if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM &&
358             ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW)
359                 goto errfin;
360
361         if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP &&
362             ai->ai_protocol != IPPROTO_TCP)
363                 goto errfin;
364
365         if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
366                 goto errfin;
367
368         if (ai->ai_addrlen != ai->ai_addr->sa_len ||
369             ai->ai_family != ai->ai_addr->sa_family)
370                 goto errfin;
371
372         printf("correct\n");
373
374         return (0);
375 errfin:
376         printf("incorrect\n");
377
378         return (-1);
379 }
380
381 static int
382 addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
383 {
384         struct addrinfo *result;
385         int rv;
386
387         printf("resolving %s: ", line);
388         rv = getaddrinfo(line, NULL, &hints, &result);
389         if (rv == 0) {
390                 printf("found\n");
391
392                 rv = addrinfo_test_correctness(result, NULL);
393                 if (rv != 0) {
394                         freeaddrinfo(result);
395                         result = NULL;
396                         return (rv);
397                 }
398
399                 clone_addrinfo(ai, result);
400                 freeaddrinfo(result);
401                 result = NULL;
402         } else {
403                 printf("not found\n");
404
405                 memset(ai, 0, sizeof(struct addrinfo));
406         }
407         return (0);
408 }
409
410 static void
411 run_tests(char *hostlist_file, const char *snapshot_file, int ai_family)
412 {
413         struct addrinfo_test_data td, td_snap;
414         char *snapshot_file_copy;
415         int rv;
416
417         if (snapshot_file == NULL)
418                 snapshot_file_copy = NULL;
419         else {
420                 snapshot_file_copy = strdup(snapshot_file);
421                 ATF_REQUIRE(snapshot_file_copy != NULL);
422         }
423
424         memset(&hints, 0, sizeof(struct addrinfo));
425         hints.ai_family = ai_family;
426         hints.ai_flags = AI_CANONNAME;
427
428         if (snapshot_file != NULL)
429                 method = TEST_BUILD_SNAPSHOT;
430
431         TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
432         TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
433
434         ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0,
435                 "can't access the hostlist file %s\n", hostlist_file);
436
437         printf("building host lists from %s\n", hostlist_file);
438
439         rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
440                 addrinfo_read_hostlist_func);
441         if (rv != 0)
442                 goto fin;
443
444         if (snapshot_file != NULL) {
445                 if (access(snapshot_file, W_OK | R_OK) != 0) {
446                         if (errno == ENOENT)
447                                 method = TEST_BUILD_SNAPSHOT;
448                         else {
449                                 printf("can't access the snapshot "
450                                     "file %s\n", snapshot_file);
451
452                                 rv = -1;
453                                 goto fin;
454                         }
455                 } else {
456                         rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
457                                 &td_snap, addrinfo_read_snapshot_func);
458                         if (rv != 0) {
459                                 printf("error reading snapshot file: %s\n",
460                                     strerror(errno));
461                                 goto fin;
462                         }
463                 }
464         }
465
466         switch (method) {
467         case TEST_GETADDRINFO:
468                 if (snapshot_file != NULL)
469                         ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap,
470                                 compare_addrinfo, NULL) == 0);
471                 break;
472         case TEST_BUILD_SNAPSHOT:
473                 if (snapshot_file != NULL) {
474                         ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo,
475                             snapshot_file, &td, sdump_addrinfo) == 0);
476                 }
477                 break;
478         default:
479                 break;
480         }
481
482 fin:
483         TEST_DATA_DESTROY(addrinfo, &td_snap);
484         TEST_DATA_DESTROY(addrinfo, &td);
485
486         free(snapshot_file_copy);
487 }
488
489 #define HOSTLIST_FILE   "mach"
490 #define RUN_TESTS(tc, snapshot_file, ai_family) do {                    \
491         char *_hostlist_file;                                           \
492         ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s",              \
493             atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE));       \
494         run_tests(_hostlist_file, snapshot_file, ai_family);            \
495         free(_hostlist_file);                                           \
496 } while (0)
497
498 ATF_TC_WITHOUT_HEAD(pf_unspec);
499 ATF_TC_BODY(pf_unspec, tc)
500 {
501
502         RUN_TESTS(tc, NULL, AF_UNSPEC);
503 }
504
505 ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot);
506 ATF_TC_BODY(pf_unspec_with_snapshot, tc)
507 {
508
509         RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC);
510 }
511
512 ATF_TC_WITHOUT_HEAD(pf_inet);
513 ATF_TC_BODY(pf_inet, tc)
514 {
515
516         ATF_REQUIRE_FEATURE("inet");
517         RUN_TESTS(tc, NULL, AF_INET);
518 }
519
520 ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot);
521 ATF_TC_BODY(pf_inet_with_snapshot, tc)
522 {
523
524         ATF_REQUIRE_FEATURE("inet");
525         RUN_TESTS(tc, "snapshot_ai4", AF_INET);
526 }
527
528 ATF_TC_WITHOUT_HEAD(pf_inet6);
529 ATF_TC_BODY(pf_inet6, tc)
530 {
531
532         ATF_REQUIRE_FEATURE("inet6");
533         RUN_TESTS(tc, NULL, AF_INET6);
534 }
535
536 ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot);
537 ATF_TC_BODY(pf_inet6_with_snapshot, tc)
538 {
539
540         ATF_REQUIRE_FEATURE("inet6");
541         RUN_TESTS(tc, "snapshot_ai6", AF_INET6);
542 }
543
544 ATF_TP_ADD_TCS(tp)
545 {
546
547         ATF_TP_ADD_TC(tp, pf_unspec);
548         ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot);
549         ATF_TP_ADD_TC(tp, pf_inet);
550         ATF_TP_ADD_TC(tp, pf_inet_with_snapshot);
551         ATF_TP_ADD_TC(tp, pf_inet6);
552         ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot);
553
554         return (atf_no_error());
555 }