]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/lwres/getaddrinfo.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / lwres / getaddrinfo.c
1 /*
2  * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001  Internet Software Consortium.
4  *
5  * This code is derived from software contributed to ISC by
6  * Berkeley Software Design, Inc.
7  *
8  * Permission to use, copy, modify, and/or distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
13  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
15  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
18  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 /* $Id: getaddrinfo.c,v 1.41.206.8 2007/09/13 23:45:58 tbox Exp $ */
22
23 #include <config.h>
24
25 #include <errno.h>
26
27 #include <isc/string.h>
28
29 #include <lwres/lwres.h>
30 #include <lwres/net.h>
31 #include <lwres/netdb.h>
32 #include <lwres/stdlib.h>
33
34 #define SA(addr)        ((struct sockaddr *)(addr))
35 #define SIN(addr)       ((struct sockaddr_in *)(addr))
36 #define SIN6(addr)      ((struct sockaddr_in6 *)(addr))
37 #define SUN(addr)       ((struct sockaddr_un *)(addr))
38
39 static struct addrinfo
40         *ai_reverse(struct addrinfo *oai),
41         *ai_clone(struct addrinfo *oai, int family),
42         *ai_alloc(int family, int addrlen);
43 #ifdef AF_LOCAL
44 static int get_local(const char *name, int socktype, struct addrinfo **res);
45 #endif
46
47 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
48     int socktype, int port);
49 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
50     int socktype, int port);
51 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
52          int, int));
53
54 #define FOUND_IPV4      0x1
55 #define FOUND_IPV6      0x2
56 #define FOUND_MAX       2
57
58 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
59
60 int
61 lwres_getaddrinfo(const char *hostname, const char *servname,
62         const struct addrinfo *hints, struct addrinfo **res)
63 {
64         struct servent *sp;
65         const char *proto;
66         int family, socktype, flags, protocol;
67         struct addrinfo *ai, *ai_list;
68         int port, err, i;
69         int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
70                  int, int);
71
72         if (hostname == NULL && servname == NULL)
73                 return (EAI_NONAME);
74
75         proto = NULL;
76         if (hints != NULL) {
77                 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
78                         return (EAI_BADFLAGS);
79                 if (hints->ai_addrlen || hints->ai_canonname ||
80                     hints->ai_addr || hints->ai_next) {
81                         errno = EINVAL;
82                         return (EAI_SYSTEM);
83                 }
84                 family = hints->ai_family;
85                 socktype = hints->ai_socktype;
86                 protocol = hints->ai_protocol;
87                 flags = hints->ai_flags;
88                 switch (family) {
89                 case AF_UNSPEC:
90                         switch (hints->ai_socktype) {
91                         case SOCK_STREAM:
92                                 proto = "tcp";
93                                 break;
94                         case SOCK_DGRAM:
95                                 proto = "udp";
96                                 break;
97                         }
98                         break;
99                 case AF_INET:
100                 case AF_INET6:
101                         switch (hints->ai_socktype) {
102                         case 0:
103                                 break;
104                         case SOCK_STREAM:
105                                 proto = "tcp";
106                                 break;
107                         case SOCK_DGRAM:
108                                 proto = "udp";
109                                 break;
110                         case SOCK_RAW:
111                                 break;
112                         default:
113                                 return (EAI_SOCKTYPE);
114                         }
115                         break;
116 #ifdef  AF_LOCAL
117                 case AF_LOCAL:
118                         switch (hints->ai_socktype) {
119                         case 0:
120                                 break;
121                         case SOCK_STREAM:
122                                 break;
123                         case SOCK_DGRAM:
124                                 break;
125                         default:
126                                 return (EAI_SOCKTYPE);
127                         }
128                         break;
129 #endif
130                 default:
131                         return (EAI_FAMILY);
132                 }
133         } else {
134                 protocol = 0;
135                 family = 0;
136                 socktype = 0;
137                 flags = 0;
138         }
139
140 #ifdef  AF_LOCAL
141         /*
142          * First, deal with AF_LOCAL.  If the family was not set,
143          * then assume AF_LOCAL if the first character of the
144          * hostname/servname is '/'.
145          */
146
147         if (hostname != NULL &&
148             (family == AF_LOCAL || (family == 0 && *hostname == '/')))
149                 return (get_local(hostname, socktype, res));
150
151         if (servname != NULL &&
152             (family == AF_LOCAL || (family == 0 && *servname == '/')))
153                 return (get_local(servname, socktype, res));
154 #endif
155
156         /*
157          * Ok, only AF_INET and AF_INET6 left.
158          */
159         ai_list = NULL;
160
161         /*
162          * First, look up the service name (port) if it was
163          * requested.  If the socket type wasn't specified, then
164          * try and figure it out.
165          */
166         if (servname != NULL) {
167                 char *e;
168
169                 port = strtol(servname, &e, 10);
170                 if (*e == '\0') {
171                         if (socktype == 0)
172                                 return (EAI_SOCKTYPE);
173                         if (port < 0 || port > 65535)
174                                 return (EAI_SERVICE);
175                         port = htons((unsigned short) port);
176                 } else {
177                         sp = getservbyname(servname, proto);
178                         if (sp == NULL)
179                                 return (EAI_SERVICE);
180                         port = sp->s_port;
181                         if (socktype == 0) {
182                                 if (strcmp(sp->s_proto, "tcp") == 0)
183                                         socktype = SOCK_STREAM;
184                                 else if (strcmp(sp->s_proto, "udp") == 0)
185                                         socktype = SOCK_DGRAM;
186                         }
187                 }
188         } else
189                 port = 0;
190
191         /*
192          * Next, deal with just a service name, and no hostname.
193          * (we verified that one of them was non-null up above).
194          */
195         if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
196                 if (family == AF_INET || family == 0) {
197                         ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
198                         if (ai == NULL)
199                                 return (EAI_MEMORY);
200                         ai->ai_socktype = socktype;
201                         ai->ai_protocol = protocol;
202                         SIN(ai->ai_addr)->sin_port = port;
203                         ai->ai_next = ai_list;
204                         ai_list = ai;
205                 }
206
207                 if (family == AF_INET6 || family == 0) {
208                         ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
209                         if (ai == NULL) {
210                                 lwres_freeaddrinfo(ai_list);
211                                 return (EAI_MEMORY);
212                         }
213                         ai->ai_socktype = socktype;
214                         ai->ai_protocol = protocol;
215                         SIN6(ai->ai_addr)->sin6_port = port;
216                         ai->ai_next = ai_list;
217                         ai_list = ai;
218                 }
219
220                 *res = ai_list;
221                 return (0);
222         }
223
224         /*
225          * If the family isn't specified or AI_NUMERICHOST specified,
226          * check first to see if it is a numeric address.
227          * Though the gethostbyname2() routine
228          * will recognize numeric addresses, it will only recognize
229          * the format that it is being called for.  Thus, a numeric
230          * AF_INET address will be treated by the AF_INET6 call as
231          * a domain name, and vice versa.  Checking for both numerics
232          * here avoids that.
233          */
234         if (hostname != NULL &&
235             (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
236                 char abuf[sizeof(struct in6_addr)];
237                 char nbuf[NI_MAXHOST];
238                 int addrsize, addroff;
239 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
240                 char *p, *ep;
241                 char ntmp[NI_MAXHOST];
242                 lwres_uint32_t scopeid;
243 #endif
244
245 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
246                 /*
247                  * Scope identifier portion.
248                  */
249                 ntmp[0] = '\0';
250                 if (strchr(hostname, '%') != NULL) {
251                         strncpy(ntmp, hostname, sizeof(ntmp) - 1);
252                         ntmp[sizeof(ntmp) - 1] = '\0';
253                         p = strchr(ntmp, '%');
254                         ep = NULL;
255
256                         /*
257                          * Vendors may want to support non-numeric
258                          * scopeid around here.
259                          */
260
261                         if (p != NULL)
262                                 scopeid = (lwres_uint32_t)strtoul(p + 1,
263                                                                   &ep, 10);
264                         if (p != NULL && ep != NULL && ep[0] == '\0')
265                                 *p = '\0';
266                         else {
267                                 ntmp[0] = '\0';
268                                 scopeid = 0;
269                         }
270                 } else
271                         scopeid = 0;
272 #endif
273
274                if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
275                    == 1)
276                {
277                         if (family == AF_INET6) {
278                                 /*
279                                  * Convert to a V4 mapped address.
280                                  */
281                                 struct in6_addr *a6 = (struct in6_addr *)abuf;
282                                 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
283                                 memset(&a6->s6_addr[10], 0xff, 2);
284                                 memset(&a6->s6_addr[0], 0, 10);
285                                 goto inet6_addr;
286                         }
287                         addrsize = sizeof(struct in_addr);
288                         addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
289                         family = AF_INET;
290                         goto common;
291 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
292                 } else if (ntmp[0] != '\0' &&
293                            lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
294                 {
295                         if (family && family != AF_INET6)
296                                 return (EAI_NONAME);
297                         addrsize = sizeof(struct in6_addr);
298                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
299                         family = AF_INET6;
300                         goto common;
301 #endif
302                 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
303                         if (family != 0 && family != AF_INET6)
304                                 return (EAI_NONAME);
305                 inet6_addr:
306                         addrsize = sizeof(struct in6_addr);
307                         addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
308                         family = AF_INET6;
309
310                 common:
311                         ai = ai_clone(ai_list, family);
312                         if (ai == NULL)
313                                 return (EAI_MEMORY);
314                         ai_list = ai;
315                         ai->ai_socktype = socktype;
316                         SIN(ai->ai_addr)->sin_port = port;
317                         memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
318                         if (flags & AI_CANONNAME) {
319 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
320                                 if (ai->ai_family == AF_INET6)
321                                         SIN6(ai->ai_addr)->sin6_scope_id =
322                                                                         scopeid;
323 #endif
324                                 if (lwres_getnameinfo(ai->ai_addr,
325                                     ai->ai_addrlen, nbuf, sizeof(nbuf),
326                                                       NULL, 0,
327                                                       NI_NUMERICHOST) == 0) {
328                                         ai->ai_canonname = strdup(nbuf);
329                                         if (ai->ai_canonname == NULL) {
330                                                 lwres_freeaddrinfo(ai_list);
331                                                 return (EAI_MEMORY);
332                                         }
333                                 } else {
334                                         /* XXX raise error? */
335                                         ai->ai_canonname = NULL;
336                                 }
337                         }
338                         goto done;
339                 } else if ((flags & AI_NUMERICHOST) != 0) {
340                         return (EAI_NONAME);
341                 }
342         }
343
344         set_order(family, net_order);
345         for (i = 0; i < FOUND_MAX; i++) {
346                 if (net_order[i] == NULL)
347                         break;
348                 err = (net_order[i])(hostname, flags, &ai_list,
349                                      socktype, port);
350                 if (err != 0)
351                         return (err);
352         }
353
354         if (ai_list == NULL)
355                 return (EAI_NODATA);
356
357 done:
358         ai_list = ai_reverse(ai_list);
359
360         *res = ai_list;
361         return (0);
362 }
363
364 static char *
365 lwres_strsep(char **stringp, const char *delim) {
366         char *string = *stringp;
367         char *s;
368         const char *d;
369         char sc, dc;
370
371         if (string == NULL)
372                 return (NULL);
373
374         for (s = string; *s != '\0'; s++) {
375                 sc = *s;
376                 for (d = delim; (dc = *d) != '\0'; d++)
377                         if (sc == dc) {
378                                 *s++ = '\0';
379                                 *stringp = s;
380                                 return (string);
381                         }
382         }
383         *stringp = NULL;
384         return (string);
385 }
386
387 static void
388 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
389                                         int, int))
390 {
391         char *order, *tok;
392         int found;
393
394         if (family) {
395                 switch (family) {
396                 case AF_INET:
397                         *net_order++ = add_ipv4;
398                         break;
399                 case AF_INET6:
400                         *net_order++ = add_ipv6;
401                         break;
402                 }
403         } else {
404                 order = getenv("NET_ORDER");
405                 found = 0;
406                 while (order != NULL) {
407                         /*
408                          * We ignore any unknown names.
409                          */
410                         tok = lwres_strsep(&order, ":");
411                         if (strcasecmp(tok, "inet6") == 0) {
412                                 if ((found & FOUND_IPV6) == 0)
413                                         *net_order++ = add_ipv6;
414                                 found |= FOUND_IPV6;
415                         } else if (strcasecmp(tok, "inet") == 0 ||
416                             strcasecmp(tok, "inet4") == 0) {
417                                 if ((found & FOUND_IPV4) == 0)
418                                         *net_order++ = add_ipv4;
419                                 found |= FOUND_IPV4;
420                         }
421                 }
422
423                 /*
424                  * Add in anything that we didn't find.
425                  */
426                 if ((found & FOUND_IPV4) == 0)
427                         *net_order++ = add_ipv4;
428                 if ((found & FOUND_IPV6) == 0)
429                         *net_order++ = add_ipv6;
430         }
431         *net_order = NULL;
432         return;
433 }
434
435 static char v4_loop[4] = { 127, 0, 0, 1 };
436
437 /*
438  * The test against 0 is there to keep the Solaris compiler
439  * from complaining about "end-of-loop code not reached".
440  */
441 #define SETERROR(code) \
442         do { result = (code);                   \
443                 if (result != 0) goto cleanup;  \
444         } while (0)
445
446 static int
447 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
448         int socktype, int port)
449 {
450         struct addrinfo *ai;
451         lwres_context_t *lwrctx = NULL;
452         lwres_gabnresponse_t *by = NULL;
453         lwres_addr_t *addr;
454         lwres_result_t lwres;
455         int result = 0;
456
457         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
458         if (lwres != LWRES_R_SUCCESS)
459                 SETERROR(EAI_FAIL);
460         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
461         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
462                 ai = ai_clone(*aip, AF_INET);
463                 if (ai == NULL) {
464                         lwres_freeaddrinfo(*aip);
465                         SETERROR(EAI_MEMORY);
466                 }
467
468                 *aip = ai;
469                 ai->ai_socktype = socktype;
470                 SIN(ai->ai_addr)->sin_port = port;
471                 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
472         } else {
473                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
474                                              LWRES_ADDRTYPE_V4, &by);
475                 if (lwres != LWRES_R_SUCCESS) {
476                         if (lwres == LWRES_R_NOTFOUND)
477                                 goto cleanup;
478                         else
479                                 SETERROR(EAI_FAIL);
480                 }
481                 addr = LWRES_LIST_HEAD(by->addrs);
482                 while (addr != NULL) {
483                         ai = ai_clone(*aip, AF_INET);
484                         if (ai == NULL) {
485                                 lwres_freeaddrinfo(*aip);
486                                 SETERROR(EAI_MEMORY);
487                         }
488                         *aip = ai;
489                         ai->ai_socktype = socktype;
490                         SIN(ai->ai_addr)->sin_port = port;
491                         memcpy(&SIN(ai->ai_addr)->sin_addr,
492                                addr->address, 4);
493                         if (flags & AI_CANONNAME) {
494                                 ai->ai_canonname = strdup(by->realname);
495                                 if (ai->ai_canonname == NULL)
496                                         SETERROR(EAI_MEMORY);
497                         }
498                         addr = LWRES_LIST_NEXT(addr, link);
499                 }
500         }
501  cleanup:
502         if (by != NULL)
503                 lwres_gabnresponse_free(lwrctx, &by);
504         if (lwrctx != NULL) {
505                 lwres_conf_clear(lwrctx);
506                 lwres_context_destroy(&lwrctx);
507         }
508         return (result);
509 }
510
511 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
512
513 static int
514 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
515          int socktype, int port)
516 {
517         struct addrinfo *ai;
518         lwres_context_t *lwrctx = NULL;
519         lwres_gabnresponse_t *by = NULL;
520         lwres_addr_t *addr;
521         lwres_result_t lwres;
522         int result = 0;
523
524         lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
525         if (lwres != LWRES_R_SUCCESS)
526                 SETERROR(EAI_FAIL);
527         (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
528
529         if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
530                 ai = ai_clone(*aip, AF_INET6);
531                 if (ai == NULL) {
532                         lwres_freeaddrinfo(*aip);
533                         SETERROR(EAI_MEMORY);
534                 }
535
536                 *aip = ai;
537                 ai->ai_socktype = socktype;
538                 SIN6(ai->ai_addr)->sin6_port = port;
539                 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
540         } else {
541                 lwres = lwres_getaddrsbyname(lwrctx, hostname,
542                                              LWRES_ADDRTYPE_V6, &by);
543                 if (lwres != LWRES_R_SUCCESS) {
544                         if (lwres == LWRES_R_NOTFOUND)
545                                 goto cleanup;
546                         else
547                                 SETERROR(EAI_FAIL);
548                 }
549                 addr = LWRES_LIST_HEAD(by->addrs);
550                 while (addr != NULL) {
551                         ai = ai_clone(*aip, AF_INET6);
552                         if (ai == NULL) {
553                                 lwres_freeaddrinfo(*aip);
554                                 SETERROR(EAI_MEMORY);
555                         }
556                         *aip = ai;
557                         ai->ai_socktype = socktype;
558                         SIN6(ai->ai_addr)->sin6_port = port;
559                         memcpy(&SIN6(ai->ai_addr)->sin6_addr,
560                                addr->address, 16);
561                         if (flags & AI_CANONNAME) {
562                                 ai->ai_canonname = strdup(by->realname);
563                                 if (ai->ai_canonname == NULL)
564                                         SETERROR(EAI_MEMORY);
565                         }
566                         addr = LWRES_LIST_NEXT(addr, link);
567                 }
568         }
569  cleanup:
570         if (by != NULL)
571                 lwres_gabnresponse_free(lwrctx, &by);
572         if (lwrctx != NULL) {
573                 lwres_conf_clear(lwrctx);
574                 lwres_context_destroy(&lwrctx);
575         }
576         return (result);
577 }
578
579 void
580 lwres_freeaddrinfo(struct addrinfo *ai) {
581         struct addrinfo *ai_next;
582
583         while (ai != NULL) {
584                 ai_next = ai->ai_next;
585                 if (ai->ai_addr != NULL)
586                         free(ai->ai_addr);
587                 if (ai->ai_canonname)
588                         free(ai->ai_canonname);
589                 free(ai);
590                 ai = ai_next;
591         }
592 }
593
594 #ifdef AF_LOCAL
595 static int
596 get_local(const char *name, int socktype, struct addrinfo **res) {
597         struct addrinfo *ai;
598         struct sockaddr_un *sun;
599
600         if (socktype == 0)
601                 return (EAI_SOCKTYPE);
602
603         ai = ai_alloc(AF_LOCAL, sizeof(*sun));
604         if (ai == NULL)
605                 return (EAI_MEMORY);
606
607         sun = SUN(ai->ai_addr);
608         strncpy(sun->sun_path, name, sizeof(sun->sun_path));
609
610         ai->ai_socktype = socktype;
611         /*
612          * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
613          * and ai->ai_next were initialized to zero.
614          */
615
616         *res = ai;
617         return (0);
618 }
619 #endif
620
621 /*
622  * Allocate an addrinfo structure, and a sockaddr structure
623  * of the specificed length.  We initialize:
624  *      ai_addrlen
625  *      ai_family
626  *      ai_addr
627  *      ai_addr->sa_family
628  *      ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
629  * and everything else is initialized to zero.
630  */
631 static struct addrinfo *
632 ai_alloc(int family, int addrlen) {
633         struct addrinfo *ai;
634
635         ai = (struct addrinfo *)calloc(1, sizeof(*ai));
636         if (ai == NULL)
637                 return (NULL);
638
639         ai->ai_addr = SA(calloc(1, addrlen));
640         if (ai->ai_addr == NULL) {
641                 free(ai);
642                 return (NULL);
643         }
644         ai->ai_addrlen = addrlen;
645         ai->ai_family = family;
646         ai->ai_addr->sa_family = family;
647 #ifdef LWRES_PLATFORM_HAVESALEN
648         ai->ai_addr->sa_len = addrlen;
649 #endif
650         return (ai);
651 }
652
653 static struct addrinfo *
654 ai_clone(struct addrinfo *oai, int family) {
655         struct addrinfo *ai;
656
657         ai = ai_alloc(family, ((family == AF_INET6) ?
658             sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
659
660         if (ai == NULL) {
661                 lwres_freeaddrinfo(oai);
662                 return (NULL);
663         }
664         if (oai == NULL)
665                 return (ai);
666
667         ai->ai_flags = oai->ai_flags;
668         ai->ai_socktype = oai->ai_socktype;
669         ai->ai_protocol = oai->ai_protocol;
670         ai->ai_canonname = NULL;
671         ai->ai_next = oai;
672         return (ai);
673 }
674
675 static struct addrinfo *
676 ai_reverse(struct addrinfo *oai) {
677         struct addrinfo *nai, *tai;
678
679         nai = NULL;
680
681         while (oai != NULL) {
682                 /*
683                  * Grab one off the old list.
684                  */
685                 tai = oai;
686                 oai = oai->ai_next;
687                 /*
688                  * Put it on the front of the new list.
689                  */
690                 tai->ai_next = nai;
691                 nai = tai;
692         }
693         return (nai);
694 }