getaddrinfo.c revision af5073d03288a53b646ec3b807ac25ced64d7879
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews/*
11e9368a226272085c337e9e74b79808c16fbdbaTinderbox User * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Copyright (C) 1999-2001 Internet Software Consortium.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *
4a14ce5ba00ab7bc55c99ffdcf59c7a4ab902721Automatic Updater * This code is derived from software contributed to ISC by
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Berkeley Software Design, Inc.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Permission to use, copy, modify, and distribute this software for any
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * purpose with or without fee is hereby granted, provided that the above
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * copyright notice and this permission notice appear in all copies.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND BERKELEY SOFTWARE DESIGN, INC.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews */
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User/* $Id: getaddrinfo.c,v 1.43 2004/03/05 05:48:26 marka Exp $ */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox User#include <config.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#include <string.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#include <errno.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#include <stdlib.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#include <lwres/lwres.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#include <lwres/net.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#include <lwres/netdb.h>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#define SA(addr) ((struct sockaddr *)(addr))
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#define SIN(addr) ((struct sockaddr_in *)(addr))
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define SIN6(addr) ((struct sockaddr_in6 *)(addr))
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#define SUN(addr) ((struct sockaddr_un *)(addr))
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrewsstatic struct addrinfo
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *ai_reverse(struct addrinfo *oai),
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *ai_clone(struct addrinfo *oai, int family),
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User *ai_alloc(int family, int addrlen);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#ifdef AF_LOCAL
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox Userstatic int get_local(const char *name, int socktype, struct addrinfo **res);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#endif
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrewsstatic int add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User int socktype, int port);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrewsstatic int add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User int socktype, int port);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox Userstatic void set_order(int, int (**)(const char *, int, struct addrinfo **,
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User int, int));
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User#define FOUND_IPV4 0x1
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User#define FOUND_IPV6 0x2
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#define FOUND_MAX 2
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#define ISC_AI_MASK (AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrewsint
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox Userlwres_getaddrinfo(const char *hostname, const char *servname,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt const struct addrinfo *hints, struct addrinfo **res)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt{
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews struct servent *sp;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews const char *proto;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews int family, socktype, flags, protocol;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt struct addrinfo *ai, *ai_list;
f6da30bb5447c23d880b09f601441e70c5313557Mark Andrews int port, err, i;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt int, int);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if (hostname == NULL && servname == NULL)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_NONAME);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User proto = NULL;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (hints != NULL) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews return (EAI_BADFLAGS);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if (hints->ai_addrlen || hints->ai_canonname ||
f7b41fd9291b8f4dba27e2b57e1d93f0913a4f1dMark Andrews hints->ai_addr || hints->ai_next) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User errno = EINVAL;
f7b41fd9291b8f4dba27e2b57e1d93f0913a4f1dMark Andrews return (EAI_SYSTEM);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews family = hints->ai_family;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User socktype = hints->ai_socktype;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews protocol = hints->ai_protocol;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User flags = hints->ai_flags;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews switch (family) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User case AF_UNSPEC:
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt switch (hints->ai_socktype) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews case SOCK_STREAM:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User proto = "tcp";
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews break;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User case SOCK_DGRAM:
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User proto = "udp";
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User break;
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User break;
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User case AF_INET:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User case AF_INET6:
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User switch (hints->ai_socktype) {
d8620c7234281056fdfd2ee40cf16636b8281092Tinderbox User case 0:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User break;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews case SOCK_STREAM:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User proto = "tcp";
9fbbfb5757a1e3e86d7dea62c4e63ffc2303ca2bAutomatic Updater break;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User case SOCK_DGRAM:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews proto = "udp";
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews break;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User case SOCK_RAW:
d71e2e0c61df16ff37c9934c371a4a60c08974f7Mark Andrews break;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt default:
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (EAI_SOCKTYPE);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt break;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#ifdef AF_LOCAL
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews case AF_LOCAL:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User switch (hints->ai_socktype) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt case 0:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews break;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt case SOCK_STREAM:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews break;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews case SOCK_DGRAM:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User break;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt default:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews return (EAI_SOCKTYPE);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews break;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#endif
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User default:
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (EAI_FAMILY);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews }
d71e2e0c61df16ff37c9934c371a4a60c08974f7Mark Andrews } else {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews protocol = 0;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt family = 0;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews socktype = 0;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews flags = 0;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#ifdef AF_LOCAL
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt /*
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * First, deal with AF_LOCAL. If the family was not set,
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * then assume AF_LOCAL if the first character of the
a057e8e33baa5fa369be28a9680585200ce3ff73Mark Andrews * hostname/servname is '/'.
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (hostname != NULL &&
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User (family == AF_LOCAL || (family == 0 && *hostname == '/')))
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews return (get_local(hostname, socktype, res));
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (servname != NULL &&
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt (family == AF_LOCAL || (family == 0 && *servname == '/')))
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (get_local(servname, socktype, res));
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User#endif
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
72938578c985138165e7a4b0a38f16daacbad95eAutomatic Updater /*
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * Ok, only AF_INET and AF_INET6 left.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt ai_list = NULL;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews /*
72938578c985138165e7a4b0a38f16daacbad95eAutomatic Updater * First, look up the service name (port) if it was
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * requested. If the socket type wasn't specified, then
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * try and figure it out.
dba3c818ae00b10388d31703e86a28415db398acTinderbox User */
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt if (servname != NULL) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt char *e;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt port = strtol(servname, &e, 10);
dba3c818ae00b10388d31703e86a28415db398acTinderbox User if (*e == '\0') {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt if (socktype == 0)
dba3c818ae00b10388d31703e86a28415db398acTinderbox User return (EAI_SOCKTYPE);
72938578c985138165e7a4b0a38f16daacbad95eAutomatic Updater if (port < 0 || port > 65535)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_SERVICE);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews port = htons((unsigned short) port);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User } else {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt sp = getservbyname(servname, proto);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (sp == NULL)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (EAI_SERVICE);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt port = sp->s_port;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt if (socktype == 0) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt if (strcmp(sp->s_proto, "tcp") == 0)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt socktype = SOCK_STREAM;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User else if (strcmp(sp->s_proto, "udp") == 0)
0e1dece22e128f9dfa723316a35c4b3f06912381Tinderbox User socktype = SOCK_DGRAM;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User }
0e1dece22e128f9dfa723316a35c4b3f06912381Tinderbox User }
0e1dece22e128f9dfa723316a35c4b3f06912381Tinderbox User } else
0e1dece22e128f9dfa723316a35c4b3f06912381Tinderbox User port = 0;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
0e1dece22e128f9dfa723316a35c4b3f06912381Tinderbox User /*
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * Next, deal with just a service name, and no hostname.
97e74139b19368e385a3564746d42db70879195eAutomatic Updater * (we verified that one of them was non-null up above).
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User */
43b94483957d3168796a816ed86cf097518817dcTinderbox User if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
dba3c818ae00b10388d31703e86a28415db398acTinderbox User if (family == AF_INET || family == 0) {
dba3c818ae00b10388d31703e86a28415db398acTinderbox User ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
dba3c818ae00b10388d31703e86a28415db398acTinderbox User if (ai == NULL)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_MEMORY);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_socktype = socktype;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ai->ai_protocol = protocol;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews SIN(ai->ai_addr)->sin_port = port;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt ai->ai_next = ai_list;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt ai_list = ai;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
3b4098640dd85040270f39b9a5ee5e22de99d3d6Mark Andrews if (family == AF_INET6 || family == 0) {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
3b4098640dd85040270f39b9a5ee5e22de99d3d6Mark Andrews if (ai == NULL) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt lwres_freeaddrinfo(ai_list);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (EAI_MEMORY);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ai->ai_socktype = socktype;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_protocol = protocol;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User SIN6(ai->ai_addr)->sin6_port = port;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_next = ai_list;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai_list = ai;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt *res = ai_list;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (0);
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews /*
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * If the family isn't specified or AI_NUMERICHOST specified,
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * check first to see if it is a numeric address.
f7b41fd9291b8f4dba27e2b57e1d93f0913a4f1dMark Andrews * Though the gethostbyname2() routine
f7b41fd9291b8f4dba27e2b57e1d93f0913a4f1dMark Andrews * will recognize numeric addresses, it will only recognize
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * the format that it is being called for. Thus, a numeric
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * AF_INET address will be treated by the AF_INET6 call as
e2e4d321999340802f77adaacd19c797d04b4b95Automatic Updater * a domain name, and vice versa. Checking for both numerics
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User * here avoids that.
e2e4d321999340802f77adaacd19c797d04b4b95Automatic Updater */
e2e4d321999340802f77adaacd19c797d04b4b95Automatic Updater if (hostname != NULL &&
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt char abuf[sizeof(struct in6_addr)];
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt char nbuf[NI_MAXHOST];
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User int addrsize, addroff;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#ifdef LWRES_HAVE_SIN6_SCOPE_ID
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User char *p, *ep;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews char ntmp[NI_MAXHOST];
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt lwres_uint32_t scopeid;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#endif
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#ifdef LWRES_HAVE_SIN6_SCOPE_ID
285254345ce5ab270848f8c11f7be146793f1e00Mark Andrews /*
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Scope identifier portion.
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt */
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ntmp[0] = '\0';
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (strchr(hostname, '%') != NULL) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews strncpy(ntmp, hostname, sizeof(ntmp) - 1);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ntmp[sizeof(ntmp) - 1] = '\0';
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User p = strchr(ntmp, '%');
3b4098640dd85040270f39b9a5ee5e22de99d3d6Mark Andrews ep = NULL;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
3b4098640dd85040270f39b9a5ee5e22de99d3d6Mark Andrews /*
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * Vendors may want to support non-numeric
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt * scopeid around here.
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt */
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (p != NULL)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User scopeid = (lwres_uint32_t)strtoul(p + 1,
d71e2e0c61df16ff37c9934c371a4a60c08974f7Mark Andrews &ep, 10);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (p != NULL && ep != NULL && ep[0] == '\0')
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews *p = '\0';
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt else {
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ntmp[0] = '\0';
7be2f6d5df28b207e3e385c555eb4f740150528dTinderbox User scopeid = 0;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User }
c25602ed66bb0b53e72963dc38bd0d5f49b14496Tinderbox User } else
c25602ed66bb0b53e72963dc38bd0d5f49b14496Tinderbox User scopeid = 0;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt#endif
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User if (lwres_net_pton(AF_INET, hostname, (struct in_addr *)abuf)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews == 1)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (family == AF_INET6) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews /*
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Convert to a V4 mapped address.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews */
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews struct in6_addr *a6 = (struct in6_addr *)abuf;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews memset(&a6->s6_addr[10], 0xff, 2);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User memset(&a6->s6_addr[0], 0, 10);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews goto inet6_addr;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt }
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User addrsize = sizeof(struct in_addr);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User family = AF_INET;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews goto common;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#ifdef LWRES_HAVE_SIN6_SCOPE_ID
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews } else if (ntmp[0] != '\0' &&
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt lwres_net_pton(AF_INET6, ntmp, abuf) == 1)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews {
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt if (family && family != AF_INET6)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_NONAME);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews addrsize = sizeof(struct in6_addr);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews family = AF_INET6;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User goto common;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#endif
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User } else if (lwres_net_pton(AF_INET6, hostname, abuf) == 1) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (family != 0 && family != AF_INET6)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_NONAME);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews inet6_addr:
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User addrsize = sizeof(struct in6_addr);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User family = AF_INET6;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews common:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai = ai_clone(ai_list, family);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (ai == NULL)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User return (EAI_MEMORY);
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ai_list = ai;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User ai->ai_socktype = socktype;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User SIN(ai->ai_addr)->sin_port = port;
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (flags & AI_CANONNAME) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#if defined(LWRES_HAVE_SIN6_SCOPE_ID)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (ai->ai_family == AF_INET6)
fd2597f75693a2279fdf588bd40dfe2407c42028Tinderbox User SIN6(ai->ai_addr)->sin6_scope_id =
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews scopeid;
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews#endif
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (lwres_getnameinfo(ai->ai_addr,
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_addrlen, nbuf, sizeof(nbuf),
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews NULL, 0,
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews NI_NUMERICHOST) == 0) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_canonname = strdup(nbuf);
cd32f419a8a5432fbb139f56ee73cbf68b9350ccTinderbox User if (ai->ai_canonname == NULL)
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt return (EAI_MEMORY);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews } else {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews /* XXX raise error? */
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews ai->ai_canonname = NULL;
4abdfc917e6635a7c81d1f931a0c79227e72d025Mark Andrews }
4abdfc917e6635a7c81d1f931a0c79227e72d025Mark Andrews }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews goto done;
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt } else if ((flags & AI_NUMERICHOST) != 0) {
4abdfc917e6635a7c81d1f931a0c79227e72d025Mark Andrews return (EAI_NONAME);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews }
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews
14a656f94b1fd0ababd84a772228dfa52276ba15Evan Hunt set_order(family, net_order);
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews for (i = 0; i < FOUND_MAX; i++) {
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews if (net_order[i] == NULL)
break;
err = (net_order[i])(hostname, flags, &ai_list,
socktype, port);
if (err != 0)
return (err);
}
if (ai_list == NULL)
return (EAI_NODATA);
done:
ai_list = ai_reverse(ai_list);
*res = ai_list;
return (0);
}
static char *
lwres_strsep(char **stringp, const char *delim) {
char *string = *stringp;
char *s;
const char *d;
char sc, dc;
if (string == NULL)
return (NULL);
for (s = string; *s != '\0'; s++) {
sc = *s;
for (d = delim; (dc = *d) != '\0'; d++)
if (sc == dc) {
*s++ = '\0';
*stringp = s;
return (string);
}
}
*stringp = NULL;
return (string);
}
static void
set_order(int family, int (**net_order)(const char *, int, struct addrinfo **,
int, int))
{
char *order, *tok;
int found;
if (family) {
switch (family) {
case AF_INET:
*net_order++ = add_ipv4;
break;
case AF_INET6:
*net_order++ = add_ipv6;
break;
}
} else {
order = getenv("NET_ORDER");
found = 0;
while (order != NULL) {
/*
* We ignore any unknown names.
*/
tok = lwres_strsep(&order, ":");
if (strcasecmp(tok, "inet6") == 0) {
if ((found & FOUND_IPV6) == 0)
*net_order++ = add_ipv6;
found |= FOUND_IPV6;
} else if (strcasecmp(tok, "inet") == 0 ||
strcasecmp(tok, "inet4") == 0) {
if ((found & FOUND_IPV4) == 0)
*net_order++ = add_ipv4;
found |= FOUND_IPV4;
}
}
/*
* Add in anything that we didn't find.
*/
if ((found & FOUND_IPV4) == 0)
*net_order++ = add_ipv4;
if ((found & FOUND_IPV6) == 0)
*net_order++ = add_ipv6;
}
*net_order = NULL;
return;
}
static char v4_loop[4] = { 127, 0, 0, 1 };
/*
* The test against 0 is there to keep the Solaris compiler
* from complaining about "end-of-loop code not reached".
*/
#define ERR(code) \
do { result = (code); \
if (result != 0) goto cleanup; \
} while (0)
static int
add_ipv4(const char *hostname, int flags, struct addrinfo **aip,
int socktype, int port)
{
struct addrinfo *ai;
lwres_context_t *lwrctx = NULL;
lwres_gabnresponse_t *by = NULL;
lwres_addr_t *addr;
lwres_result_t lwres;
int result = 0;
lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
if (lwres != LWRES_R_SUCCESS)
ERR(EAI_FAIL);
(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
ai = ai_clone(*aip, AF_INET);
if (ai == NULL) {
lwres_freeaddrinfo(*aip);
ERR(EAI_MEMORY);
}
*aip = ai;
ai->ai_socktype = socktype;
SIN(ai->ai_addr)->sin_port = port;
memcpy(&SIN(ai->ai_addr)->sin_addr, v4_loop, 4);
} else {
lwres = lwres_getaddrsbyname(lwrctx, hostname,
LWRES_ADDRTYPE_V4, &by);
if (lwres != LWRES_R_SUCCESS) {
if (lwres == LWRES_R_NOTFOUND)
goto cleanup;
else
ERR(EAI_FAIL);
}
addr = LWRES_LIST_HEAD(by->addrs);
while (addr != NULL) {
ai = ai_clone(*aip, AF_INET);
if (ai == NULL) {
lwres_freeaddrinfo(*aip);
ERR(EAI_MEMORY);
}
*aip = ai;
ai->ai_socktype = socktype;
SIN(ai->ai_addr)->sin_port = port;
memcpy(&SIN(ai->ai_addr)->sin_addr,
addr->address, 4);
if (flags & AI_CANONNAME) {
ai->ai_canonname = strdup(by->realname);
if (ai->ai_canonname == NULL)
ERR(EAI_MEMORY);
}
addr = LWRES_LIST_NEXT(addr, link);
}
}
cleanup:
if (by != NULL)
lwres_gabnresponse_free(lwrctx, &by);
if (lwrctx != NULL) {
lwres_conf_clear(lwrctx);
lwres_context_destroy(&lwrctx);
}
return (result);
}
static char v6_loop[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
static int
add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
int socktype, int port)
{
struct addrinfo *ai;
lwres_context_t *lwrctx = NULL;
lwres_gabnresponse_t *by = NULL;
lwres_addr_t *addr;
lwres_result_t lwres;
int result = 0;
lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
if (lwres != LWRES_R_SUCCESS)
ERR(EAI_FAIL);
(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
ai = ai_clone(*aip, AF_INET6);
if (ai == NULL) {
lwres_freeaddrinfo(*aip);
ERR(EAI_MEMORY);
}
*aip = ai;
ai->ai_socktype = socktype;
SIN6(ai->ai_addr)->sin6_port = port;
memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
} else {
lwres = lwres_getaddrsbyname(lwrctx, hostname,
LWRES_ADDRTYPE_V6, &by);
if (lwres != LWRES_R_SUCCESS) {
if (lwres == LWRES_R_NOTFOUND)
goto cleanup;
else
ERR(EAI_FAIL);
}
addr = LWRES_LIST_HEAD(by->addrs);
while (addr != NULL) {
ai = ai_clone(*aip, AF_INET6);
if (ai == NULL) {
lwres_freeaddrinfo(*aip);
ERR(EAI_MEMORY);
}
*aip = ai;
ai->ai_socktype = socktype;
SIN6(ai->ai_addr)->sin6_port = port;
memcpy(&SIN6(ai->ai_addr)->sin6_addr,
addr->address, 16);
if (flags & AI_CANONNAME) {
ai->ai_canonname = strdup(by->realname);
if (ai->ai_canonname == NULL)
ERR(EAI_MEMORY);
}
addr = LWRES_LIST_NEXT(addr, link);
}
}
cleanup:
if (by != NULL)
lwres_gabnresponse_free(lwrctx, &by);
if (lwrctx != NULL) {
lwres_conf_clear(lwrctx);
lwres_context_destroy(&lwrctx);
}
return (result);
}
void
lwres_freeaddrinfo(struct addrinfo *ai) {
struct addrinfo *ai_next;
while (ai != NULL) {
ai_next = ai->ai_next;
if (ai->ai_addr != NULL)
free(ai->ai_addr);
if (ai->ai_canonname)
free(ai->ai_canonname);
free(ai);
ai = ai_next;
}
}
#ifdef AF_LOCAL
static int
get_local(const char *name, int socktype, struct addrinfo **res) {
struct addrinfo *ai;
struct sockaddr_un *sun;
if (socktype == 0)
return (EAI_SOCKTYPE);
ai = ai_alloc(AF_LOCAL, sizeof(*sun));
if (ai == NULL)
return (EAI_MEMORY);
sun = SUN(ai->ai_addr);
strncpy(sun->sun_path, name, sizeof(sun->sun_path));
ai->ai_socktype = socktype;
/*
* ai->ai_flags, ai->ai_protocol, ai->ai_canonname,
* and ai->ai_next were initialized to zero.
*/
*res = ai;
return (0);
}
#endif
/*
* Allocate an addrinfo structure, and a sockaddr structure
* of the specificed length. We initialize:
* ai_addrlen
* ai_family
* ai_addr
* ai_addr->sa_family
* ai_addr->sa_len (LWRES_PLATFORM_HAVESALEN)
* and everything else is initialized to zero.
*/
static struct addrinfo *
ai_alloc(int family, int addrlen) {
struct addrinfo *ai;
ai = (struct addrinfo *)calloc(1, sizeof(*ai));
if (ai == NULL)
return (NULL);
ai->ai_addr = SA(calloc(1, addrlen));
if (ai->ai_addr == NULL) {
free(ai);
return (NULL);
}
ai->ai_addrlen = addrlen;
ai->ai_family = family;
ai->ai_addr->sa_family = family;
#ifdef LWRES_PLATFORM_HAVESALEN
ai->ai_addr->sa_len = addrlen;
#endif
return (ai);
}
static struct addrinfo *
ai_clone(struct addrinfo *oai, int family) {
struct addrinfo *ai;
ai = ai_alloc(family, ((family == AF_INET6) ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)));
if (ai == NULL) {
lwres_freeaddrinfo(oai);
return (NULL);
}
if (oai == NULL)
return (ai);
ai->ai_flags = oai->ai_flags;
ai->ai_socktype = oai->ai_socktype;
ai->ai_protocol = oai->ai_protocol;
ai->ai_canonname = NULL;
ai->ai_next = oai;
return (ai);
}
static struct addrinfo *
ai_reverse(struct addrinfo *oai) {
struct addrinfo *nai, *tai;
nai = NULL;
while (oai != NULL) {
/*
* Grab one off the old list.
*/
tai = oai;
oai = oai->ai_next;
/*
* Put it on the front of the new list.
*/
tai->ai_next = nai;
nai = tai;
}
return (nai);
}