getaddrinfo.c revision 140906
1121474Sume/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */ 262614Sitojun 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 655163Sshin * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1855163Sshin * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin */ 3155163Sshin 3255163Sshin/* 3355163Sshin * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 3455163Sshin * 3555163Sshin * Issues to be discussed: 3655163Sshin * - Thread safe-ness must be checked. 3755163Sshin * - Return values. There are nonstandard return values defined and used 3855163Sshin * in the source code. This is because RFC2553 is silent about which error 3955163Sshin * code must be returned for which situation. 4061877Sume * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 41105940Sume * invalid. current code - SEGV on freeaddrinfo(NULL) 42105940Sume * 4356627Sshin * Note: 4456627Sshin * - The code filters out AFs that are not supported by the kernel, 4556627Sshin * when globbing NULL hostname (to loopback, or wildcard). Is it the right 4656627Sshin * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 4756627Sshin * in ai_flags? 4861877Sume * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 4961877Sume * (1) what should we do against numeric hostname (2) what should we do 5061877Sume * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 5161877Sume * non-loopback address configured? global address configured? 52105940Sume * 53105940Sume * OS specific notes for netbsd/openbsd/freebsd4/bsdi4: 5461877Sume * - To avoid search order issue, we have a big amount of code duplicate 5561877Sume * from gethnamaddr.c and some other places. The issues that there's no 5661877Sume * lower layer function to lookup "IPv4 or IPv6" record. Calling 5761877Sume * gethostbyname2 from getaddrinfo will end up in wrong search order, as 58105940Sume * presented above. 59105940Sume * 60105940Sume * OS specific notes for freebsd4: 61105940Sume * - FreeBSD supported $GAI. The code does not. 62105940Sume * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not. 6355163Sshin */ 6455163Sshin 6592986Sobrien#include <sys/cdefs.h> 6692986Sobrien__FBSDID("$FreeBSD: head/lib/libc/net/getaddrinfo.c 140906 2005-01-27 14:41:56Z ume $"); 6792986Sobrien 6871579Sdeischen#include "namespace.h" 6955163Sshin#include <sys/types.h> 7055163Sshin#include <sys/param.h> 7155163Sshin#include <sys/socket.h> 7255163Sshin#include <net/if.h> 7355163Sshin#include <netinet/in.h> 74121747Sume#include <sys/queue.h> 75121747Sume#ifdef INET6 76121747Sume#include <net/if_var.h> 77121747Sume#include <sys/sysctl.h> 78129901Sume#include <sys/ioctl.h> 79121747Sume#include <netinet6/in6_var.h> /* XXX */ 80121747Sume#endif 8155163Sshin#include <arpa/inet.h> 8255163Sshin#include <arpa/nameser.h> 83121474Sume#include <rpc/rpc.h> 84121474Sume#include <rpcsvc/yp_prot.h> 85121474Sume#include <rpcsvc/ypclnt.h> 8655163Sshin#include <netdb.h> 87114681Sdeischen#include <pthread.h> 8855163Sshin#include <resolv.h> 8955163Sshin#include <string.h> 9055163Sshin#include <stdlib.h> 9155163Sshin#include <stddef.h> 9255163Sshin#include <ctype.h> 9355163Sshin#include <unistd.h> 9455163Sshin#include <stdio.h> 9561877Sume#include <errno.h> 96102237Spirzyk 97102237Spirzyk#include "res_config.h" 98102237Spirzyk 9978012Sume#ifdef DEBUG 10078012Sume#include <syslog.h> 10178012Sume#endif 10255163Sshin 10365532Snectar#include <stdarg.h> 10465532Snectar#include <nsswitch.h> 10571579Sdeischen#include "un-namespace.h" 106111618Snectar#include "libc_private.h" 10765532Snectar 10855163Sshin#if defined(__KAME__) && defined(INET6) 10955163Sshin# define FAITH 11055163Sshin#endif 11155163Sshin 112105940Sume#define SUCCESS 0 113105940Sume#define ANY 0 114105940Sume#define YES 1 115105940Sume#define NO 0 11655163Sshin 11755163Sshinstatic const char in_addrany[] = { 0, 0, 0, 0 }; 118105940Sumestatic const char in_loopback[] = { 127, 0, 0, 1 }; 119105940Sume#ifdef INET6 12055163Sshinstatic const char in6_addrany[] = { 12155163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 12255163Sshin}; 12355163Sshinstatic const char in6_loopback[] = { 12455163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 12555163Sshin}; 126105940Sume#endif 12755163Sshin 128121747Sumestruct policyqueue { 129121747Sume TAILQ_ENTRY(policyqueue) pc_entry; 130121747Sume#ifdef INET6 131121747Sume struct in6_addrpolicy pc_policy; 132121747Sume#endif 133121747Sume}; 134121747SumeTAILQ_HEAD(policyhead, policyqueue); 135121747Sume 13655163Sshinstatic const struct afd { 13755163Sshin int a_af; 13855163Sshin int a_addrlen; 13955163Sshin int a_socklen; 14055163Sshin int a_off; 14155163Sshin const char *a_addrany; 14273665Sobrien const char *a_loopback; 14355163Sshin int a_scoped; 14455163Sshin} afdl [] = { 14555163Sshin#ifdef INET6 14655163Sshin#define N_INET6 0 14755163Sshin {PF_INET6, sizeof(struct in6_addr), 14855163Sshin sizeof(struct sockaddr_in6), 14955163Sshin offsetof(struct sockaddr_in6, sin6_addr), 15055163Sshin in6_addrany, in6_loopback, 1}, 15155163Sshin#define N_INET 1 15255163Sshin#else 15355163Sshin#define N_INET 0 15455163Sshin#endif 15555163Sshin {PF_INET, sizeof(struct in_addr), 15655163Sshin sizeof(struct sockaddr_in), 15755163Sshin offsetof(struct sockaddr_in, sin_addr), 15855163Sshin in_addrany, in_loopback, 0}, 15955163Sshin {0, 0, 0, 0, NULL, NULL, 0}, 16055163Sshin}; 16155163Sshin 16255163Sshinstruct explore { 16361877Sume int e_af; 16455163Sshin int e_socktype; 16555163Sshin int e_protocol; 16655163Sshin const char *e_protostr; 16755163Sshin int e_wild; 168105940Sume#define WILD_AF(ex) ((ex)->e_wild & 0x01) 169105940Sume#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 170105940Sume#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 17155163Sshin}; 17255163Sshin 17355163Sshinstatic const struct explore explore[] = { 17461877Sume#if 0 175121474Sume { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 17661877Sume#endif 17761877Sume#ifdef INET6 178121474Sume { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 179121474Sume { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 180121474Sume { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 18161877Sume#endif 182121474Sume { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 183121474Sume { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 184121474Sume { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 185121474Sume { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 186121474Sume { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 187121474Sume { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 18861877Sume { -1, 0, 0, NULL, 0 }, 18955163Sshin}; 19055163Sshin 19155163Sshin#ifdef INET6 192105940Sume#define PTON_MAX 16 19355163Sshin#else 194105940Sume#define PTON_MAX 4 19555163Sshin#endif 19655163Sshin 197121747Sume#define AIO_SRCFLAG_DEPRECATED 0x1 198121747Sume 199121747Sumestruct ai_order { 200121747Sume union { 201121747Sume struct sockaddr_storage aiou_ss; 202121747Sume struct sockaddr aiou_sa; 203121747Sume } aio_src_un; 204121747Sume#define aio_srcsa aio_src_un.aiou_sa 205121747Sume u_int32_t aio_srcflag; 206121747Sume int aio_srcscope; 207121747Sume int aio_dstscope; 208121747Sume struct policyqueue *aio_srcpolicy; 209121747Sume struct policyqueue *aio_dstpolicy; 210121747Sume struct addrinfo *aio_ai; 211121747Sume int aio_matchlen; 212121747Sume}; 213121747Sume 21465532Snectarstatic const ns_src default_dns_files[] = { 21565532Snectar { NSSRC_FILES, NS_SUCCESS }, 21665532Snectar { NSSRC_DNS, NS_SUCCESS }, 21765532Snectar { 0 } 21865532Snectar}; 21965532Snectar 22061877Sumestruct res_target { 22161877Sume struct res_target *next; 22261877Sume const char *name; /* domain name */ 22362614Sitojun int qclass, qtype; /* class and type of query */ 22461877Sume u_char *answer; /* buffer to put answer */ 22561877Sume int anslen; /* size of answer buffer */ 22661877Sume int n; /* result length */ 22761877Sume}; 22861877Sume 229121426Sume#define MAXPACKET (64*1024) 230121426Sume 231121426Sumetypedef union { 232121426Sume HEADER hdr; 233121426Sume u_char buf[MAXPACKET]; 234121426Sume} querybuf; 235121426Sume 23692905Sobrienstatic int str_isnumber(const char *); 23792941Sobrienstatic int explore_null(const struct addrinfo *, 23892941Sobrien const char *, struct addrinfo **); 23992941Sobrienstatic int explore_numeric(const struct addrinfo *, const char *, 240140906Sume const char *, struct addrinfo **, const char *); 24192941Sobrienstatic int explore_numeric_scope(const struct addrinfo *, const char *, 24292941Sobrien const char *, struct addrinfo **); 24392941Sobrienstatic int get_canonname(const struct addrinfo *, 24492941Sobrien struct addrinfo *, const char *); 24592941Sobrienstatic struct addrinfo *get_ai(const struct addrinfo *, 24692941Sobrien const struct afd *, const char *); 24792905Sobrienstatic int get_portmatch(const struct addrinfo *, const char *); 24892905Sobrienstatic int get_port(struct addrinfo *, const char *, int); 24992905Sobrienstatic const struct afd *find_afd(int); 250121474Sumestatic int addrconfig(struct addrinfo *); 251129901Sumestatic void set_source(struct ai_order *, struct policyhead *); 252121747Sumestatic int comp_dst(const void *, const void *); 25361877Sume#ifdef INET6 254105943Sumestatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 25561877Sume#endif 256121747Sumestatic int gai_addr2scopetype(struct sockaddr *); 25755163Sshin 258121426Sumestatic int explore_fqdn(const struct addrinfo *, const char *, 259121426Sume const char *, struct addrinfo **); 260121426Sume 261121747Sumestatic int reorder(struct addrinfo *); 262121747Sumestatic int get_addrselectpolicy(struct policyhead *); 263121747Sumestatic void free_addrselectpolicy(struct policyhead *); 264121747Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 265121747Sume struct policyhead *); 266129901Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 267121747Sume 26892941Sobrienstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 26992941Sobrien const struct addrinfo *); 270121426Sume#if defined(RESOLVSORT) 271121426Sumestatic int addr4sort(struct addrinfo *); 272121426Sume#endif 273105943Sumestatic int _dns_getaddrinfo(void *, void *, va_list); 27492905Sobrienstatic void _sethtent(void); 27592905Sobrienstatic void _endhtent(void); 27692905Sobrienstatic struct addrinfo *_gethtent(const char *, const struct addrinfo *); 27792905Sobrienstatic int _files_getaddrinfo(void *, void *, va_list); 27861877Sume#ifdef YP 27992905Sobrienstatic struct addrinfo *_yphostent(char *, const struct addrinfo *); 28092905Sobrienstatic int _yp_getaddrinfo(void *, void *, va_list); 28161877Sume#endif 28261877Sume 28392905Sobrienstatic int res_queryN(const char *, struct res_target *); 28492905Sobrienstatic int res_searchN(const char *, struct res_target *); 28592941Sobrienstatic int res_querydomainN(const char *, const char *, 28692941Sobrien struct res_target *); 28761877Sume 288121347Sumestatic struct ai_errlist { 289121347Sume const char *str; 290121347Sume int code; 291121347Sume} ai_errlist[] = { 292121347Sume { "Success", 0, }, 293121347Sume { "Temporary failure in name resolution", EAI_AGAIN, }, 294121347Sume { "Invalid value for ai_flags", EAI_BADFLAGS, }, 295121347Sume { "Non-recoverable failure in name resolution", EAI_FAIL, }, 296121347Sume { "ai_family not supported", EAI_FAMILY, }, 297121347Sume { "Memory allocation failure", EAI_MEMORY, }, 298121347Sume { "hostname nor servname provided, or not known", EAI_NONAME, }, 299121347Sume { "servname not supported for ai_socktype", EAI_SERVICE, }, 300121347Sume { "ai_socktype not supported", EAI_SOCKTYPE, }, 301121347Sume { "System error returned in errno", EAI_SYSTEM, }, 302121347Sume { "Invalid value for hints", EAI_BADHINTS, }, 303121347Sume { "Resolved protocol is unknown", EAI_PROTOCOL, }, 304121347Sume /* backward compatibility with userland code prior to 2553bis-02 */ 305121347Sume { "Address family for hostname not supported", 1, }, 306121347Sume { "No address associated with hostname", 7, }, 307121347Sume { NULL, -1, }, 30855163Sshin}; 30955163Sshin 310104558Sume/* 311126243Sgreen * XXX: Many dependencies are not thread-safe. So, we share lock between 312104558Sume * getaddrinfo() and getipnodeby*(). Still, we cannot use 313104558Sume * getaddrinfo() and getipnodeby*() in conjunction with other 314126243Sgreen * functions which call them. 315104558Sume */ 316114681Sdeischenpthread_mutex_t __getaddrinfo_thread_lock = PTHREAD_MUTEX_INITIALIZER; 317104558Sume#define THREAD_LOCK() \ 318114681Sdeischen if (__isthreaded) _pthread_mutex_lock(&__getaddrinfo_thread_lock); 319104558Sume#define THREAD_UNLOCK() \ 320114681Sdeischen if (__isthreaded) _pthread_mutex_unlock(&__getaddrinfo_thread_lock); 321104558Sume 32255163Sshin/* XXX macros that make external reference is BAD. */ 32355163Sshin 324105940Sume#define GET_AI(ai, afd, addr) \ 32555163Sshindo { \ 32655163Sshin /* external reference: pai, error, and label free */ \ 32755163Sshin (ai) = get_ai(pai, (afd), (addr)); \ 32855163Sshin if ((ai) == NULL) { \ 32955163Sshin error = EAI_MEMORY; \ 33055163Sshin goto free; \ 33155163Sshin } \ 33261877Sume} while (/*CONSTCOND*/0) 33355163Sshin 334105940Sume#define GET_PORT(ai, serv) \ 33555163Sshindo { \ 33655163Sshin /* external reference: error and label free */ \ 33755163Sshin error = get_port((ai), (serv), 0); \ 33855163Sshin if (error != 0) \ 33955163Sshin goto free; \ 34061877Sume} while (/*CONSTCOND*/0) 34155163Sshin 342105940Sume#define GET_CANONNAME(ai, str) \ 34355163Sshindo { \ 34455163Sshin /* external reference: pai, error and label free */ \ 34555163Sshin error = get_canonname(pai, (ai), (str)); \ 34655163Sshin if (error != 0) \ 34755163Sshin goto free; \ 34861877Sume} while (/*CONSTCOND*/0) 34955163Sshin 350105940Sume#define ERR(err) \ 35155163Sshindo { \ 35255163Sshin /* external reference: error, and label bad */ \ 35355163Sshin error = (err); \ 35455163Sshin goto bad; \ 35561877Sume /*NOTREACHED*/ \ 35661877Sume} while (/*CONSTCOND*/0) 35755163Sshin 358105940Sume#define MATCH_FAMILY(x, y, w) \ 35961877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 360105940Sume#define MATCH(x, y, w) \ 36161877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 36255163Sshin 36355163Sshinchar * 36455163Sshingai_strerror(ecode) 36555163Sshin int ecode; 36655163Sshin{ 367121347Sume struct ai_errlist *p; 368121347Sume 369121347Sume for (p = ai_errlist; p->str; p++) { 370121347Sume if (p->code == ecode) 371121347Sume return (char *)p->str; 372121347Sume } 373121348Sume return "Unknown error"; 37455163Sshin} 37555163Sshin 37655163Sshinvoid 37755163Sshinfreeaddrinfo(ai) 37855163Sshin struct addrinfo *ai; 37955163Sshin{ 38055163Sshin struct addrinfo *next; 38155163Sshin 38255163Sshin do { 38355163Sshin next = ai->ai_next; 38455163Sshin if (ai->ai_canonname) 38555163Sshin free(ai->ai_canonname); 38655163Sshin /* no need to free(ai->ai_addr) */ 38755163Sshin free(ai); 38861877Sume ai = next; 38961877Sume } while (ai); 39055163Sshin} 39155163Sshin 39255163Sshinstatic int 39355163Sshinstr_isnumber(p) 39455163Sshin const char *p; 39555163Sshin{ 39662836Sitojun char *ep; 39762836Sitojun 39862836Sitojun if (*p == '\0') 39962836Sitojun return NO; 40062836Sitojun ep = NULL; 401105943Sume errno = 0; 40262836Sitojun (void)strtoul(p, &ep, 10); 403105943Sume if (errno == 0 && ep && *ep == '\0') 40462836Sitojun return YES; 40562836Sitojun else 40662836Sitojun return NO; 40755163Sshin} 40855163Sshin 40955163Sshinint 41055163Sshingetaddrinfo(hostname, servname, hints, res) 41155163Sshin const char *hostname, *servname; 41255163Sshin const struct addrinfo *hints; 41355163Sshin struct addrinfo **res; 41455163Sshin{ 41555163Sshin struct addrinfo sentinel; 41655163Sshin struct addrinfo *cur; 41755163Sshin int error = 0; 418121474Sume struct addrinfo ai; 419121474Sume struct addrinfo ai0; 42055163Sshin struct addrinfo *pai; 42155163Sshin const struct explore *ex; 422121747Sume int numeric = 0; 42355163Sshin 42461877Sume memset(&sentinel, 0, sizeof(sentinel)); 42555163Sshin cur = &sentinel; 42655163Sshin pai = &ai; 42755163Sshin pai->ai_flags = 0; 42855163Sshin pai->ai_family = PF_UNSPEC; 42955163Sshin pai->ai_socktype = ANY; 43055163Sshin pai->ai_protocol = ANY; 43155163Sshin pai->ai_addrlen = 0; 43255163Sshin pai->ai_canonname = NULL; 43355163Sshin pai->ai_addr = NULL; 43455163Sshin pai->ai_next = NULL; 43555163Sshin 43655163Sshin if (hostname == NULL && servname == NULL) 43755163Sshin return EAI_NONAME; 43855163Sshin if (hints) { 43955163Sshin /* error check for hints */ 44055163Sshin if (hints->ai_addrlen || hints->ai_canonname || 44155163Sshin hints->ai_addr || hints->ai_next) 44255163Sshin ERR(EAI_BADHINTS); /* xxx */ 44355163Sshin if (hints->ai_flags & ~AI_MASK) 44455163Sshin ERR(EAI_BADFLAGS); 44555163Sshin switch (hints->ai_family) { 44655163Sshin case PF_UNSPEC: 44755163Sshin case PF_INET: 44855163Sshin#ifdef INET6 44955163Sshin case PF_INET6: 45055163Sshin#endif 45155163Sshin break; 45255163Sshin default: 45355163Sshin ERR(EAI_FAMILY); 45455163Sshin } 45555163Sshin memcpy(pai, hints, sizeof(*pai)); 45655163Sshin 45755163Sshin /* 45855163Sshin * if both socktype/protocol are specified, check if they 45955163Sshin * are meaningful combination. 46055163Sshin */ 46155163Sshin if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 46261877Sume for (ex = explore; ex->e_af >= 0; ex++) { 463121474Sume if (pai->ai_family != ex->e_af) 46461877Sume continue; 465121474Sume if (ex->e_socktype == ANY) 46655163Sshin continue; 467121474Sume if (ex->e_protocol == ANY) 46855163Sshin continue; 469121474Sume if (pai->ai_socktype == ex->e_socktype && 470121474Sume pai->ai_protocol != ex->e_protocol) { 471121474Sume ERR(EAI_BADHINTS); 472121474Sume } 47355163Sshin } 47455163Sshin } 47555163Sshin } 47655163Sshin 47761877Sume /* 47861877Sume * post-2553: AI_ALL and AI_V4MAPPED are effective only against 479105940Sume * AF_INET6 query. They need to be ignored if specified in other 48061877Sume * occassions. 48161877Sume */ 48261877Sume switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 48361877Sume case AI_V4MAPPED: 48461877Sume case AI_ALL | AI_V4MAPPED: 48561877Sume if (pai->ai_family != AF_INET6) 48661877Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 48761877Sume break; 48861877Sume case AI_ALL: 48961877Sume#if 1 49061877Sume /* illegal */ 49161877Sume ERR(EAI_BADFLAGS); 49261877Sume#else 49361877Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 49461877Sume#endif 49561877Sume break; 49661877Sume } 49755163Sshin 49855163Sshin /* 49961877Sume * check for special cases. (1) numeric servname is disallowed if 50061877Sume * socktype/protocol are left unspecified. (2) servname is disallowed 50161877Sume * for raw and other inet{,6} sockets. 50255163Sshin */ 50355163Sshin if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 50461877Sume#ifdef PF_INET6 505121474Sume || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 50655163Sshin#endif 50755163Sshin ) { 50861877Sume ai0 = *pai; /* backup *pai */ 50955163Sshin 51061877Sume if (pai->ai_family == PF_UNSPEC) { 51161877Sume#ifdef PF_INET6 51255163Sshin pai->ai_family = PF_INET6; 51355163Sshin#else 51455163Sshin pai->ai_family = PF_INET; 51555163Sshin#endif 51661877Sume } 51755163Sshin error = get_portmatch(pai, servname); 51855163Sshin if (error) 51955163Sshin ERR(error); 52061877Sume 52161877Sume *pai = ai0; 52255163Sshin } 52355163Sshin 52461877Sume ai0 = *pai; 52561877Sume 526121474Sume /* NULL hostname, or numeric hostname */ 527121474Sume for (ex = explore; ex->e_af >= 0; ex++) { 52855163Sshin *pai = ai0; 52955163Sshin 530121474Sume /* PF_UNSPEC entries are prepared for DNS queries only */ 531121474Sume if (ex->e_af == PF_UNSPEC) 53255163Sshin continue; 53361877Sume 534121474Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 535121474Sume continue; 536121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 537121474Sume continue; 538121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 539121474Sume continue; 540121474Sume 54155163Sshin if (pai->ai_family == PF_UNSPEC) 542121474Sume pai->ai_family = ex->e_af; 543121474Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 544121474Sume pai->ai_socktype = ex->e_socktype; 545121474Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 546121474Sume pai->ai_protocol = ex->e_protocol; 54755163Sshin 548121474Sume if (hostname == NULL) 549121474Sume error = explore_null(pai, servname, &cur->ai_next); 550121474Sume else 551140906Sume error = explore_numeric_scope(pai, hostname, servname, 552140906Sume &cur->ai_next); 55355163Sshin 554121474Sume if (error) 555121474Sume goto free; 556121474Sume 557121474Sume while (cur && cur->ai_next) 558121474Sume cur = cur->ai_next; 55955163Sshin } 56055163Sshin 561121474Sume /* 562121474Sume * XXX 563121474Sume * If numreic representation of AF1 can be interpreted as FQDN 564121474Sume * representation of AF2, we need to think again about the code below. 565121474Sume */ 566121747Sume if (sentinel.ai_next) { 567121747Sume numeric = 1; 568121474Sume goto good; 569121747Sume } 570121474Sume 571121425Sume if (hostname == NULL) 572121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 57355163Sshin if (pai->ai_flags & AI_NUMERICHOST) 57490053Sroam ERR(EAI_NONAME); 57555163Sshin 576121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 577121474Sume ERR(EAI_FAIL); 578121474Sume 57961877Sume /* 58061877Sume * hostname as alphabetical name. 581121474Sume * we would like to prefer AF_INET6 than AF_INET, so we'll make a 582121474Sume * outer loop by AFs. 58361877Sume */ 58461877Sume for (ex = explore; ex->e_af >= 0; ex++) { 58561877Sume *pai = ai0; 58655163Sshin 587121474Sume /* require exact match for family field */ 588121474Sume if (pai->ai_family != ex->e_af) 58961877Sume continue; 59055163Sshin 591121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 592121474Sume WILD_SOCKTYPE(ex))) { 59361877Sume continue; 594121474Sume } 595121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 596121474Sume WILD_PROTOCOL(ex))) { 59761877Sume continue; 598121474Sume } 59955163Sshin 60061877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 60161877Sume pai->ai_socktype = ex->e_socktype; 60261877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 60361877Sume pai->ai_protocol = ex->e_protocol; 60461877Sume 605121474Sume error = explore_fqdn(pai, hostname, servname, 606121474Sume &cur->ai_next); 60761877Sume 60861877Sume while (cur && cur->ai_next) 60961877Sume cur = cur->ai_next; 61055163Sshin } 61155163Sshin 612121747Sume /* XXX inhibit errors if we have the result */ 61361877Sume if (sentinel.ai_next) 61461877Sume error = 0; 61561877Sume 616121747Sumegood: 617121747Sume /* 618121747Sume * ensure we return either: 619121747Sume * - error == 0, non-NULL *res 620121747Sume * - error != 0, NULL *res 621121747Sume */ 62261877Sume if (error == 0) { 62361877Sume if (sentinel.ai_next) { 624121747Sume /* 625121747Sume * If the returned entry is for an active connection, 626121747Sume * and the given name is not numeric, reorder the 627121747Sume * list, so that the application would try the list 628121747Sume * in the most efficient order. 629121747Sume */ 630121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 631121747Sume if (!numeric) 632121747Sume (void)reorder(&sentinel); 633121747Sume } 63461877Sume *res = sentinel.ai_next; 635121474Sume return SUCCESS; 63661877Sume } else 63761877Sume error = EAI_FAIL; 63855163Sshin } 639121747Sumefree: 640121747Sumebad: 641121474Sume if (sentinel.ai_next) 642121474Sume freeaddrinfo(sentinel.ai_next); 643121474Sume *res = NULL; 64455163Sshin return error; 64555163Sshin} 64655163Sshin 647121747Sumestatic int 648121747Sumereorder(sentinel) 649121747Sume struct addrinfo *sentinel; 650121747Sume{ 651121747Sume struct addrinfo *ai, **aip; 652121747Sume struct ai_order *aio; 653121747Sume int i, n; 654121747Sume struct policyhead policyhead; 655121747Sume 656121747Sume /* count the number of addrinfo elements for sorting. */ 657121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 658121747Sume ; 659121747Sume 660121747Sume /* 661121747Sume * If the number is small enough, we can skip the reordering process. 662121747Sume */ 663121747Sume if (n <= 1) 664121747Sume return(n); 665121747Sume 666121747Sume /* allocate a temporary array for sort and initialization of it. */ 667121747Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 668121747Sume return(n); /* give up reordering */ 669121747Sume memset(aio, 0, sizeof(*aio) * n); 670121747Sume 671121747Sume /* retrieve address selection policy from the kernel */ 672121747Sume TAILQ_INIT(&policyhead); 673121747Sume if (!get_addrselectpolicy(&policyhead)) { 674121747Sume /* no policy is installed into kernel, we don't sort. */ 675121747Sume free(aio); 676121747Sume return (n); 677121747Sume } 678121747Sume 679121747Sume for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 680121747Sume aio[i].aio_ai = ai; 681121747Sume aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 682121747Sume aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 683121747Sume &policyhead); 684129901Sume set_source(&aio[i], &policyhead); 685121747Sume } 686121747Sume 687121747Sume /* perform sorting. */ 688121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 689121747Sume 690121747Sume /* reorder the addrinfo chain. */ 691121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 692121747Sume *aip = aio[i].aio_ai; 693121747Sume aip = &aio[i].aio_ai->ai_next; 694121747Sume } 695121747Sume *aip = NULL; 696121747Sume 697121747Sume /* cleanup and return */ 698121747Sume free(aio); 699121747Sume free_addrselectpolicy(&policyhead); 700121747Sume return(n); 701121747Sume} 702121747Sume 703121747Sumestatic int 704121747Sumeget_addrselectpolicy(head) 705121747Sume struct policyhead *head; 706121747Sume{ 707121747Sume#ifdef INET6 708121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 709121747Sume size_t l; 710121747Sume char *buf; 711121747Sume struct in6_addrpolicy *pol, *ep; 712121747Sume 713121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 714121747Sume return (0); 715121747Sume if ((buf = malloc(l)) == NULL) 716121747Sume return (0); 717121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 718121747Sume free(buf); 719121747Sume return (0); 720121747Sume } 721121747Sume 722121747Sume ep = (struct in6_addrpolicy *)(buf + l); 723121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 724121747Sume struct policyqueue *new; 725121747Sume 726121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 727121747Sume free_addrselectpolicy(head); /* make the list empty */ 728121747Sume break; 729121747Sume } 730121747Sume new->pc_policy = *pol; 731121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 732121747Sume } 733121747Sume 734121747Sume free(buf); 735121747Sume return (1); 736121747Sume#else 737121747Sume return (0); 738121747Sume#endif 739121747Sume} 740121747Sume 741121747Sumestatic void 742121747Sumefree_addrselectpolicy(head) 743121747Sume struct policyhead *head; 744121747Sume{ 745121747Sume struct policyqueue *ent, *nent; 746121747Sume 747121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 748121747Sume nent = TAILQ_NEXT(ent, pc_entry); 749121747Sume TAILQ_REMOVE(head, ent, pc_entry); 750121747Sume free(ent); 751121747Sume } 752121747Sume} 753121747Sume 754121747Sumestatic struct policyqueue * 755121747Sumematch_addrselectpolicy(addr, head) 756121747Sume struct sockaddr *addr; 757121747Sume struct policyhead *head; 758121747Sume{ 759121747Sume#ifdef INET6 760121747Sume struct policyqueue *ent, *bestent = NULL; 761121747Sume struct in6_addrpolicy *pol; 762121747Sume int matchlen, bestmatchlen = -1; 763121747Sume u_char *mp, *ep, *k, *p, m; 764121747Sume struct sockaddr_in6 key; 765121747Sume 766121747Sume switch(addr->sa_family) { 767121747Sume case AF_INET6: 768121747Sume key = *(struct sockaddr_in6 *)addr; 769121747Sume break; 770121747Sume case AF_INET: 771121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 772121747Sume memset(&key, 0, sizeof(key)); 773121747Sume key.sin6_family = AF_INET6; 774121747Sume key.sin6_len = sizeof(key); 775121747Sume key.sin6_addr.s6_addr[10] = 0xff; 776121747Sume key.sin6_addr.s6_addr[11] = 0xff; 777121747Sume memcpy(&key.sin6_addr.s6_addr[12], 778121747Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 779121747Sume break; 780121747Sume default: 781121747Sume return(NULL); 782121747Sume } 783121747Sume 784121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 785121747Sume pol = &ent->pc_policy; 786121747Sume matchlen = 0; 787121747Sume 788121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 789121747Sume ep = mp + 16; /* XXX: scope field? */ 790121747Sume k = (u_char *)&key.sin6_addr; 791121747Sume p = (u_char *)&pol->addr.sin6_addr; 792121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 793121747Sume m = *mp; 794121747Sume if ((*k & m) != *p) 795121747Sume goto next; /* not match */ 796121747Sume if (m == 0xff) /* short cut for a typical case */ 797121747Sume matchlen += 8; 798121747Sume else { 799121747Sume while (m >= 0x80) { 800121747Sume matchlen++; 801121747Sume m <<= 1; 802121747Sume } 803121747Sume } 804121747Sume } 805121747Sume 806121747Sume /* matched. check if this is better than the current best. */ 807121747Sume if (matchlen > bestmatchlen) { 808121747Sume bestent = ent; 809121747Sume bestmatchlen = matchlen; 810121747Sume } 811121747Sume 812121747Sume next: 813121747Sume continue; 814121747Sume } 815121747Sume 816121747Sume return(bestent); 817121747Sume#else 818121747Sume return(NULL); 819121747Sume#endif 820121747Sume 821121747Sume} 822121747Sume 823129901Sumestatic void 824129901Sumeset_source(aio, ph) 825129901Sume struct ai_order *aio; 826129901Sume struct policyhead *ph; 827129901Sume{ 828129901Sume struct addrinfo ai = *aio->aio_ai; 829129901Sume struct sockaddr_storage ss; 830129901Sume int s, srclen; 831129901Sume 832129901Sume /* set unspec ("no source is available"), just in case */ 833129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 834129901Sume aio->aio_srcscope = -1; 835129901Sume 836129901Sume switch(ai.ai_family) { 837129901Sume case AF_INET: 838129901Sume#ifdef INET6 839129901Sume case AF_INET6: 840129901Sume#endif 841129901Sume break; 842129901Sume default: /* ignore unsupported AFs explicitly */ 843129901Sume return; 844129901Sume } 845129901Sume 846129901Sume /* XXX: make a dummy addrinfo to call connect() */ 847129901Sume ai.ai_socktype = SOCK_DGRAM; 848129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 849129901Sume ai.ai_next = NULL; 850129901Sume memset(&ss, 0, sizeof(ss)); 851129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 852129901Sume ai.ai_addr = (struct sockaddr *)&ss; 853129901Sume get_port(&ai, "1", 0); 854129901Sume 855129901Sume /* open a socket to get the source address for the given dst */ 856129901Sume if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) 857129901Sume return; /* give up */ 858129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 859129901Sume goto cleanup; 860129901Sume srclen = ai.ai_addrlen; 861129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 862129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 863129901Sume goto cleanup; 864129901Sume } 865129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 866129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 867129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 868129901Sume#ifdef INET6 869129901Sume if (ai.ai_family == AF_INET6) { 870129901Sume struct in6_ifreq ifr6; 871129901Sume u_int32_t flags6; 872129901Sume 873129901Sume /* XXX: interface name should not be hardcoded */ 874129901Sume strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name)); 875129901Sume memset(&ifr6, 0, sizeof(ifr6)); 876129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 877129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 878129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 879129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 880129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 881129901Sume } 882129901Sume } 883129901Sume#endif 884129901Sume 885129901Sume cleanup: 886129901Sume _close(s); 887129901Sume return; 888129901Sume} 889129901Sume 890121747Sumestatic int 891129901Sumematchlen(src, dst) 892129901Sume struct sockaddr *src, *dst; 893129901Sume{ 894129901Sume int match = 0; 895129901Sume u_char *s, *d; 896129901Sume u_char *lim, r; 897129901Sume int addrlen; 898129901Sume 899129901Sume switch (src->sa_family) { 900129901Sume#ifdef INET6 901129901Sume case AF_INET6: 902129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 903129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 904129901Sume addrlen = sizeof(struct in6_addr); 905129901Sume lim = s + addrlen; 906129901Sume break; 907129901Sume#endif 908129901Sume case AF_INET: 909129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 910129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 911129901Sume addrlen = sizeof(struct in_addr); 912129901Sume lim = s + addrlen; 913129901Sume break; 914129901Sume default: 915129901Sume return(0); 916129901Sume } 917129901Sume 918129901Sume while (s < lim) 919129901Sume if ((r = (*d++ ^ *s++)) != 0) { 920129901Sume while (r < addrlen * 8) { 921129901Sume match++; 922129901Sume r <<= 1; 923129901Sume } 924129901Sume break; 925129901Sume } else 926129901Sume match += 8; 927129901Sume return(match); 928129901Sume} 929129901Sume 930129901Sumestatic int 931121747Sumecomp_dst(arg1, arg2) 932121747Sume const void *arg1, *arg2; 933121747Sume{ 934121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 935121747Sume 936121747Sume /* 937121747Sume * Rule 1: Avoid unusable destinations. 938121747Sume * XXX: we currently do not consider if an appropriate route exists. 939121747Sume */ 940121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 941121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 942121747Sume return(-1); 943121747Sume } 944121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 945121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 946121747Sume return(1); 947121747Sume } 948121747Sume 949121747Sume /* Rule 2: Prefer matching scope. */ 950121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 951121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 952121747Sume return(-1); 953121747Sume } 954121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 955121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 956121747Sume return(1); 957121747Sume } 958121747Sume 959121747Sume /* Rule 3: Avoid deprecated addresses. */ 960121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 961121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 962121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 963121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 964121747Sume return(-1); 965121747Sume } 966121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 967121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 968121747Sume return(1); 969121747Sume } 970121747Sume } 971121747Sume 972121747Sume /* Rule 4: Prefer home addresses. */ 973121747Sume /* XXX: not implemented yet */ 974121747Sume 975121747Sume /* Rule 5: Prefer matching label. */ 976121747Sume#ifdef INET6 977121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 978121747Sume dst1->aio_srcpolicy->pc_policy.label == 979121747Sume dst1->aio_dstpolicy->pc_policy.label && 980121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 981121747Sume dst2->aio_srcpolicy->pc_policy.label != 982121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 983121747Sume return(-1); 984121747Sume } 985121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 986121747Sume dst2->aio_srcpolicy->pc_policy.label == 987121747Sume dst2->aio_dstpolicy->pc_policy.label && 988121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 989121747Sume dst1->aio_srcpolicy->pc_policy.label != 990121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 991121747Sume return(1); 992121747Sume } 993121747Sume#endif 994121747Sume 995121747Sume /* Rule 6: Prefer higher precedence. */ 996121747Sume#ifdef INET6 997121747Sume if (dst1->aio_dstpolicy && 998121747Sume (dst2->aio_dstpolicy == NULL || 999121747Sume dst1->aio_dstpolicy->pc_policy.preced > 1000121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1001121747Sume return(-1); 1002121747Sume } 1003121747Sume if (dst2->aio_dstpolicy && 1004121747Sume (dst1->aio_dstpolicy == NULL || 1005121747Sume dst2->aio_dstpolicy->pc_policy.preced > 1006121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1007121747Sume return(1); 1008121747Sume } 1009121747Sume#endif 1010121747Sume 1011121747Sume /* Rule 7: Prefer native transport. */ 1012121747Sume /* XXX: not implemented yet */ 1013121747Sume 1014121747Sume /* Rule 8: Prefer smaller scope. */ 1015121747Sume if (dst1->aio_dstscope >= 0 && 1016121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1017121747Sume return(-1); 1018121747Sume } 1019121747Sume if (dst2->aio_dstscope >= 0 && 1020121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1021121747Sume return(1); 1022121747Sume } 1023121747Sume 1024121747Sume /* 1025121747Sume * Rule 9: Use longest matching prefix. 1026121747Sume * We compare the match length in a same AF only. 1027121747Sume */ 1028121747Sume if (dst1->aio_ai->ai_addr->sa_family == 1029121747Sume dst2->aio_ai->ai_addr->sa_family) { 1030121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1031121747Sume return(-1); 1032121747Sume } 1033121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1034121747Sume return(1); 1035121747Sume } 1036121747Sume } 1037121747Sume 1038121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1039121747Sume return(-1); 1040121747Sume} 1041121747Sume 104255163Sshin/* 1043121747Sume * Copy from scope.c. 1044121747Sume * XXX: we should standardize the functions and link them as standard 1045121747Sume * library. 1046121747Sume */ 1047121747Sumestatic int 1048121747Sumegai_addr2scopetype(sa) 1049121747Sume struct sockaddr *sa; 1050121747Sume{ 1051121747Sume#ifdef INET6 1052121747Sume struct sockaddr_in6 *sa6; 1053121747Sume#endif 1054121747Sume struct sockaddr_in *sa4; 1055121747Sume 1056121747Sume switch(sa->sa_family) { 1057121747Sume#ifdef INET6 1058121747Sume case AF_INET6: 1059121747Sume sa6 = (struct sockaddr_in6 *)sa; 1060121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1061121747Sume /* just use the scope field of the multicast address */ 1062121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1063121747Sume } 1064121747Sume /* 1065121747Sume * Unicast addresses: map scope type to corresponding scope 1066121747Sume * value defined for multcast addresses. 1067121747Sume * XXX: hardcoded scope type values are bad... 1068121747Sume */ 1069121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1070121747Sume return(1); /* node local scope */ 1071121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1072121747Sume return(2); /* link-local scope */ 1073121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1074121747Sume return(5); /* site-local scope */ 1075121747Sume return(14); /* global scope */ 1076121747Sume break; 1077121747Sume#endif 1078121747Sume case AF_INET: 1079121747Sume /* 1080121747Sume * IPv4 pseudo scoping according to RFC 3484. 1081121747Sume */ 1082121747Sume sa4 = (struct sockaddr_in *)sa; 1083121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1084121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1085121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1086121747Sume return(2); 1087121747Sume /* Private addresses have site-local scope. */ 1088121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1089121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1090121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1091121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1092121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1093129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1094121747Sume /* Loopback addresses have link-local scope. */ 1095121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1096121747Sume return(2); 1097121747Sume return(14); 1098121747Sume break; 1099121747Sume default: 1100121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1101121747Sume return(-1); 1102121747Sume } 1103121747Sume} 1104121747Sume 1105121747Sume/* 110655163Sshin * hostname == NULL. 110755163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 110855163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 110955163Sshin */ 111055163Sshinstatic int 111161877Sumeexplore_null(pai, servname, res) 111255163Sshin const struct addrinfo *pai; 111355163Sshin const char *servname; 111455163Sshin struct addrinfo **res; 111555163Sshin{ 1116121474Sume int s; 111755163Sshin const struct afd *afd; 111855163Sshin struct addrinfo *cur; 111955163Sshin struct addrinfo sentinel; 112055163Sshin int error; 112155163Sshin 112255163Sshin *res = NULL; 112355163Sshin sentinel.ai_next = NULL; 112455163Sshin cur = &sentinel; 112555163Sshin 112655163Sshin /* 1127121474Sume * filter out AFs that are not supported by the kernel 1128121474Sume * XXX errno? 1129121474Sume */ 1130121474Sume s = _socket(pai->ai_family, SOCK_DGRAM, 0); 1131121474Sume if (s < 0) { 1132121474Sume if (errno != EMFILE) 1133121474Sume return 0; 1134121474Sume } else 1135121474Sume _close(s); 1136121474Sume 1137121474Sume /* 113861877Sume * if the servname does not match socktype/protocol, ignore it. 113961877Sume */ 114061877Sume if (get_portmatch(pai, servname) != 0) 114155163Sshin return 0; 114261877Sume 114355163Sshin afd = find_afd(pai->ai_family); 114455163Sshin if (afd == NULL) 114555163Sshin return 0; 114655163Sshin 114761877Sume if (pai->ai_flags & AI_PASSIVE) { 114861877Sume GET_AI(cur->ai_next, afd, afd->a_addrany); 114961877Sume /* xxx meaningless? 115061877Sume * GET_CANONNAME(cur->ai_next, "anyaddr"); 115161877Sume */ 115261877Sume GET_PORT(cur->ai_next, servname); 115361877Sume } else { 115461877Sume GET_AI(cur->ai_next, afd, afd->a_loopback); 115561877Sume /* xxx meaningless? 115661877Sume * GET_CANONNAME(cur->ai_next, "localhost"); 115761877Sume */ 115861877Sume GET_PORT(cur->ai_next, servname); 115961877Sume } 116061877Sume cur = cur->ai_next; 116155163Sshin 116255163Sshin *res = sentinel.ai_next; 116355163Sshin return 0; 116455163Sshin 116555163Sshinfree: 116655163Sshin if (sentinel.ai_next) 116755163Sshin freeaddrinfo(sentinel.ai_next); 116855163Sshin return error; 116955163Sshin} 117055163Sshin 117155163Sshin/* 117255163Sshin * numeric hostname 117355163Sshin */ 117455163Sshinstatic int 1175140906Sumeexplore_numeric(pai, hostname, servname, res, canonname) 117655163Sshin const struct addrinfo *pai; 117755163Sshin const char *hostname; 117855163Sshin const char *servname; 117955163Sshin struct addrinfo **res; 1180140906Sume const char *canonname; 118155163Sshin{ 118255163Sshin const struct afd *afd; 118355163Sshin struct addrinfo *cur; 118455163Sshin struct addrinfo sentinel; 118555163Sshin int error; 118655163Sshin char pton[PTON_MAX]; 118755163Sshin 118855163Sshin *res = NULL; 118955163Sshin sentinel.ai_next = NULL; 119055163Sshin cur = &sentinel; 119155163Sshin 1192121474Sume /* 1193121474Sume * if the servname does not match socktype/protocol, ignore it. 1194121474Sume */ 1195121474Sume if (get_portmatch(pai, servname) != 0) 1196121474Sume return 0; 1197121474Sume 119855163Sshin afd = find_afd(pai->ai_family); 119955163Sshin if (afd == NULL) 120055163Sshin return 0; 120155163Sshin 120262614Sitojun switch (afd->a_af) { 120362614Sitojun#if 1 /*X/Open spec*/ 120462614Sitojun case AF_INET: 120562614Sitojun if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 120662614Sitojun if (pai->ai_family == afd->a_af || 120762614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 120862614Sitojun GET_AI(cur->ai_next, afd, pton); 120962614Sitojun GET_PORT(cur->ai_next, servname); 1210140906Sume if ((pai->ai_flags & AI_CANONNAME)) { 1211140906Sume /* 1212140906Sume * Set the numeric address itself as 1213140906Sume * the canonical name, based on a 1214140906Sume * clarification in rfc3493. 1215140906Sume */ 1216140906Sume GET_CANONNAME(cur->ai_next, canonname); 1217140906Sume } 121862614Sitojun while (cur && cur->ai_next) 121962614Sitojun cur = cur->ai_next; 122062614Sitojun } else 122162614Sitojun ERR(EAI_FAMILY); /*xxx*/ 122262614Sitojun } 122362614Sitojun break; 122462614Sitojun#endif 122562614Sitojun default: 122662614Sitojun if (inet_pton(afd->a_af, hostname, pton) == 1) { 122762614Sitojun if (pai->ai_family == afd->a_af || 122862614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 122962614Sitojun GET_AI(cur->ai_next, afd, pton); 123062614Sitojun GET_PORT(cur->ai_next, servname); 1231140906Sume if ((pai->ai_flags & AI_CANONNAME)) { 1232140906Sume /* 1233140906Sume * Set the numeric address itself as 1234140906Sume * the canonical name, based on a 1235140906Sume * clarification in rfc3493. 1236140906Sume */ 1237140906Sume GET_CANONNAME(cur->ai_next, canonname); 1238140906Sume } 123962614Sitojun while (cur && cur->ai_next) 124062614Sitojun cur = cur->ai_next; 124162614Sitojun } else 1242105940Sume ERR(EAI_FAMILY); /* XXX */ 124362614Sitojun } 124462614Sitojun break; 124555163Sshin } 124655163Sshin 124755163Sshin *res = sentinel.ai_next; 124855163Sshin return 0; 124955163Sshin 125055163Sshinfree: 125155163Sshinbad: 125255163Sshin if (sentinel.ai_next) 125355163Sshin freeaddrinfo(sentinel.ai_next); 125455163Sshin return error; 125555163Sshin} 125655163Sshin 125755163Sshin/* 125855163Sshin * numeric hostname with scope 125955163Sshin */ 126055163Sshinstatic int 126155163Sshinexplore_numeric_scope(pai, hostname, servname, res) 126255163Sshin const struct addrinfo *pai; 126355163Sshin const char *hostname; 126455163Sshin const char *servname; 126555163Sshin struct addrinfo **res; 126655163Sshin{ 126761877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1268140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 126955163Sshin#else 127055163Sshin const struct afd *afd; 127155163Sshin struct addrinfo *cur; 127255163Sshin int error; 127361877Sume char *cp, *hostname2 = NULL, *scope, *addr; 127455163Sshin struct sockaddr_in6 *sin6; 127555163Sshin 1276121474Sume /* 1277121474Sume * if the servname does not match socktype/protocol, ignore it. 1278121474Sume */ 1279121474Sume if (get_portmatch(pai, servname) != 0) 1280121474Sume return 0; 1281121474Sume 128255163Sshin afd = find_afd(pai->ai_family); 128355163Sshin if (afd == NULL) 128455163Sshin return 0; 128565532Snectar 128655163Sshin if (!afd->a_scoped) 1287140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 128855163Sshin 128955163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 129055163Sshin if (cp == NULL) 1291140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 129255163Sshin 129355163Sshin /* 129455163Sshin * Handle special case of <scoped_address><delimiter><scope id> 129555163Sshin */ 129655163Sshin hostname2 = strdup(hostname); 129755163Sshin if (hostname2 == NULL) 129855163Sshin return EAI_MEMORY; 129955163Sshin /* terminate at the delimiter */ 130055163Sshin hostname2[cp - hostname] = '\0'; 130161877Sume addr = hostname2; 130261877Sume scope = cp + 1; 130355163Sshin 1304140906Sume error = explore_numeric(pai, addr, servname, res, hostname); 130561877Sume if (error == 0) { 1306105943Sume u_int32_t scopeid; 130755163Sshin 130855163Sshin for (cur = *res; cur; cur = cur->ai_next) { 130955163Sshin if (cur->ai_family != AF_INET6) 131055163Sshin continue; 131161877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1312105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 131361877Sume free(hostname2); 1314121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 131561877Sume } 131661877Sume sin6->sin6_scope_id = scopeid; 131755163Sshin } 131855163Sshin } 131955163Sshin 132055163Sshin free(hostname2); 132155163Sshin 132255163Sshin return error; 132355163Sshin#endif 132455163Sshin} 132555163Sshin 132655163Sshinstatic int 132755163Sshinget_canonname(pai, ai, str) 132855163Sshin const struct addrinfo *pai; 132955163Sshin struct addrinfo *ai; 133055163Sshin const char *str; 133155163Sshin{ 133255163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1333121474Sume ai->ai_canonname = (char *)malloc(strlen(str) + 1); 133455163Sshin if (ai->ai_canonname == NULL) 133555163Sshin return EAI_MEMORY; 1336121474Sume strlcpy(ai->ai_canonname, str, strlen(str) + 1); 133755163Sshin } 133855163Sshin return 0; 133955163Sshin} 134055163Sshin 134155163Sshinstatic struct addrinfo * 134255163Sshinget_ai(pai, afd, addr) 134355163Sshin const struct addrinfo *pai; 134455163Sshin const struct afd *afd; 134555163Sshin const char *addr; 134655163Sshin{ 134755163Sshin char *p; 134855163Sshin struct addrinfo *ai; 134955163Sshin#ifdef FAITH 135055163Sshin struct in6_addr faith_prefix; 135155163Sshin char *fp_str; 135255163Sshin int translate = 0; 135355163Sshin#endif 135455163Sshin 135555163Sshin#ifdef FAITH 135655163Sshin /* 135755163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 135855163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 135955163Sshin * 136055163Sshin * +-----------------------------------+------------+ 136155163Sshin * | faith prefix part (12 bytes) | embedded | 136255163Sshin * | | IPv4 addr part (4 bytes) 136355163Sshin * +-----------------------------------+------------+ 136455163Sshin * 136555163Sshin * faith prefix part is specified as ascii IPv6 addr format 136655163Sshin * in environmental variable GAI. 136755163Sshin * For FAITH to work correctly, routing to faith prefix must be 136855163Sshin * setup toward a machine where a FAITH daemon operates. 136955163Sshin * Also, the machine must enable some mechanizm 137055163Sshin * (e.g. faith interface hack) to divert those packet with 137155163Sshin * faith prefixed destination addr to user-land FAITH daemon. 137255163Sshin */ 137355163Sshin fp_str = getenv("GAI"); 137455163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 137555163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 137655163Sshin u_int32_t v4a; 137755163Sshin u_int8_t v4a_top; 137855163Sshin 137955163Sshin memcpy(&v4a, addr, sizeof v4a); 138055163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 138155163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 138255163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 138355163Sshin afd = &afdl[N_INET6]; 138455163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 138555163Sshin sizeof(struct in_addr)); 138655163Sshin translate = 1; 138755163Sshin } 138855163Sshin } 138955163Sshin#endif 139055163Sshin 139155163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 139255163Sshin + (afd->a_socklen)); 139355163Sshin if (ai == NULL) 139455163Sshin return NULL; 139555163Sshin 139655163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 139761877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 139861877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 139955163Sshin ai->ai_addr->sa_len = afd->a_socklen; 140055163Sshin ai->ai_addrlen = afd->a_socklen; 140155163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 140265532Snectar p = (char *)(void *)(ai->ai_addr); 140355163Sshin#ifdef FAITH 140455163Sshin if (translate == 1) 140565532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 140655163Sshin else 140755163Sshin#endif 140865532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 140955163Sshin return ai; 141055163Sshin} 141155163Sshin 141255163Sshinstatic int 141355163Sshinget_portmatch(ai, servname) 141455163Sshin const struct addrinfo *ai; 141555163Sshin const char *servname; 141655163Sshin{ 141761877Sume 141855163Sshin /* get_port does not touch first argument. when matchonly == 1. */ 141961877Sume /* LINTED const cast */ 142055163Sshin return get_port((struct addrinfo *)ai, servname, 1); 142155163Sshin} 142255163Sshin 142355163Sshinstatic int 142455163Sshinget_port(ai, servname, matchonly) 142555163Sshin struct addrinfo *ai; 142655163Sshin const char *servname; 142755163Sshin int matchonly; 142855163Sshin{ 142955163Sshin const char *proto; 143055163Sshin struct servent *sp; 143155163Sshin int port; 143255163Sshin int allownumeric; 143355163Sshin 143455163Sshin if (servname == NULL) 143555163Sshin return 0; 143661877Sume switch (ai->ai_family) { 143761877Sume case AF_INET: 143861877Sume#ifdef AF_INET6 143961877Sume case AF_INET6: 144055163Sshin#endif 144161877Sume break; 144261877Sume default: 144355163Sshin return 0; 144461877Sume } 144555163Sshin 144655163Sshin switch (ai->ai_socktype) { 144755163Sshin case SOCK_RAW: 144855163Sshin return EAI_SERVICE; 144955163Sshin case SOCK_DGRAM: 145055163Sshin case SOCK_STREAM: 145155163Sshin allownumeric = 1; 145255163Sshin break; 145355163Sshin case ANY: 145455163Sshin allownumeric = 0; 145555163Sshin break; 145655163Sshin default: 145755163Sshin return EAI_SOCKTYPE; 145855163Sshin } 145955163Sshin 146055163Sshin if (str_isnumber(servname)) { 146155163Sshin if (!allownumeric) 146255163Sshin return EAI_SERVICE; 1463105940Sume port = atoi(servname); 146455163Sshin if (port < 0 || port > 65535) 146555163Sshin return EAI_SERVICE; 1466105940Sume port = htons(port); 146755163Sshin } else { 1468121474Sume switch (ai->ai_socktype) { 1469121474Sume case SOCK_DGRAM: 147055163Sshin proto = "udp"; 147155163Sshin break; 1472121474Sume case SOCK_STREAM: 147355163Sshin proto = "tcp"; 147455163Sshin break; 147555163Sshin default: 147655163Sshin proto = NULL; 147755163Sshin break; 147855163Sshin } 147955163Sshin 1480126243Sgreen THREAD_LOCK(); 1481126243Sgreen if ((sp = getservbyname(servname, proto)) == NULL) { 1482126243Sgreen THREAD_UNLOCK(); 148355163Sshin return EAI_SERVICE; 1484126243Sgreen } 148555163Sshin port = sp->s_port; 1486126243Sgreen THREAD_UNLOCK(); 148755163Sshin } 148855163Sshin 148955163Sshin if (!matchonly) { 149055163Sshin switch (ai->ai_family) { 149155163Sshin case AF_INET: 149261877Sume ((struct sockaddr_in *)(void *) 149361877Sume ai->ai_addr)->sin_port = port; 149455163Sshin break; 149555163Sshin#ifdef INET6 149655163Sshin case AF_INET6: 149761877Sume ((struct sockaddr_in6 *)(void *) 149861877Sume ai->ai_addr)->sin6_port = port; 149955163Sshin break; 150055163Sshin#endif 150155163Sshin } 150255163Sshin } 150355163Sshin 150455163Sshin return 0; 150555163Sshin} 150655163Sshin 150755163Sshinstatic const struct afd * 150855163Sshinfind_afd(af) 150955163Sshin int af; 151055163Sshin{ 151155163Sshin const struct afd *afd; 151255163Sshin 151355163Sshin if (af == PF_UNSPEC) 151455163Sshin return NULL; 151555163Sshin for (afd = afdl; afd->a_af; afd++) { 151655163Sshin if (afd->a_af == af) 151755163Sshin return afd; 151855163Sshin } 151955163Sshin return NULL; 152055163Sshin} 152161877Sume 152261877Sume/* 152361877Sume * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 152461877Sume * will take care of it. 152561877Sume * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 152661877Sume * if the code is right or not. 1527121474Sume * 1528121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1529121474Sume * _dns_getaddrinfo. 153061877Sume */ 153161877Sumestatic int 1532121474Sumeaddrconfig(pai) 1533121474Sume struct addrinfo *pai; 153461877Sume{ 1535121474Sume int s, af; 153661877Sume 1537121474Sume /* 1538121474Sume * TODO: 1539121474Sume * Note that implementation dependent test for address 1540121474Sume * configuration should be done everytime called 1541121474Sume * (or apropriate interval), 1542121474Sume * because addresses will be dynamically assigned or deleted. 1543121474Sume */ 1544121474Sume af = pai->ai_family; 1545121474Sume if (af == AF_UNSPEC) { 1546121474Sume if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1547121474Sume af = AF_INET; 1548121474Sume else { 1549121474Sume _close(s); 1550121474Sume if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1551121474Sume af = AF_INET6; 1552121474Sume else 1553121474Sume _close(s); 1554121474Sume } 1555121474Sume } 1556121474Sume if (af != AF_UNSPEC) { 1557121474Sume if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 155861877Sume return 0; 1559121474Sume _close(s); 1560121474Sume } 1561121474Sume pai->ai_family = af; 156261877Sume return 1; 156361877Sume} 156461877Sume 156561877Sume#ifdef INET6 156661877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 156761877Sumestatic int 1568105943Sumeip6_str2scopeid(scope, sin6, scopeid) 156961877Sume char *scope; 157061877Sume struct sockaddr_in6 *sin6; 1571105943Sume u_int32_t *scopeid; 157261877Sume{ 1573105943Sume u_long lscopeid; 1574121474Sume struct in6_addr *a6; 157561877Sume char *ep; 157661877Sume 1577121474Sume a6 = &sin6->sin6_addr; 1578121474Sume 157962836Sitojun /* empty scopeid portion is invalid */ 158062836Sitojun if (*scope == '\0') 158162836Sitojun return -1; 158262836Sitojun 1583121474Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 158461877Sume /* 158561877Sume * We currently assume a one-to-one mapping between links 158661877Sume * and interfaces, so we simply use interface indices for 158761877Sume * like-local scopes. 158861877Sume */ 1589105943Sume *scopeid = if_nametoindex(scope); 1590105943Sume if (*scopeid == 0) 159161877Sume goto trynumeric; 1592105943Sume return 0; 159361877Sume } 159461877Sume 159561877Sume /* still unclear about literal, allow numeric only - placeholder */ 159661877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 159761877Sume goto trynumeric; 159861877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 159961877Sume goto trynumeric; 160061877Sume else 160161877Sume goto trynumeric; /* global */ 160261877Sume 160361877Sume /* try to convert to a numeric id as a last resort */ 1604121474Sume trynumeric: 1605105943Sume errno = 0; 1606105943Sume lscopeid = strtoul(scope, &ep, 10); 1607105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1608105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1609105943Sume return 0; 161061877Sume else 161161877Sume return -1; 161261877Sume} 161361877Sume#endif 161461877Sume 1615121426Sume/* 1616121426Sume * FQDN hostname, DNS lookup 1617121426Sume */ 1618102237Spirzykstatic int 1619121426Sumeexplore_fqdn(pai, hostname, servname, res) 1620121426Sume const struct addrinfo *pai; 1621121426Sume const char *hostname; 1622121426Sume const char *servname; 1623121426Sume struct addrinfo **res; 1624102237Spirzyk{ 1625121426Sume struct addrinfo *result; 1626121426Sume struct addrinfo *cur; 1627121426Sume int error = 0; 1628121426Sume static const ns_dtab dtab[] = { 1629121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1630121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1631121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1632121426Sume { 0 } 1633121426Sume }; 1634102237Spirzyk 1635121426Sume result = NULL; 1636121426Sume 1637121426Sume /* 1638121426Sume * if the servname does not match socktype/protocol, ignore it. 1639121426Sume */ 1640126243Sgreen if (get_portmatch(pai, servname) != 0) 1641102237Spirzyk return 0; 1642102237Spirzyk 1643121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1644121426Sume default_dns_files, hostname, pai)) { 1645121426Sume case NS_TRYAGAIN: 1646121426Sume error = EAI_AGAIN; 1647121426Sume goto free; 1648121426Sume case NS_UNAVAIL: 1649121426Sume error = EAI_FAIL; 1650121426Sume goto free; 1651121426Sume case NS_NOTFOUND: 1652121426Sume error = EAI_NONAME; 1653121426Sume goto free; 1654121426Sume case NS_SUCCESS: 1655121426Sume error = 0; 1656121426Sume for (cur = result; cur; cur = cur->ai_next) { 1657121426Sume GET_PORT(cur, servname); 1658121426Sume /* canonname should be filled already */ 1659121426Sume } 1660121426Sume break; 1661102237Spirzyk } 1662102237Spirzyk 1663121426Sume *res = result; 1664121426Sume 1665102237Spirzyk return 0; 1666121426Sume 1667121426Sumefree: 1668121426Sume if (result) 1669121426Sume freeaddrinfo(result); 1670121426Sume return error; 1671102237Spirzyk} 1672102237Spirzyk 167361877Sume#ifdef DEBUG 167461877Sumestatic const char AskedForGot[] = 167561877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 167661877Sume#endif 167765532Snectarstatic FILE *hostf = NULL; 167861877Sume 167961877Sumestatic struct addrinfo * 168061877Sumegetanswer(answer, anslen, qname, qtype, pai) 168161877Sume const querybuf *answer; 168261877Sume int anslen; 168361877Sume const char *qname; 168461877Sume int qtype; 168561877Sume const struct addrinfo *pai; 168661877Sume{ 168761877Sume struct addrinfo sentinel, *cur; 168861877Sume struct addrinfo ai; 168961877Sume const struct afd *afd; 169061877Sume char *canonname; 169161877Sume const HEADER *hp; 169261877Sume const u_char *cp; 169361877Sume int n; 169461877Sume const u_char *eom; 1695105940Sume char *bp, *ep; 1696105940Sume int type, class, ancount, qdcount; 169761877Sume int haveanswer, had_error; 169861877Sume char tbuf[MAXDNAME]; 169992905Sobrien int (*name_ok)(const char *); 170061877Sume char hostbuf[8*1024]; 170161877Sume 170261877Sume memset(&sentinel, 0, sizeof(sentinel)); 170361877Sume cur = &sentinel; 170461877Sume 170561877Sume canonname = NULL; 170661877Sume eom = answer->buf + anslen; 170761877Sume switch (qtype) { 170861877Sume case T_A: 170961877Sume case T_AAAA: 171061877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 171161877Sume name_ok = res_hnok; 171261877Sume break; 171361877Sume default: 171461877Sume return (NULL); /* XXX should be abort(); */ 171561877Sume } 171661877Sume /* 171761877Sume * find first satisfactory answer 171861877Sume */ 171961877Sume hp = &answer->hdr; 172061877Sume ancount = ntohs(hp->ancount); 172161877Sume qdcount = ntohs(hp->qdcount); 172261877Sume bp = hostbuf; 1723105940Sume ep = hostbuf + sizeof hostbuf; 172461877Sume cp = answer->buf + HFIXEDSZ; 172561877Sume if (qdcount != 1) { 172661877Sume h_errno = NO_RECOVERY; 172761877Sume return (NULL); 172861877Sume } 1729105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 173061877Sume if ((n < 0) || !(*name_ok)(bp)) { 173161877Sume h_errno = NO_RECOVERY; 173261877Sume return (NULL); 173361877Sume } 173461877Sume cp += n + QFIXEDSZ; 173561877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 173661877Sume /* res_send() has already verified that the query name is the 173761877Sume * same as the one we sent; this just gets the expanded name 173861877Sume * (i.e., with the succeeding search-domain tacked on). 173961877Sume */ 174061877Sume n = strlen(bp) + 1; /* for the \0 */ 174161877Sume if (n >= MAXHOSTNAMELEN) { 174261877Sume h_errno = NO_RECOVERY; 174361877Sume return (NULL); 174461877Sume } 174561877Sume canonname = bp; 174661877Sume bp += n; 174761877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 174861877Sume qname = canonname; 174961877Sume } 175061877Sume haveanswer = 0; 175161877Sume had_error = 0; 175261877Sume while (ancount-- > 0 && cp < eom && !had_error) { 1753105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 175461877Sume if ((n < 0) || !(*name_ok)(bp)) { 175561877Sume had_error++; 175661877Sume continue; 175761877Sume } 175861877Sume cp += n; /* name */ 175961877Sume type = _getshort(cp); 176061877Sume cp += INT16SZ; /* type */ 176161877Sume class = _getshort(cp); 176261877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 176361877Sume n = _getshort(cp); 176461877Sume cp += INT16SZ; /* len */ 176561877Sume if (class != C_IN) { 176661877Sume /* XXX - debug? syslog? */ 176761877Sume cp += n; 176861877Sume continue; /* XXX - had_error++ ? */ 176961877Sume } 177061877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 177161877Sume type == T_CNAME) { 177261877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 177361877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 177461877Sume had_error++; 177561877Sume continue; 177661877Sume } 177761877Sume cp += n; 177861877Sume /* Get canonical name. */ 177961877Sume n = strlen(tbuf) + 1; /* for the \0 */ 1780105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 178161877Sume had_error++; 178261877Sume continue; 178361877Sume } 1784114443Snectar strlcpy(bp, tbuf, ep - bp); 178561877Sume canonname = bp; 178661877Sume bp += n; 178761877Sume continue; 178861877Sume } 178961877Sume if (qtype == T_ANY) { 179061877Sume if (!(type == T_A || type == T_AAAA)) { 179161877Sume cp += n; 179261877Sume continue; 179361877Sume } 179461877Sume } else if (type != qtype) { 179561877Sume#ifdef DEBUG 179661877Sume if (type != T_KEY && type != T_SIG) 179761877Sume syslog(LOG_NOTICE|LOG_AUTH, 179861877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 179961877Sume qname, p_class(C_IN), p_type(qtype), 180061877Sume p_type(type)); 180161877Sume#endif 180261877Sume cp += n; 180361877Sume continue; /* XXX - had_error++ ? */ 180461877Sume } 180561877Sume switch (type) { 180661877Sume case T_A: 180761877Sume case T_AAAA: 180861877Sume if (strcasecmp(canonname, bp) != 0) { 180961877Sume#ifdef DEBUG 181061877Sume syslog(LOG_NOTICE|LOG_AUTH, 181161877Sume AskedForGot, canonname, bp); 181261877Sume#endif 181361877Sume cp += n; 181461877Sume continue; /* XXX - had_error++ ? */ 181561877Sume } 181661877Sume if (type == T_A && n != INADDRSZ) { 181761877Sume cp += n; 181861877Sume continue; 181961877Sume } 182061877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 182161877Sume cp += n; 182261877Sume continue; 182361877Sume } 182461877Sume#ifdef FILTER_V4MAPPED 182561877Sume if (type == T_AAAA) { 182661877Sume struct in6_addr in6; 182761877Sume memcpy(&in6, cp, sizeof(in6)); 182861877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 182961877Sume cp += n; 183061877Sume continue; 183161877Sume } 183261877Sume } 183361877Sume#endif 183461877Sume if (!haveanswer) { 183561877Sume int nn; 183661877Sume 183761877Sume canonname = bp; 183861877Sume nn = strlen(bp) + 1; /* for the \0 */ 183961877Sume bp += nn; 184061877Sume } 184161877Sume 184261877Sume /* don't overwrite pai */ 184361877Sume ai = *pai; 184461877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 184561877Sume afd = find_afd(ai.ai_family); 184661877Sume if (afd == NULL) { 184761877Sume cp += n; 184861877Sume continue; 184961877Sume } 185061877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 185161877Sume if (cur->ai_next == NULL) 185261877Sume had_error++; 185361877Sume while (cur && cur->ai_next) 185461877Sume cur = cur->ai_next; 185561877Sume cp += n; 185661877Sume break; 185761877Sume default: 185861877Sume abort(); 185961877Sume } 186061877Sume if (!had_error) 186161877Sume haveanswer++; 186261877Sume } 186361877Sume if (haveanswer) { 1864102237Spirzyk#if defined(RESOLVSORT) 1865102237Spirzyk /* 1866102237Spirzyk * We support only IPv4 address for backward 1867102237Spirzyk * compatibility against gethostbyname(3). 1868102237Spirzyk */ 1869102237Spirzyk if (_res.nsort && qtype == T_A) { 1870102237Spirzyk if (addr4sort(&sentinel) < 0) { 1871102237Spirzyk freeaddrinfo(sentinel.ai_next); 1872102237Spirzyk h_errno = NO_RECOVERY; 1873102237Spirzyk return NULL; 1874102237Spirzyk } 1875102237Spirzyk } 1876102237Spirzyk#endif /*RESOLVSORT*/ 187761877Sume if (!canonname) 187861877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 187961877Sume else 188061877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 188161877Sume h_errno = NETDB_SUCCESS; 188261877Sume return sentinel.ai_next; 188361877Sume } 188461877Sume 188561877Sume h_errno = NO_RECOVERY; 188661877Sume return NULL; 188761877Sume} 188861877Sume 1889121426Sume#ifdef RESOLVSORT 1890121426Sumestruct addr_ptr { 1891121426Sume struct addrinfo *ai; 1892121426Sume int aval; 1893121426Sume}; 1894121426Sume 1895121426Sumestatic int 1896121426Sumeaddr4sort(struct addrinfo *sentinel) 1897121426Sume{ 1898121426Sume struct addrinfo *ai; 1899121426Sume struct addr_ptr *addrs, addr; 1900121426Sume struct sockaddr_in *sin; 1901121426Sume int naddrs, i, j; 1902121426Sume int needsort = 0; 1903121426Sume 1904121426Sume if (!sentinel) 1905121426Sume return -1; 1906121426Sume naddrs = 0; 1907121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 1908121426Sume naddrs++; 1909121426Sume if (naddrs < 2) 1910121426Sume return 0; /* We don't need sorting. */ 1911121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 1912121426Sume return -1; 1913121426Sume i = 0; 1914121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 1915121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 1916121426Sume for (j = 0; (unsigned)j < _res.nsort; j++) { 1917121426Sume if (_res.sort_list[j].addr.s_addr == 1918121426Sume (sin->sin_addr.s_addr & _res.sort_list[j].mask)) 1919121426Sume break; 1920121426Sume } 1921121426Sume addrs[i].ai = ai; 1922121426Sume addrs[i].aval = j; 1923121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 1924121426Sume needsort = i; 1925121426Sume i++; 1926121426Sume } 1927121426Sume if (!needsort) { 1928121426Sume free(addrs); 1929121426Sume return 0; 1930121426Sume } 1931121426Sume 1932121426Sume while (needsort < naddrs) { 1933121426Sume for (j = needsort - 1; j >= 0; j--) { 1934121426Sume if (addrs[j].aval > addrs[j+1].aval) { 1935121426Sume addr = addrs[j]; 1936121426Sume addrs[j] = addrs[j + 1]; 1937121426Sume addrs[j + 1] = addr; 1938121426Sume } else 1939121426Sume break; 1940121426Sume } 1941121426Sume needsort++; 1942121426Sume } 1943121426Sume 1944121426Sume ai = sentinel; 1945121426Sume for (i = 0; i < naddrs; ++i) { 1946121426Sume ai->ai_next = addrs[i].ai; 1947121426Sume ai = ai->ai_next; 1948121426Sume } 1949121426Sume ai->ai_next = NULL; 1950121426Sume free(addrs); 1951121426Sume return 0; 1952121426Sume} 1953121426Sume#endif /*RESOLVSORT*/ 1954121426Sume 195561877Sume/*ARGSUSED*/ 195661877Sumestatic int 195765532Snectar_dns_getaddrinfo(rv, cb_data, ap) 195865532Snectar void *rv; 195965532Snectar void *cb_data; 196065532Snectar va_list ap; 196161877Sume{ 196261877Sume struct addrinfo *ai; 1963103357Sume querybuf *buf, *buf2; 1964130600Sume const char *hostname; 196565532Snectar const struct addrinfo *pai; 196661877Sume struct addrinfo sentinel, *cur; 196761877Sume struct res_target q, q2; 196861877Sume 1969130600Sume hostname = va_arg(ap, char *); 197065532Snectar pai = va_arg(ap, const struct addrinfo *); 197165532Snectar 197261877Sume memset(&q, 0, sizeof(q2)); 197361877Sume memset(&q2, 0, sizeof(q2)); 197461877Sume memset(&sentinel, 0, sizeof(sentinel)); 197561877Sume cur = &sentinel; 197661877Sume 1977103357Sume buf = malloc(sizeof(*buf)); 1978103357Sume if (!buf) { 1979103357Sume h_errno = NETDB_INTERNAL; 1980103357Sume return NS_NOTFOUND; 1981103357Sume } 1982103357Sume buf2 = malloc(sizeof(*buf2)); 1983103357Sume if (!buf2) { 1984103357Sume free(buf); 1985103357Sume h_errno = NETDB_INTERNAL; 1986103357Sume return NS_NOTFOUND; 1987103357Sume } 1988103357Sume 198961877Sume switch (pai->ai_family) { 199061877Sume case AF_UNSPEC: 1991130600Sume q.name = hostname; 199262614Sitojun q.qclass = C_IN; 1993140896Sume q.qtype = T_A; 1994103357Sume q.answer = buf->buf; 1995103357Sume q.anslen = sizeof(buf->buf); 199661877Sume q.next = &q2; 1997130600Sume q2.name = hostname; 199862614Sitojun q2.qclass = C_IN; 1999140896Sume q2.qtype = T_AAAA; 2000103357Sume q2.answer = buf2->buf; 2001103357Sume q2.anslen = sizeof(buf2->buf); 200261877Sume break; 200361877Sume case AF_INET: 2004130600Sume q.name = hostname; 200562614Sitojun q.qclass = C_IN; 200662614Sitojun q.qtype = T_A; 2007103357Sume q.answer = buf->buf; 2008103357Sume q.anslen = sizeof(buf->buf); 200961877Sume break; 201061877Sume case AF_INET6: 2011130600Sume q.name = hostname; 201262614Sitojun q.qclass = C_IN; 201362614Sitojun q.qtype = T_AAAA; 2014103357Sume q.answer = buf->buf; 2015103357Sume q.anslen = sizeof(buf->buf); 201661877Sume break; 201761877Sume default: 2018103357Sume free(buf); 2019103357Sume free(buf2); 202065532Snectar return NS_UNAVAIL; 202161877Sume } 2022130600Sume if (res_searchN(hostname, &q) < 0) { 2023103357Sume free(buf); 2024103357Sume free(buf2); 202565532Snectar return NS_NOTFOUND; 2026103357Sume } 2027140896Sume /* prefer IPv6 */ 202861877Sume if (q.next) { 2029103357Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); 2030140896Sume if (ai) { 203161877Sume cur->ai_next = ai; 2032140896Sume while (cur && cur->ai_next) 2033140896Sume cur = cur->ai_next; 2034140896Sume } 203561877Sume } 2036140896Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai); 2037140896Sume if (ai) 2038140896Sume cur->ai_next = ai; 2039103357Sume free(buf); 2040103357Sume free(buf2); 204161877Sume if (sentinel.ai_next == NULL) 204261877Sume switch (h_errno) { 204361877Sume case HOST_NOT_FOUND: 204465532Snectar return NS_NOTFOUND; 204561877Sume case TRY_AGAIN: 204665532Snectar return NS_TRYAGAIN; 204761877Sume default: 204865532Snectar return NS_UNAVAIL; 204961877Sume } 205065532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 205165532Snectar return NS_SUCCESS; 205261877Sume} 205361877Sume 205465532Snectarstatic void 205565532Snectar_sethtent() 205665532Snectar{ 205765532Snectar if (!hostf) 205865532Snectar hostf = fopen(_PATH_HOSTS, "r" ); 205965532Snectar else 206065532Snectar rewind(hostf); 206165532Snectar} 206265532Snectar 206365532Snectarstatic void 206465532Snectar_endhtent() 206565532Snectar{ 206665532Snectar if (hostf) { 206765532Snectar (void) fclose(hostf); 206865532Snectar hostf = NULL; 206965532Snectar } 207065532Snectar} 207165532Snectar 207261877Sumestatic struct addrinfo * 207365532Snectar_gethtent(name, pai) 207461877Sume const char *name; 207561877Sume const struct addrinfo *pai; 207661877Sume{ 207761877Sume char *p; 207861877Sume char *cp, *tname, *cname; 207961877Sume struct addrinfo hints, *res0, *res; 208061877Sume int error; 208161877Sume const char *addr; 208261877Sume char hostbuf[8*1024]; 208361877Sume 208465532Snectar if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 208565532Snectar return (NULL); 2086105940Sumeagain: 208761877Sume if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 208861877Sume return (NULL); 208961877Sume if (*p == '#') 209061877Sume goto again; 2091139612Ssobomax cp = strpbrk(p, "#\n"); 2092139612Ssobomax if (cp != NULL) 2093139612Ssobomax *cp = '\0'; 209461877Sume if (!(cp = strpbrk(p, " \t"))) 209561877Sume goto again; 209661877Sume *cp++ = '\0'; 209761877Sume addr = p; 209861877Sume cname = NULL; 209961877Sume /* if this is not something we're looking for, skip it. */ 210061877Sume while (cp && *cp) { 210161877Sume if (*cp == ' ' || *cp == '\t') { 210261877Sume cp++; 210361877Sume continue; 210461877Sume } 210561877Sume tname = cp; 210661877Sume if (cname == NULL) 210761877Sume cname = cp; 210861877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 210961877Sume *cp++ = '\0'; 211061877Sume if (strcasecmp(name, tname) == 0) 211161877Sume goto found; 211261877Sume } 211361877Sume goto again; 211461877Sume 211561877Sumefound: 2116105940Sume /* we should not glob socktype/protocol here */ 2117105940Sume memset(&hints, 0, sizeof(hints)); 2118105940Sume hints.ai_family = pai->ai_family; 2119105940Sume hints.ai_socktype = SOCK_DGRAM; 2120105940Sume hints.ai_protocol = 0; 212161877Sume hints.ai_flags = AI_NUMERICHOST; 2122105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 212361877Sume if (error) 212461877Sume goto again; 212561877Sume#ifdef FILTER_V4MAPPED 212661877Sume /* XXX should check all items in the chain */ 212761877Sume if (res0->ai_family == AF_INET6 && 212861877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 212961877Sume freeaddrinfo(res0); 213061877Sume goto again; 213161877Sume } 213261877Sume#endif 213361877Sume for (res = res0; res; res = res->ai_next) { 213461877Sume /* cover it up */ 213561877Sume res->ai_flags = pai->ai_flags; 2136105940Sume res->ai_socktype = pai->ai_socktype; 2137105940Sume res->ai_protocol = pai->ai_protocol; 213861877Sume 213961877Sume if (pai->ai_flags & AI_CANONNAME) { 214061877Sume if (get_canonname(pai, res, cname) != 0) { 214161877Sume freeaddrinfo(res0); 214261877Sume goto again; 214361877Sume } 214461877Sume } 214561877Sume } 214661877Sume return res0; 214761877Sume} 214861877Sume 214961877Sume/*ARGSUSED*/ 215061877Sumestatic int 215165532Snectar_files_getaddrinfo(rv, cb_data, ap) 215265532Snectar void *rv; 215365532Snectar void *cb_data; 215465532Snectar va_list ap; 215565532Snectar{ 215665532Snectar const char *name; 215761877Sume const struct addrinfo *pai; 215861877Sume struct addrinfo sentinel, *cur; 215961877Sume struct addrinfo *p; 216061877Sume 216165532Snectar name = va_arg(ap, char *); 216265532Snectar pai = va_arg(ap, struct addrinfo *); 216365532Snectar 216465532Snectar memset(&sentinel, 0, sizeof(sentinel)); 216561877Sume cur = &sentinel; 216661877Sume 2167126243Sgreen THREAD_LOCK(); 216865532Snectar _sethtent(); 216965532Snectar while ((p = _gethtent(name, pai)) != NULL) { 217061877Sume cur->ai_next = p; 217161877Sume while (cur && cur->ai_next) 217261877Sume cur = cur->ai_next; 217361877Sume } 217465532Snectar _endhtent(); 2175126243Sgreen THREAD_UNLOCK(); 217661877Sume 217765532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 217865532Snectar if (sentinel.ai_next == NULL) 217965532Snectar return NS_NOTFOUND; 218065532Snectar return NS_SUCCESS; 218161877Sume} 218261877Sume 218361877Sume#ifdef YP 218465532Snectarstatic char *__ypdomain; 218565532Snectar 218661877Sume/*ARGSUSED*/ 218765532Snectarstatic struct addrinfo * 218865532Snectar_yphostent(line, pai) 218965532Snectar char *line; 219061877Sume const struct addrinfo *pai; 219161877Sume{ 219261877Sume struct addrinfo sentinel, *cur; 219365532Snectar struct addrinfo hints, *res, *res0; 219461877Sume int error; 219565532Snectar char *p = line; 219665532Snectar const char *addr, *canonname; 219765532Snectar char *nextline; 219865532Snectar char *cp; 219961877Sume 220065532Snectar addr = canonname = NULL; 220165532Snectar 220265532Snectar memset(&sentinel, 0, sizeof(sentinel)); 220361877Sume cur = &sentinel; 220461877Sume 220565532Snectarnextline: 220665532Snectar /* terminate line */ 220765532Snectar cp = strchr(p, '\n'); 220865532Snectar if (cp) { 220965532Snectar *cp++ = '\0'; 221065532Snectar nextline = cp; 221165532Snectar } else 221265532Snectar nextline = NULL; 221361877Sume 221465532Snectar cp = strpbrk(p, " \t"); 221565532Snectar if (cp == NULL) { 221665532Snectar if (canonname == NULL) 221765532Snectar return (NULL); 221865532Snectar else 221965532Snectar goto done; 222061877Sume } 222165532Snectar *cp++ = '\0'; 222261877Sume 222365532Snectar addr = p; 222461877Sume 222565532Snectar while (cp && *cp) { 222665532Snectar if (*cp == ' ' || *cp == '\t') { 222765532Snectar cp++; 222861877Sume continue; 222965532Snectar } 223065532Snectar if (!canonname) 223165532Snectar canonname = cp; 223265532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 223365532Snectar *cp++ = '\0'; 223465532Snectar } 223561877Sume 2236121474Sume hints = *pai; 223765532Snectar hints.ai_flags = AI_NUMERICHOST; 2238121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 223965532Snectar if (error == 0) { 224065532Snectar for (res = res0; res; res = res->ai_next) { 224165532Snectar /* cover it up */ 224265532Snectar res->ai_flags = pai->ai_flags; 224361877Sume 224465532Snectar if (pai->ai_flags & AI_CANONNAME) 224565532Snectar (void)get_canonname(pai, res, canonname); 224661877Sume } 224765532Snectar } else 224865532Snectar res0 = NULL; 224965532Snectar if (res0) { 225065532Snectar cur->ai_next = res0; 225161877Sume while (cur && cur->ai_next) 225261877Sume cur = cur->ai_next; 225361877Sume } 225461877Sume 225565532Snectar if (nextline) { 225665532Snectar p = nextline; 225765532Snectar goto nextline; 225865532Snectar } 225961877Sume 226065532Snectardone: 226165532Snectar return sentinel.ai_next; 226261877Sume} 226365532Snectar 226465532Snectar/*ARGSUSED*/ 226565532Snectarstatic int 226665532Snectar_yp_getaddrinfo(rv, cb_data, ap) 226765532Snectar void *rv; 226865532Snectar void *cb_data; 226965532Snectar va_list ap; 227065532Snectar{ 227165532Snectar struct addrinfo sentinel, *cur; 227265532Snectar struct addrinfo *ai = NULL; 227365532Snectar static char *__ypcurrent; 227465532Snectar int __ypcurrentlen, r; 227565532Snectar const char *name; 227665532Snectar const struct addrinfo *pai; 227765532Snectar 227865532Snectar name = va_arg(ap, char *); 227965532Snectar pai = va_arg(ap, const struct addrinfo *); 228065532Snectar 228165532Snectar memset(&sentinel, 0, sizeof(sentinel)); 228265532Snectar cur = &sentinel; 228365532Snectar 2284126243Sgreen THREAD_LOCK(); 228565532Snectar if (!__ypdomain) { 2286126243Sgreen if (_yp_check(&__ypdomain) == 0) { 2287126243Sgreen THREAD_UNLOCK(); 228865532Snectar return NS_UNAVAIL; 2289126243Sgreen } 229065532Snectar } 229165532Snectar if (__ypcurrent) 229265532Snectar free(__ypcurrent); 229365532Snectar __ypcurrent = NULL; 229465532Snectar 229565532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 229665532Snectar if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 229765532Snectar r = yp_match(__ypdomain, "hosts.byname", name, 229865532Snectar (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 229965532Snectar if (r == 0) { 230065532Snectar struct addrinfo ai4; 230165532Snectar 230265532Snectar ai4 = *pai; 230365532Snectar ai4.ai_family = AF_INET; 230465532Snectar ai = _yphostent(__ypcurrent, &ai4); 230565532Snectar if (ai) { 230665532Snectar cur->ai_next = ai; 230765532Snectar while (cur && cur->ai_next) 230865532Snectar cur = cur->ai_next; 230965532Snectar } 231065532Snectar } 231165532Snectar } 231265532Snectar 231365532Snectar /* ipnodes.byname can hold both IPv4/v6 */ 231465532Snectar r = yp_match(__ypdomain, "ipnodes.byname", name, 231565532Snectar (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 231665532Snectar if (r == 0) { 231765532Snectar ai = _yphostent(__ypcurrent, pai); 231865532Snectar if (ai) { 231965532Snectar cur->ai_next = ai; 232065532Snectar while (cur && cur->ai_next) 232165532Snectar cur = cur->ai_next; 232265532Snectar } 232365532Snectar } 2324126243Sgreen THREAD_UNLOCK(); 232565532Snectar 232665532Snectar if (sentinel.ai_next == NULL) { 232765532Snectar h_errno = HOST_NOT_FOUND; 232865532Snectar return NS_NOTFOUND; 232965532Snectar } 233065532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 233165532Snectar return NS_SUCCESS; 233265532Snectar} 233361877Sume#endif 233461877Sume 233561877Sume/* resolver logic */ 233661877Sume 233792905Sobrienextern const char *__hostalias(const char *); 233861877Sume 233961877Sume/* 234061877Sume * Formulate a normal query, send, and await answer. 234161877Sume * Returned answer is placed in supplied buffer "answer". 234261877Sume * Perform preliminary check of answer, returning success only 234361877Sume * if no error is indicated and the answer count is nonzero. 234461877Sume * Return the size of the response on success, -1 on error. 234561877Sume * Error number is left in h_errno. 234661877Sume * 234761877Sume * Caller must parse answer and determine whether it answers the question. 234861877Sume */ 234961877Sumestatic int 235061877Sumeres_queryN(name, target) 235161877Sume const char *name; /* domain name */ 235261877Sume struct res_target *target; 235361877Sume{ 2354103357Sume u_char *buf; 235561877Sume HEADER *hp; 235661877Sume int n; 235761877Sume struct res_target *t; 235861877Sume int rcode; 235961877Sume int ancount; 236061877Sume 236161877Sume rcode = NOERROR; 236261877Sume ancount = 0; 236361877Sume 236461877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 236561877Sume h_errno = NETDB_INTERNAL; 236661877Sume return (-1); 236761877Sume } 236861877Sume 2369103357Sume buf = malloc(MAXPACKET); 2370103357Sume if (!buf) { 2371103357Sume h_errno = NETDB_INTERNAL; 2372103357Sume return -1; 2373103357Sume } 2374103357Sume 237561877Sume for (t = target; t; t = t->next) { 237661877Sume int class, type; 237761877Sume u_char *answer; 237861877Sume int anslen; 237961877Sume 238061877Sume hp = (HEADER *)(void *)t->answer; 238161877Sume hp->rcode = NOERROR; /* default */ 238261877Sume 238361877Sume /* make it easier... */ 238462614Sitojun class = t->qclass; 238562614Sitojun type = t->qtype; 238661877Sume answer = t->answer; 238761877Sume anslen = t->anslen; 238861877Sume#ifdef DEBUG 238961877Sume if (_res.options & RES_DEBUG) 239061877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 239161877Sume#endif 239261877Sume 239361877Sume n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 2394103357Sume buf, MAXPACKET); 239578012Sume if (n > 0 && (_res.options & RES_USE_EDNS0) != 0) 2396103357Sume n = res_opt(n, buf, MAXPACKET, anslen); 239761877Sume if (n <= 0) { 239861877Sume#ifdef DEBUG 239961877Sume if (_res.options & RES_DEBUG) 240061877Sume printf(";; res_query: mkquery failed\n"); 240161877Sume#endif 2402103357Sume free(buf); 240361877Sume h_errno = NO_RECOVERY; 240461877Sume return (n); 240561877Sume } 240661877Sume n = res_send(buf, n, answer, anslen); 240761877Sume#if 0 240861877Sume if (n < 0) { 240961877Sume#ifdef DEBUG 241061877Sume if (_res.options & RES_DEBUG) 241161877Sume printf(";; res_query: send error\n"); 241261877Sume#endif 2413103357Sume free(buf); 241461877Sume h_errno = TRY_AGAIN; 241561877Sume return (n); 241661877Sume } 241761877Sume#endif 241861877Sume 2419103350Snectar if (n < 0 || n > anslen) 2420103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2421103350Snectar if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 242261877Sume rcode = hp->rcode; /* record most recent error */ 242361877Sume#ifdef DEBUG 242461877Sume if (_res.options & RES_DEBUG) 2425105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 242661877Sume ntohs(hp->ancount)); 242761877Sume#endif 242861877Sume continue; 242961877Sume } 243061877Sume 243161877Sume ancount += ntohs(hp->ancount); 243261877Sume 243361877Sume t->n = n; 243461877Sume } 243561877Sume 2436103357Sume free(buf); 2437103357Sume 243861877Sume if (ancount == 0) { 243961877Sume switch (rcode) { 244061877Sume case NXDOMAIN: 244161877Sume h_errno = HOST_NOT_FOUND; 244261877Sume break; 244361877Sume case SERVFAIL: 244461877Sume h_errno = TRY_AGAIN; 244561877Sume break; 244661877Sume case NOERROR: 244761877Sume h_errno = NO_DATA; 244861877Sume break; 244961877Sume case FORMERR: 245061877Sume case NOTIMP: 245161877Sume case REFUSED: 245261877Sume default: 245361877Sume h_errno = NO_RECOVERY; 245461877Sume break; 245561877Sume } 245661877Sume return (-1); 245761877Sume } 245861877Sume return (ancount); 245961877Sume} 246061877Sume 246161877Sume/* 246261877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 246361877Sume * Return the size of the response on success, -1 on error. 246461877Sume * If enabled, implement search rules until answer or unrecoverable failure 246561877Sume * is detected. Error code, if any, is left in h_errno. 246661877Sume */ 246761877Sumestatic int 246861877Sumeres_searchN(name, target) 246961877Sume const char *name; /* domain name */ 247061877Sume struct res_target *target; 247161877Sume{ 247261877Sume const char *cp, * const *domain; 247361877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 247461877Sume u_int dots; 247561877Sume int trailing_dot, ret, saved_herrno; 247661877Sume int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 247761877Sume 247861877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 247961877Sume h_errno = NETDB_INTERNAL; 248061877Sume return (-1); 248161877Sume } 248261877Sume 248361877Sume errno = 0; 248461877Sume h_errno = HOST_NOT_FOUND; /* default, if we never query */ 248561877Sume dots = 0; 248661877Sume for (cp = name; *cp; cp++) 248761877Sume dots += (*cp == '.'); 248861877Sume trailing_dot = 0; 248961877Sume if (cp > name && *--cp == '.') 249061877Sume trailing_dot++; 249161877Sume 249261877Sume /* 249361877Sume * if there aren't any dots, it could be a user-level alias 249461877Sume */ 249561877Sume if (!dots && (cp = __hostalias(name)) != NULL) 249661877Sume return (res_queryN(cp, target)); 249761877Sume 249861877Sume /* 249961877Sume * If there are dots in the name already, let's just give it a try 250061877Sume * 'as is'. The threshold can be set with the "ndots" option. 250161877Sume */ 250261877Sume saved_herrno = -1; 250361877Sume if (dots >= _res.ndots) { 250461877Sume ret = res_querydomainN(name, NULL, target); 250561877Sume if (ret > 0) 250661877Sume return (ret); 250761877Sume saved_herrno = h_errno; 250861877Sume tried_as_is++; 250961877Sume } 251061877Sume 251161877Sume /* 251261877Sume * We do at least one level of search if 251361877Sume * - there is no dot and RES_DEFNAME is set, or 251461877Sume * - there is at least one dot, there is no trailing dot, 251561877Sume * and RES_DNSRCH is set. 251661877Sume */ 251761877Sume if ((!dots && (_res.options & RES_DEFNAMES)) || 251861877Sume (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 251961877Sume int done = 0; 252061877Sume 252161877Sume for (domain = (const char * const *)_res.dnsrch; 252261877Sume *domain && !done; 252361877Sume domain++) { 252461877Sume 252561877Sume ret = res_querydomainN(name, *domain, target); 252661877Sume if (ret > 0) 252761877Sume return (ret); 252861877Sume 252961877Sume /* 253061877Sume * If no server present, give up. 253161877Sume * If name isn't found in this domain, 253261877Sume * keep trying higher domains in the search list 253361877Sume * (if that's enabled). 253461877Sume * On a NO_DATA error, keep trying, otherwise 253561877Sume * a wildcard entry of another type could keep us 253661877Sume * from finding this entry higher in the domain. 253761877Sume * If we get some other error (negative answer or 253861877Sume * server failure), then stop searching up, 253961877Sume * but try the input name below in case it's 254061877Sume * fully-qualified. 254161877Sume */ 254261877Sume if (errno == ECONNREFUSED) { 254361877Sume h_errno = TRY_AGAIN; 254461877Sume return (-1); 254561877Sume } 254661877Sume 254761877Sume switch (h_errno) { 254861877Sume case NO_DATA: 254961877Sume got_nodata++; 255061877Sume /* FALLTHROUGH */ 255161877Sume case HOST_NOT_FOUND: 255261877Sume /* keep trying */ 255361877Sume break; 255461877Sume case TRY_AGAIN: 255561877Sume if (hp->rcode == SERVFAIL) { 255661877Sume /* try next search element, if any */ 255761877Sume got_servfail++; 255861877Sume break; 255961877Sume } 256061877Sume /* FALLTHROUGH */ 256161877Sume default: 256261877Sume /* anything else implies that we're done */ 256361877Sume done++; 256461877Sume } 256561877Sume /* 256661877Sume * if we got here for some reason other than DNSRCH, 256761877Sume * we only wanted one iteration of the loop, so stop. 256861877Sume */ 256961877Sume if (!(_res.options & RES_DNSRCH)) 257061877Sume done++; 257161877Sume } 257261877Sume } 257361877Sume 257461877Sume /* 257561877Sume * if we have not already tried the name "as is", do that now. 257661877Sume * note that we do this regardless of how many dots were in the 257761877Sume * name or whether it ends with a dot. 257861877Sume */ 257961877Sume if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 258061877Sume ret = res_querydomainN(name, NULL, target); 258161877Sume if (ret > 0) 258261877Sume return (ret); 258361877Sume } 258461877Sume 258561877Sume /* 258661877Sume * if we got here, we didn't satisfy the search. 258761877Sume * if we did an initial full query, return that query's h_errno 258861877Sume * (note that we wouldn't be here if that query had succeeded). 258961877Sume * else if we ever got a nodata, send that back as the reason. 259061877Sume * else send back meaningless h_errno, that being the one from 259161877Sume * the last DNSRCH we did. 259261877Sume */ 259361877Sume if (saved_herrno != -1) 259461877Sume h_errno = saved_herrno; 259561877Sume else if (got_nodata) 259661877Sume h_errno = NO_DATA; 259761877Sume else if (got_servfail) 259861877Sume h_errno = TRY_AGAIN; 259961877Sume return (-1); 260061877Sume} 260161877Sume 260261877Sume/* 260361877Sume * Perform a call on res_query on the concatenation of name and domain, 260461877Sume * removing a trailing dot from name if domain is NULL. 260561877Sume */ 260661877Sumestatic int 260761877Sumeres_querydomainN(name, domain, target) 260861877Sume const char *name, *domain; 260961877Sume struct res_target *target; 261061877Sume{ 261161877Sume char nbuf[MAXDNAME]; 261261877Sume const char *longname = nbuf; 261361877Sume size_t n, d; 261461877Sume 261561877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 261661877Sume h_errno = NETDB_INTERNAL; 261761877Sume return (-1); 261861877Sume } 261961877Sume#ifdef DEBUG 262061877Sume if (_res.options & RES_DEBUG) 262161877Sume printf(";; res_querydomain(%s, %s)\n", 262261877Sume name, domain?domain:"<Nil>"); 262361877Sume#endif 262461877Sume if (domain == NULL) { 262561877Sume /* 262661877Sume * Check for trailing '.'; 262761877Sume * copy without '.' if present. 262861877Sume */ 262961877Sume n = strlen(name); 263061877Sume if (n >= MAXDNAME) { 263161877Sume h_errno = NO_RECOVERY; 263261877Sume return (-1); 263361877Sume } 263461877Sume if (n > 0 && name[--n] == '.') { 263561877Sume strncpy(nbuf, name, n); 263661877Sume nbuf[n] = '\0'; 263761877Sume } else 263861877Sume longname = name; 263961877Sume } else { 264061877Sume n = strlen(name); 264161877Sume d = strlen(domain); 264261877Sume if (n + d + 1 >= MAXDNAME) { 264361877Sume h_errno = NO_RECOVERY; 264461877Sume return (-1); 264561877Sume } 2646105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 264761877Sume } 264861877Sume return (res_queryN(longname, target)); 264961877Sume} 2650