4 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * This code is derived from software contributed to ISC by
8 * Berkeley Software Design, Inc.
10 * Permission to use, copy, modify, and/or distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
15 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
17 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
20 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 /* Id: getaddrinfo.c,v 1.54 2008/11/25 23:47:23 tbox Exp */
28 * lwres_getaddrinfo() is used to get a list of IP addresses and port
29 * numbers for host hostname and service servname. The function is the
30 * lightweight resolver's implementation of getaddrinfo() as defined in
31 * RFC2133. hostname and servname are pointers to null-terminated strings
32 * or NULL. hostname is either a host name or a numeric host address
33 * string: a dotted decimal IPv4 address or an IPv6 address. servname is
34 * either a decimal port number or a service name as listed in
37 * If the operating system does not provide a struct addrinfo, the
38 * following structure is used:
42 * int ai_flags; // AI_PASSIVE, AI_CANONNAME
43 * int ai_family; // PF_xxx
44 * int ai_socktype; // SOCK_xxx
45 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
46 * size_t ai_addrlen; // length of ai_addr
47 * char *ai_canonname; // canonical name for hostname
48 * struct sockaddr *ai_addr; // binary address
49 * struct addrinfo *ai_next; // next structure in linked list
54 * hints is an optional pointer to a struct addrinfo. This structure can
55 * be used to provide hints concerning the type of socket that the caller
56 * supports or wishes to use. The caller can supply the following
57 * structure elements in *hints:
61 * The protocol family that should be used. When ai_family is set
62 * to PF_UNSPEC, it means the caller will accept any protocol
63 * family supported by the operating system.</li>
66 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
67 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
68 * will accept any socket type.</li>
71 * indicates which transport protocol is wanted: IPPROTO_UDP or
72 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any
76 * Flag bits. If the AI_CANONNAME bit is set, a successful call to
77 * lwres_getaddrinfo() will return a null-terminated string
78 * containing the canonical name of the specified hostname in
79 * ai_canonname of the first addrinfo structure returned. Setting
80 * the AI_PASSIVE bit indicates that the returned socket address
81 * structure is intended for used in a call to bind(2). In this
82 * case, if the hostname argument is a NULL pointer, then the IP
83 * address portion of the socket address structure will be set to
84 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
85 * address.<br /><br />
87 * When ai_flags does not set the AI_PASSIVE bit, the returned
88 * socket address structure will be ready for use in a call to
89 * connect(2) for a connection-oriented protocol or connect(2),
90 * sendto(2), or sendmsg(2) if a connectionless protocol was
91 * chosen. The IP address portion of the socket address structure
92 * will be set to the loopback address if hostname is a NULL
93 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
95 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname
96 * should be treated as a numeric string defining an IPv4 or IPv6
97 * address and no name resolution should be attempted.
100 * All other elements of the struct addrinfo passed via hints must be
103 * A hints of NULL is treated as if the caller provided a struct addrinfo
104 * initialized to zero with ai_familyset to PF_UNSPEC.
106 * After a successful call to lwres_getaddrinfo(), *res is a pointer to a
107 * linked list of one or more addrinfo structures. Each struct addrinfo
108 * in this list cn be processed by following the ai_next pointer, until a
109 * NULL pointer is encountered. The three members ai_family, ai_socktype,
110 * and ai_protocol in each returned addrinfo structure contain the
111 * corresponding arguments for a call to socket(2). For each addrinfo
112 * structure in the list, the ai_addr member points to a filled-in socket
113 * address structure of length ai_addrlen.
115 * All of the information returned by lwres_getaddrinfo() is dynamically
116 * allocated: the addrinfo structures, and the socket address structures
117 * and canonical host name strings pointed to by the addrinfostructures.
118 * Memory allocated for the dynamically allocated structures created by a
119 * successful call to lwres_getaddrinfo() is released by
120 * lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by
121 * a call to lwres_getaddrinfo().
123 * \section lwresreturn RETURN VALUES
125 * lwres_getaddrinfo() returns zero on success or one of the error codes
126 * listed in gai_strerror() if an error occurs. If both hostname and
127 * servname are NULL lwres_getaddrinfo() returns #EAI_NONAME.
129 * \section lwressee SEE ALSO
131 * lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(),
132 * lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2),
133 * sendto(2), sendmsg(2), socket(2).
140 #include <isc/string.h>
142 #include <lwres/lwres.h>
143 #include <lwres/net.h>
144 #include <lwres/netdb.h>
145 #include <lwres/stdlib.h>
147 #define SA(addr) ((struct sockaddr *)(addr))
148 #define SIN(addr) ((struct sockaddr_in *)(addr))
149 #define SIN6(addr) ((struct sockaddr_in6 *)(addr))
150 #define SLOCAL(addr) ((struct sockaddr_un *)(addr))
154 static struct addrinfo
155 *ai_reverse(struct addrinfo
*oai
),
156 *ai_clone(struct addrinfo
*oai
, int family
),
157 *ai_alloc(int family
, int addrlen
);
159 static int get_local(const char *name
, int socktype
, struct addrinfo
**res
);
162 static int add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
163 int socktype
, int port
);
164 static int add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
165 int socktype
, int port
);
166 static void set_order(int, int (**)(const char *, int, struct addrinfo
**,
169 #define FOUND_IPV4 0x1
170 #define FOUND_IPV6 0x2
173 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
174 /*% Get a list of IP addresses and port numbers for host hostname and service servname. */
176 lwres_getaddrinfo(const char *hostname
, const char *servname
,
177 const struct addrinfo
*hints
, struct addrinfo
**res
)
181 int family
, socktype
, flags
, protocol
;
182 struct addrinfo
*ai
, *ai_list
;
184 int (*net_order
[FOUND_MAX
+1])(const char *, int, struct addrinfo
**,
187 if (hostname
== NULL
&& servname
== NULL
)
192 if ((hints
->ai_flags
& ~(ISC_AI_MASK
)) != 0)
193 return (EAI_BADFLAGS
);
194 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
195 hints
->ai_addr
|| hints
->ai_next
) {
199 family
= hints
->ai_family
;
200 socktype
= hints
->ai_socktype
;
201 protocol
= hints
->ai_protocol
;
202 flags
= hints
->ai_flags
;
205 switch (hints
->ai_socktype
) {
216 switch (hints
->ai_socktype
) {
228 return (EAI_SOCKTYPE
);
233 switch (hints
->ai_socktype
) {
241 return (EAI_SOCKTYPE
);
257 * First, deal with AF_LOCAL. If the family was not set,
258 * then assume AF_LOCAL if the first character of the
259 * hostname/servname is '/'.
262 if (hostname
!= NULL
&&
263 (family
== AF_LOCAL
|| (family
== 0 && *hostname
== '/')))
264 return (get_local(hostname
, socktype
, res
));
266 if (servname
!= NULL
&&
267 (family
== AF_LOCAL
|| (family
== 0 && *servname
== '/')))
268 return (get_local(servname
, socktype
, res
));
272 * Ok, only AF_INET and AF_INET6 left.
277 * First, look up the service name (port) if it was
278 * requested. If the socket type wasn't specified, then
279 * try and figure it out.
281 if (servname
!= NULL
) {
284 port
= strtol(servname
, &e
, 10);
287 return (EAI_SOCKTYPE
);
288 if (port
< 0 || port
> 65535)
289 return (EAI_SERVICE
);
290 port
= htons((unsigned short) port
);
292 sp
= getservbyname(servname
, proto
);
294 return (EAI_SERVICE
);
297 if (strcmp(sp
->s_proto
, "tcp") == 0)
298 socktype
= SOCK_STREAM
;
299 else if (strcmp(sp
->s_proto
, "udp") == 0)
300 socktype
= SOCK_DGRAM
;
307 * Next, deal with just a service name, and no hostname.
308 * (we verified that one of them was non-null up above).
310 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) != 0) {
311 if (family
== AF_INET
|| family
== 0) {
312 ai
= ai_alloc(AF_INET
, sizeof(struct sockaddr_in
));
315 ai
->ai_socktype
= socktype
;
316 ai
->ai_protocol
= protocol
;
317 SIN(ai
->ai_addr
)->sin_port
= port
;
318 ai
->ai_next
= ai_list
;
322 if (family
== AF_INET6
|| family
== 0) {
323 ai
= ai_alloc(AF_INET6
, sizeof(struct sockaddr_in6
));
325 lwres_freeaddrinfo(ai_list
);
328 ai
->ai_socktype
= socktype
;
329 ai
->ai_protocol
= protocol
;
330 SIN6(ai
->ai_addr
)->sin6_port
= port
;
331 ai
->ai_next
= ai_list
;
340 * If the family isn't specified or AI_NUMERICHOST specified,
341 * check first to see if it is a numeric address.
342 * Though the gethostbyname2() routine
343 * will recognize numeric addresses, it will only recognize
344 * the format that it is being called for. Thus, a numeric
345 * AF_INET address will be treated by the AF_INET6 call as
346 * a domain name, and vice versa. Checking for both numerics
349 if (hostname
!= NULL
&&
350 (family
== 0 || (flags
& AI_NUMERICHOST
) != 0)) {
351 char abuf
[sizeof(struct in6_addr
)];
352 char nbuf
[NI_MAXHOST
];
353 int addrsize
, addroff
;
354 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
356 char ntmp
[NI_MAXHOST
];
357 lwres_uint32_t scopeid
;
360 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
362 * Scope identifier portion.
365 if (strchr(hostname
, '%') != NULL
) {
366 strncpy(ntmp
, hostname
, sizeof(ntmp
) - 1);
367 ntmp
[sizeof(ntmp
) - 1] = '\0';
368 p
= strchr(ntmp
, '%');
372 * Vendors may want to support non-numeric
373 * scopeid around here.
377 scopeid
= (lwres_uint32_t
)strtoul(p
+ 1,
379 if (p
!= NULL
&& ep
!= NULL
&& ep
[0] == '\0')
389 if (lwres_net_pton(AF_INET
, hostname
, (struct in_addr
*)abuf
)
392 if (family
== AF_INET6
) {
394 * Convert to a V4 mapped address.
396 struct in6_addr
*a6
= (struct in6_addr
*)abuf
;
397 memcpy(&a6
->s6_addr
[12], &a6
->s6_addr
[0], 4);
398 memset(&a6
->s6_addr
[10], 0xff, 2);
399 memset(&a6
->s6_addr
[0], 0, 10);
402 addrsize
= sizeof(struct in_addr
);
403 addroff
= (char *)(&SIN(0)->sin_addr
) - (char *)0;
406 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
407 } else if (ntmp
[0] != '\0' &&
408 lwres_net_pton(AF_INET6
, ntmp
, abuf
) == 1)
410 if (family
&& family
!= AF_INET6
)
412 addrsize
= sizeof(struct in6_addr
);
413 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
417 } else if (lwres_net_pton(AF_INET6
, hostname
, abuf
) == 1) {
418 if (family
!= 0 && family
!= AF_INET6
)
421 addrsize
= sizeof(struct in6_addr
);
422 addroff
= (char *)(&SIN6(0)->sin6_addr
) - (char *)0;
426 ai
= ai_clone(ai_list
, family
);
430 ai
->ai_socktype
= socktype
;
431 SIN(ai
->ai_addr
)->sin_port
= port
;
432 memcpy((char *)ai
->ai_addr
+ addroff
, abuf
, addrsize
);
433 if (flags
& AI_CANONNAME
) {
434 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
435 if (ai
->ai_family
== AF_INET6
)
436 SIN6(ai
->ai_addr
)->sin6_scope_id
=
439 if (lwres_getnameinfo(ai
->ai_addr
,
440 ai
->ai_addrlen
, nbuf
, sizeof(nbuf
),
442 NI_NUMERICHOST
) == 0) {
443 ai
->ai_canonname
= strdup(nbuf
);
444 if (ai
->ai_canonname
== NULL
) {
445 lwres_freeaddrinfo(ai_list
);
449 /* XXX raise error? */
450 ai
->ai_canonname
= NULL
;
454 } else if ((flags
& AI_NUMERICHOST
) != 0) {
459 set_order(family
, net_order
);
460 for (i
= 0; i
< FOUND_MAX
; i
++) {
461 if (net_order
[i
] == NULL
)
463 err
= (net_order
[i
])(hostname
, flags
, &ai_list
,
473 ai_list
= ai_reverse(ai_list
);
480 lwres_strsep(char **stringp
, const char *delim
) {
481 char *string
= *stringp
;
489 for (s
= string
; *s
!= '\0'; s
++) {
491 for (d
= delim
; (dc
= *d
) != '\0'; d
++)
503 set_order(int family
, int (**net_order
)(const char *, int, struct addrinfo
**,
512 *net_order
++ = add_ipv4
;
515 *net_order
++ = add_ipv6
;
519 order
= getenv("NET_ORDER");
521 while (order
!= NULL
) {
523 * We ignore any unknown names.
525 tok
= lwres_strsep(&order
, ":");
526 if (strcasecmp(tok
, "inet6") == 0) {
527 if ((found
& FOUND_IPV6
) == 0)
528 *net_order
++ = add_ipv6
;
530 } else if (strcasecmp(tok
, "inet") == 0 ||
531 strcasecmp(tok
, "inet4") == 0) {
532 if ((found
& FOUND_IPV4
) == 0)
533 *net_order
++ = add_ipv4
;
539 * Add in anything that we didn't find.
541 if ((found
& FOUND_IPV4
) == 0)
542 *net_order
++ = add_ipv4
;
543 if ((found
& FOUND_IPV6
) == 0)
544 *net_order
++ = add_ipv6
;
550 static char v4_loop
[4] = { 127, 0, 0, 1 };
553 * The test against 0 is there to keep the Solaris compiler
554 * from complaining about "end-of-loop code not reached".
556 #define SETERROR(code) \
557 do { result = (code); \
558 if (result != 0) goto cleanup; \
562 add_ipv4(const char *hostname
, int flags
, struct addrinfo
**aip
,
563 int socktype
, int port
)
566 lwres_context_t
*lwrctx
= NULL
;
567 lwres_gabnresponse_t
*by
= NULL
;
569 lwres_result_t lwres
;
572 lwres
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
573 if (lwres
!= LWRES_R_SUCCESS
)
575 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
576 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
577 ai
= ai_clone(*aip
, AF_INET
);
579 lwres_freeaddrinfo(*aip
);
580 SETERROR(EAI_MEMORY
);
584 ai
->ai_socktype
= socktype
;
585 SIN(ai
->ai_addr
)->sin_port
= port
;
586 memcpy(&SIN(ai
->ai_addr
)->sin_addr
, v4_loop
, 4);
588 lwres
= lwres_getaddrsbyname(lwrctx
, hostname
,
589 LWRES_ADDRTYPE_V4
, &by
);
590 if (lwres
!= LWRES_R_SUCCESS
) {
591 if (lwres
== LWRES_R_NOTFOUND
)
596 addr
= LWRES_LIST_HEAD(by
->addrs
);
597 while (addr
!= NULL
) {
598 ai
= ai_clone(*aip
, AF_INET
);
600 lwres_freeaddrinfo(*aip
);
601 SETERROR(EAI_MEMORY
);
604 ai
->ai_socktype
= socktype
;
605 SIN(ai
->ai_addr
)->sin_port
= port
;
606 memcpy(&SIN(ai
->ai_addr
)->sin_addr
,
608 if (flags
& AI_CANONNAME
) {
609 ai
->ai_canonname
= strdup(by
->realname
);
610 if (ai
->ai_canonname
== NULL
)
611 SETERROR(EAI_MEMORY
);
613 addr
= LWRES_LIST_NEXT(addr
, link
);
618 lwres_gabnresponse_free(lwrctx
, &by
);
619 if (lwrctx
!= NULL
) {
620 lwres_conf_clear(lwrctx
);
621 lwres_context_destroy(&lwrctx
);
626 static char v6_loop
[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
629 add_ipv6(const char *hostname
, int flags
, struct addrinfo
**aip
,
630 int socktype
, int port
)
633 lwres_context_t
*lwrctx
= NULL
;
634 lwres_gabnresponse_t
*by
= NULL
;
636 lwres_result_t lwres
;
639 lwres
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
640 if (lwres
!= LWRES_R_SUCCESS
)
642 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
644 if (hostname
== NULL
&& (flags
& AI_PASSIVE
) == 0) {
645 ai
= ai_clone(*aip
, AF_INET6
);
647 lwres_freeaddrinfo(*aip
);
648 SETERROR(EAI_MEMORY
);
652 ai
->ai_socktype
= socktype
;
653 SIN6(ai
->ai_addr
)->sin6_port
= port
;
654 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
, v6_loop
, 16);
656 lwres
= lwres_getaddrsbyname(lwrctx
, hostname
,
657 LWRES_ADDRTYPE_V6
, &by
);
658 if (lwres
!= LWRES_R_SUCCESS
) {
659 if (lwres
== LWRES_R_NOTFOUND
)
664 addr
= LWRES_LIST_HEAD(by
->addrs
);
665 while (addr
!= NULL
) {
666 ai
= ai_clone(*aip
, AF_INET6
);
668 lwres_freeaddrinfo(*aip
);
669 SETERROR(EAI_MEMORY
);
672 ai
->ai_socktype
= socktype
;
673 SIN6(ai
->ai_addr
)->sin6_port
= port
;
674 memcpy(&SIN6(ai
->ai_addr
)->sin6_addr
,
676 if (flags
& AI_CANONNAME
) {
677 ai
->ai_canonname
= strdup(by
->realname
);
678 if (ai
->ai_canonname
== NULL
)
679 SETERROR(EAI_MEMORY
);
681 addr
= LWRES_LIST_NEXT(addr
, link
);
686 lwres_gabnresponse_free(lwrctx
, &by
);
687 if (lwrctx
!= NULL
) {
688 lwres_conf_clear(lwrctx
);
689 lwres_context_destroy(&lwrctx
);
694 /*% Free address info. */
696 lwres_freeaddrinfo(struct addrinfo
*ai
) {
697 struct addrinfo
*ai_next
;
700 ai_next
= ai
->ai_next
;
701 if (ai
->ai_addr
!= NULL
)
703 if (ai
->ai_canonname
)
704 free(ai
->ai_canonname
);
712 get_local(const char *name
, int socktype
, struct addrinfo
**res
) {
714 struct sockaddr_un
*slocal
;
717 return (EAI_SOCKTYPE
);
719 ai
= ai_alloc(AF_LOCAL
, sizeof(*slocal
));
723 slocal
= SLOCAL(ai
->ai_addr
);
724 strncpy(slocal
->sun_path
, name
, sizeof(slocal
->sun_path
));
726 ai
->ai_socktype
= socktype
;
728 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
729 * and ai->ai_next were initialized to zero.
738 * Allocate an addrinfo structure, and a sockaddr structure
739 * of the specificed length. We initialize:
744 * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
745 * and everything else is initialized to zero.
747 static struct addrinfo
*
748 ai_alloc(int family
, int addrlen
) {
751 ai
= (struct addrinfo
*)calloc(1, sizeof(*ai
));
755 ai
->ai_addr
= SA(calloc(1, addrlen
));
756 if (ai
->ai_addr
== NULL
) {
760 ai
->ai_addrlen
= addrlen
;
761 ai
->ai_family
= family
;
762 ai
->ai_addr
->sa_family
= family
;
763 #ifdef LWRES_PLATFORM_HAVESALEN
764 ai
->ai_addr
->sa_len
= addrlen
;
769 static struct addrinfo
*
770 ai_clone(struct addrinfo
*oai
, int family
) {
773 ai
= ai_alloc(family
, ((family
== AF_INET6
) ?
774 sizeof(struct sockaddr_in6
) : sizeof(struct sockaddr_in
)));
777 lwres_freeaddrinfo(oai
);
783 ai
->ai_flags
= oai
->ai_flags
;
784 ai
->ai_socktype
= oai
->ai_socktype
;
785 ai
->ai_protocol
= oai
->ai_protocol
;
786 ai
->ai_canonname
= NULL
;
791 static struct addrinfo
*
792 ai_reverse(struct addrinfo
*oai
) {
793 struct addrinfo
*nai
, *tai
;
797 while (oai
!= NULL
) {
799 * Grab one off the old list.
804 * Put it on the front of the new list.