2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
5 * This code is derived from software contributed to ISC by
6 * Berkeley Software Design, Inc.
8 * Permission to use, copy, modify, and 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.
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.
21 /* $Id: getaddrinfo.c,v 1.43.18.6 2006/11/14 01:07:28 marka Exp $ */
26 * lwres_getaddrinfo() is used to get a list of IP addresses and port
27 * numbers for host hostname and service servname. The function is the
28 * lightweight resolver's implementation of getaddrinfo() as defined in
29 * RFC2133. hostname and servname are pointers to null-terminated strings
30 * or NULL. hostname is either a host name or a numeric host address
31 * string: a dotted decimal IPv4 address or an IPv6 address. servname is
32 * either a decimal port number or a service name as listed in
35 * If the operating system does not provide a struct addrinfo, the
36 * following structure is used:
40 * int ai_flags; // AI_PASSIVE, AI_CANONNAME
41 * int ai_family; // PF_xxx
42 * int ai_socktype; // SOCK_xxx
43 * int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
44 * size_t ai_addrlen; // length of ai_addr
45 * char *ai_canonname; // canonical name for hostname
46 * struct sockaddr *ai_addr; // binary address
47 * struct addrinfo *ai_next; // next structure in linked list
52 * hints is an optional pointer to a struct addrinfo. This structure can
53 * be used to provide hints concerning the type of socket that the caller
54 * supports or wishes to use. The caller can supply the following
55 * structure elements in *hints:
59 * The protocol family that should be used. When ai_family is set
60 * to PF_UNSPEC, it means the caller will accept any protocol
61 * family supported by the operating system.</li>
64 * denotes the type of socket -- SOCK_STREAM, SOCK_DGRAM or
65 * SOCK_RAW -- that is wanted. When ai_socktype is zero the caller
66 * will accept any socket type.</li>
69 * indicates which transport protocol is wanted: IPPROTO_UDP or
70 * IPPROTO_TCP. If ai_protocol is zero the caller will accept any
74 * Flag bits. If the AI_CANONNAME bit is set, a successful call to
75 * lwres_getaddrinfo() will return a null-terminated string
76 * containing the canonical name of the specified hostname in
77 * ai_canonname of the first addrinfo structure returned. Setting
78 * the AI_PASSIVE bit indicates that the returned socket address
79 * structure is intended for used in a call to bind(2). In this
80 * case, if the hostname argument is a NULL pointer, then the IP
81 * address portion of the socket address structure will be set to
82 * INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6
83 * address.<br /><br />
85 * When ai_flags does not set the AI_PASSIVE bit, the returned
86 * socket address structure will be ready for use in a call to
87 * connect(2) for a connection-oriented protocol or connect(2),
88 * sendto(2), or sendmsg(2) if a connectionless protocol was
89 * chosen. The IP address portion of the socket address structure
90 * will be set to the loopback address if hostname is a NULL
91 * pointer and AI_PASSIVE is not set in ai_flags.<br /><br />
93 * If ai_flags is set to AI_NUMERICHOST it indicates that hostname
94 * should be treated as a numeric string defining an IPv4 or IPv6
95 * address and no name resolution should be attempted.
98 * All other elements of the struct addrinfo passed via hints must be
101 * A hints of NULL is treated as if the caller provided a struct addrinfo
102 * initialized to zero with ai_familyset to PF_UNSPEC.
104 * After a successful call to lwres_getaddrinfo(), *res is a pointer to a
105 * linked list of one or more addrinfo structures. Each struct addrinfo
106 * in this list cn be processed by following the ai_next pointer, until a
107 * NULL pointer is encountered. The three members ai_family, ai_socktype,
108 * and ai_protocol in each returned addrinfo structure contain the
109 * corresponding arguments for a call to socket(2). For each addrinfo
110 * structure in the list, the ai_addr member points to a filled-in socket
111 * address structure of length ai_addrlen.
113 * All of the information returned by lwres_getaddrinfo() is dynamically
114 * allocated: the addrinfo structures, and the socket address structures
115 * and canonical host name strings pointed to by the addrinfostructures.
116 * Memory allocated for the dynamically allocated structures created by a
117 * successful call to lwres_getaddrinfo() is released by
118 * lwres_freeaddrinfo(). ai is a pointer to a struct addrinfo created by
119 * a call to lwres_getaddrinfo().
121 * \section lwresreturn RETURN VALUES
123 * lwres_getaddrinfo() returns zero on success or one of the error codes
124 * listed in gai_strerror() if an error occurs. If both hostname and
125 * servname are NULL lwres_getaddrinfo() returns #EAI_NONAME.
127 * \section lwressee SEE ALSO
129 * lwres(3), lwres_getaddrinfo(), lwres_freeaddrinfo(),
130 * lwres_gai_strerror(), RFC2133, getservbyname(3), connect(2),
131 * sendto(2), sendmsg(2), socket(2).
139 #include <lwres/lwres.h>
140 #include <lwres/net.h>
141 #include <lwres/netdb.h>
142 #include <lwres/stdlib.h>
144 #define SA(addr) ((struct sockaddr *)(addr))
145 #define SIN(addr) ((struct sockaddr_in *)(addr))
146 #define SIN6(addr) ((struct sockaddr_in6 *)(addr))
147 #define SUN(addr) ((struct sockaddr_un *)(addr))
151 static struct addrinfo
152 *ai_reverse(struct addrinfo *oai),
153 *ai_clone(struct addrinfo *oai, int family),
154 *ai_alloc(int family, int addrlen);
156 static int get_local(const char *name, int socktype, struct addrinfo **res);
159 static int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
160 int socktype, int port);
161 static int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
162 int socktype, int port);
163 static void set_order(int, int (**)(const char *, int, struct addrinfo **,
166 #define FOUND_IPV4 0x1
167 #define FOUND_IPV6 0x2
170 #define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
171 /*% Get a list of IP addresses and port numbers for host hostname and service servname. */
173 lwres_getaddrinfo(const char *hostname, const char *servname,
174 const struct addrinfo *hints, struct addrinfo **res)
178 int family, socktype, flags, protocol;
179 struct addrinfo *ai, *ai_list;
181 int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
184 if (hostname == NULL && servname == NULL)
189 if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
190 return (EAI_BADFLAGS);
191 if (hints->ai_addrlen || hints->ai_canonname ||
192 hints->ai_addr || hints->ai_next) {
196 family = hints->ai_family;
197 socktype = hints->ai_socktype;
198 protocol = hints->ai_protocol;
199 flags = hints->ai_flags;
202 switch (hints->ai_socktype) {
213 switch (hints->ai_socktype) {
225 return (EAI_SOCKTYPE);
230 switch (hints->ai_socktype) {
238 return (EAI_SOCKTYPE);
254 * First, deal with AF_LOCAL. If the family was not set,
255 * then assume AF_LOCAL if the first character of the
256 * hostname/servname is '/'.
259 if (hostname != NULL &&
260 (family == AF_LOCAL || (family == 0 && *hostname == '/')))
261 return (get_local(hostname, socktype, res));
263 if (servname != NULL &&
264 (family == AF_LOCAL || (family == 0 && *servname == '/')))
265 return (get_local(servname, socktype, res));
269 * Ok, only AF_INET and AF_INET6 left.
274 * First, look up the service name (port) if it was
275 * requested. If the socket type wasn't specified, then
276 * try and figure it out.
278 if (servname != NULL) {
281 port = strtol(servname, &e, 10);
284 return (EAI_SOCKTYPE);
285 if (port < 0 || port > 65535)
286 return (EAI_SERVICE);
287 port = htons((unsigned short) port);
289 sp = getservbyname(servname, proto);
291 return (EAI_SERVICE);
294 if (strcmp(sp->s_proto, "tcp") == 0)
295 socktype = SOCK_STREAM;
296 else if (strcmp(sp->s_proto, "udp") == 0)
297 socktype = SOCK_DGRAM;
304 * Next, deal with just a service name, and no hostname.
305 * (we verified that one of them was non-null up above).
307 if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
308 if (family == AF_INET || family == 0) {
309 ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
312 ai->ai_socktype = socktype;
313 ai->ai_protocol = protocol;
314 SIN(ai->ai_addr)->sin_port = port;
315 ai->ai_next = ai_list;
319 if (family == AF_INET6 || family == 0) {
320 ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
322 lwres_freeaddrinfo(ai_list);
325 ai->ai_socktype = socktype;
326 ai->ai_protocol = protocol;
327 SIN6(ai->ai_addr)->sin6_port = port;
328 ai->ai_next = ai_list;
337 * If the family isn't specified or AI_NUMERICHOST specified,
338 * check first to see if it is a numeric address.
339 * Though the gethostbyname2() routine
340 * will recognize numeric addresses, it will only recognize
341 * the format that it is being called for. Thus, a numeric
342 * AF_INET address will be treated by the AF_INET6 call as
343 * a domain name, and vice versa. Checking for both numerics
346 if (hostname != NULL &&
347 (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
348 char abuf[sizeof(struct in6_addr)];
349 char nbuf[NI_MAXHOST];
350 int addrsize, addroff;
351 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
353 char ntmp[NI_MAXHOST];
354 lwres_uint32_t scopeid;
357 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
359 * Scope identifier portion.
362 if (strchr(hostname, '%') != NULL) {
363 strncpy(ntmp, hostname, sizeof(ntmp) - 1);
364 ntmp[sizeof(ntmp) - 1] = '\0';
365 p = strchr(ntmp, '%');
369 * Vendors may want to support non-numeric
370 * scopeid around here.
374 scopeid = (lwres_uint32_t)strtoul(p + 1,
376 if (p != NULL && ep != NULL && ep[0] == '\0')
386 if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
389 if (family == AF_INET6) {
391 * Convert to a V4 mapped address.
393 struct in6_addr *a6 = (struct in6_addr *)abuf;
394 memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
395 memset(&a6->s6_addr[10], 0xff, 2);
396 memset(&a6->s6_addr[0], 0, 10);
399 addrsize = sizeof(struct in_addr);
400 addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
403 #ifdef LWRES_HAVE_SIN6_SCOPE_ID
404 } else if (ntmp[0] != '\0' &&
405 lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
407 if (family && family != AF_INET6)
409 addrsize = sizeof(struct in6_addr);
410 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
414 } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
415 if (family != 0 && family != AF_INET6)
418 addrsize = sizeof(struct in6_addr);
419 addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
423 ai = ai_clone(ai_list, family);
427 ai->ai_socktype = socktype;
428 SIN(ai->ai_addr)->sin_port = port;
429 memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
430 if (flags & AI_CANONNAME) {
431 #if defined(LWRES_HAVE_SIN6_SCOPE_ID)
432 if (ai->ai_family == AF_INET6)
433 SIN6(ai->ai_addr)->sin6_scope_id =
436 if (lwres_getnameinfo(ai->ai_addr,
437 ai->ai_addrlen, nbuf, sizeof(nbuf),
439 NI_NUMERICHOST) == 0) {
440 ai->ai_canonname = strdup(nbuf);
441 if (ai->ai_canonname == NULL) {
442 lwres_freeaddrinfo(ai_list);
446 /* XXX raise error? */
447 ai->ai_canonname = NULL;
451 } else if ((flags & AI_NUMERICHOST) != 0) {
456 set_order(family, net_order);
457 for (i = 0; i < FOUND_MAX; i++) {
458 if (net_order[i] == NULL)
460 err = (net_order[i])(hostname, flags, &ai_list,
470 ai_list = ai_reverse(ai_list);
477 lwres_strsep(char **stringp, const char *delim) {
478 char *string = *stringp;
486 for (s = string; *s != '\0'; s++) {
488 for (d = delim; (dc = *d) != '\0'; d++)
500 set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
509 *net_order++ = add_ipv4;
512 *net_order++ = add_ipv6;
516 order = getenv("NET_ORDER");
518 while (order != NULL) {
520 * We ignore any unknown names.
522 tok = lwres_strsep(&order, ":");
523 if (strcasecmp(tok, "inet6") == 0) {
524 if ((found & FOUND_IPV6) == 0)
525 *net_order++ = add_ipv6;
527 } else if (strcasecmp(tok, "inet") == 0 ||
528 strcasecmp(tok, "inet4") == 0) {
529 if ((found & FOUND_IPV4) == 0)
530 *net_order++ = add_ipv4;
536 * Add in anything that we didn't find.
538 if ((found & FOUND_IPV4) == 0)
539 *net_order++ = add_ipv4;
540 if ((found & FOUND_IPV6) == 0)
541 *net_order++ = add_ipv6;
547 static char v4_loop[4] = { 127, 0, 0, 1 };
550 * The test against 0 is there to keep the Solaris compiler
551 * from complaining about "end-of-loop code not reached".
553 #define SETERROR(code) \
554 do { result = (code); \
555 if (result != 0) goto cleanup; \
559 add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
560 int socktype, int port)
563 lwres_context_t *lwrctx = NULL;
564 lwres_gabnresponse_t *by = NULL;
566 lwres_result_t lwres;
569 lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
570 if (lwres != LWRES_R_SUCCESS)
572 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
573 if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
574 ai = ai_clone(*aip, AF_INET);
576 lwres_freeaddrinfo(*aip);
577 SETERROR(EAI_MEMORY);
581 ai->ai_socktype = socktype;
582 SIN(ai->ai_addr)->sin_port = port;
583 memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
585 lwres = lwres_getaddrsbyname(lwrctx, hostname,
586 LWRES_ADDRTYPE_V4, &by);
587 if (lwres != LWRES_R_SUCCESS) {
588 if (lwres == LWRES_R_NOTFOUND)
593 addr = LWRES_LIST_HEAD(by->addrs);
594 while (addr != NULL) {
595 ai = ai_clone(*aip, AF_INET);
597 lwres_freeaddrinfo(*aip);
598 SETERROR(EAI_MEMORY);
601 ai->ai_socktype = socktype;
602 SIN(ai->ai_addr)->sin_port = port;
603 memcpy(&SIN(ai->ai_addr)->sin_addr,
605 if (flags & AI_CANONNAME) {
606 ai->ai_canonname = strdup(by->realname);
607 if (ai->ai_canonname == NULL)
608 SETERROR(EAI_MEMORY);
610 addr = LWRES_LIST_NEXT(addr, link);
615 lwres_gabnresponse_free(lwrctx, &by);
616 if (lwrctx != NULL) {
617 lwres_conf_clear(lwrctx);
618 lwres_context_destroy(&lwrctx);
623 static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
626 add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
627 int socktype, int port)
630 lwres_context_t *lwrctx = NULL;
631 lwres_gabnresponse_t *by = NULL;
633 lwres_result_t lwres;
636 lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
637 if (lwres != LWRES_R_SUCCESS)
639 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
641 if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
642 ai = ai_clone(*aip, AF_INET6);
644 lwres_freeaddrinfo(*aip);
645 SETERROR(EAI_MEMORY);
649 ai->ai_socktype = socktype;
650 SIN6(ai->ai_addr)->sin6_port = port;
651 memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
653 lwres = lwres_getaddrsbyname(lwrctx, hostname,
654 LWRES_ADDRTYPE_V6, &by);
655 if (lwres != LWRES_R_SUCCESS) {
656 if (lwres == LWRES_R_NOTFOUND)
661 addr = LWRES_LIST_HEAD(by->addrs);
662 while (addr != NULL) {
663 ai = ai_clone(*aip, AF_INET6);
665 lwres_freeaddrinfo(*aip);
666 SETERROR(EAI_MEMORY);
669 ai->ai_socktype = socktype;
670 SIN6(ai->ai_addr)->sin6_port = port;
671 memcpy(&SIN6(ai->ai_addr)->sin6_addr,
673 if (flags & AI_CANONNAME) {
674 ai->ai_canonname = strdup(by->realname);
675 if (ai->ai_canonname == NULL)
676 SETERROR(EAI_MEMORY);
678 addr = LWRES_LIST_NEXT(addr, link);
683 lwres_gabnresponse_free(lwrctx, &by);
684 if (lwrctx != NULL) {
685 lwres_conf_clear(lwrctx);
686 lwres_context_destroy(&lwrctx);
691 /*% Free address info. */
693 lwres_freeaddrinfo(struct addrinfo *ai) {
694 struct addrinfo *ai_next;
697 ai_next = ai->ai_next;
698 if (ai->ai_addr != NULL)
700 if (ai->ai_canonname)
701 free(ai->ai_canonname);
709 get_local(const char *name, int socktype, struct addrinfo **res) {
711 struct sockaddr_un *sun;
714 return (EAI_SOCKTYPE);
716 ai = ai_alloc(AF_LOCAL, sizeof(*sun));
720 sun = SUN(ai->ai_addr);
721 strncpy(sun->sun_path, name, sizeof(sun->sun_path));
723 ai->ai_socktype = socktype;
725 * ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
726 * and ai->ai_next were initialized to zero.
735 * Allocate an addrinfo structure, and a sockaddr structure
736 * of the specificed length. We initialize:
741 * ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
742 * and everything else is initialized to zero.
744 static struct addrinfo *
745 ai_alloc(int family, int addrlen) {
748 ai = (struct addrinfo *)calloc(1, sizeof(*ai));
752 ai->ai_addr = SA(calloc(1, addrlen));
753 if (ai->ai_addr == NULL) {
757 ai->ai_addrlen = addrlen;
758 ai->ai_family = family;
759 ai->ai_addr->sa_family = family;
760 #ifdef LWRES_PLATFORM_HAVESALEN
761 ai->ai_addr->sa_len = addrlen;
766 static struct addrinfo *
767 ai_clone(struct addrinfo *oai, int family) {
770 ai = ai_alloc(family, ((family == AF_INET6) ?
771 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
774 lwres_freeaddrinfo(oai);
780 ai->ai_flags = oai->ai_flags;
781 ai->ai_socktype = oai->ai_socktype;
782 ai->ai_protocol = oai->ai_protocol;
783 ai->ai_canonname = NULL;
788 static struct addrinfo *
789 ai_reverse(struct addrinfo *oai) {
790 struct addrinfo *nai, *tai;
794 while (oai != NULL) {
796 * Grab one off the old list.
801 * Put it on the front of the new list.