getaddrinfo.c revision 129905
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 129905 2004-05-31 21:09:14Z 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 *, 240121474Sume const char *, struct addrinfo **); 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 551121474Sume error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 55255163Sshin 553121474Sume if (error) 554121474Sume goto free; 555121474Sume 556121474Sume while (cur && cur->ai_next) 557121474Sume cur = cur->ai_next; 55855163Sshin } 55955163Sshin 560121474Sume /* 561121474Sume * XXX 562121474Sume * If numreic representation of AF1 can be interpreted as FQDN 563121474Sume * representation of AF2, we need to think again about the code below. 564121474Sume */ 565121747Sume if (sentinel.ai_next) { 566121747Sume numeric = 1; 567121474Sume goto good; 568121747Sume } 569121474Sume 570121425Sume if (hostname == NULL) 571121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 57255163Sshin if (pai->ai_flags & AI_NUMERICHOST) 57390053Sroam ERR(EAI_NONAME); 57455163Sshin 575121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 576121474Sume ERR(EAI_FAIL); 577121474Sume 57861877Sume /* 57961877Sume * hostname as alphabetical name. 580121474Sume * we would like to prefer AF_INET6 than AF_INET, so we'll make a 581121474Sume * outer loop by AFs. 58261877Sume */ 58361877Sume for (ex = explore; ex->e_af >= 0; ex++) { 58461877Sume *pai = ai0; 58555163Sshin 586121474Sume /* require exact match for family field */ 587121474Sume if (pai->ai_family != ex->e_af) 58861877Sume continue; 58955163Sshin 590121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 591121474Sume WILD_SOCKTYPE(ex))) { 59261877Sume continue; 593121474Sume } 594121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 595121474Sume WILD_PROTOCOL(ex))) { 59661877Sume continue; 597121474Sume } 59855163Sshin 59961877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 60061877Sume pai->ai_socktype = ex->e_socktype; 60161877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 60261877Sume pai->ai_protocol = ex->e_protocol; 60361877Sume 604121474Sume error = explore_fqdn(pai, hostname, servname, 605121474Sume &cur->ai_next); 60661877Sume 60761877Sume while (cur && cur->ai_next) 60861877Sume cur = cur->ai_next; 60955163Sshin } 61055163Sshin 611121747Sume /* XXX inhibit errors if we have the result */ 61261877Sume if (sentinel.ai_next) 61361877Sume error = 0; 61461877Sume 615121747Sumegood: 616121747Sume /* 617121747Sume * ensure we return either: 618121747Sume * - error == 0, non-NULL *res 619121747Sume * - error != 0, NULL *res 620121747Sume */ 62161877Sume if (error == 0) { 62261877Sume if (sentinel.ai_next) { 623121747Sume /* 624121747Sume * If the returned entry is for an active connection, 625121747Sume * and the given name is not numeric, reorder the 626121747Sume * list, so that the application would try the list 627121747Sume * in the most efficient order. 628121747Sume */ 629121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 630121747Sume if (!numeric) 631121747Sume (void)reorder(&sentinel); 632121747Sume } 63361877Sume *res = sentinel.ai_next; 634121474Sume return SUCCESS; 63561877Sume } else 63661877Sume error = EAI_FAIL; 63755163Sshin } 638121747Sumefree: 639121747Sumebad: 640121474Sume if (sentinel.ai_next) 641121474Sume freeaddrinfo(sentinel.ai_next); 642121474Sume *res = NULL; 64355163Sshin return error; 64455163Sshin} 64555163Sshin 646121747Sumestatic int 647121747Sumereorder(sentinel) 648121747Sume struct addrinfo *sentinel; 649121747Sume{ 650121747Sume struct addrinfo *ai, **aip; 651121747Sume struct ai_order *aio; 652121747Sume int i, n; 653121747Sume struct policyhead policyhead; 654121747Sume 655121747Sume /* count the number of addrinfo elements for sorting. */ 656121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 657121747Sume ; 658121747Sume 659121747Sume /* 660121747Sume * If the number is small enough, we can skip the reordering process. 661121747Sume */ 662121747Sume if (n <= 1) 663121747Sume return(n); 664121747Sume 665121747Sume /* allocate a temporary array for sort and initialization of it. */ 666121747Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 667121747Sume return(n); /* give up reordering */ 668121747Sume memset(aio, 0, sizeof(*aio) * n); 669121747Sume 670121747Sume /* retrieve address selection policy from the kernel */ 671121747Sume TAILQ_INIT(&policyhead); 672121747Sume if (!get_addrselectpolicy(&policyhead)) { 673121747Sume /* no policy is installed into kernel, we don't sort. */ 674121747Sume free(aio); 675121747Sume return (n); 676121747Sume } 677121747Sume 678121747Sume for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 679121747Sume aio[i].aio_ai = ai; 680121747Sume aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 681121747Sume aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 682121747Sume &policyhead); 683129901Sume set_source(&aio[i], &policyhead); 684121747Sume } 685121747Sume 686121747Sume /* perform sorting. */ 687121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 688121747Sume 689121747Sume /* reorder the addrinfo chain. */ 690121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 691121747Sume *aip = aio[i].aio_ai; 692121747Sume aip = &aio[i].aio_ai->ai_next; 693121747Sume } 694121747Sume *aip = NULL; 695121747Sume 696121747Sume /* cleanup and return */ 697121747Sume free(aio); 698121747Sume free_addrselectpolicy(&policyhead); 699121747Sume return(n); 700121747Sume} 701121747Sume 702121747Sumestatic int 703121747Sumeget_addrselectpolicy(head) 704121747Sume struct policyhead *head; 705121747Sume{ 706121747Sume#ifdef INET6 707121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 708121747Sume size_t l; 709121747Sume char *buf; 710121747Sume struct in6_addrpolicy *pol, *ep; 711121747Sume 712121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 713121747Sume return (0); 714121747Sume if ((buf = malloc(l)) == NULL) 715121747Sume return (0); 716121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 717121747Sume free(buf); 718121747Sume return (0); 719121747Sume } 720121747Sume 721121747Sume ep = (struct in6_addrpolicy *)(buf + l); 722121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 723121747Sume struct policyqueue *new; 724121747Sume 725121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 726121747Sume free_addrselectpolicy(head); /* make the list empty */ 727121747Sume break; 728121747Sume } 729121747Sume new->pc_policy = *pol; 730121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 731121747Sume } 732121747Sume 733121747Sume free(buf); 734121747Sume return (1); 735121747Sume#else 736121747Sume return (0); 737121747Sume#endif 738121747Sume} 739121747Sume 740121747Sumestatic void 741121747Sumefree_addrselectpolicy(head) 742121747Sume struct policyhead *head; 743121747Sume{ 744121747Sume struct policyqueue *ent, *nent; 745121747Sume 746121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 747121747Sume nent = TAILQ_NEXT(ent, pc_entry); 748121747Sume TAILQ_REMOVE(head, ent, pc_entry); 749121747Sume free(ent); 750121747Sume } 751121747Sume} 752121747Sume 753121747Sumestatic struct policyqueue * 754121747Sumematch_addrselectpolicy(addr, head) 755121747Sume struct sockaddr *addr; 756121747Sume struct policyhead *head; 757121747Sume{ 758121747Sume#ifdef INET6 759121747Sume struct policyqueue *ent, *bestent = NULL; 760121747Sume struct in6_addrpolicy *pol; 761121747Sume int matchlen, bestmatchlen = -1; 762121747Sume u_char *mp, *ep, *k, *p, m; 763121747Sume struct sockaddr_in6 key; 764121747Sume 765121747Sume switch(addr->sa_family) { 766121747Sume case AF_INET6: 767121747Sume key = *(struct sockaddr_in6 *)addr; 768121747Sume break; 769121747Sume case AF_INET: 770121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 771121747Sume memset(&key, 0, sizeof(key)); 772121747Sume key.sin6_family = AF_INET6; 773121747Sume key.sin6_len = sizeof(key); 774121747Sume key.sin6_addr.s6_addr[10] = 0xff; 775121747Sume key.sin6_addr.s6_addr[11] = 0xff; 776121747Sume memcpy(&key.sin6_addr.s6_addr[12], 777121747Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 778121747Sume break; 779121747Sume default: 780121747Sume return(NULL); 781121747Sume } 782121747Sume 783121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 784121747Sume pol = &ent->pc_policy; 785121747Sume matchlen = 0; 786121747Sume 787121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 788121747Sume ep = mp + 16; /* XXX: scope field? */ 789121747Sume k = (u_char *)&key.sin6_addr; 790121747Sume p = (u_char *)&pol->addr.sin6_addr; 791121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 792121747Sume m = *mp; 793121747Sume if ((*k & m) != *p) 794121747Sume goto next; /* not match */ 795121747Sume if (m == 0xff) /* short cut for a typical case */ 796121747Sume matchlen += 8; 797121747Sume else { 798121747Sume while (m >= 0x80) { 799121747Sume matchlen++; 800121747Sume m <<= 1; 801121747Sume } 802121747Sume } 803121747Sume } 804121747Sume 805121747Sume /* matched. check if this is better than the current best. */ 806121747Sume if (matchlen > bestmatchlen) { 807121747Sume bestent = ent; 808121747Sume bestmatchlen = matchlen; 809121747Sume } 810121747Sume 811121747Sume next: 812121747Sume continue; 813121747Sume } 814121747Sume 815121747Sume return(bestent); 816121747Sume#else 817121747Sume return(NULL); 818121747Sume#endif 819121747Sume 820121747Sume} 821121747Sume 822129901Sumestatic void 823129901Sumeset_source(aio, ph) 824129901Sume struct ai_order *aio; 825129901Sume struct policyhead *ph; 826129901Sume{ 827129901Sume struct addrinfo ai = *aio->aio_ai; 828129901Sume struct sockaddr_storage ss; 829129901Sume int s, srclen; 830129901Sume 831129901Sume /* set unspec ("no source is available"), just in case */ 832129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 833129901Sume aio->aio_srcscope = -1; 834129901Sume 835129901Sume switch(ai.ai_family) { 836129901Sume case AF_INET: 837129901Sume#ifdef INET6 838129901Sume case AF_INET6: 839129901Sume#endif 840129901Sume break; 841129901Sume default: /* ignore unsupported AFs explicitly */ 842129901Sume return; 843129901Sume } 844129901Sume 845129901Sume /* XXX: make a dummy addrinfo to call connect() */ 846129901Sume ai.ai_socktype = SOCK_DGRAM; 847129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 848129901Sume ai.ai_next = NULL; 849129901Sume memset(&ss, 0, sizeof(ss)); 850129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 851129901Sume ai.ai_addr = (struct sockaddr *)&ss; 852129901Sume get_port(&ai, "1", 0); 853129901Sume 854129901Sume /* open a socket to get the source address for the given dst */ 855129901Sume if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) 856129901Sume return; /* give up */ 857129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 858129901Sume goto cleanup; 859129901Sume srclen = ai.ai_addrlen; 860129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 861129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 862129901Sume goto cleanup; 863129901Sume } 864129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 865129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 866129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 867129901Sume#ifdef INET6 868129901Sume if (ai.ai_family == AF_INET6) { 869129901Sume struct in6_ifreq ifr6; 870129901Sume u_int32_t flags6; 871129901Sume 872129901Sume /* XXX: interface name should not be hardcoded */ 873129901Sume strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name)); 874129901Sume memset(&ifr6, 0, sizeof(ifr6)); 875129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 876129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 877129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 878129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 879129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 880129901Sume } 881129901Sume } 882129901Sume#endif 883129901Sume 884129901Sume cleanup: 885129901Sume _close(s); 886129901Sume return; 887129901Sume} 888129901Sume 889121747Sumestatic int 890129901Sumematchlen(src, dst) 891129901Sume struct sockaddr *src, *dst; 892129901Sume{ 893129901Sume int match = 0; 894129901Sume u_char *s, *d; 895129901Sume u_char *lim, r; 896129901Sume int addrlen; 897129901Sume 898129901Sume switch (src->sa_family) { 899129901Sume#ifdef INET6 900129901Sume case AF_INET6: 901129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 902129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 903129901Sume addrlen = sizeof(struct in6_addr); 904129901Sume lim = s + addrlen; 905129901Sume break; 906129901Sume#endif 907129901Sume case AF_INET: 908129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 909129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 910129901Sume addrlen = sizeof(struct in_addr); 911129901Sume lim = s + addrlen; 912129901Sume break; 913129901Sume default: 914129901Sume return(0); 915129901Sume } 916129901Sume 917129901Sume while (s < lim) 918129901Sume if ((r = (*d++ ^ *s++)) != 0) { 919129901Sume while (r < addrlen * 8) { 920129901Sume match++; 921129901Sume r <<= 1; 922129901Sume } 923129901Sume break; 924129901Sume } else 925129901Sume match += 8; 926129901Sume return(match); 927129901Sume} 928129901Sume 929129901Sumestatic int 930121747Sumecomp_dst(arg1, arg2) 931121747Sume const void *arg1, *arg2; 932121747Sume{ 933121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 934121747Sume 935121747Sume /* 936121747Sume * Rule 1: Avoid unusable destinations. 937121747Sume * XXX: we currently do not consider if an appropriate route exists. 938121747Sume */ 939121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 940121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 941121747Sume return(-1); 942121747Sume } 943121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 944121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 945121747Sume return(1); 946121747Sume } 947121747Sume 948121747Sume /* Rule 2: Prefer matching scope. */ 949121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 950121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 951121747Sume return(-1); 952121747Sume } 953121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 954121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 955121747Sume return(1); 956121747Sume } 957121747Sume 958121747Sume /* Rule 3: Avoid deprecated addresses. */ 959121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 960121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 961121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 962121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 963121747Sume return(-1); 964121747Sume } 965121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 966121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 967121747Sume return(1); 968121747Sume } 969121747Sume } 970121747Sume 971121747Sume /* Rule 4: Prefer home addresses. */ 972121747Sume /* XXX: not implemented yet */ 973121747Sume 974121747Sume /* Rule 5: Prefer matching label. */ 975121747Sume#ifdef INET6 976121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 977121747Sume dst1->aio_srcpolicy->pc_policy.label == 978121747Sume dst1->aio_dstpolicy->pc_policy.label && 979121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 980121747Sume dst2->aio_srcpolicy->pc_policy.label != 981121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 982121747Sume return(-1); 983121747Sume } 984121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 985121747Sume dst2->aio_srcpolicy->pc_policy.label == 986121747Sume dst2->aio_dstpolicy->pc_policy.label && 987121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 988121747Sume dst1->aio_srcpolicy->pc_policy.label != 989121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 990121747Sume return(1); 991121747Sume } 992121747Sume#endif 993121747Sume 994121747Sume /* Rule 6: Prefer higher precedence. */ 995121747Sume#ifdef INET6 996121747Sume if (dst1->aio_dstpolicy && 997121747Sume (dst2->aio_dstpolicy == NULL || 998121747Sume dst1->aio_dstpolicy->pc_policy.preced > 999121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 1000121747Sume return(-1); 1001121747Sume } 1002121747Sume if (dst2->aio_dstpolicy && 1003121747Sume (dst1->aio_dstpolicy == NULL || 1004121747Sume dst2->aio_dstpolicy->pc_policy.preced > 1005121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 1006121747Sume return(1); 1007121747Sume } 1008121747Sume#endif 1009121747Sume 1010121747Sume /* Rule 7: Prefer native transport. */ 1011121747Sume /* XXX: not implemented yet */ 1012121747Sume 1013121747Sume /* Rule 8: Prefer smaller scope. */ 1014121747Sume if (dst1->aio_dstscope >= 0 && 1015121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 1016121747Sume return(-1); 1017121747Sume } 1018121747Sume if (dst2->aio_dstscope >= 0 && 1019121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 1020121747Sume return(1); 1021121747Sume } 1022121747Sume 1023121747Sume /* 1024121747Sume * Rule 9: Use longest matching prefix. 1025121747Sume * We compare the match length in a same AF only. 1026121747Sume */ 1027121747Sume if (dst1->aio_ai->ai_addr->sa_family == 1028121747Sume dst2->aio_ai->ai_addr->sa_family) { 1029121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 1030121747Sume return(-1); 1031121747Sume } 1032121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 1033121747Sume return(1); 1034121747Sume } 1035121747Sume } 1036121747Sume 1037121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 1038121747Sume return(-1); 1039121747Sume} 1040121747Sume 104155163Sshin/* 1042121747Sume * Copy from scope.c. 1043121747Sume * XXX: we should standardize the functions and link them as standard 1044121747Sume * library. 1045121747Sume */ 1046121747Sumestatic int 1047121747Sumegai_addr2scopetype(sa) 1048121747Sume struct sockaddr *sa; 1049121747Sume{ 1050121747Sume#ifdef INET6 1051121747Sume struct sockaddr_in6 *sa6; 1052121747Sume#endif 1053121747Sume struct sockaddr_in *sa4; 1054121747Sume 1055121747Sume switch(sa->sa_family) { 1056121747Sume#ifdef INET6 1057121747Sume case AF_INET6: 1058121747Sume sa6 = (struct sockaddr_in6 *)sa; 1059121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1060121747Sume /* just use the scope field of the multicast address */ 1061121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1062121747Sume } 1063121747Sume /* 1064121747Sume * Unicast addresses: map scope type to corresponding scope 1065121747Sume * value defined for multcast addresses. 1066121747Sume * XXX: hardcoded scope type values are bad... 1067121747Sume */ 1068121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1069121747Sume return(1); /* node local scope */ 1070121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1071121747Sume return(2); /* link-local scope */ 1072121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1073121747Sume return(5); /* site-local scope */ 1074121747Sume return(14); /* global scope */ 1075121747Sume break; 1076121747Sume#endif 1077121747Sume case AF_INET: 1078121747Sume /* 1079121747Sume * IPv4 pseudo scoping according to RFC 3484. 1080121747Sume */ 1081121747Sume sa4 = (struct sockaddr_in *)sa; 1082121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1083121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1084121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1085121747Sume return(2); 1086121747Sume /* Private addresses have site-local scope. */ 1087121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1088121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1089121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1090121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1091121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1092129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1093121747Sume /* Loopback addresses have link-local scope. */ 1094121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1095121747Sume return(2); 1096121747Sume return(14); 1097121747Sume break; 1098121747Sume default: 1099121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1100121747Sume return(-1); 1101121747Sume } 1102121747Sume} 1103121747Sume 1104121747Sume/* 110555163Sshin * hostname == NULL. 110655163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 110755163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 110855163Sshin */ 110955163Sshinstatic int 111061877Sumeexplore_null(pai, servname, res) 111155163Sshin const struct addrinfo *pai; 111255163Sshin const char *servname; 111355163Sshin struct addrinfo **res; 111455163Sshin{ 1115121474Sume int s; 111655163Sshin const struct afd *afd; 111755163Sshin struct addrinfo *cur; 111855163Sshin struct addrinfo sentinel; 111955163Sshin int error; 112055163Sshin 112155163Sshin *res = NULL; 112255163Sshin sentinel.ai_next = NULL; 112355163Sshin cur = &sentinel; 112455163Sshin 112555163Sshin /* 1126121474Sume * filter out AFs that are not supported by the kernel 1127121474Sume * XXX errno? 1128121474Sume */ 1129121474Sume s = _socket(pai->ai_family, SOCK_DGRAM, 0); 1130121474Sume if (s < 0) { 1131121474Sume if (errno != EMFILE) 1132121474Sume return 0; 1133121474Sume } else 1134121474Sume _close(s); 1135121474Sume 1136121474Sume /* 113761877Sume * if the servname does not match socktype/protocol, ignore it. 113861877Sume */ 113961877Sume if (get_portmatch(pai, servname) != 0) 114055163Sshin return 0; 114161877Sume 114255163Sshin afd = find_afd(pai->ai_family); 114355163Sshin if (afd == NULL) 114455163Sshin return 0; 114555163Sshin 114661877Sume if (pai->ai_flags & AI_PASSIVE) { 114761877Sume GET_AI(cur->ai_next, afd, afd->a_addrany); 114861877Sume /* xxx meaningless? 114961877Sume * GET_CANONNAME(cur->ai_next, "anyaddr"); 115061877Sume */ 115161877Sume GET_PORT(cur->ai_next, servname); 115261877Sume } else { 115361877Sume GET_AI(cur->ai_next, afd, afd->a_loopback); 115461877Sume /* xxx meaningless? 115561877Sume * GET_CANONNAME(cur->ai_next, "localhost"); 115661877Sume */ 115761877Sume GET_PORT(cur->ai_next, servname); 115861877Sume } 115961877Sume cur = cur->ai_next; 116055163Sshin 116155163Sshin *res = sentinel.ai_next; 116255163Sshin return 0; 116355163Sshin 116455163Sshinfree: 116555163Sshin if (sentinel.ai_next) 116655163Sshin freeaddrinfo(sentinel.ai_next); 116755163Sshin return error; 116855163Sshin} 116955163Sshin 117055163Sshin/* 117155163Sshin * numeric hostname 117255163Sshin */ 117355163Sshinstatic int 1174121474Sumeexplore_numeric(pai, hostname, servname, res) 117555163Sshin const struct addrinfo *pai; 117655163Sshin const char *hostname; 117755163Sshin const char *servname; 117855163Sshin struct addrinfo **res; 117955163Sshin{ 118055163Sshin const struct afd *afd; 118155163Sshin struct addrinfo *cur; 118255163Sshin struct addrinfo sentinel; 118355163Sshin int error; 118455163Sshin char pton[PTON_MAX]; 118555163Sshin 118655163Sshin *res = NULL; 118755163Sshin sentinel.ai_next = NULL; 118855163Sshin cur = &sentinel; 118955163Sshin 1190121474Sume /* 1191121474Sume * if the servname does not match socktype/protocol, ignore it. 1192121474Sume */ 1193121474Sume if (get_portmatch(pai, servname) != 0) 1194121474Sume return 0; 1195121474Sume 119655163Sshin afd = find_afd(pai->ai_family); 119755163Sshin if (afd == NULL) 119855163Sshin return 0; 119955163Sshin 120062614Sitojun switch (afd->a_af) { 120162614Sitojun#if 1 /*X/Open spec*/ 120262614Sitojun case AF_INET: 120362614Sitojun if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 120462614Sitojun if (pai->ai_family == afd->a_af || 120562614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 120662614Sitojun GET_AI(cur->ai_next, afd, pton); 120762614Sitojun GET_PORT(cur->ai_next, servname); 120862614Sitojun while (cur && cur->ai_next) 120962614Sitojun cur = cur->ai_next; 121062614Sitojun } else 121162614Sitojun ERR(EAI_FAMILY); /*xxx*/ 121262614Sitojun } 121362614Sitojun break; 121462614Sitojun#endif 121562614Sitojun default: 121662614Sitojun if (inet_pton(afd->a_af, hostname, pton) == 1) { 121762614Sitojun if (pai->ai_family == afd->a_af || 121862614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 121962614Sitojun GET_AI(cur->ai_next, afd, pton); 122062614Sitojun GET_PORT(cur->ai_next, servname); 122162614Sitojun while (cur && cur->ai_next) 122262614Sitojun cur = cur->ai_next; 122362614Sitojun } else 1224105940Sume ERR(EAI_FAMILY); /* XXX */ 122562614Sitojun } 122662614Sitojun break; 122755163Sshin } 122855163Sshin 122955163Sshin *res = sentinel.ai_next; 123055163Sshin return 0; 123155163Sshin 123255163Sshinfree: 123355163Sshinbad: 123455163Sshin if (sentinel.ai_next) 123555163Sshin freeaddrinfo(sentinel.ai_next); 123655163Sshin return error; 123755163Sshin} 123855163Sshin 123955163Sshin/* 124055163Sshin * numeric hostname with scope 124155163Sshin */ 124255163Sshinstatic int 124355163Sshinexplore_numeric_scope(pai, hostname, servname, res) 124455163Sshin const struct addrinfo *pai; 124555163Sshin const char *hostname; 124655163Sshin const char *servname; 124755163Sshin struct addrinfo **res; 124855163Sshin{ 124961877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1250121474Sume return explore_numeric(pai, hostname, servname, res); 125155163Sshin#else 125255163Sshin const struct afd *afd; 125355163Sshin struct addrinfo *cur; 125455163Sshin int error; 125561877Sume char *cp, *hostname2 = NULL, *scope, *addr; 125655163Sshin struct sockaddr_in6 *sin6; 125755163Sshin 1258121474Sume /* 1259121474Sume * if the servname does not match socktype/protocol, ignore it. 1260121474Sume */ 1261121474Sume if (get_portmatch(pai, servname) != 0) 1262121474Sume return 0; 1263121474Sume 126455163Sshin afd = find_afd(pai->ai_family); 126555163Sshin if (afd == NULL) 126655163Sshin return 0; 126765532Snectar 126855163Sshin if (!afd->a_scoped) 1269121474Sume return explore_numeric(pai, hostname, servname, res); 127055163Sshin 127155163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 127255163Sshin if (cp == NULL) 1273121474Sume return explore_numeric(pai, hostname, servname, res); 127455163Sshin 127555163Sshin /* 127655163Sshin * Handle special case of <scoped_address><delimiter><scope id> 127755163Sshin */ 127855163Sshin hostname2 = strdup(hostname); 127955163Sshin if (hostname2 == NULL) 128055163Sshin return EAI_MEMORY; 128155163Sshin /* terminate at the delimiter */ 128255163Sshin hostname2[cp - hostname] = '\0'; 128361877Sume addr = hostname2; 128461877Sume scope = cp + 1; 128555163Sshin 1286121474Sume error = explore_numeric(pai, addr, servname, res); 128761877Sume if (error == 0) { 1288105943Sume u_int32_t scopeid; 128955163Sshin 129055163Sshin for (cur = *res; cur; cur = cur->ai_next) { 129155163Sshin if (cur->ai_family != AF_INET6) 129255163Sshin continue; 129361877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1294105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 129561877Sume free(hostname2); 1296121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 129761877Sume } 129861877Sume sin6->sin6_scope_id = scopeid; 129955163Sshin } 130055163Sshin } 130155163Sshin 130255163Sshin free(hostname2); 130355163Sshin 130455163Sshin return error; 130555163Sshin#endif 130655163Sshin} 130755163Sshin 130855163Sshinstatic int 130955163Sshinget_canonname(pai, ai, str) 131055163Sshin const struct addrinfo *pai; 131155163Sshin struct addrinfo *ai; 131255163Sshin const char *str; 131355163Sshin{ 131455163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1315121474Sume ai->ai_canonname = (char *)malloc(strlen(str) + 1); 131655163Sshin if (ai->ai_canonname == NULL) 131755163Sshin return EAI_MEMORY; 1318121474Sume strlcpy(ai->ai_canonname, str, strlen(str) + 1); 131955163Sshin } 132055163Sshin return 0; 132155163Sshin} 132255163Sshin 132355163Sshinstatic struct addrinfo * 132455163Sshinget_ai(pai, afd, addr) 132555163Sshin const struct addrinfo *pai; 132655163Sshin const struct afd *afd; 132755163Sshin const char *addr; 132855163Sshin{ 132955163Sshin char *p; 133055163Sshin struct addrinfo *ai; 133155163Sshin#ifdef FAITH 133255163Sshin struct in6_addr faith_prefix; 133355163Sshin char *fp_str; 133455163Sshin int translate = 0; 133555163Sshin#endif 133655163Sshin 133755163Sshin#ifdef FAITH 133855163Sshin /* 133955163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 134055163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 134155163Sshin * 134255163Sshin * +-----------------------------------+------------+ 134355163Sshin * | faith prefix part (12 bytes) | embedded | 134455163Sshin * | | IPv4 addr part (4 bytes) 134555163Sshin * +-----------------------------------+------------+ 134655163Sshin * 134755163Sshin * faith prefix part is specified as ascii IPv6 addr format 134855163Sshin * in environmental variable GAI. 134955163Sshin * For FAITH to work correctly, routing to faith prefix must be 135055163Sshin * setup toward a machine where a FAITH daemon operates. 135155163Sshin * Also, the machine must enable some mechanizm 135255163Sshin * (e.g. faith interface hack) to divert those packet with 135355163Sshin * faith prefixed destination addr to user-land FAITH daemon. 135455163Sshin */ 135555163Sshin fp_str = getenv("GAI"); 135655163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 135755163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 135855163Sshin u_int32_t v4a; 135955163Sshin u_int8_t v4a_top; 136055163Sshin 136155163Sshin memcpy(&v4a, addr, sizeof v4a); 136255163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 136355163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 136455163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 136555163Sshin afd = &afdl[N_INET6]; 136655163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 136755163Sshin sizeof(struct in_addr)); 136855163Sshin translate = 1; 136955163Sshin } 137055163Sshin } 137155163Sshin#endif 137255163Sshin 137355163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 137455163Sshin + (afd->a_socklen)); 137555163Sshin if (ai == NULL) 137655163Sshin return NULL; 137755163Sshin 137855163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 137961877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 138061877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 138155163Sshin ai->ai_addr->sa_len = afd->a_socklen; 138255163Sshin ai->ai_addrlen = afd->a_socklen; 138355163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 138465532Snectar p = (char *)(void *)(ai->ai_addr); 138555163Sshin#ifdef FAITH 138655163Sshin if (translate == 1) 138765532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 138855163Sshin else 138955163Sshin#endif 139065532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 139155163Sshin return ai; 139255163Sshin} 139355163Sshin 139455163Sshinstatic int 139555163Sshinget_portmatch(ai, servname) 139655163Sshin const struct addrinfo *ai; 139755163Sshin const char *servname; 139855163Sshin{ 139961877Sume 140055163Sshin /* get_port does not touch first argument. when matchonly == 1. */ 140161877Sume /* LINTED const cast */ 140255163Sshin return get_port((struct addrinfo *)ai, servname, 1); 140355163Sshin} 140455163Sshin 140555163Sshinstatic int 140655163Sshinget_port(ai, servname, matchonly) 140755163Sshin struct addrinfo *ai; 140855163Sshin const char *servname; 140955163Sshin int matchonly; 141055163Sshin{ 141155163Sshin const char *proto; 141255163Sshin struct servent *sp; 141355163Sshin int port; 141455163Sshin int allownumeric; 141555163Sshin 141655163Sshin if (servname == NULL) 141755163Sshin return 0; 141861877Sume switch (ai->ai_family) { 141961877Sume case AF_INET: 142061877Sume#ifdef AF_INET6 142161877Sume case AF_INET6: 142255163Sshin#endif 142361877Sume break; 142461877Sume default: 142555163Sshin return 0; 142661877Sume } 142755163Sshin 142855163Sshin switch (ai->ai_socktype) { 142955163Sshin case SOCK_RAW: 143055163Sshin return EAI_SERVICE; 143155163Sshin case SOCK_DGRAM: 143255163Sshin case SOCK_STREAM: 143355163Sshin allownumeric = 1; 143455163Sshin break; 143555163Sshin case ANY: 143655163Sshin allownumeric = 0; 143755163Sshin break; 143855163Sshin default: 143955163Sshin return EAI_SOCKTYPE; 144055163Sshin } 144155163Sshin 144255163Sshin if (str_isnumber(servname)) { 144355163Sshin if (!allownumeric) 144455163Sshin return EAI_SERVICE; 1445105940Sume port = atoi(servname); 144655163Sshin if (port < 0 || port > 65535) 144755163Sshin return EAI_SERVICE; 1448105940Sume port = htons(port); 144955163Sshin } else { 1450121474Sume switch (ai->ai_socktype) { 1451121474Sume case SOCK_DGRAM: 145255163Sshin proto = "udp"; 145355163Sshin break; 1454121474Sume case SOCK_STREAM: 145555163Sshin proto = "tcp"; 145655163Sshin break; 145755163Sshin default: 145855163Sshin proto = NULL; 145955163Sshin break; 146055163Sshin } 146155163Sshin 1462126243Sgreen THREAD_LOCK(); 1463126243Sgreen if ((sp = getservbyname(servname, proto)) == NULL) { 1464126243Sgreen THREAD_UNLOCK(); 146555163Sshin return EAI_SERVICE; 1466126243Sgreen } 146755163Sshin port = sp->s_port; 1468126243Sgreen THREAD_UNLOCK(); 146955163Sshin } 147055163Sshin 147155163Sshin if (!matchonly) { 147255163Sshin switch (ai->ai_family) { 147355163Sshin case AF_INET: 147461877Sume ((struct sockaddr_in *)(void *) 147561877Sume ai->ai_addr)->sin_port = port; 147655163Sshin break; 147755163Sshin#ifdef INET6 147855163Sshin case AF_INET6: 147961877Sume ((struct sockaddr_in6 *)(void *) 148061877Sume ai->ai_addr)->sin6_port = port; 148155163Sshin break; 148255163Sshin#endif 148355163Sshin } 148455163Sshin } 148555163Sshin 148655163Sshin return 0; 148755163Sshin} 148855163Sshin 148955163Sshinstatic const struct afd * 149055163Sshinfind_afd(af) 149155163Sshin int af; 149255163Sshin{ 149355163Sshin const struct afd *afd; 149455163Sshin 149555163Sshin if (af == PF_UNSPEC) 149655163Sshin return NULL; 149755163Sshin for (afd = afdl; afd->a_af; afd++) { 149855163Sshin if (afd->a_af == af) 149955163Sshin return afd; 150055163Sshin } 150155163Sshin return NULL; 150255163Sshin} 150361877Sume 150461877Sume/* 150561877Sume * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 150661877Sume * will take care of it. 150761877Sume * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 150861877Sume * if the code is right or not. 1509121474Sume * 1510121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1511121474Sume * _dns_getaddrinfo. 151261877Sume */ 151361877Sumestatic int 1514121474Sumeaddrconfig(pai) 1515121474Sume struct addrinfo *pai; 151661877Sume{ 1517121474Sume int s, af; 151861877Sume 1519121474Sume /* 1520121474Sume * TODO: 1521121474Sume * Note that implementation dependent test for address 1522121474Sume * configuration should be done everytime called 1523121474Sume * (or apropriate interval), 1524121474Sume * because addresses will be dynamically assigned or deleted. 1525121474Sume */ 1526121474Sume af = pai->ai_family; 1527121474Sume if (af == AF_UNSPEC) { 1528121474Sume if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1529121474Sume af = AF_INET; 1530121474Sume else { 1531121474Sume _close(s); 1532121474Sume if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1533121474Sume af = AF_INET6; 1534121474Sume else 1535121474Sume _close(s); 1536121474Sume } 1537121474Sume } 1538121474Sume if (af != AF_UNSPEC) { 1539121474Sume if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 154061877Sume return 0; 1541121474Sume _close(s); 1542121474Sume } 1543121474Sume pai->ai_family = af; 154461877Sume return 1; 154561877Sume} 154661877Sume 154761877Sume#ifdef INET6 154861877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 154961877Sumestatic int 1550105943Sumeip6_str2scopeid(scope, sin6, scopeid) 155161877Sume char *scope; 155261877Sume struct sockaddr_in6 *sin6; 1553105943Sume u_int32_t *scopeid; 155461877Sume{ 1555105943Sume u_long lscopeid; 1556121474Sume struct in6_addr *a6; 155761877Sume char *ep; 155861877Sume 1559121474Sume a6 = &sin6->sin6_addr; 1560121474Sume 156162836Sitojun /* empty scopeid portion is invalid */ 156262836Sitojun if (*scope == '\0') 156362836Sitojun return -1; 156462836Sitojun 1565121474Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 156661877Sume /* 156761877Sume * We currently assume a one-to-one mapping between links 156861877Sume * and interfaces, so we simply use interface indices for 156961877Sume * like-local scopes. 157061877Sume */ 1571105943Sume *scopeid = if_nametoindex(scope); 1572105943Sume if (*scopeid == 0) 157361877Sume goto trynumeric; 1574105943Sume return 0; 157561877Sume } 157661877Sume 157761877Sume /* still unclear about literal, allow numeric only - placeholder */ 157861877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 157961877Sume goto trynumeric; 158061877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 158161877Sume goto trynumeric; 158261877Sume else 158361877Sume goto trynumeric; /* global */ 158461877Sume 158561877Sume /* try to convert to a numeric id as a last resort */ 1586121474Sume trynumeric: 1587105943Sume errno = 0; 1588105943Sume lscopeid = strtoul(scope, &ep, 10); 1589105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1590105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1591105943Sume return 0; 159261877Sume else 159361877Sume return -1; 159461877Sume} 159561877Sume#endif 159661877Sume 1597121426Sume/* 1598121426Sume * FQDN hostname, DNS lookup 1599121426Sume */ 1600102237Spirzykstatic int 1601121426Sumeexplore_fqdn(pai, hostname, servname, res) 1602121426Sume const struct addrinfo *pai; 1603121426Sume const char *hostname; 1604121426Sume const char *servname; 1605121426Sume struct addrinfo **res; 1606102237Spirzyk{ 1607121426Sume struct addrinfo *result; 1608121426Sume struct addrinfo *cur; 1609121426Sume int error = 0; 1610121426Sume static const ns_dtab dtab[] = { 1611121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1612121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1613121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1614121426Sume { 0 } 1615121426Sume }; 1616102237Spirzyk 1617121426Sume result = NULL; 1618121426Sume 1619121426Sume /* 1620121426Sume * if the servname does not match socktype/protocol, ignore it. 1621121426Sume */ 1622126243Sgreen if (get_portmatch(pai, servname) != 0) 1623102237Spirzyk return 0; 1624102237Spirzyk 1625121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1626121426Sume default_dns_files, hostname, pai)) { 1627121426Sume case NS_TRYAGAIN: 1628121426Sume error = EAI_AGAIN; 1629121426Sume goto free; 1630121426Sume case NS_UNAVAIL: 1631121426Sume error = EAI_FAIL; 1632121426Sume goto free; 1633121426Sume case NS_NOTFOUND: 1634121426Sume error = EAI_NONAME; 1635121426Sume goto free; 1636121426Sume case NS_SUCCESS: 1637121426Sume error = 0; 1638121426Sume for (cur = result; cur; cur = cur->ai_next) { 1639121426Sume GET_PORT(cur, servname); 1640121426Sume /* canonname should be filled already */ 1641121426Sume } 1642121426Sume break; 1643102237Spirzyk } 1644102237Spirzyk 1645121426Sume *res = result; 1646121426Sume 1647102237Spirzyk return 0; 1648121426Sume 1649121426Sumefree: 1650121426Sume if (result) 1651121426Sume freeaddrinfo(result); 1652121426Sume return error; 1653102237Spirzyk} 1654102237Spirzyk 165561877Sume#ifdef DEBUG 165661877Sumestatic const char AskedForGot[] = 165761877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 165861877Sume#endif 165965532Snectarstatic FILE *hostf = NULL; 166061877Sume 166161877Sumestatic struct addrinfo * 166261877Sumegetanswer(answer, anslen, qname, qtype, pai) 166361877Sume const querybuf *answer; 166461877Sume int anslen; 166561877Sume const char *qname; 166661877Sume int qtype; 166761877Sume const struct addrinfo *pai; 166861877Sume{ 166961877Sume struct addrinfo sentinel, *cur; 167061877Sume struct addrinfo ai; 167161877Sume const struct afd *afd; 167261877Sume char *canonname; 167361877Sume const HEADER *hp; 167461877Sume const u_char *cp; 167561877Sume int n; 167661877Sume const u_char *eom; 1677105940Sume char *bp, *ep; 1678105940Sume int type, class, ancount, qdcount; 167961877Sume int haveanswer, had_error; 168061877Sume char tbuf[MAXDNAME]; 168192905Sobrien int (*name_ok)(const char *); 168261877Sume char hostbuf[8*1024]; 168361877Sume 168461877Sume memset(&sentinel, 0, sizeof(sentinel)); 168561877Sume cur = &sentinel; 168661877Sume 168761877Sume canonname = NULL; 168861877Sume eom = answer->buf + anslen; 168961877Sume switch (qtype) { 169061877Sume case T_A: 169161877Sume case T_AAAA: 169261877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 169361877Sume name_ok = res_hnok; 169461877Sume break; 169561877Sume default: 169661877Sume return (NULL); /* XXX should be abort(); */ 169761877Sume } 169861877Sume /* 169961877Sume * find first satisfactory answer 170061877Sume */ 170161877Sume hp = &answer->hdr; 170261877Sume ancount = ntohs(hp->ancount); 170361877Sume qdcount = ntohs(hp->qdcount); 170461877Sume bp = hostbuf; 1705105940Sume ep = hostbuf + sizeof hostbuf; 170661877Sume cp = answer->buf + HFIXEDSZ; 170761877Sume if (qdcount != 1) { 170861877Sume h_errno = NO_RECOVERY; 170961877Sume return (NULL); 171061877Sume } 1711105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 171261877Sume if ((n < 0) || !(*name_ok)(bp)) { 171361877Sume h_errno = NO_RECOVERY; 171461877Sume return (NULL); 171561877Sume } 171661877Sume cp += n + QFIXEDSZ; 171761877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 171861877Sume /* res_send() has already verified that the query name is the 171961877Sume * same as the one we sent; this just gets the expanded name 172061877Sume * (i.e., with the succeeding search-domain tacked on). 172161877Sume */ 172261877Sume n = strlen(bp) + 1; /* for the \0 */ 172361877Sume if (n >= MAXHOSTNAMELEN) { 172461877Sume h_errno = NO_RECOVERY; 172561877Sume return (NULL); 172661877Sume } 172761877Sume canonname = bp; 172861877Sume bp += n; 172961877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 173061877Sume qname = canonname; 173161877Sume } 173261877Sume haveanswer = 0; 173361877Sume had_error = 0; 173461877Sume while (ancount-- > 0 && cp < eom && !had_error) { 1735105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 173661877Sume if ((n < 0) || !(*name_ok)(bp)) { 173761877Sume had_error++; 173861877Sume continue; 173961877Sume } 174061877Sume cp += n; /* name */ 174161877Sume type = _getshort(cp); 174261877Sume cp += INT16SZ; /* type */ 174361877Sume class = _getshort(cp); 174461877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 174561877Sume n = _getshort(cp); 174661877Sume cp += INT16SZ; /* len */ 174761877Sume if (class != C_IN) { 174861877Sume /* XXX - debug? syslog? */ 174961877Sume cp += n; 175061877Sume continue; /* XXX - had_error++ ? */ 175161877Sume } 175261877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 175361877Sume type == T_CNAME) { 175461877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 175561877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 175661877Sume had_error++; 175761877Sume continue; 175861877Sume } 175961877Sume cp += n; 176061877Sume /* Get canonical name. */ 176161877Sume n = strlen(tbuf) + 1; /* for the \0 */ 1762105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 176361877Sume had_error++; 176461877Sume continue; 176561877Sume } 1766114443Snectar strlcpy(bp, tbuf, ep - bp); 176761877Sume canonname = bp; 176861877Sume bp += n; 176961877Sume continue; 177061877Sume } 177161877Sume if (qtype == T_ANY) { 177261877Sume if (!(type == T_A || type == T_AAAA)) { 177361877Sume cp += n; 177461877Sume continue; 177561877Sume } 177661877Sume } else if (type != qtype) { 177761877Sume#ifdef DEBUG 177861877Sume if (type != T_KEY && type != T_SIG) 177961877Sume syslog(LOG_NOTICE|LOG_AUTH, 178061877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 178161877Sume qname, p_class(C_IN), p_type(qtype), 178261877Sume p_type(type)); 178361877Sume#endif 178461877Sume cp += n; 178561877Sume continue; /* XXX - had_error++ ? */ 178661877Sume } 178761877Sume switch (type) { 178861877Sume case T_A: 178961877Sume case T_AAAA: 179061877Sume if (strcasecmp(canonname, bp) != 0) { 179161877Sume#ifdef DEBUG 179261877Sume syslog(LOG_NOTICE|LOG_AUTH, 179361877Sume AskedForGot, canonname, bp); 179461877Sume#endif 179561877Sume cp += n; 179661877Sume continue; /* XXX - had_error++ ? */ 179761877Sume } 179861877Sume if (type == T_A && n != INADDRSZ) { 179961877Sume cp += n; 180061877Sume continue; 180161877Sume } 180261877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 180361877Sume cp += n; 180461877Sume continue; 180561877Sume } 180661877Sume#ifdef FILTER_V4MAPPED 180761877Sume if (type == T_AAAA) { 180861877Sume struct in6_addr in6; 180961877Sume memcpy(&in6, cp, sizeof(in6)); 181061877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 181161877Sume cp += n; 181261877Sume continue; 181361877Sume } 181461877Sume } 181561877Sume#endif 181661877Sume if (!haveanswer) { 181761877Sume int nn; 181861877Sume 181961877Sume canonname = bp; 182061877Sume nn = strlen(bp) + 1; /* for the \0 */ 182161877Sume bp += nn; 182261877Sume } 182361877Sume 182461877Sume /* don't overwrite pai */ 182561877Sume ai = *pai; 182661877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 182761877Sume afd = find_afd(ai.ai_family); 182861877Sume if (afd == NULL) { 182961877Sume cp += n; 183061877Sume continue; 183161877Sume } 183261877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 183361877Sume if (cur->ai_next == NULL) 183461877Sume had_error++; 183561877Sume while (cur && cur->ai_next) 183661877Sume cur = cur->ai_next; 183761877Sume cp += n; 183861877Sume break; 183961877Sume default: 184061877Sume abort(); 184161877Sume } 184261877Sume if (!had_error) 184361877Sume haveanswer++; 184461877Sume } 184561877Sume if (haveanswer) { 1846102237Spirzyk#if defined(RESOLVSORT) 1847102237Spirzyk /* 1848102237Spirzyk * We support only IPv4 address for backward 1849102237Spirzyk * compatibility against gethostbyname(3). 1850102237Spirzyk */ 1851102237Spirzyk if (_res.nsort && qtype == T_A) { 1852102237Spirzyk if (addr4sort(&sentinel) < 0) { 1853102237Spirzyk freeaddrinfo(sentinel.ai_next); 1854102237Spirzyk h_errno = NO_RECOVERY; 1855102237Spirzyk return NULL; 1856102237Spirzyk } 1857102237Spirzyk } 1858102237Spirzyk#endif /*RESOLVSORT*/ 185961877Sume if (!canonname) 186061877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 186161877Sume else 186261877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 186361877Sume h_errno = NETDB_SUCCESS; 186461877Sume return sentinel.ai_next; 186561877Sume } 186661877Sume 186761877Sume h_errno = NO_RECOVERY; 186861877Sume return NULL; 186961877Sume} 187061877Sume 1871121426Sume#ifdef RESOLVSORT 1872121426Sumestruct addr_ptr { 1873121426Sume struct addrinfo *ai; 1874121426Sume int aval; 1875121426Sume}; 1876121426Sume 1877121426Sumestatic int 1878121426Sumeaddr4sort(struct addrinfo *sentinel) 1879121426Sume{ 1880121426Sume struct addrinfo *ai; 1881121426Sume struct addr_ptr *addrs, addr; 1882121426Sume struct sockaddr_in *sin; 1883121426Sume int naddrs, i, j; 1884121426Sume int needsort = 0; 1885121426Sume 1886121426Sume if (!sentinel) 1887121426Sume return -1; 1888121426Sume naddrs = 0; 1889121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 1890121426Sume naddrs++; 1891121426Sume if (naddrs < 2) 1892121426Sume return 0; /* We don't need sorting. */ 1893121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 1894121426Sume return -1; 1895121426Sume i = 0; 1896121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 1897121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 1898121426Sume for (j = 0; (unsigned)j < _res.nsort; j++) { 1899121426Sume if (_res.sort_list[j].addr.s_addr == 1900121426Sume (sin->sin_addr.s_addr & _res.sort_list[j].mask)) 1901121426Sume break; 1902121426Sume } 1903121426Sume addrs[i].ai = ai; 1904121426Sume addrs[i].aval = j; 1905121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 1906121426Sume needsort = i; 1907121426Sume i++; 1908121426Sume } 1909121426Sume if (!needsort) { 1910121426Sume free(addrs); 1911121426Sume return 0; 1912121426Sume } 1913121426Sume 1914121426Sume while (needsort < naddrs) { 1915121426Sume for (j = needsort - 1; j >= 0; j--) { 1916121426Sume if (addrs[j].aval > addrs[j+1].aval) { 1917121426Sume addr = addrs[j]; 1918121426Sume addrs[j] = addrs[j + 1]; 1919121426Sume addrs[j + 1] = addr; 1920121426Sume } else 1921121426Sume break; 1922121426Sume } 1923121426Sume needsort++; 1924121426Sume } 1925121426Sume 1926121426Sume ai = sentinel; 1927121426Sume for (i = 0; i < naddrs; ++i) { 1928121426Sume ai->ai_next = addrs[i].ai; 1929121426Sume ai = ai->ai_next; 1930121426Sume } 1931121426Sume ai->ai_next = NULL; 1932121426Sume free(addrs); 1933121426Sume return 0; 1934121426Sume} 1935121426Sume#endif /*RESOLVSORT*/ 1936121426Sume 193761877Sume/*ARGSUSED*/ 193861877Sumestatic int 193965532Snectar_dns_getaddrinfo(rv, cb_data, ap) 194065532Snectar void *rv; 194165532Snectar void *cb_data; 194265532Snectar va_list ap; 194361877Sume{ 194461877Sume struct addrinfo *ai; 1945103357Sume querybuf *buf, *buf2; 194661877Sume const char *name; 194765532Snectar const struct addrinfo *pai; 194861877Sume struct addrinfo sentinel, *cur; 194961877Sume struct res_target q, q2; 195061877Sume 195165532Snectar name = va_arg(ap, char *); 195265532Snectar pai = va_arg(ap, const struct addrinfo *); 195365532Snectar 195461877Sume memset(&q, 0, sizeof(q2)); 195561877Sume memset(&q2, 0, sizeof(q2)); 195661877Sume memset(&sentinel, 0, sizeof(sentinel)); 195761877Sume cur = &sentinel; 195861877Sume 1959103357Sume buf = malloc(sizeof(*buf)); 1960103357Sume if (!buf) { 1961103357Sume h_errno = NETDB_INTERNAL; 1962103357Sume return NS_NOTFOUND; 1963103357Sume } 1964103357Sume buf2 = malloc(sizeof(*buf2)); 1965103357Sume if (!buf2) { 1966103357Sume free(buf); 1967103357Sume h_errno = NETDB_INTERNAL; 1968103357Sume return NS_NOTFOUND; 1969103357Sume } 1970103357Sume 197161877Sume switch (pai->ai_family) { 197261877Sume case AF_UNSPEC: 197361877Sume /* prefer IPv6 */ 1974105940Sume q.name = name; 197562614Sitojun q.qclass = C_IN; 197662614Sitojun q.qtype = T_AAAA; 1977103357Sume q.answer = buf->buf; 1978103357Sume q.anslen = sizeof(buf->buf); 197961877Sume q.next = &q2; 1980105943Sume q2.name = name; 198162614Sitojun q2.qclass = C_IN; 198262614Sitojun q2.qtype = T_A; 1983103357Sume q2.answer = buf2->buf; 1984103357Sume q2.anslen = sizeof(buf2->buf); 198561877Sume break; 198661877Sume case AF_INET: 1987105940Sume q.name = name; 198862614Sitojun q.qclass = C_IN; 198962614Sitojun q.qtype = T_A; 1990103357Sume q.answer = buf->buf; 1991103357Sume q.anslen = sizeof(buf->buf); 199261877Sume break; 199361877Sume case AF_INET6: 1994105940Sume q.name = name; 199562614Sitojun q.qclass = C_IN; 199662614Sitojun q.qtype = T_AAAA; 1997103357Sume q.answer = buf->buf; 1998103357Sume q.anslen = sizeof(buf->buf); 199961877Sume break; 200061877Sume default: 2001103357Sume free(buf); 2002103357Sume free(buf2); 200365532Snectar return NS_UNAVAIL; 200461877Sume } 2005103357Sume if (res_searchN(name, &q) < 0) { 2006103357Sume free(buf); 2007103357Sume free(buf2); 200865532Snectar return NS_NOTFOUND; 2009103357Sume } 2010103357Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai); 201161877Sume if (ai) { 201261877Sume cur->ai_next = ai; 201361877Sume while (cur && cur->ai_next) 201461877Sume cur = cur->ai_next; 201561877Sume } 201661877Sume if (q.next) { 2017103357Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai); 201861877Sume if (ai) 201961877Sume cur->ai_next = ai; 202061877Sume } 2021103357Sume free(buf); 2022103357Sume free(buf2); 202361877Sume if (sentinel.ai_next == NULL) 202461877Sume switch (h_errno) { 202561877Sume case HOST_NOT_FOUND: 202665532Snectar return NS_NOTFOUND; 202761877Sume case TRY_AGAIN: 202865532Snectar return NS_TRYAGAIN; 202961877Sume default: 203065532Snectar return NS_UNAVAIL; 203161877Sume } 203265532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 203365532Snectar return NS_SUCCESS; 203461877Sume} 203561877Sume 203665532Snectarstatic void 203765532Snectar_sethtent() 203865532Snectar{ 203965532Snectar if (!hostf) 204065532Snectar hostf = fopen(_PATH_HOSTS, "r" ); 204165532Snectar else 204265532Snectar rewind(hostf); 204365532Snectar} 204465532Snectar 204565532Snectarstatic void 204665532Snectar_endhtent() 204765532Snectar{ 204865532Snectar if (hostf) { 204965532Snectar (void) fclose(hostf); 205065532Snectar hostf = NULL; 205165532Snectar } 205265532Snectar} 205365532Snectar 205461877Sumestatic struct addrinfo * 205565532Snectar_gethtent(name, pai) 205661877Sume const char *name; 205761877Sume const struct addrinfo *pai; 205861877Sume{ 205961877Sume char *p; 206061877Sume char *cp, *tname, *cname; 206161877Sume struct addrinfo hints, *res0, *res; 206261877Sume int error; 206361877Sume const char *addr; 206461877Sume char hostbuf[8*1024]; 206561877Sume 206665532Snectar if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 206765532Snectar return (NULL); 2068105940Sumeagain: 206961877Sume if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 207061877Sume return (NULL); 207161877Sume if (*p == '#') 207261877Sume goto again; 207361877Sume if (!(cp = strpbrk(p, "#\n"))) 207461877Sume goto again; 207561877Sume *cp = '\0'; 207661877Sume if (!(cp = strpbrk(p, " \t"))) 207761877Sume goto again; 207861877Sume *cp++ = '\0'; 207961877Sume addr = p; 208061877Sume cname = NULL; 208161877Sume /* if this is not something we're looking for, skip it. */ 208261877Sume while (cp && *cp) { 208361877Sume if (*cp == ' ' || *cp == '\t') { 208461877Sume cp++; 208561877Sume continue; 208661877Sume } 208761877Sume tname = cp; 208861877Sume if (cname == NULL) 208961877Sume cname = cp; 209061877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 209161877Sume *cp++ = '\0'; 209261877Sume if (strcasecmp(name, tname) == 0) 209361877Sume goto found; 209461877Sume } 209561877Sume goto again; 209661877Sume 209761877Sumefound: 2098105940Sume /* we should not glob socktype/protocol here */ 2099105940Sume memset(&hints, 0, sizeof(hints)); 2100105940Sume hints.ai_family = pai->ai_family; 2101105940Sume hints.ai_socktype = SOCK_DGRAM; 2102105940Sume hints.ai_protocol = 0; 210361877Sume hints.ai_flags = AI_NUMERICHOST; 2104105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 210561877Sume if (error) 210661877Sume goto again; 210761877Sume#ifdef FILTER_V4MAPPED 210861877Sume /* XXX should check all items in the chain */ 210961877Sume if (res0->ai_family == AF_INET6 && 211061877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 211161877Sume freeaddrinfo(res0); 211261877Sume goto again; 211361877Sume } 211461877Sume#endif 211561877Sume for (res = res0; res; res = res->ai_next) { 211661877Sume /* cover it up */ 211761877Sume res->ai_flags = pai->ai_flags; 2118105940Sume res->ai_socktype = pai->ai_socktype; 2119105940Sume res->ai_protocol = pai->ai_protocol; 212061877Sume 212161877Sume if (pai->ai_flags & AI_CANONNAME) { 212261877Sume if (get_canonname(pai, res, cname) != 0) { 212361877Sume freeaddrinfo(res0); 212461877Sume goto again; 212561877Sume } 212661877Sume } 212761877Sume } 212861877Sume return res0; 212961877Sume} 213061877Sume 213161877Sume/*ARGSUSED*/ 213261877Sumestatic int 213365532Snectar_files_getaddrinfo(rv, cb_data, ap) 213465532Snectar void *rv; 213565532Snectar void *cb_data; 213665532Snectar va_list ap; 213765532Snectar{ 213865532Snectar const char *name; 213961877Sume const struct addrinfo *pai; 214061877Sume struct addrinfo sentinel, *cur; 214161877Sume struct addrinfo *p; 214261877Sume 214365532Snectar name = va_arg(ap, char *); 214465532Snectar pai = va_arg(ap, struct addrinfo *); 214565532Snectar 214665532Snectar memset(&sentinel, 0, sizeof(sentinel)); 214761877Sume cur = &sentinel; 214861877Sume 2149126243Sgreen THREAD_LOCK(); 215065532Snectar _sethtent(); 215165532Snectar while ((p = _gethtent(name, pai)) != NULL) { 215261877Sume cur->ai_next = p; 215361877Sume while (cur && cur->ai_next) 215461877Sume cur = cur->ai_next; 215561877Sume } 215665532Snectar _endhtent(); 2157126243Sgreen THREAD_UNLOCK(); 215861877Sume 215965532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 216065532Snectar if (sentinel.ai_next == NULL) 216165532Snectar return NS_NOTFOUND; 216265532Snectar return NS_SUCCESS; 216361877Sume} 216461877Sume 216561877Sume#ifdef YP 216665532Snectarstatic char *__ypdomain; 216765532Snectar 216861877Sume/*ARGSUSED*/ 216965532Snectarstatic struct addrinfo * 217065532Snectar_yphostent(line, pai) 217165532Snectar char *line; 217261877Sume const struct addrinfo *pai; 217361877Sume{ 217461877Sume struct addrinfo sentinel, *cur; 217565532Snectar struct addrinfo hints, *res, *res0; 217661877Sume int error; 217765532Snectar char *p = line; 217865532Snectar const char *addr, *canonname; 217965532Snectar char *nextline; 218065532Snectar char *cp; 218161877Sume 218265532Snectar addr = canonname = NULL; 218365532Snectar 218465532Snectar memset(&sentinel, 0, sizeof(sentinel)); 218561877Sume cur = &sentinel; 218661877Sume 218765532Snectarnextline: 218865532Snectar /* terminate line */ 218965532Snectar cp = strchr(p, '\n'); 219065532Snectar if (cp) { 219165532Snectar *cp++ = '\0'; 219265532Snectar nextline = cp; 219365532Snectar } else 219465532Snectar nextline = NULL; 219561877Sume 219665532Snectar cp = strpbrk(p, " \t"); 219765532Snectar if (cp == NULL) { 219865532Snectar if (canonname == NULL) 219965532Snectar return (NULL); 220065532Snectar else 220165532Snectar goto done; 220261877Sume } 220365532Snectar *cp++ = '\0'; 220461877Sume 220565532Snectar addr = p; 220661877Sume 220765532Snectar while (cp && *cp) { 220865532Snectar if (*cp == ' ' || *cp == '\t') { 220965532Snectar cp++; 221061877Sume continue; 221165532Snectar } 221265532Snectar if (!canonname) 221365532Snectar canonname = cp; 221465532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 221565532Snectar *cp++ = '\0'; 221665532Snectar } 221761877Sume 2218121474Sume hints = *pai; 221965532Snectar hints.ai_flags = AI_NUMERICHOST; 2220121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 222165532Snectar if (error == 0) { 222265532Snectar for (res = res0; res; res = res->ai_next) { 222365532Snectar /* cover it up */ 222465532Snectar res->ai_flags = pai->ai_flags; 222561877Sume 222665532Snectar if (pai->ai_flags & AI_CANONNAME) 222765532Snectar (void)get_canonname(pai, res, canonname); 222861877Sume } 222965532Snectar } else 223065532Snectar res0 = NULL; 223165532Snectar if (res0) { 223265532Snectar cur->ai_next = res0; 223361877Sume while (cur && cur->ai_next) 223461877Sume cur = cur->ai_next; 223561877Sume } 223661877Sume 223765532Snectar if (nextline) { 223865532Snectar p = nextline; 223965532Snectar goto nextline; 224065532Snectar } 224161877Sume 224265532Snectardone: 224365532Snectar return sentinel.ai_next; 224461877Sume} 224565532Snectar 224665532Snectar/*ARGSUSED*/ 224765532Snectarstatic int 224865532Snectar_yp_getaddrinfo(rv, cb_data, ap) 224965532Snectar void *rv; 225065532Snectar void *cb_data; 225165532Snectar va_list ap; 225265532Snectar{ 225365532Snectar struct addrinfo sentinel, *cur; 225465532Snectar struct addrinfo *ai = NULL; 225565532Snectar static char *__ypcurrent; 225665532Snectar int __ypcurrentlen, r; 225765532Snectar const char *name; 225865532Snectar const struct addrinfo *pai; 225965532Snectar 226065532Snectar name = va_arg(ap, char *); 226165532Snectar pai = va_arg(ap, const struct addrinfo *); 226265532Snectar 226365532Snectar memset(&sentinel, 0, sizeof(sentinel)); 226465532Snectar cur = &sentinel; 226565532Snectar 2266126243Sgreen THREAD_LOCK(); 226765532Snectar if (!__ypdomain) { 2268126243Sgreen if (_yp_check(&__ypdomain) == 0) { 2269126243Sgreen THREAD_UNLOCK(); 227065532Snectar return NS_UNAVAIL; 2271126243Sgreen } 227265532Snectar } 227365532Snectar if (__ypcurrent) 227465532Snectar free(__ypcurrent); 227565532Snectar __ypcurrent = NULL; 227665532Snectar 227765532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 227865532Snectar if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 227965532Snectar r = yp_match(__ypdomain, "hosts.byname", name, 228065532Snectar (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 228165532Snectar if (r == 0) { 228265532Snectar struct addrinfo ai4; 228365532Snectar 228465532Snectar ai4 = *pai; 228565532Snectar ai4.ai_family = AF_INET; 228665532Snectar ai = _yphostent(__ypcurrent, &ai4); 228765532Snectar if (ai) { 228865532Snectar cur->ai_next = ai; 228965532Snectar while (cur && cur->ai_next) 229065532Snectar cur = cur->ai_next; 229165532Snectar } 229265532Snectar } 229365532Snectar } 229465532Snectar 229565532Snectar /* ipnodes.byname can hold both IPv4/v6 */ 229665532Snectar r = yp_match(__ypdomain, "ipnodes.byname", name, 229765532Snectar (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 229865532Snectar if (r == 0) { 229965532Snectar ai = _yphostent(__ypcurrent, pai); 230065532Snectar if (ai) { 230165532Snectar cur->ai_next = ai; 230265532Snectar while (cur && cur->ai_next) 230365532Snectar cur = cur->ai_next; 230465532Snectar } 230565532Snectar } 2306126243Sgreen THREAD_UNLOCK(); 230765532Snectar 230865532Snectar if (sentinel.ai_next == NULL) { 230965532Snectar h_errno = HOST_NOT_FOUND; 231065532Snectar return NS_NOTFOUND; 231165532Snectar } 231265532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 231365532Snectar return NS_SUCCESS; 231465532Snectar} 231561877Sume#endif 231661877Sume 231761877Sume/* resolver logic */ 231861877Sume 231992905Sobrienextern const char *__hostalias(const char *); 232061877Sume 232161877Sume/* 232261877Sume * Formulate a normal query, send, and await answer. 232361877Sume * Returned answer is placed in supplied buffer "answer". 232461877Sume * Perform preliminary check of answer, returning success only 232561877Sume * if no error is indicated and the answer count is nonzero. 232661877Sume * Return the size of the response on success, -1 on error. 232761877Sume * Error number is left in h_errno. 232861877Sume * 232961877Sume * Caller must parse answer and determine whether it answers the question. 233061877Sume */ 233161877Sumestatic int 233261877Sumeres_queryN(name, target) 233361877Sume const char *name; /* domain name */ 233461877Sume struct res_target *target; 233561877Sume{ 2336103357Sume u_char *buf; 233761877Sume HEADER *hp; 233861877Sume int n; 233961877Sume struct res_target *t; 234061877Sume int rcode; 234161877Sume int ancount; 234261877Sume 234361877Sume rcode = NOERROR; 234461877Sume ancount = 0; 234561877Sume 234661877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 234761877Sume h_errno = NETDB_INTERNAL; 234861877Sume return (-1); 234961877Sume } 235061877Sume 2351103357Sume buf = malloc(MAXPACKET); 2352103357Sume if (!buf) { 2353103357Sume h_errno = NETDB_INTERNAL; 2354103357Sume return -1; 2355103357Sume } 2356103357Sume 235761877Sume for (t = target; t; t = t->next) { 235861877Sume int class, type; 235961877Sume u_char *answer; 236061877Sume int anslen; 236161877Sume 236261877Sume hp = (HEADER *)(void *)t->answer; 236361877Sume hp->rcode = NOERROR; /* default */ 236461877Sume 236561877Sume /* make it easier... */ 236662614Sitojun class = t->qclass; 236762614Sitojun type = t->qtype; 236861877Sume answer = t->answer; 236961877Sume anslen = t->anslen; 237061877Sume#ifdef DEBUG 237161877Sume if (_res.options & RES_DEBUG) 237261877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 237361877Sume#endif 237461877Sume 237561877Sume n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 2376103357Sume buf, MAXPACKET); 237778012Sume if (n > 0 && (_res.options & RES_USE_EDNS0) != 0) 2378103357Sume n = res_opt(n, buf, MAXPACKET, anslen); 237961877Sume if (n <= 0) { 238061877Sume#ifdef DEBUG 238161877Sume if (_res.options & RES_DEBUG) 238261877Sume printf(";; res_query: mkquery failed\n"); 238361877Sume#endif 2384103357Sume free(buf); 238561877Sume h_errno = NO_RECOVERY; 238661877Sume return (n); 238761877Sume } 238861877Sume n = res_send(buf, n, answer, anslen); 238961877Sume#if 0 239061877Sume if (n < 0) { 239161877Sume#ifdef DEBUG 239261877Sume if (_res.options & RES_DEBUG) 239361877Sume printf(";; res_query: send error\n"); 239461877Sume#endif 2395103357Sume free(buf); 239661877Sume h_errno = TRY_AGAIN; 239761877Sume return (n); 239861877Sume } 239961877Sume#endif 240061877Sume 2401103350Snectar if (n < 0 || n > anslen) 2402103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2403103350Snectar if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 240461877Sume rcode = hp->rcode; /* record most recent error */ 240561877Sume#ifdef DEBUG 240661877Sume if (_res.options & RES_DEBUG) 2407105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 240861877Sume ntohs(hp->ancount)); 240961877Sume#endif 241061877Sume continue; 241161877Sume } 241261877Sume 241361877Sume ancount += ntohs(hp->ancount); 241461877Sume 241561877Sume t->n = n; 241661877Sume } 241761877Sume 2418103357Sume free(buf); 2419103357Sume 242061877Sume if (ancount == 0) { 242161877Sume switch (rcode) { 242261877Sume case NXDOMAIN: 242361877Sume h_errno = HOST_NOT_FOUND; 242461877Sume break; 242561877Sume case SERVFAIL: 242661877Sume h_errno = TRY_AGAIN; 242761877Sume break; 242861877Sume case NOERROR: 242961877Sume h_errno = NO_DATA; 243061877Sume break; 243161877Sume case FORMERR: 243261877Sume case NOTIMP: 243361877Sume case REFUSED: 243461877Sume default: 243561877Sume h_errno = NO_RECOVERY; 243661877Sume break; 243761877Sume } 243861877Sume return (-1); 243961877Sume } 244061877Sume return (ancount); 244161877Sume} 244261877Sume 244361877Sume/* 244461877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 244561877Sume * Return the size of the response on success, -1 on error. 244661877Sume * If enabled, implement search rules until answer or unrecoverable failure 244761877Sume * is detected. Error code, if any, is left in h_errno. 244861877Sume */ 244961877Sumestatic int 245061877Sumeres_searchN(name, target) 245161877Sume const char *name; /* domain name */ 245261877Sume struct res_target *target; 245361877Sume{ 245461877Sume const char *cp, * const *domain; 245561877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 245661877Sume u_int dots; 245761877Sume int trailing_dot, ret, saved_herrno; 245861877Sume int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 245961877Sume 246061877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 246161877Sume h_errno = NETDB_INTERNAL; 246261877Sume return (-1); 246361877Sume } 246461877Sume 246561877Sume errno = 0; 246661877Sume h_errno = HOST_NOT_FOUND; /* default, if we never query */ 246761877Sume dots = 0; 246861877Sume for (cp = name; *cp; cp++) 246961877Sume dots += (*cp == '.'); 247061877Sume trailing_dot = 0; 247161877Sume if (cp > name && *--cp == '.') 247261877Sume trailing_dot++; 247361877Sume 247461877Sume /* 247561877Sume * if there aren't any dots, it could be a user-level alias 247661877Sume */ 247761877Sume if (!dots && (cp = __hostalias(name)) != NULL) 247861877Sume return (res_queryN(cp, target)); 247961877Sume 248061877Sume /* 248161877Sume * If there are dots in the name already, let's just give it a try 248261877Sume * 'as is'. The threshold can be set with the "ndots" option. 248361877Sume */ 248461877Sume saved_herrno = -1; 248561877Sume if (dots >= _res.ndots) { 248661877Sume ret = res_querydomainN(name, NULL, target); 248761877Sume if (ret > 0) 248861877Sume return (ret); 248961877Sume saved_herrno = h_errno; 249061877Sume tried_as_is++; 249161877Sume } 249261877Sume 249361877Sume /* 249461877Sume * We do at least one level of search if 249561877Sume * - there is no dot and RES_DEFNAME is set, or 249661877Sume * - there is at least one dot, there is no trailing dot, 249761877Sume * and RES_DNSRCH is set. 249861877Sume */ 249961877Sume if ((!dots && (_res.options & RES_DEFNAMES)) || 250061877Sume (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 250161877Sume int done = 0; 250261877Sume 250361877Sume for (domain = (const char * const *)_res.dnsrch; 250461877Sume *domain && !done; 250561877Sume domain++) { 250661877Sume 250761877Sume ret = res_querydomainN(name, *domain, target); 250861877Sume if (ret > 0) 250961877Sume return (ret); 251061877Sume 251161877Sume /* 251261877Sume * If no server present, give up. 251361877Sume * If name isn't found in this domain, 251461877Sume * keep trying higher domains in the search list 251561877Sume * (if that's enabled). 251661877Sume * On a NO_DATA error, keep trying, otherwise 251761877Sume * a wildcard entry of another type could keep us 251861877Sume * from finding this entry higher in the domain. 251961877Sume * If we get some other error (negative answer or 252061877Sume * server failure), then stop searching up, 252161877Sume * but try the input name below in case it's 252261877Sume * fully-qualified. 252361877Sume */ 252461877Sume if (errno == ECONNREFUSED) { 252561877Sume h_errno = TRY_AGAIN; 252661877Sume return (-1); 252761877Sume } 252861877Sume 252961877Sume switch (h_errno) { 253061877Sume case NO_DATA: 253161877Sume got_nodata++; 253261877Sume /* FALLTHROUGH */ 253361877Sume case HOST_NOT_FOUND: 253461877Sume /* keep trying */ 253561877Sume break; 253661877Sume case TRY_AGAIN: 253761877Sume if (hp->rcode == SERVFAIL) { 253861877Sume /* try next search element, if any */ 253961877Sume got_servfail++; 254061877Sume break; 254161877Sume } 254261877Sume /* FALLTHROUGH */ 254361877Sume default: 254461877Sume /* anything else implies that we're done */ 254561877Sume done++; 254661877Sume } 254761877Sume /* 254861877Sume * if we got here for some reason other than DNSRCH, 254961877Sume * we only wanted one iteration of the loop, so stop. 255061877Sume */ 255161877Sume if (!(_res.options & RES_DNSRCH)) 255261877Sume done++; 255361877Sume } 255461877Sume } 255561877Sume 255661877Sume /* 255761877Sume * if we have not already tried the name "as is", do that now. 255861877Sume * note that we do this regardless of how many dots were in the 255961877Sume * name or whether it ends with a dot. 256061877Sume */ 256161877Sume if (!tried_as_is && (dots || !(_res.options & RES_NOTLDQUERY))) { 256261877Sume ret = res_querydomainN(name, NULL, target); 256361877Sume if (ret > 0) 256461877Sume return (ret); 256561877Sume } 256661877Sume 256761877Sume /* 256861877Sume * if we got here, we didn't satisfy the search. 256961877Sume * if we did an initial full query, return that query's h_errno 257061877Sume * (note that we wouldn't be here if that query had succeeded). 257161877Sume * else if we ever got a nodata, send that back as the reason. 257261877Sume * else send back meaningless h_errno, that being the one from 257361877Sume * the last DNSRCH we did. 257461877Sume */ 257561877Sume if (saved_herrno != -1) 257661877Sume h_errno = saved_herrno; 257761877Sume else if (got_nodata) 257861877Sume h_errno = NO_DATA; 257961877Sume else if (got_servfail) 258061877Sume h_errno = TRY_AGAIN; 258161877Sume return (-1); 258261877Sume} 258361877Sume 258461877Sume/* 258561877Sume * Perform a call on res_query on the concatenation of name and domain, 258661877Sume * removing a trailing dot from name if domain is NULL. 258761877Sume */ 258861877Sumestatic int 258961877Sumeres_querydomainN(name, domain, target) 259061877Sume const char *name, *domain; 259161877Sume struct res_target *target; 259261877Sume{ 259361877Sume char nbuf[MAXDNAME]; 259461877Sume const char *longname = nbuf; 259561877Sume size_t n, d; 259661877Sume 259761877Sume if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 259861877Sume h_errno = NETDB_INTERNAL; 259961877Sume return (-1); 260061877Sume } 260161877Sume#ifdef DEBUG 260261877Sume if (_res.options & RES_DEBUG) 260361877Sume printf(";; res_querydomain(%s, %s)\n", 260461877Sume name, domain?domain:"<Nil>"); 260561877Sume#endif 260661877Sume if (domain == NULL) { 260761877Sume /* 260861877Sume * Check for trailing '.'; 260961877Sume * copy without '.' if present. 261061877Sume */ 261161877Sume n = strlen(name); 261261877Sume if (n >= MAXDNAME) { 261361877Sume h_errno = NO_RECOVERY; 261461877Sume return (-1); 261561877Sume } 261661877Sume if (n > 0 && name[--n] == '.') { 261761877Sume strncpy(nbuf, name, n); 261861877Sume nbuf[n] = '\0'; 261961877Sume } else 262061877Sume longname = name; 262161877Sume } else { 262261877Sume n = strlen(name); 262361877Sume d = strlen(domain); 262461877Sume if (n + d + 1 >= MAXDNAME) { 262561877Sume h_errno = NO_RECOVERY; 262661877Sume return (-1); 262761877Sume } 2628105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 262961877Sume } 263061877Sume return (res_queryN(longname, target)); 263161877Sume} 2632