getaddrinfo.c revision 157203
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 157203 2006-03-28 07:42:57Z 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> 8755163Sshin#include <resolv.h> 8855163Sshin#include <string.h> 8955163Sshin#include <stdlib.h> 9055163Sshin#include <stddef.h> 9155163Sshin#include <ctype.h> 9255163Sshin#include <unistd.h> 9355163Sshin#include <stdio.h> 9461877Sume#include <errno.h> 95102237Spirzyk 96102237Spirzyk#include "res_config.h" 97102237Spirzyk 9878012Sume#ifdef DEBUG 9978012Sume#include <syslog.h> 10078012Sume#endif 10155163Sshin 10265532Snectar#include <stdarg.h> 10365532Snectar#include <nsswitch.h> 10471579Sdeischen#include "un-namespace.h" 105111618Snectar#include "libc_private.h" 10665532Snectar 10755163Sshin#if defined(__KAME__) && defined(INET6) 10855163Sshin# define FAITH 10955163Sshin#endif 11055163Sshin 111105940Sume#define SUCCESS 0 112105940Sume#define ANY 0 113105940Sume#define YES 1 114105940Sume#define NO 0 11555163Sshin 11655163Sshinstatic const char in_addrany[] = { 0, 0, 0, 0 }; 117105940Sumestatic const char in_loopback[] = { 127, 0, 0, 1 }; 118105940Sume#ifdef INET6 11955163Sshinstatic const char in6_addrany[] = { 12055163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 12155163Sshin}; 12255163Sshinstatic const char in6_loopback[] = { 12355163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 12455163Sshin}; 125105940Sume#endif 12655163Sshin 127121747Sumestruct policyqueue { 128121747Sume TAILQ_ENTRY(policyqueue) pc_entry; 129121747Sume#ifdef INET6 130121747Sume struct in6_addrpolicy pc_policy; 131121747Sume#endif 132121747Sume}; 133121747SumeTAILQ_HEAD(policyhead, policyqueue); 134121747Sume 13555163Sshinstatic const struct afd { 13655163Sshin int a_af; 13755163Sshin int a_addrlen; 138146244Sume socklen_t a_socklen; 13955163Sshin int a_off; 14055163Sshin const char *a_addrany; 14173665Sobrien const char *a_loopback; 14255163Sshin int a_scoped; 14355163Sshin} afdl [] = { 14455163Sshin#ifdef INET6 14555163Sshin#define N_INET6 0 14655163Sshin {PF_INET6, sizeof(struct in6_addr), 14755163Sshin sizeof(struct sockaddr_in6), 14855163Sshin offsetof(struct sockaddr_in6, sin6_addr), 14955163Sshin in6_addrany, in6_loopback, 1}, 15055163Sshin#define N_INET 1 15155163Sshin#else 15255163Sshin#define N_INET 0 15355163Sshin#endif 15455163Sshin {PF_INET, sizeof(struct in_addr), 15555163Sshin sizeof(struct sockaddr_in), 15655163Sshin offsetof(struct sockaddr_in, sin_addr), 15755163Sshin in_addrany, in_loopback, 0}, 15855163Sshin {0, 0, 0, 0, NULL, NULL, 0}, 15955163Sshin}; 16055163Sshin 16155163Sshinstruct explore { 16261877Sume int e_af; 16355163Sshin int e_socktype; 16455163Sshin int e_protocol; 16555163Sshin const char *e_protostr; 16655163Sshin int e_wild; 167105940Sume#define WILD_AF(ex) ((ex)->e_wild & 0x01) 168105940Sume#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 169105940Sume#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 17055163Sshin}; 17155163Sshin 17255163Sshinstatic const struct explore explore[] = { 17361877Sume#if 0 174121474Sume { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 17561877Sume#endif 17661877Sume#ifdef INET6 177121474Sume { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 178121474Sume { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 179121474Sume { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 18061877Sume#endif 181121474Sume { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 182121474Sume { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 183121474Sume { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 184121474Sume { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 185121474Sume { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 186121474Sume { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 18761877Sume { -1, 0, 0, NULL, 0 }, 18855163Sshin}; 18955163Sshin 19055163Sshin#ifdef INET6 191105940Sume#define PTON_MAX 16 19255163Sshin#else 193105940Sume#define PTON_MAX 4 19455163Sshin#endif 19555163Sshin 196121747Sume#define AIO_SRCFLAG_DEPRECATED 0x1 197121747Sume 198121747Sumestruct ai_order { 199121747Sume union { 200121747Sume struct sockaddr_storage aiou_ss; 201121747Sume struct sockaddr aiou_sa; 202121747Sume } aio_src_un; 203121747Sume#define aio_srcsa aio_src_un.aiou_sa 204121747Sume u_int32_t aio_srcflag; 205121747Sume int aio_srcscope; 206121747Sume int aio_dstscope; 207121747Sume struct policyqueue *aio_srcpolicy; 208121747Sume struct policyqueue *aio_dstpolicy; 209121747Sume struct addrinfo *aio_ai; 210121747Sume int aio_matchlen; 211121747Sume}; 212121747Sume 21365532Snectarstatic const ns_src default_dns_files[] = { 21465532Snectar { NSSRC_FILES, NS_SUCCESS }, 21565532Snectar { NSSRC_DNS, NS_SUCCESS }, 21665532Snectar { 0 } 21765532Snectar}; 21865532Snectar 21961877Sumestruct res_target { 22061877Sume struct res_target *next; 22161877Sume const char *name; /* domain name */ 22262614Sitojun int qclass, qtype; /* class and type of query */ 22361877Sume u_char *answer; /* buffer to put answer */ 22461877Sume int anslen; /* size of answer buffer */ 22561877Sume int n; /* result length */ 22661877Sume}; 22761877Sume 228121426Sume#define MAXPACKET (64*1024) 229121426Sume 230121426Sumetypedef union { 231121426Sume HEADER hdr; 232121426Sume u_char buf[MAXPACKET]; 233121426Sume} querybuf; 234121426Sume 235140908Sumestatic int str2number(const char *); 23692941Sobrienstatic int explore_null(const struct addrinfo *, 23792941Sobrien const char *, struct addrinfo **); 23892941Sobrienstatic int explore_numeric(const struct addrinfo *, const char *, 239140906Sume const char *, struct addrinfo **, const char *); 24092941Sobrienstatic int explore_numeric_scope(const struct addrinfo *, const char *, 24192941Sobrien const char *, struct addrinfo **); 24292941Sobrienstatic int get_canonname(const struct addrinfo *, 24392941Sobrien struct addrinfo *, const char *); 24492941Sobrienstatic struct addrinfo *get_ai(const struct addrinfo *, 24592941Sobrien const struct afd *, const char *); 24692905Sobrienstatic int get_portmatch(const struct addrinfo *, const char *); 24792905Sobrienstatic int get_port(struct addrinfo *, const char *, int); 24892905Sobrienstatic const struct afd *find_afd(int); 249121474Sumestatic int addrconfig(struct addrinfo *); 250129901Sumestatic void set_source(struct ai_order *, struct policyhead *); 251121747Sumestatic int comp_dst(const void *, const void *); 25261877Sume#ifdef INET6 253105943Sumestatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 25461877Sume#endif 255121747Sumestatic int gai_addr2scopetype(struct sockaddr *); 25655163Sshin 257121426Sumestatic int explore_fqdn(const struct addrinfo *, const char *, 258121426Sume const char *, struct addrinfo **); 259121426Sume 260121747Sumestatic int reorder(struct addrinfo *); 261121747Sumestatic int get_addrselectpolicy(struct policyhead *); 262121747Sumestatic void free_addrselectpolicy(struct policyhead *); 263121747Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 264121747Sume struct policyhead *); 265129901Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 266121747Sume 26792941Sobrienstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 268156960Sume const struct addrinfo *, res_state); 269121426Sume#if defined(RESOLVSORT) 270156960Sumestatic int addr4sort(struct addrinfo *, res_state); 271121426Sume#endif 272105943Sumestatic int _dns_getaddrinfo(void *, void *, va_list); 273144634Sumestatic void _sethtent(FILE **); 274144634Sumestatic void _endhtent(FILE **); 275144634Sumestatic struct addrinfo *_gethtent(FILE **, const char *, 276144634Sume 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 283156960Sumestatic int res_queryN(const char *, struct res_target *, res_state); 284156960Sumestatic int res_searchN(const char *, struct res_target *, res_state); 28592941Sobrienstatic int res_querydomainN(const char *, const char *, 286156960Sume struct res_target *, res_state); 28761877Sume 28855163Sshin/* XXX macros that make external reference is BAD. */ 28955163Sshin 290105940Sume#define GET_AI(ai, afd, addr) \ 29155163Sshindo { \ 29255163Sshin /* external reference: pai, error, and label free */ \ 29355163Sshin (ai) = get_ai(pai, (afd), (addr)); \ 29455163Sshin if ((ai) == NULL) { \ 29555163Sshin error = EAI_MEMORY; \ 29655163Sshin goto free; \ 29755163Sshin } \ 29861877Sume} while (/*CONSTCOND*/0) 29955163Sshin 300105940Sume#define GET_PORT(ai, serv) \ 30155163Sshindo { \ 30255163Sshin /* external reference: error and label free */ \ 30355163Sshin error = get_port((ai), (serv), 0); \ 30455163Sshin if (error != 0) \ 30555163Sshin goto free; \ 30661877Sume} while (/*CONSTCOND*/0) 30755163Sshin 308105940Sume#define GET_CANONNAME(ai, str) \ 30955163Sshindo { \ 31055163Sshin /* external reference: pai, error and label free */ \ 31155163Sshin error = get_canonname(pai, (ai), (str)); \ 31255163Sshin if (error != 0) \ 31355163Sshin goto free; \ 31461877Sume} while (/*CONSTCOND*/0) 31555163Sshin 316105940Sume#define ERR(err) \ 31755163Sshindo { \ 31855163Sshin /* external reference: error, and label bad */ \ 31955163Sshin error = (err); \ 32055163Sshin goto bad; \ 32161877Sume /*NOTREACHED*/ \ 32261877Sume} while (/*CONSTCOND*/0) 32355163Sshin 324105940Sume#define MATCH_FAMILY(x, y, w) \ 32561877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 326105940Sume#define MATCH(x, y, w) \ 32761877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 32855163Sshin 32955163Sshinvoid 330157119Sumefreeaddrinfo(struct addrinfo *ai) 33155163Sshin{ 33255163Sshin struct addrinfo *next; 33355163Sshin 33455163Sshin do { 33555163Sshin next = ai->ai_next; 33655163Sshin if (ai->ai_canonname) 33755163Sshin free(ai->ai_canonname); 33855163Sshin /* no need to free(ai->ai_addr) */ 33955163Sshin free(ai); 34061877Sume ai = next; 34161877Sume } while (ai); 34255163Sshin} 34355163Sshin 34455163Sshinstatic int 345157119Sumestr2number(const char *p) 34655163Sshin{ 34762836Sitojun char *ep; 348140908Sume unsigned long v; 34962836Sitojun 35062836Sitojun if (*p == '\0') 351140908Sume return -1; 35262836Sitojun ep = NULL; 353105943Sume errno = 0; 354140908Sume v = strtoul(p, &ep, 10); 355140908Sume if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) 356140908Sume return v; 35762836Sitojun else 358140908Sume return -1; 35955163Sshin} 36055163Sshin 36155163Sshinint 362157119Sumegetaddrinfo(const char *hostname, const char *servname, 363157119Sume const struct addrinfo *hints, struct addrinfo **res) 36455163Sshin{ 36555163Sshin struct addrinfo sentinel; 36655163Sshin struct addrinfo *cur; 36755163Sshin int error = 0; 368121474Sume struct addrinfo ai; 369121474Sume struct addrinfo ai0; 37055163Sshin struct addrinfo *pai; 37155163Sshin const struct explore *ex; 372121747Sume int numeric = 0; 37355163Sshin 37461877Sume memset(&sentinel, 0, sizeof(sentinel)); 37555163Sshin cur = &sentinel; 37655163Sshin pai = &ai; 37755163Sshin pai->ai_flags = 0; 37855163Sshin pai->ai_family = PF_UNSPEC; 37955163Sshin pai->ai_socktype = ANY; 38055163Sshin pai->ai_protocol = ANY; 38155163Sshin pai->ai_addrlen = 0; 38255163Sshin pai->ai_canonname = NULL; 38355163Sshin pai->ai_addr = NULL; 38455163Sshin pai->ai_next = NULL; 38555163Sshin 38655163Sshin if (hostname == NULL && servname == NULL) 38755163Sshin return EAI_NONAME; 38855163Sshin if (hints) { 38955163Sshin /* error check for hints */ 39055163Sshin if (hints->ai_addrlen || hints->ai_canonname || 39155163Sshin hints->ai_addr || hints->ai_next) 39255163Sshin ERR(EAI_BADHINTS); /* xxx */ 39355163Sshin if (hints->ai_flags & ~AI_MASK) 39455163Sshin ERR(EAI_BADFLAGS); 39555163Sshin switch (hints->ai_family) { 39655163Sshin case PF_UNSPEC: 39755163Sshin case PF_INET: 39855163Sshin#ifdef INET6 39955163Sshin case PF_INET6: 40055163Sshin#endif 40155163Sshin break; 40255163Sshin default: 40355163Sshin ERR(EAI_FAMILY); 40455163Sshin } 40555163Sshin memcpy(pai, hints, sizeof(*pai)); 40655163Sshin 40755163Sshin /* 40855163Sshin * if both socktype/protocol are specified, check if they 40955163Sshin * are meaningful combination. 41055163Sshin */ 41155163Sshin if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 41261877Sume for (ex = explore; ex->e_af >= 0; ex++) { 413121474Sume if (pai->ai_family != ex->e_af) 41461877Sume continue; 415121474Sume if (ex->e_socktype == ANY) 41655163Sshin continue; 417121474Sume if (ex->e_protocol == ANY) 41855163Sshin continue; 419121474Sume if (pai->ai_socktype == ex->e_socktype && 420121474Sume pai->ai_protocol != ex->e_protocol) { 421121474Sume ERR(EAI_BADHINTS); 422121474Sume } 42355163Sshin } 42455163Sshin } 42555163Sshin } 42655163Sshin 42761877Sume /* 42861877Sume * post-2553: AI_ALL and AI_V4MAPPED are effective only against 429105940Sume * AF_INET6 query. They need to be ignored if specified in other 43061877Sume * occassions. 43161877Sume */ 43261877Sume switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 43361877Sume case AI_V4MAPPED: 43461877Sume case AI_ALL | AI_V4MAPPED: 43561877Sume if (pai->ai_family != AF_INET6) 43661877Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 43761877Sume break; 43861877Sume case AI_ALL: 43961877Sume#if 1 44061877Sume /* illegal */ 44161877Sume ERR(EAI_BADFLAGS); 44261877Sume#else 44361877Sume pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 44461877Sume#endif 44561877Sume break; 44661877Sume } 44755163Sshin 44855163Sshin /* 44961877Sume * check for special cases. (1) numeric servname is disallowed if 45061877Sume * socktype/protocol are left unspecified. (2) servname is disallowed 45161877Sume * for raw and other inet{,6} sockets. 45255163Sshin */ 45355163Sshin if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 45461877Sume#ifdef PF_INET6 455121474Sume || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 45655163Sshin#endif 45755163Sshin ) { 45861877Sume ai0 = *pai; /* backup *pai */ 45955163Sshin 46061877Sume if (pai->ai_family == PF_UNSPEC) { 46161877Sume#ifdef PF_INET6 46255163Sshin pai->ai_family = PF_INET6; 46355163Sshin#else 46455163Sshin pai->ai_family = PF_INET; 46555163Sshin#endif 46661877Sume } 46755163Sshin error = get_portmatch(pai, servname); 46855163Sshin if (error) 46955163Sshin ERR(error); 47061877Sume 47161877Sume *pai = ai0; 47255163Sshin } 47355163Sshin 47461877Sume ai0 = *pai; 47561877Sume 476121474Sume /* NULL hostname, or numeric hostname */ 477121474Sume for (ex = explore; ex->e_af >= 0; ex++) { 47855163Sshin *pai = ai0; 47955163Sshin 480121474Sume /* PF_UNSPEC entries are prepared for DNS queries only */ 481121474Sume if (ex->e_af == PF_UNSPEC) 48255163Sshin continue; 48361877Sume 484121474Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 485121474Sume continue; 486121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 487121474Sume continue; 488121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 489121474Sume continue; 490121474Sume 49155163Sshin if (pai->ai_family == PF_UNSPEC) 492121474Sume pai->ai_family = ex->e_af; 493121474Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 494121474Sume pai->ai_socktype = ex->e_socktype; 495121474Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 496121474Sume pai->ai_protocol = ex->e_protocol; 49755163Sshin 498121474Sume if (hostname == NULL) 499121474Sume error = explore_null(pai, servname, &cur->ai_next); 500121474Sume else 501140906Sume error = explore_numeric_scope(pai, hostname, servname, 502140906Sume &cur->ai_next); 50355163Sshin 504121474Sume if (error) 505121474Sume goto free; 506121474Sume 507121474Sume while (cur && cur->ai_next) 508121474Sume cur = cur->ai_next; 50955163Sshin } 51055163Sshin 511121474Sume /* 512121474Sume * XXX 513121474Sume * If numreic representation of AF1 can be interpreted as FQDN 514121474Sume * representation of AF2, we need to think again about the code below. 515121474Sume */ 516121747Sume if (sentinel.ai_next) { 517121747Sume numeric = 1; 518121474Sume goto good; 519121747Sume } 520121474Sume 521121425Sume if (hostname == NULL) 522121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 52355163Sshin if (pai->ai_flags & AI_NUMERICHOST) 52490053Sroam ERR(EAI_NONAME); 52555163Sshin 526121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 527121474Sume ERR(EAI_FAIL); 528121474Sume 52961877Sume /* 53061877Sume * hostname as alphabetical name. 531121474Sume * we would like to prefer AF_INET6 than AF_INET, so we'll make a 532121474Sume * outer loop by AFs. 53361877Sume */ 53461877Sume for (ex = explore; ex->e_af >= 0; ex++) { 53561877Sume *pai = ai0; 53655163Sshin 537121474Sume /* require exact match for family field */ 538121474Sume if (pai->ai_family != ex->e_af) 53961877Sume continue; 54055163Sshin 541121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 542121474Sume WILD_SOCKTYPE(ex))) { 54361877Sume continue; 544121474Sume } 545121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 546121474Sume WILD_PROTOCOL(ex))) { 54761877Sume continue; 548121474Sume } 54955163Sshin 55061877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 55161877Sume pai->ai_socktype = ex->e_socktype; 55261877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 55361877Sume pai->ai_protocol = ex->e_protocol; 55461877Sume 555121474Sume error = explore_fqdn(pai, hostname, servname, 556121474Sume &cur->ai_next); 55761877Sume 55861877Sume while (cur && cur->ai_next) 55961877Sume cur = cur->ai_next; 56055163Sshin } 56155163Sshin 562121747Sume /* XXX inhibit errors if we have the result */ 56361877Sume if (sentinel.ai_next) 56461877Sume error = 0; 56561877Sume 566121747Sumegood: 567121747Sume /* 568121747Sume * ensure we return either: 569121747Sume * - error == 0, non-NULL *res 570121747Sume * - error != 0, NULL *res 571121747Sume */ 57261877Sume if (error == 0) { 57361877Sume if (sentinel.ai_next) { 574121747Sume /* 575121747Sume * If the returned entry is for an active connection, 576121747Sume * and the given name is not numeric, reorder the 577121747Sume * list, so that the application would try the list 578121747Sume * in the most efficient order. 579121747Sume */ 580121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 581121747Sume if (!numeric) 582121747Sume (void)reorder(&sentinel); 583121747Sume } 58461877Sume *res = sentinel.ai_next; 585121474Sume return SUCCESS; 58661877Sume } else 58761877Sume error = EAI_FAIL; 58855163Sshin } 589121747Sumefree: 590121747Sumebad: 591121474Sume if (sentinel.ai_next) 592121474Sume freeaddrinfo(sentinel.ai_next); 593121474Sume *res = NULL; 59455163Sshin return error; 59555163Sshin} 59655163Sshin 597121747Sumestatic int 598157119Sumereorder(struct addrinfo *sentinel) 599121747Sume{ 600121747Sume struct addrinfo *ai, **aip; 601121747Sume struct ai_order *aio; 602121747Sume int i, n; 603121747Sume struct policyhead policyhead; 604121747Sume 605121747Sume /* count the number of addrinfo elements for sorting. */ 606121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 607121747Sume ; 608121747Sume 609121747Sume /* 610121747Sume * If the number is small enough, we can skip the reordering process. 611121747Sume */ 612121747Sume if (n <= 1) 613121747Sume return(n); 614121747Sume 615121747Sume /* allocate a temporary array for sort and initialization of it. */ 616121747Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 617121747Sume return(n); /* give up reordering */ 618121747Sume memset(aio, 0, sizeof(*aio) * n); 619121747Sume 620121747Sume /* retrieve address selection policy from the kernel */ 621121747Sume TAILQ_INIT(&policyhead); 622121747Sume if (!get_addrselectpolicy(&policyhead)) { 623121747Sume /* no policy is installed into kernel, we don't sort. */ 624121747Sume free(aio); 625121747Sume return (n); 626121747Sume } 627121747Sume 628121747Sume for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 629121747Sume aio[i].aio_ai = ai; 630121747Sume aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 631121747Sume aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 632121747Sume &policyhead); 633129901Sume set_source(&aio[i], &policyhead); 634121747Sume } 635121747Sume 636121747Sume /* perform sorting. */ 637121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 638121747Sume 639121747Sume /* reorder the addrinfo chain. */ 640121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 641121747Sume *aip = aio[i].aio_ai; 642121747Sume aip = &aio[i].aio_ai->ai_next; 643121747Sume } 644121747Sume *aip = NULL; 645121747Sume 646121747Sume /* cleanup and return */ 647121747Sume free(aio); 648121747Sume free_addrselectpolicy(&policyhead); 649121747Sume return(n); 650121747Sume} 651121747Sume 652121747Sumestatic int 653157119Sumeget_addrselectpolicy(struct policyhead *head) 654121747Sume{ 655121747Sume#ifdef INET6 656121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 657121747Sume size_t l; 658121747Sume char *buf; 659121747Sume struct in6_addrpolicy *pol, *ep; 660121747Sume 661121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 662121747Sume return (0); 663121747Sume if ((buf = malloc(l)) == NULL) 664121747Sume return (0); 665121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 666121747Sume free(buf); 667121747Sume return (0); 668121747Sume } 669121747Sume 670121747Sume ep = (struct in6_addrpolicy *)(buf + l); 671121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 672121747Sume struct policyqueue *new; 673121747Sume 674121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 675121747Sume free_addrselectpolicy(head); /* make the list empty */ 676121747Sume break; 677121747Sume } 678121747Sume new->pc_policy = *pol; 679121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 680121747Sume } 681121747Sume 682121747Sume free(buf); 683121747Sume return (1); 684121747Sume#else 685121747Sume return (0); 686121747Sume#endif 687121747Sume} 688121747Sume 689121747Sumestatic void 690157119Sumefree_addrselectpolicy(struct policyhead *head) 691121747Sume{ 692121747Sume struct policyqueue *ent, *nent; 693121747Sume 694121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 695121747Sume nent = TAILQ_NEXT(ent, pc_entry); 696121747Sume TAILQ_REMOVE(head, ent, pc_entry); 697121747Sume free(ent); 698121747Sume } 699121747Sume} 700121747Sume 701121747Sumestatic struct policyqueue * 702157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 703121747Sume{ 704121747Sume#ifdef INET6 705121747Sume struct policyqueue *ent, *bestent = NULL; 706121747Sume struct in6_addrpolicy *pol; 707121747Sume int matchlen, bestmatchlen = -1; 708121747Sume u_char *mp, *ep, *k, *p, m; 709121747Sume struct sockaddr_in6 key; 710121747Sume 711121747Sume switch(addr->sa_family) { 712121747Sume case AF_INET6: 713121747Sume key = *(struct sockaddr_in6 *)addr; 714121747Sume break; 715121747Sume case AF_INET: 716121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 717121747Sume memset(&key, 0, sizeof(key)); 718121747Sume key.sin6_family = AF_INET6; 719121747Sume key.sin6_len = sizeof(key); 720121747Sume key.sin6_addr.s6_addr[10] = 0xff; 721121747Sume key.sin6_addr.s6_addr[11] = 0xff; 722121747Sume memcpy(&key.sin6_addr.s6_addr[12], 723121747Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 724121747Sume break; 725121747Sume default: 726121747Sume return(NULL); 727121747Sume } 728121747Sume 729121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 730121747Sume pol = &ent->pc_policy; 731121747Sume matchlen = 0; 732121747Sume 733121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 734121747Sume ep = mp + 16; /* XXX: scope field? */ 735121747Sume k = (u_char *)&key.sin6_addr; 736121747Sume p = (u_char *)&pol->addr.sin6_addr; 737121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 738121747Sume m = *mp; 739121747Sume if ((*k & m) != *p) 740121747Sume goto next; /* not match */ 741121747Sume if (m == 0xff) /* short cut for a typical case */ 742121747Sume matchlen += 8; 743121747Sume else { 744121747Sume while (m >= 0x80) { 745121747Sume matchlen++; 746121747Sume m <<= 1; 747121747Sume } 748121747Sume } 749121747Sume } 750121747Sume 751121747Sume /* matched. check if this is better than the current best. */ 752121747Sume if (matchlen > bestmatchlen) { 753121747Sume bestent = ent; 754121747Sume bestmatchlen = matchlen; 755121747Sume } 756121747Sume 757121747Sume next: 758121747Sume continue; 759121747Sume } 760121747Sume 761121747Sume return(bestent); 762121747Sume#else 763121747Sume return(NULL); 764121747Sume#endif 765121747Sume 766121747Sume} 767121747Sume 768129901Sumestatic void 769157119Sumeset_source(struct ai_order *aio, struct policyhead *ph) 770129901Sume{ 771129901Sume struct addrinfo ai = *aio->aio_ai; 772129901Sume struct sockaddr_storage ss; 773145786Sume socklen_t srclen; 774145786Sume int s; 775129901Sume 776129901Sume /* set unspec ("no source is available"), just in case */ 777129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 778129901Sume aio->aio_srcscope = -1; 779129901Sume 780129901Sume switch(ai.ai_family) { 781129901Sume case AF_INET: 782129901Sume#ifdef INET6 783129901Sume case AF_INET6: 784129901Sume#endif 785129901Sume break; 786129901Sume default: /* ignore unsupported AFs explicitly */ 787129901Sume return; 788129901Sume } 789129901Sume 790129901Sume /* XXX: make a dummy addrinfo to call connect() */ 791129901Sume ai.ai_socktype = SOCK_DGRAM; 792129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 793129901Sume ai.ai_next = NULL; 794129901Sume memset(&ss, 0, sizeof(ss)); 795129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 796129901Sume ai.ai_addr = (struct sockaddr *)&ss; 797129901Sume get_port(&ai, "1", 0); 798129901Sume 799129901Sume /* open a socket to get the source address for the given dst */ 800129901Sume if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) 801129901Sume return; /* give up */ 802129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 803129901Sume goto cleanup; 804129901Sume srclen = ai.ai_addrlen; 805129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 806129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 807129901Sume goto cleanup; 808129901Sume } 809129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 810129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 811129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 812129901Sume#ifdef INET6 813129901Sume if (ai.ai_family == AF_INET6) { 814129901Sume struct in6_ifreq ifr6; 815129901Sume u_int32_t flags6; 816129901Sume 817129901Sume /* XXX: interface name should not be hardcoded */ 818129901Sume strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name)); 819129901Sume memset(&ifr6, 0, sizeof(ifr6)); 820129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 821129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 822129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 823129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 824129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 825129901Sume } 826129901Sume } 827129901Sume#endif 828129901Sume 829129901Sume cleanup: 830129901Sume _close(s); 831129901Sume return; 832129901Sume} 833129901Sume 834121747Sumestatic int 835157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 836129901Sume{ 837129901Sume int match = 0; 838129901Sume u_char *s, *d; 839129901Sume u_char *lim, r; 840129901Sume int addrlen; 841129901Sume 842129901Sume switch (src->sa_family) { 843129901Sume#ifdef INET6 844129901Sume case AF_INET6: 845129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 846129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 847129901Sume addrlen = sizeof(struct in6_addr); 848129901Sume lim = s + addrlen; 849129901Sume break; 850129901Sume#endif 851129901Sume case AF_INET: 852146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 853146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 854129901Sume addrlen = sizeof(struct in_addr); 855129901Sume lim = s + addrlen; 856129901Sume break; 857129901Sume default: 858129901Sume return(0); 859129901Sume } 860129901Sume 861129901Sume while (s < lim) 862129901Sume if ((r = (*d++ ^ *s++)) != 0) { 863129901Sume while (r < addrlen * 8) { 864129901Sume match++; 865129901Sume r <<= 1; 866129901Sume } 867129901Sume break; 868129901Sume } else 869129901Sume match += 8; 870129901Sume return(match); 871129901Sume} 872129901Sume 873129901Sumestatic int 874157119Sumecomp_dst(const void *arg1, const void *arg2) 875121747Sume{ 876121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 877121747Sume 878121747Sume /* 879121747Sume * Rule 1: Avoid unusable destinations. 880121747Sume * XXX: we currently do not consider if an appropriate route exists. 881121747Sume */ 882121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 883121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 884121747Sume return(-1); 885121747Sume } 886121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 887121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 888121747Sume return(1); 889121747Sume } 890121747Sume 891121747Sume /* Rule 2: Prefer matching scope. */ 892121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 893121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 894121747Sume return(-1); 895121747Sume } 896121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 897121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 898121747Sume return(1); 899121747Sume } 900121747Sume 901121747Sume /* Rule 3: Avoid deprecated addresses. */ 902121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 903121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 904121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 905121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 906121747Sume return(-1); 907121747Sume } 908121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 909121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 910121747Sume return(1); 911121747Sume } 912121747Sume } 913121747Sume 914121747Sume /* Rule 4: Prefer home addresses. */ 915121747Sume /* XXX: not implemented yet */ 916121747Sume 917121747Sume /* Rule 5: Prefer matching label. */ 918121747Sume#ifdef INET6 919121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 920121747Sume dst1->aio_srcpolicy->pc_policy.label == 921121747Sume dst1->aio_dstpolicy->pc_policy.label && 922121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 923121747Sume dst2->aio_srcpolicy->pc_policy.label != 924121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 925121747Sume return(-1); 926121747Sume } 927121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 928121747Sume dst2->aio_srcpolicy->pc_policy.label == 929121747Sume dst2->aio_dstpolicy->pc_policy.label && 930121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 931121747Sume dst1->aio_srcpolicy->pc_policy.label != 932121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 933121747Sume return(1); 934121747Sume } 935121747Sume#endif 936121747Sume 937121747Sume /* Rule 6: Prefer higher precedence. */ 938121747Sume#ifdef INET6 939121747Sume if (dst1->aio_dstpolicy && 940121747Sume (dst2->aio_dstpolicy == NULL || 941121747Sume dst1->aio_dstpolicy->pc_policy.preced > 942121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 943121747Sume return(-1); 944121747Sume } 945121747Sume if (dst2->aio_dstpolicy && 946121747Sume (dst1->aio_dstpolicy == NULL || 947121747Sume dst2->aio_dstpolicy->pc_policy.preced > 948121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 949121747Sume return(1); 950121747Sume } 951121747Sume#endif 952121747Sume 953121747Sume /* Rule 7: Prefer native transport. */ 954121747Sume /* XXX: not implemented yet */ 955121747Sume 956121747Sume /* Rule 8: Prefer smaller scope. */ 957121747Sume if (dst1->aio_dstscope >= 0 && 958121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 959121747Sume return(-1); 960121747Sume } 961121747Sume if (dst2->aio_dstscope >= 0 && 962121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 963121747Sume return(1); 964121747Sume } 965121747Sume 966121747Sume /* 967121747Sume * Rule 9: Use longest matching prefix. 968121747Sume * We compare the match length in a same AF only. 969121747Sume */ 970121747Sume if (dst1->aio_ai->ai_addr->sa_family == 971121747Sume dst2->aio_ai->ai_addr->sa_family) { 972121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 973121747Sume return(-1); 974121747Sume } 975121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 976121747Sume return(1); 977121747Sume } 978121747Sume } 979121747Sume 980121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 981121747Sume return(-1); 982121747Sume} 983121747Sume 98455163Sshin/* 985121747Sume * Copy from scope.c. 986121747Sume * XXX: we should standardize the functions and link them as standard 987121747Sume * library. 988121747Sume */ 989121747Sumestatic int 990157119Sumegai_addr2scopetype(struct sockaddr *sa) 991121747Sume{ 992121747Sume#ifdef INET6 993121747Sume struct sockaddr_in6 *sa6; 994121747Sume#endif 995121747Sume struct sockaddr_in *sa4; 996121747Sume 997121747Sume switch(sa->sa_family) { 998121747Sume#ifdef INET6 999121747Sume case AF_INET6: 1000121747Sume sa6 = (struct sockaddr_in6 *)sa; 1001121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 1002121747Sume /* just use the scope field of the multicast address */ 1003121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1004121747Sume } 1005121747Sume /* 1006121747Sume * Unicast addresses: map scope type to corresponding scope 1007121747Sume * value defined for multcast addresses. 1008121747Sume * XXX: hardcoded scope type values are bad... 1009121747Sume */ 1010121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1011121747Sume return(1); /* node local scope */ 1012121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1013121747Sume return(2); /* link-local scope */ 1014121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1015121747Sume return(5); /* site-local scope */ 1016121747Sume return(14); /* global scope */ 1017121747Sume break; 1018121747Sume#endif 1019121747Sume case AF_INET: 1020121747Sume /* 1021121747Sume * IPv4 pseudo scoping according to RFC 3484. 1022121747Sume */ 1023121747Sume sa4 = (struct sockaddr_in *)sa; 1024121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1025121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1026121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1027121747Sume return(2); 1028121747Sume /* Private addresses have site-local scope. */ 1029121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1030121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1031121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1032121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1033121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1034129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1035121747Sume /* Loopback addresses have link-local scope. */ 1036121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1037121747Sume return(2); 1038121747Sume return(14); 1039121747Sume break; 1040121747Sume default: 1041121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1042121747Sume return(-1); 1043121747Sume } 1044121747Sume} 1045121747Sume 1046121747Sume/* 104755163Sshin * hostname == NULL. 104855163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 104955163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 105055163Sshin */ 105155163Sshinstatic int 1052157119Sumeexplore_null(const struct addrinfo *pai, const char *servname, 1053157119Sume struct addrinfo **res) 105455163Sshin{ 1055121474Sume int s; 105655163Sshin const struct afd *afd; 105755163Sshin struct addrinfo *cur; 105855163Sshin struct addrinfo sentinel; 105955163Sshin int error; 106055163Sshin 106155163Sshin *res = NULL; 106255163Sshin sentinel.ai_next = NULL; 106355163Sshin cur = &sentinel; 106455163Sshin 106555163Sshin /* 1066121474Sume * filter out AFs that are not supported by the kernel 1067121474Sume * XXX errno? 1068121474Sume */ 1069121474Sume s = _socket(pai->ai_family, SOCK_DGRAM, 0); 1070121474Sume if (s < 0) { 1071121474Sume if (errno != EMFILE) 1072121474Sume return 0; 1073121474Sume } else 1074121474Sume _close(s); 1075121474Sume 1076121474Sume /* 107761877Sume * if the servname does not match socktype/protocol, ignore it. 107861877Sume */ 107961877Sume if (get_portmatch(pai, servname) != 0) 108055163Sshin return 0; 108161877Sume 108255163Sshin afd = find_afd(pai->ai_family); 108355163Sshin if (afd == NULL) 108455163Sshin return 0; 108555163Sshin 108661877Sume if (pai->ai_flags & AI_PASSIVE) { 108761877Sume GET_AI(cur->ai_next, afd, afd->a_addrany); 108861877Sume /* xxx meaningless? 108961877Sume * GET_CANONNAME(cur->ai_next, "anyaddr"); 109061877Sume */ 109161877Sume GET_PORT(cur->ai_next, servname); 109261877Sume } else { 109361877Sume GET_AI(cur->ai_next, afd, afd->a_loopback); 109461877Sume /* xxx meaningless? 109561877Sume * GET_CANONNAME(cur->ai_next, "localhost"); 109661877Sume */ 109761877Sume GET_PORT(cur->ai_next, servname); 109861877Sume } 109961877Sume cur = cur->ai_next; 110055163Sshin 110155163Sshin *res = sentinel.ai_next; 110255163Sshin return 0; 110355163Sshin 110455163Sshinfree: 110555163Sshin if (sentinel.ai_next) 110655163Sshin freeaddrinfo(sentinel.ai_next); 110755163Sshin return error; 110855163Sshin} 110955163Sshin 111055163Sshin/* 111155163Sshin * numeric hostname 111255163Sshin */ 111355163Sshinstatic int 1114157119Sumeexplore_numeric(const struct addrinfo *pai, const char *hostname, 1115157119Sume const char *servname, struct addrinfo **res, const char *canonname) 111655163Sshin{ 111755163Sshin const struct afd *afd; 111855163Sshin struct addrinfo *cur; 111955163Sshin struct addrinfo sentinel; 112055163Sshin int error; 112155163Sshin char pton[PTON_MAX]; 112255163Sshin 112355163Sshin *res = NULL; 112455163Sshin sentinel.ai_next = NULL; 112555163Sshin cur = &sentinel; 112655163Sshin 1127121474Sume /* 1128121474Sume * if the servname does not match socktype/protocol, ignore it. 1129121474Sume */ 1130121474Sume if (get_portmatch(pai, servname) != 0) 1131121474Sume return 0; 1132121474Sume 113355163Sshin afd = find_afd(pai->ai_family); 113455163Sshin if (afd == NULL) 113555163Sshin return 0; 113655163Sshin 113762614Sitojun switch (afd->a_af) { 113862614Sitojun#if 1 /*X/Open spec*/ 113962614Sitojun case AF_INET: 114062614Sitojun if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 114162614Sitojun if (pai->ai_family == afd->a_af || 114262614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 114362614Sitojun GET_AI(cur->ai_next, afd, pton); 114462614Sitojun GET_PORT(cur->ai_next, servname); 1145140906Sume if ((pai->ai_flags & AI_CANONNAME)) { 1146140906Sume /* 1147140906Sume * Set the numeric address itself as 1148140906Sume * the canonical name, based on a 1149140906Sume * clarification in rfc3493. 1150140906Sume */ 1151140906Sume GET_CANONNAME(cur->ai_next, canonname); 1152140906Sume } 115362614Sitojun while (cur && cur->ai_next) 115462614Sitojun cur = cur->ai_next; 115562614Sitojun } else 115662614Sitojun ERR(EAI_FAMILY); /*xxx*/ 115762614Sitojun } 115862614Sitojun break; 115962614Sitojun#endif 116062614Sitojun default: 116162614Sitojun if (inet_pton(afd->a_af, hostname, pton) == 1) { 116262614Sitojun if (pai->ai_family == afd->a_af || 116362614Sitojun pai->ai_family == PF_UNSPEC /*?*/) { 116462614Sitojun GET_AI(cur->ai_next, afd, pton); 116562614Sitojun GET_PORT(cur->ai_next, servname); 1166140906Sume if ((pai->ai_flags & AI_CANONNAME)) { 1167140906Sume /* 1168140906Sume * Set the numeric address itself as 1169140906Sume * the canonical name, based on a 1170140906Sume * clarification in rfc3493. 1171140906Sume */ 1172140906Sume GET_CANONNAME(cur->ai_next, canonname); 1173140906Sume } 117462614Sitojun while (cur && cur->ai_next) 117562614Sitojun cur = cur->ai_next; 117662614Sitojun } else 1177105940Sume ERR(EAI_FAMILY); /* XXX */ 117862614Sitojun } 117962614Sitojun break; 118055163Sshin } 118155163Sshin 118255163Sshin *res = sentinel.ai_next; 118355163Sshin return 0; 118455163Sshin 118555163Sshinfree: 118655163Sshinbad: 118755163Sshin if (sentinel.ai_next) 118855163Sshin freeaddrinfo(sentinel.ai_next); 118955163Sshin return error; 119055163Sshin} 119155163Sshin 119255163Sshin/* 119355163Sshin * numeric hostname with scope 119455163Sshin */ 119555163Sshinstatic int 1196157119Sumeexplore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1197157119Sume const char *servname, struct addrinfo **res) 119855163Sshin{ 119961877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1200140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 120155163Sshin#else 120255163Sshin const struct afd *afd; 120355163Sshin struct addrinfo *cur; 120455163Sshin int error; 120561877Sume char *cp, *hostname2 = NULL, *scope, *addr; 120655163Sshin struct sockaddr_in6 *sin6; 120755163Sshin 1208121474Sume /* 1209121474Sume * if the servname does not match socktype/protocol, ignore it. 1210121474Sume */ 1211121474Sume if (get_portmatch(pai, servname) != 0) 1212121474Sume return 0; 1213121474Sume 121455163Sshin afd = find_afd(pai->ai_family); 121555163Sshin if (afd == NULL) 121655163Sshin return 0; 121765532Snectar 121855163Sshin if (!afd->a_scoped) 1219140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 122055163Sshin 122155163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 122255163Sshin if (cp == NULL) 1223140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 122455163Sshin 122555163Sshin /* 122655163Sshin * Handle special case of <scoped_address><delimiter><scope id> 122755163Sshin */ 122855163Sshin hostname2 = strdup(hostname); 122955163Sshin if (hostname2 == NULL) 123055163Sshin return EAI_MEMORY; 123155163Sshin /* terminate at the delimiter */ 123255163Sshin hostname2[cp - hostname] = '\0'; 123361877Sume addr = hostname2; 123461877Sume scope = cp + 1; 123555163Sshin 1236140906Sume error = explore_numeric(pai, addr, servname, res, hostname); 123761877Sume if (error == 0) { 1238105943Sume u_int32_t scopeid; 123955163Sshin 124055163Sshin for (cur = *res; cur; cur = cur->ai_next) { 124155163Sshin if (cur->ai_family != AF_INET6) 124255163Sshin continue; 124361877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1244105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 124561877Sume free(hostname2); 1246121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 124761877Sume } 124861877Sume sin6->sin6_scope_id = scopeid; 124955163Sshin } 125055163Sshin } 125155163Sshin 125255163Sshin free(hostname2); 125355163Sshin 125455163Sshin return error; 125555163Sshin#endif 125655163Sshin} 125755163Sshin 125855163Sshinstatic int 1259157119Sumeget_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 126055163Sshin{ 126155163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1262140947Sume ai->ai_canonname = strdup(str); 126355163Sshin if (ai->ai_canonname == NULL) 126455163Sshin return EAI_MEMORY; 126555163Sshin } 126655163Sshin return 0; 126755163Sshin} 126855163Sshin 126955163Sshinstatic struct addrinfo * 1270157119Sumeget_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 127155163Sshin{ 127255163Sshin char *p; 127355163Sshin struct addrinfo *ai; 127455163Sshin#ifdef FAITH 127555163Sshin struct in6_addr faith_prefix; 127655163Sshin char *fp_str; 127755163Sshin int translate = 0; 127855163Sshin#endif 127955163Sshin 128055163Sshin#ifdef FAITH 128155163Sshin /* 128255163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 128355163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 128455163Sshin * 128555163Sshin * +-----------------------------------+------------+ 128655163Sshin * | faith prefix part (12 bytes) | embedded | 128755163Sshin * | | IPv4 addr part (4 bytes) 128855163Sshin * +-----------------------------------+------------+ 128955163Sshin * 129055163Sshin * faith prefix part is specified as ascii IPv6 addr format 129155163Sshin * in environmental variable GAI. 129255163Sshin * For FAITH to work correctly, routing to faith prefix must be 129355163Sshin * setup toward a machine where a FAITH daemon operates. 129455163Sshin * Also, the machine must enable some mechanizm 129555163Sshin * (e.g. faith interface hack) to divert those packet with 129655163Sshin * faith prefixed destination addr to user-land FAITH daemon. 129755163Sshin */ 129855163Sshin fp_str = getenv("GAI"); 129955163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 130055163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 130155163Sshin u_int32_t v4a; 130255163Sshin u_int8_t v4a_top; 130355163Sshin 130455163Sshin memcpy(&v4a, addr, sizeof v4a); 130555163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 130655163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 130755163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 130855163Sshin afd = &afdl[N_INET6]; 130955163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 131055163Sshin sizeof(struct in_addr)); 131155163Sshin translate = 1; 131255163Sshin } 131355163Sshin } 131455163Sshin#endif 131555163Sshin 131655163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 131755163Sshin + (afd->a_socklen)); 131855163Sshin if (ai == NULL) 131955163Sshin return NULL; 132055163Sshin 132155163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 132261877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 132361877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 132455163Sshin ai->ai_addr->sa_len = afd->a_socklen; 132555163Sshin ai->ai_addrlen = afd->a_socklen; 132655163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 132765532Snectar p = (char *)(void *)(ai->ai_addr); 132855163Sshin#ifdef FAITH 132955163Sshin if (translate == 1) 133065532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 133155163Sshin else 133255163Sshin#endif 133365532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 133455163Sshin return ai; 133555163Sshin} 133655163Sshin 133755163Sshinstatic int 1338157119Sumeget_portmatch(const struct addrinfo *ai, const char *servname) 133955163Sshin{ 134061877Sume 1341140908Sume /* get_port does not touch first argument when matchonly == 1. */ 134261877Sume /* LINTED const cast */ 134355163Sshin return get_port((struct addrinfo *)ai, servname, 1); 134455163Sshin} 134555163Sshin 134655163Sshinstatic int 1347157119Sumeget_port(struct addrinfo *ai, const char *servname, int matchonly) 134855163Sshin{ 134955163Sshin const char *proto; 135055163Sshin struct servent *sp; 135155163Sshin int port; 135255163Sshin int allownumeric; 135355163Sshin 135455163Sshin if (servname == NULL) 135555163Sshin return 0; 135661877Sume switch (ai->ai_family) { 135761877Sume case AF_INET: 135861877Sume#ifdef AF_INET6 135961877Sume case AF_INET6: 136055163Sshin#endif 136161877Sume break; 136261877Sume default: 136355163Sshin return 0; 136461877Sume } 136555163Sshin 136655163Sshin switch (ai->ai_socktype) { 136755163Sshin case SOCK_RAW: 136855163Sshin return EAI_SERVICE; 136955163Sshin case SOCK_DGRAM: 137055163Sshin case SOCK_STREAM: 137155163Sshin allownumeric = 1; 137255163Sshin break; 137355163Sshin case ANY: 137455163Sshin allownumeric = 0; 137555163Sshin break; 137655163Sshin default: 137755163Sshin return EAI_SOCKTYPE; 137855163Sshin } 137955163Sshin 1380140908Sume port = str2number(servname); 1381140908Sume if (port >= 0) { 138255163Sshin if (!allownumeric) 138355163Sshin return EAI_SERVICE; 138455163Sshin if (port < 0 || port > 65535) 138555163Sshin return EAI_SERVICE; 1386105940Sume port = htons(port); 138755163Sshin } else { 1388140908Sume if (ai->ai_flags & AI_NUMERICSERV) 1389140908Sume return EAI_NONAME; 1390121474Sume switch (ai->ai_socktype) { 1391121474Sume case SOCK_DGRAM: 139255163Sshin proto = "udp"; 139355163Sshin break; 1394121474Sume case SOCK_STREAM: 139555163Sshin proto = "tcp"; 139655163Sshin break; 139755163Sshin default: 139855163Sshin proto = NULL; 139955163Sshin break; 140055163Sshin } 140155163Sshin 1402145118Sume if ((sp = getservbyname(servname, proto)) == NULL) 140355163Sshin return EAI_SERVICE; 140455163Sshin port = sp->s_port; 140555163Sshin } 140655163Sshin 140755163Sshin if (!matchonly) { 140855163Sshin switch (ai->ai_family) { 140955163Sshin case AF_INET: 141061877Sume ((struct sockaddr_in *)(void *) 141161877Sume ai->ai_addr)->sin_port = port; 141255163Sshin break; 141355163Sshin#ifdef INET6 141455163Sshin case AF_INET6: 141561877Sume ((struct sockaddr_in6 *)(void *) 141661877Sume ai->ai_addr)->sin6_port = port; 141755163Sshin break; 141855163Sshin#endif 141955163Sshin } 142055163Sshin } 142155163Sshin 142255163Sshin return 0; 142355163Sshin} 142455163Sshin 142555163Sshinstatic const struct afd * 1426157119Sumefind_afd(int af) 142755163Sshin{ 142855163Sshin const struct afd *afd; 142955163Sshin 143055163Sshin if (af == PF_UNSPEC) 143155163Sshin return NULL; 143255163Sshin for (afd = afdl; afd->a_af; afd++) { 143355163Sshin if (afd->a_af == af) 143455163Sshin return afd; 143555163Sshin } 143655163Sshin return NULL; 143755163Sshin} 143861877Sume 143961877Sume/* 144061877Sume * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 144161877Sume * will take care of it. 144261877Sume * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 144361877Sume * if the code is right or not. 1444121474Sume * 1445121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1446121474Sume * _dns_getaddrinfo. 144761877Sume */ 144861877Sumestatic int 1449157119Sumeaddrconfig(struct addrinfo *pai) 145061877Sume{ 1451121474Sume int s, af; 145261877Sume 1453121474Sume /* 1454121474Sume * TODO: 1455121474Sume * Note that implementation dependent test for address 1456121474Sume * configuration should be done everytime called 1457121474Sume * (or apropriate interval), 1458121474Sume * because addresses will be dynamically assigned or deleted. 1459121474Sume */ 1460121474Sume af = pai->ai_family; 1461121474Sume if (af == AF_UNSPEC) { 1462121474Sume if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1463121474Sume af = AF_INET; 1464121474Sume else { 1465121474Sume _close(s); 1466121474Sume if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1467121474Sume af = AF_INET6; 1468121474Sume else 1469121474Sume _close(s); 1470121474Sume } 1471121474Sume } 1472121474Sume if (af != AF_UNSPEC) { 1473121474Sume if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 147461877Sume return 0; 1475121474Sume _close(s); 1476121474Sume } 1477121474Sume pai->ai_family = af; 147861877Sume return 1; 147961877Sume} 148061877Sume 148161877Sume#ifdef INET6 148261877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 148361877Sumestatic int 1484157119Sumeip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 148561877Sume{ 1486105943Sume u_long lscopeid; 1487121474Sume struct in6_addr *a6; 148861877Sume char *ep; 148961877Sume 1490121474Sume a6 = &sin6->sin6_addr; 1491121474Sume 149262836Sitojun /* empty scopeid portion is invalid */ 149362836Sitojun if (*scope == '\0') 149462836Sitojun return -1; 149562836Sitojun 1496121474Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 149761877Sume /* 149861877Sume * We currently assume a one-to-one mapping between links 149961877Sume * and interfaces, so we simply use interface indices for 150061877Sume * like-local scopes. 150161877Sume */ 1502105943Sume *scopeid = if_nametoindex(scope); 1503105943Sume if (*scopeid == 0) 150461877Sume goto trynumeric; 1505105943Sume return 0; 150661877Sume } 150761877Sume 150861877Sume /* still unclear about literal, allow numeric only - placeholder */ 150961877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 151061877Sume goto trynumeric; 151161877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 151261877Sume goto trynumeric; 151361877Sume else 151461877Sume goto trynumeric; /* global */ 151561877Sume 151661877Sume /* try to convert to a numeric id as a last resort */ 1517121474Sume trynumeric: 1518105943Sume errno = 0; 1519105943Sume lscopeid = strtoul(scope, &ep, 10); 1520105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1521105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1522105943Sume return 0; 152361877Sume else 152461877Sume return -1; 152561877Sume} 152661877Sume#endif 152761877Sume 1528121426Sume/* 1529121426Sume * FQDN hostname, DNS lookup 1530121426Sume */ 1531102237Spirzykstatic int 1532157119Sumeexplore_fqdn(const struct addrinfo *pai, const char *hostname, 1533157119Sume const char *servname, struct addrinfo **res) 1534102237Spirzyk{ 1535121426Sume struct addrinfo *result; 1536121426Sume struct addrinfo *cur; 1537121426Sume int error = 0; 1538121426Sume static const ns_dtab dtab[] = { 1539121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1540121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1541121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1542121426Sume { 0 } 1543121426Sume }; 1544102237Spirzyk 1545121426Sume result = NULL; 1546121426Sume 1547121426Sume /* 1548121426Sume * if the servname does not match socktype/protocol, ignore it. 1549121426Sume */ 1550126243Sgreen if (get_portmatch(pai, servname) != 0) 1551102237Spirzyk return 0; 1552102237Spirzyk 1553121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1554121426Sume default_dns_files, hostname, pai)) { 1555121426Sume case NS_TRYAGAIN: 1556121426Sume error = EAI_AGAIN; 1557121426Sume goto free; 1558121426Sume case NS_UNAVAIL: 1559121426Sume error = EAI_FAIL; 1560121426Sume goto free; 1561121426Sume case NS_NOTFOUND: 1562121426Sume error = EAI_NONAME; 1563121426Sume goto free; 1564121426Sume case NS_SUCCESS: 1565121426Sume error = 0; 1566121426Sume for (cur = result; cur; cur = cur->ai_next) { 1567121426Sume GET_PORT(cur, servname); 1568121426Sume /* canonname should be filled already */ 1569121426Sume } 1570121426Sume break; 1571102237Spirzyk } 1572102237Spirzyk 1573121426Sume *res = result; 1574121426Sume 1575102237Spirzyk return 0; 1576121426Sume 1577121426Sumefree: 1578121426Sume if (result) 1579121426Sume freeaddrinfo(result); 1580121426Sume return error; 1581102237Spirzyk} 1582102237Spirzyk 158361877Sume#ifdef DEBUG 158461877Sumestatic const char AskedForGot[] = 158561877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 158661877Sume#endif 158761877Sume 158861877Sumestatic struct addrinfo * 1589157119Sumegetanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1590157119Sume const struct addrinfo *pai, res_state res) 159161877Sume{ 159261877Sume struct addrinfo sentinel, *cur; 159361877Sume struct addrinfo ai; 159461877Sume const struct afd *afd; 159561877Sume char *canonname; 159661877Sume const HEADER *hp; 159761877Sume const u_char *cp; 159861877Sume int n; 159961877Sume const u_char *eom; 1600105940Sume char *bp, *ep; 1601105940Sume int type, class, ancount, qdcount; 160261877Sume int haveanswer, had_error; 160361877Sume char tbuf[MAXDNAME]; 160492905Sobrien int (*name_ok)(const char *); 160561877Sume char hostbuf[8*1024]; 160661877Sume 160761877Sume memset(&sentinel, 0, sizeof(sentinel)); 160861877Sume cur = &sentinel; 160961877Sume 161061877Sume canonname = NULL; 161161877Sume eom = answer->buf + anslen; 161261877Sume switch (qtype) { 161361877Sume case T_A: 161461877Sume case T_AAAA: 161561877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 161661877Sume name_ok = res_hnok; 161761877Sume break; 161861877Sume default: 161961877Sume return (NULL); /* XXX should be abort(); */ 162061877Sume } 162161877Sume /* 162261877Sume * find first satisfactory answer 162361877Sume */ 162461877Sume hp = &answer->hdr; 162561877Sume ancount = ntohs(hp->ancount); 162661877Sume qdcount = ntohs(hp->qdcount); 162761877Sume bp = hostbuf; 1628105940Sume ep = hostbuf + sizeof hostbuf; 162961877Sume cp = answer->buf + HFIXEDSZ; 163061877Sume if (qdcount != 1) { 1631156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 163261877Sume return (NULL); 163361877Sume } 1634105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 163561877Sume if ((n < 0) || !(*name_ok)(bp)) { 1636156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 163761877Sume return (NULL); 163861877Sume } 163961877Sume cp += n + QFIXEDSZ; 164061877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 164161877Sume /* res_send() has already verified that the query name is the 164261877Sume * same as the one we sent; this just gets the expanded name 164361877Sume * (i.e., with the succeeding search-domain tacked on). 164461877Sume */ 164561877Sume n = strlen(bp) + 1; /* for the \0 */ 164661877Sume if (n >= MAXHOSTNAMELEN) { 1647156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 164861877Sume return (NULL); 164961877Sume } 165061877Sume canonname = bp; 165161877Sume bp += n; 165261877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 165361877Sume qname = canonname; 165461877Sume } 165561877Sume haveanswer = 0; 165661877Sume had_error = 0; 165761877Sume while (ancount-- > 0 && cp < eom && !had_error) { 1658105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 165961877Sume if ((n < 0) || !(*name_ok)(bp)) { 166061877Sume had_error++; 166161877Sume continue; 166261877Sume } 166361877Sume cp += n; /* name */ 166461877Sume type = _getshort(cp); 166561877Sume cp += INT16SZ; /* type */ 166661877Sume class = _getshort(cp); 166761877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 166861877Sume n = _getshort(cp); 166961877Sume cp += INT16SZ; /* len */ 167061877Sume if (class != C_IN) { 167161877Sume /* XXX - debug? syslog? */ 167261877Sume cp += n; 167361877Sume continue; /* XXX - had_error++ ? */ 167461877Sume } 167561877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 167661877Sume type == T_CNAME) { 167761877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 167861877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 167961877Sume had_error++; 168061877Sume continue; 168161877Sume } 168261877Sume cp += n; 168361877Sume /* Get canonical name. */ 168461877Sume n = strlen(tbuf) + 1; /* for the \0 */ 1685105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 168661877Sume had_error++; 168761877Sume continue; 168861877Sume } 1689114443Snectar strlcpy(bp, tbuf, ep - bp); 169061877Sume canonname = bp; 169161877Sume bp += n; 169261877Sume continue; 169361877Sume } 169461877Sume if (qtype == T_ANY) { 169561877Sume if (!(type == T_A || type == T_AAAA)) { 169661877Sume cp += n; 169761877Sume continue; 169861877Sume } 169961877Sume } else if (type != qtype) { 170061877Sume#ifdef DEBUG 170161877Sume if (type != T_KEY && type != T_SIG) 170261877Sume syslog(LOG_NOTICE|LOG_AUTH, 170361877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 170461877Sume qname, p_class(C_IN), p_type(qtype), 170561877Sume p_type(type)); 170661877Sume#endif 170761877Sume cp += n; 170861877Sume continue; /* XXX - had_error++ ? */ 170961877Sume } 171061877Sume switch (type) { 171161877Sume case T_A: 171261877Sume case T_AAAA: 171361877Sume if (strcasecmp(canonname, bp) != 0) { 171461877Sume#ifdef DEBUG 171561877Sume syslog(LOG_NOTICE|LOG_AUTH, 171661877Sume AskedForGot, canonname, bp); 171761877Sume#endif 171861877Sume cp += n; 171961877Sume continue; /* XXX - had_error++ ? */ 172061877Sume } 172161877Sume if (type == T_A && n != INADDRSZ) { 172261877Sume cp += n; 172361877Sume continue; 172461877Sume } 172561877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 172661877Sume cp += n; 172761877Sume continue; 172861877Sume } 172961877Sume#ifdef FILTER_V4MAPPED 173061877Sume if (type == T_AAAA) { 173161877Sume struct in6_addr in6; 173261877Sume memcpy(&in6, cp, sizeof(in6)); 173361877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 173461877Sume cp += n; 173561877Sume continue; 173661877Sume } 173761877Sume } 173861877Sume#endif 173961877Sume if (!haveanswer) { 174061877Sume int nn; 174161877Sume 174261877Sume canonname = bp; 174361877Sume nn = strlen(bp) + 1; /* for the \0 */ 174461877Sume bp += nn; 174561877Sume } 174661877Sume 174761877Sume /* don't overwrite pai */ 174861877Sume ai = *pai; 174961877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 175061877Sume afd = find_afd(ai.ai_family); 175161877Sume if (afd == NULL) { 175261877Sume cp += n; 175361877Sume continue; 175461877Sume } 175561877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 175661877Sume if (cur->ai_next == NULL) 175761877Sume had_error++; 175861877Sume while (cur && cur->ai_next) 175961877Sume cur = cur->ai_next; 176061877Sume cp += n; 176161877Sume break; 176261877Sume default: 176361877Sume abort(); 176461877Sume } 176561877Sume if (!had_error) 176661877Sume haveanswer++; 176761877Sume } 176861877Sume if (haveanswer) { 1769102237Spirzyk#if defined(RESOLVSORT) 1770102237Spirzyk /* 1771102237Spirzyk * We support only IPv4 address for backward 1772102237Spirzyk * compatibility against gethostbyname(3). 1773102237Spirzyk */ 1774156960Sume if (res->nsort && qtype == T_A) { 1775156960Sume if (addr4sort(&sentinel, res) < 0) { 1776102237Spirzyk freeaddrinfo(sentinel.ai_next); 1777156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 1778102237Spirzyk return NULL; 1779102237Spirzyk } 1780102237Spirzyk } 1781102237Spirzyk#endif /*RESOLVSORT*/ 178261877Sume if (!canonname) 178361877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 178461877Sume else 178561877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 1786156960Sume RES_SET_H_ERRNO(res, NETDB_SUCCESS); 178761877Sume return sentinel.ai_next; 178861877Sume } 178961877Sume 1790156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 179161877Sume return NULL; 179261877Sume} 179361877Sume 1794121426Sume#ifdef RESOLVSORT 1795121426Sumestruct addr_ptr { 1796121426Sume struct addrinfo *ai; 1797121426Sume int aval; 1798121426Sume}; 1799121426Sume 1800121426Sumestatic int 1801156960Sumeaddr4sort(struct addrinfo *sentinel, res_state res) 1802121426Sume{ 1803121426Sume struct addrinfo *ai; 1804121426Sume struct addr_ptr *addrs, addr; 1805121426Sume struct sockaddr_in *sin; 1806121426Sume int naddrs, i, j; 1807121426Sume int needsort = 0; 1808121426Sume 1809121426Sume if (!sentinel) 1810121426Sume return -1; 1811121426Sume naddrs = 0; 1812121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 1813121426Sume naddrs++; 1814121426Sume if (naddrs < 2) 1815121426Sume return 0; /* We don't need sorting. */ 1816121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 1817121426Sume return -1; 1818121426Sume i = 0; 1819121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 1820121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 1821156960Sume for (j = 0; (unsigned)j < res->nsort; j++) { 1822157119Sume if (res->sort_list[j].addr.s_addr == 1823156960Sume (sin->sin_addr.s_addr & res->sort_list[j].mask)) 1824121426Sume break; 1825121426Sume } 1826121426Sume addrs[i].ai = ai; 1827121426Sume addrs[i].aval = j; 1828121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 1829121426Sume needsort = i; 1830121426Sume i++; 1831121426Sume } 1832121426Sume if (!needsort) { 1833121426Sume free(addrs); 1834121426Sume return 0; 1835121426Sume } 1836121426Sume 1837121426Sume while (needsort < naddrs) { 1838121426Sume for (j = needsort - 1; j >= 0; j--) { 1839121426Sume if (addrs[j].aval > addrs[j+1].aval) { 1840121426Sume addr = addrs[j]; 1841121426Sume addrs[j] = addrs[j + 1]; 1842121426Sume addrs[j + 1] = addr; 1843121426Sume } else 1844121426Sume break; 1845121426Sume } 1846121426Sume needsort++; 1847121426Sume } 1848121426Sume 1849121426Sume ai = sentinel; 1850121426Sume for (i = 0; i < naddrs; ++i) { 1851121426Sume ai->ai_next = addrs[i].ai; 1852121426Sume ai = ai->ai_next; 1853121426Sume } 1854121426Sume ai->ai_next = NULL; 1855121426Sume free(addrs); 1856121426Sume return 0; 1857121426Sume} 1858121426Sume#endif /*RESOLVSORT*/ 1859121426Sume 186061877Sume/*ARGSUSED*/ 186161877Sumestatic int 1862157119Sume_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 186361877Sume{ 186461877Sume struct addrinfo *ai; 1865103357Sume querybuf *buf, *buf2; 1866130600Sume const char *hostname; 186765532Snectar const struct addrinfo *pai; 186861877Sume struct addrinfo sentinel, *cur; 186961877Sume struct res_target q, q2; 1870156960Sume res_state res; 187161877Sume 1872130600Sume hostname = va_arg(ap, char *); 187365532Snectar pai = va_arg(ap, const struct addrinfo *); 187465532Snectar 1875156946Sdelphij memset(&q, 0, sizeof(q)); 187661877Sume memset(&q2, 0, sizeof(q2)); 187761877Sume memset(&sentinel, 0, sizeof(sentinel)); 187861877Sume cur = &sentinel; 187961877Sume 1880103357Sume buf = malloc(sizeof(*buf)); 1881103357Sume if (!buf) { 1882156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 1883103357Sume return NS_NOTFOUND; 1884103357Sume } 1885103357Sume buf2 = malloc(sizeof(*buf2)); 1886103357Sume if (!buf2) { 1887103357Sume free(buf); 1888156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 1889103357Sume return NS_NOTFOUND; 1890103357Sume } 1891103357Sume 189261877Sume switch (pai->ai_family) { 189361877Sume case AF_UNSPEC: 1894130600Sume q.name = hostname; 189562614Sitojun q.qclass = C_IN; 1896140896Sume q.qtype = T_A; 1897103357Sume q.answer = buf->buf; 1898103357Sume q.anslen = sizeof(buf->buf); 189961877Sume q.next = &q2; 1900130600Sume q2.name = hostname; 190162614Sitojun q2.qclass = C_IN; 1902140896Sume q2.qtype = T_AAAA; 1903103357Sume q2.answer = buf2->buf; 1904103357Sume q2.anslen = sizeof(buf2->buf); 190561877Sume break; 190661877Sume case AF_INET: 1907130600Sume q.name = hostname; 190862614Sitojun q.qclass = C_IN; 190962614Sitojun q.qtype = T_A; 1910103357Sume q.answer = buf->buf; 1911103357Sume q.anslen = sizeof(buf->buf); 191261877Sume break; 191361877Sume case AF_INET6: 1914130600Sume q.name = hostname; 191562614Sitojun q.qclass = C_IN; 191662614Sitojun q.qtype = T_AAAA; 1917103357Sume q.answer = buf->buf; 1918103357Sume q.anslen = sizeof(buf->buf); 191961877Sume break; 192061877Sume default: 1921103357Sume free(buf); 1922103357Sume free(buf2); 192365532Snectar return NS_UNAVAIL; 192461877Sume } 1925156960Sume 1926156960Sume res = __res_state(); 1927156960Sume if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { 1928156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 1929103357Sume free(buf); 1930103357Sume free(buf2); 193165532Snectar return NS_NOTFOUND; 1932103357Sume } 1933156960Sume 1934156960Sume if (res_searchN(hostname, &q, res) < 0) { 1935156960Sume free(buf); 1936156960Sume free(buf2); 1937156960Sume return NS_NOTFOUND; 1938156960Sume } 1939140896Sume /* prefer IPv6 */ 194061877Sume if (q.next) { 1941156960Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); 1942140896Sume if (ai) { 194361877Sume cur->ai_next = ai; 1944140896Sume while (cur && cur->ai_next) 1945140896Sume cur = cur->ai_next; 1946140896Sume } 194761877Sume } 1948156960Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); 1949140896Sume if (ai) 1950140896Sume cur->ai_next = ai; 1951103357Sume free(buf); 1952103357Sume free(buf2); 195361877Sume if (sentinel.ai_next == NULL) 1954156960Sume switch (res->res_h_errno) { 195561877Sume case HOST_NOT_FOUND: 195665532Snectar return NS_NOTFOUND; 195761877Sume case TRY_AGAIN: 195865532Snectar return NS_TRYAGAIN; 195961877Sume default: 196065532Snectar return NS_UNAVAIL; 196161877Sume } 196265532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 196365532Snectar return NS_SUCCESS; 196461877Sume} 196561877Sume 196665532Snectarstatic void 1967144634Sume_sethtent(FILE **hostf) 196865532Snectar{ 1969144634Sume if (!*hostf) 1970144634Sume *hostf = fopen(_PATH_HOSTS, "r"); 197165532Snectar else 1972144634Sume rewind(*hostf); 197365532Snectar} 197465532Snectar 197565532Snectarstatic void 1976144634Sume_endhtent(FILE **hostf) 197765532Snectar{ 1978144634Sume if (*hostf) { 1979144634Sume (void) fclose(*hostf); 1980144634Sume *hostf = NULL; 198165532Snectar } 198265532Snectar} 198365532Snectar 198461877Sumestatic struct addrinfo * 1985144634Sume_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) 198661877Sume{ 198761877Sume char *p; 198861877Sume char *cp, *tname, *cname; 198961877Sume struct addrinfo hints, *res0, *res; 199061877Sume int error; 199161877Sume const char *addr; 199261877Sume char hostbuf[8*1024]; 199361877Sume 1994144634Sume if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r"))) 199565532Snectar return (NULL); 1996105940Sumeagain: 1997144634Sume if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) 199861877Sume return (NULL); 199961877Sume if (*p == '#') 200061877Sume goto again; 2001139612Ssobomax cp = strpbrk(p, "#\n"); 2002139612Ssobomax if (cp != NULL) 2003139612Ssobomax *cp = '\0'; 200461877Sume if (!(cp = strpbrk(p, " \t"))) 200561877Sume goto again; 200661877Sume *cp++ = '\0'; 200761877Sume addr = p; 200861877Sume cname = NULL; 200961877Sume /* if this is not something we're looking for, skip it. */ 201061877Sume while (cp && *cp) { 201161877Sume if (*cp == ' ' || *cp == '\t') { 201261877Sume cp++; 201361877Sume continue; 201461877Sume } 201561877Sume tname = cp; 201661877Sume if (cname == NULL) 201761877Sume cname = cp; 201861877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 201961877Sume *cp++ = '\0'; 202061877Sume if (strcasecmp(name, tname) == 0) 202161877Sume goto found; 202261877Sume } 202361877Sume goto again; 202461877Sume 202561877Sumefound: 2026105940Sume /* we should not glob socktype/protocol here */ 2027105940Sume memset(&hints, 0, sizeof(hints)); 2028105940Sume hints.ai_family = pai->ai_family; 2029105940Sume hints.ai_socktype = SOCK_DGRAM; 2030105940Sume hints.ai_protocol = 0; 203161877Sume hints.ai_flags = AI_NUMERICHOST; 2032105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 203361877Sume if (error) 203461877Sume goto again; 203561877Sume#ifdef FILTER_V4MAPPED 203661877Sume /* XXX should check all items in the chain */ 203761877Sume if (res0->ai_family == AF_INET6 && 203861877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 203961877Sume freeaddrinfo(res0); 204061877Sume goto again; 204161877Sume } 204261877Sume#endif 204361877Sume for (res = res0; res; res = res->ai_next) { 204461877Sume /* cover it up */ 204561877Sume res->ai_flags = pai->ai_flags; 2046105940Sume res->ai_socktype = pai->ai_socktype; 2047105940Sume res->ai_protocol = pai->ai_protocol; 204861877Sume 204961877Sume if (pai->ai_flags & AI_CANONNAME) { 205061877Sume if (get_canonname(pai, res, cname) != 0) { 205161877Sume freeaddrinfo(res0); 205261877Sume goto again; 205361877Sume } 205461877Sume } 205561877Sume } 205661877Sume return res0; 205761877Sume} 205861877Sume 205961877Sume/*ARGSUSED*/ 206061877Sumestatic int 2061157119Sume_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 206265532Snectar{ 206365532Snectar const char *name; 206461877Sume const struct addrinfo *pai; 206561877Sume struct addrinfo sentinel, *cur; 206661877Sume struct addrinfo *p; 2067144634Sume FILE *hostf = NULL; 206861877Sume 206965532Snectar name = va_arg(ap, char *); 207065532Snectar pai = va_arg(ap, struct addrinfo *); 207165532Snectar 207265532Snectar memset(&sentinel, 0, sizeof(sentinel)); 207361877Sume cur = &sentinel; 207461877Sume 2075144634Sume _sethtent(&hostf); 2076144634Sume while ((p = _gethtent(&hostf, name, pai)) != NULL) { 207761877Sume cur->ai_next = p; 207861877Sume while (cur && cur->ai_next) 207961877Sume cur = cur->ai_next; 208061877Sume } 2081144634Sume _endhtent(&hostf); 208261877Sume 208365532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 208465532Snectar if (sentinel.ai_next == NULL) 208565532Snectar return NS_NOTFOUND; 208665532Snectar return NS_SUCCESS; 208761877Sume} 208861877Sume 208961877Sume#ifdef YP 209061877Sume/*ARGSUSED*/ 209165532Snectarstatic struct addrinfo * 2092157119Sume_yphostent(char *line, const struct addrinfo *pai) 209361877Sume{ 209461877Sume struct addrinfo sentinel, *cur; 209565532Snectar struct addrinfo hints, *res, *res0; 209661877Sume int error; 209765532Snectar char *p = line; 209865532Snectar const char *addr, *canonname; 209965532Snectar char *nextline; 210065532Snectar char *cp; 210161877Sume 210265532Snectar addr = canonname = NULL; 210365532Snectar 210465532Snectar memset(&sentinel, 0, sizeof(sentinel)); 210561877Sume cur = &sentinel; 210661877Sume 210765532Snectarnextline: 210865532Snectar /* terminate line */ 210965532Snectar cp = strchr(p, '\n'); 211065532Snectar if (cp) { 211165532Snectar *cp++ = '\0'; 211265532Snectar nextline = cp; 211365532Snectar } else 211465532Snectar nextline = NULL; 211561877Sume 211665532Snectar cp = strpbrk(p, " \t"); 211765532Snectar if (cp == NULL) { 211865532Snectar if (canonname == NULL) 211965532Snectar return (NULL); 212065532Snectar else 212165532Snectar goto done; 212261877Sume } 212365532Snectar *cp++ = '\0'; 212461877Sume 212565532Snectar addr = p; 212661877Sume 212765532Snectar while (cp && *cp) { 212865532Snectar if (*cp == ' ' || *cp == '\t') { 212965532Snectar cp++; 213061877Sume continue; 213165532Snectar } 213265532Snectar if (!canonname) 213365532Snectar canonname = cp; 213465532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 213565532Snectar *cp++ = '\0'; 213665532Snectar } 213761877Sume 2138121474Sume hints = *pai; 213965532Snectar hints.ai_flags = AI_NUMERICHOST; 2140121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 214165532Snectar if (error == 0) { 214265532Snectar for (res = res0; res; res = res->ai_next) { 214365532Snectar /* cover it up */ 214465532Snectar res->ai_flags = pai->ai_flags; 214561877Sume 214665532Snectar if (pai->ai_flags & AI_CANONNAME) 214765532Snectar (void)get_canonname(pai, res, canonname); 214861877Sume } 214965532Snectar } else 215065532Snectar res0 = NULL; 215165532Snectar if (res0) { 215265532Snectar cur->ai_next = res0; 215361877Sume while (cur && cur->ai_next) 215461877Sume cur = cur->ai_next; 215561877Sume } 215661877Sume 215765532Snectar if (nextline) { 215865532Snectar p = nextline; 215965532Snectar goto nextline; 216065532Snectar } 216161877Sume 216265532Snectardone: 216365532Snectar return sentinel.ai_next; 216461877Sume} 216565532Snectar 216665532Snectar/*ARGSUSED*/ 216765532Snectarstatic int 2168157119Sume_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) 216965532Snectar{ 217065532Snectar struct addrinfo sentinel, *cur; 217165532Snectar struct addrinfo *ai = NULL; 2172144679Sume char *ypbuf; 2173144679Sume int ypbuflen, r; 217465532Snectar const char *name; 217565532Snectar const struct addrinfo *pai; 2176144679Sume char *ypdomain; 217765532Snectar 2178144679Sume if (_yp_check(&ypdomain) == 0) 2179144679Sume return NS_UNAVAIL; 2180144679Sume 218165532Snectar name = va_arg(ap, char *); 218265532Snectar pai = va_arg(ap, const struct addrinfo *); 218365532Snectar 218465532Snectar memset(&sentinel, 0, sizeof(sentinel)); 218565532Snectar cur = &sentinel; 218665532Snectar 218765532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 218865532Snectar if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 2189144679Sume r = yp_match(ypdomain, "hosts.byname", name, 2190144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 219165532Snectar if (r == 0) { 219265532Snectar struct addrinfo ai4; 219365532Snectar 219465532Snectar ai4 = *pai; 219565532Snectar ai4.ai_family = AF_INET; 2196144679Sume ai = _yphostent(ypbuf, &ai4); 219765532Snectar if (ai) { 219865532Snectar cur->ai_next = ai; 219965532Snectar while (cur && cur->ai_next) 220065532Snectar cur = cur->ai_next; 220165532Snectar } 2202146190Sume free(ypbuf); 220365532Snectar } 220465532Snectar } 220565532Snectar 220665532Snectar /* ipnodes.byname can hold both IPv4/v6 */ 2207144679Sume r = yp_match(ypdomain, "ipnodes.byname", name, 2208144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 220965532Snectar if (r == 0) { 2210144679Sume ai = _yphostent(ypbuf, pai); 2211144679Sume if (ai) 221265532Snectar cur->ai_next = ai; 2213144679Sume free(ypbuf); 221465532Snectar } 221565532Snectar 221665532Snectar if (sentinel.ai_next == NULL) { 2217156960Sume RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); 221865532Snectar return NS_NOTFOUND; 221965532Snectar } 222065532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 222165532Snectar return NS_SUCCESS; 222265532Snectar} 222361877Sume#endif 222461877Sume 222561877Sume/* resolver logic */ 222661877Sume 222761877Sume/* 222861877Sume * Formulate a normal query, send, and await answer. 222961877Sume * Returned answer is placed in supplied buffer "answer". 223061877Sume * Perform preliminary check of answer, returning success only 223161877Sume * if no error is indicated and the answer count is nonzero. 223261877Sume * Return the size of the response on success, -1 on error. 223361877Sume * Error number is left in h_errno. 223461877Sume * 223561877Sume * Caller must parse answer and determine whether it answers the question. 223661877Sume */ 223761877Sumestatic int 2238157119Sumeres_queryN(const char *name, struct res_target *target, res_state res) 223961877Sume{ 2240103357Sume u_char *buf; 224161877Sume HEADER *hp; 224261877Sume int n; 2243157203Sume u_int oflags; 224461877Sume struct res_target *t; 224561877Sume int rcode; 224661877Sume int ancount; 224761877Sume 224861877Sume rcode = NOERROR; 224961877Sume ancount = 0; 225061877Sume 2251103357Sume buf = malloc(MAXPACKET); 2252103357Sume if (!buf) { 2253156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2254103357Sume return -1; 2255103357Sume } 2256103357Sume 225761877Sume for (t = target; t; t = t->next) { 225861877Sume int class, type; 225961877Sume u_char *answer; 226061877Sume int anslen; 226161877Sume 226261877Sume hp = (HEADER *)(void *)t->answer; 226361877Sume 226461877Sume /* make it easier... */ 226562614Sitojun class = t->qclass; 226662614Sitojun type = t->qtype; 226761877Sume answer = t->answer; 226861877Sume anslen = t->anslen; 2269157203Sume 2270157203Sume oflags = res->_flags; 2271157203Sume 2272157203Sumeagain: 2273157203Sume hp->rcode = NOERROR; /* default */ 2274157203Sume 227561877Sume#ifdef DEBUG 2276156960Sume if (res->options & RES_DEBUG) 227761877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 227861877Sume#endif 227961877Sume 2280156960Sume n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 2281103357Sume buf, MAXPACKET); 2282157203Sume if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && 2283157203Sume (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) 2284156960Sume n = res_nopt(res, n, buf, MAXPACKET, anslen); 228561877Sume if (n <= 0) { 228661877Sume#ifdef DEBUG 2287156960Sume if (res->options & RES_DEBUG) 228861877Sume printf(";; res_query: mkquery failed\n"); 228961877Sume#endif 2290103357Sume free(buf); 2291156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 229261877Sume return (n); 229361877Sume } 2294156960Sume n = res_nsend(res, buf, n, answer, anslen); 229561877Sume if (n < 0) { 2296157203Sume /* 2297157203Sume * if the query choked with EDNS0, retry 2298157203Sume * without EDNS0 2299157203Sume */ 2300157203Sume if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) 2301157203Sume != 0U && 2302157203Sume ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { 2303157203Sume res->_flags |= RES_F_EDNS0ERR; 2304157203Sume if (res->options & RES_DEBUG) 2305157203Sume printf(";; res_nquery: retry without EDNS0\n"); 2306157203Sume goto again; 2307157203Sume } 2308157203Sume rcode = hp->rcode; /* record most recent error */ 230961877Sume#ifdef DEBUG 2310156960Sume if (res->options & RES_DEBUG) 231161877Sume printf(";; res_query: send error\n"); 231261877Sume#endif 2313157203Sume continue; 231461877Sume } 231561877Sume 2316157081Sume if (n > anslen) 2317103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2318157203Sume if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 231961877Sume rcode = hp->rcode; /* record most recent error */ 232061877Sume#ifdef DEBUG 2321156960Sume if (res->options & RES_DEBUG) 2322105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 232361877Sume ntohs(hp->ancount)); 232461877Sume#endif 232561877Sume continue; 232661877Sume } 232761877Sume 232861877Sume ancount += ntohs(hp->ancount); 232961877Sume 233061877Sume t->n = n; 233161877Sume } 233261877Sume 2333103357Sume free(buf); 2334103357Sume 233561877Sume if (ancount == 0) { 233661877Sume switch (rcode) { 233761877Sume case NXDOMAIN: 2338156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); 233961877Sume break; 234061877Sume case SERVFAIL: 2341156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 234261877Sume break; 234361877Sume case NOERROR: 2344156960Sume RES_SET_H_ERRNO(res, NO_DATA); 234561877Sume break; 234661877Sume case FORMERR: 234761877Sume case NOTIMP: 234861877Sume case REFUSED: 234961877Sume default: 2350156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 235161877Sume break; 235261877Sume } 235361877Sume return (-1); 235461877Sume } 235561877Sume return (ancount); 235661877Sume} 235761877Sume 235861877Sume/* 235961877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 236061877Sume * Return the size of the response on success, -1 on error. 236161877Sume * If enabled, implement search rules until answer or unrecoverable failure 236261877Sume * is detected. Error code, if any, is left in h_errno. 236361877Sume */ 236461877Sumestatic int 2365157119Sumeres_searchN(const char *name, struct res_target *target, res_state res) 236661877Sume{ 236761877Sume const char *cp, * const *domain; 236861877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 236961877Sume u_int dots; 237061877Sume int trailing_dot, ret, saved_herrno; 2371155983Sume int got_nodata = 0, got_servfail = 0, root_on_list = 0; 2372155983Sume int tried_as_is = 0; 2373155983Sume int searched = 0; 2374145113Sume char abuf[MAXDNAME]; 237561877Sume 237661877Sume errno = 0; 2377156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ 237861877Sume dots = 0; 237961877Sume for (cp = name; *cp; cp++) 238061877Sume dots += (*cp == '.'); 238161877Sume trailing_dot = 0; 238261877Sume if (cp > name && *--cp == '.') 238361877Sume trailing_dot++; 238461877Sume 238561877Sume /* 238661877Sume * if there aren't any dots, it could be a user-level alias 238761877Sume */ 2388156960Sume if (!dots && 2389156960Sume (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) 2390156960Sume return (res_queryN(cp, target, res)); 239161877Sume 239261877Sume /* 2393155983Sume * If there are enough dots in the name, let's just give it a 2394155983Sume * try 'as is'. The threshold can be set with the "ndots" option. 2395155983Sume * Also, query 'as is', if there is a trailing dot in the name. 239661877Sume */ 239761877Sume saved_herrno = -1; 2398156960Sume if (dots >= res->ndots || trailing_dot) { 2399156960Sume ret = res_querydomainN(name, NULL, target, res); 2400155983Sume if (ret > 0 || trailing_dot) 240161877Sume return (ret); 2402156155Sume if (errno == ECONNREFUSED) { 2403156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 2404156155Sume return (-1); 2405156155Sume } 2406156960Sume switch (res->res_h_errno) { 2407156155Sume case NO_DATA: 2408156155Sume case HOST_NOT_FOUND: 2409156155Sume break; 2410157093Sume case TRY_AGAIN: 2411157093Sume if (hp->rcode == SERVFAIL) 2412157093Sume break; 2413157093Sume /* FALLTHROUGH */ 2414156155Sume default: 2415156155Sume return (-1); 2416156155Sume } 2417156960Sume saved_herrno = res->res_h_errno; 241861877Sume tried_as_is++; 241961877Sume } 242061877Sume 242161877Sume /* 242261877Sume * We do at least one level of search if 242361877Sume * - there is no dot and RES_DEFNAME is set, or 242461877Sume * - there is at least one dot, there is no trailing dot, 242561877Sume * and RES_DNSRCH is set. 242661877Sume */ 2427156960Sume if ((!dots && (res->options & RES_DEFNAMES)) || 2428156960Sume (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 242961877Sume int done = 0; 243061877Sume 2431156960Sume for (domain = (const char * const *)res->dnsrch; 243261877Sume *domain && !done; 243361877Sume domain++) { 2434155983Sume searched = 1; 243561877Sume 2436155983Sume if (domain[0][0] == '\0' || 2437155983Sume (domain[0][0] == '.' && domain[0][1] == '\0')) 2438155983Sume root_on_list++; 2439155983Sume 2440155983Sume if (root_on_list && tried_as_is) 2441155983Sume continue; 2442155983Sume 2443156960Sume ret = res_querydomainN(name, *domain, target, res); 244461877Sume if (ret > 0) 244561877Sume return (ret); 244661877Sume 244761877Sume /* 244861877Sume * If no server present, give up. 244961877Sume * If name isn't found in this domain, 245061877Sume * keep trying higher domains in the search list 245161877Sume * (if that's enabled). 245261877Sume * On a NO_DATA error, keep trying, otherwise 245361877Sume * a wildcard entry of another type could keep us 245461877Sume * from finding this entry higher in the domain. 245561877Sume * If we get some other error (negative answer or 245661877Sume * server failure), then stop searching up, 245761877Sume * but try the input name below in case it's 245861877Sume * fully-qualified. 245961877Sume */ 246061877Sume if (errno == ECONNREFUSED) { 2461156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 246261877Sume return (-1); 246361877Sume } 246461877Sume 2465156960Sume switch (res->res_h_errno) { 246661877Sume case NO_DATA: 246761877Sume got_nodata++; 246861877Sume /* FALLTHROUGH */ 246961877Sume case HOST_NOT_FOUND: 247061877Sume /* keep trying */ 247161877Sume break; 247261877Sume case TRY_AGAIN: 2473157093Sume got_servfail++; 247461877Sume if (hp->rcode == SERVFAIL) { 247561877Sume /* try next search element, if any */ 247661877Sume break; 247761877Sume } 247861877Sume /* FALLTHROUGH */ 247961877Sume default: 248061877Sume /* anything else implies that we're done */ 248161877Sume done++; 248261877Sume } 248361877Sume /* 248461877Sume * if we got here for some reason other than DNSRCH, 248561877Sume * we only wanted one iteration of the loop, so stop. 248661877Sume */ 2487156960Sume if (!(res->options & RES_DNSRCH)) 248861877Sume done++; 248961877Sume } 249061877Sume } 249161877Sume 2492156960Sume switch (res->res_h_errno) { 2493156155Sume case NO_DATA: 2494156155Sume case HOST_NOT_FOUND: 2495156155Sume break; 2496157093Sume case TRY_AGAIN: 2497157093Sume if (hp->rcode == SERVFAIL) 2498157093Sume break; 2499157093Sume /* FALLTHROUGH */ 2500156155Sume default: 2501156155Sume goto giveup; 2502156155Sume } 2503156155Sume 250461877Sume /* 2505155983Sume * If the query has not already been tried as is then try it 2506155983Sume * unless RES_NOTLDQUERY is set and there were no dots. 250761877Sume */ 2508156960Sume if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && 2509155983Sume !(tried_as_is || root_on_list)) { 2510156960Sume ret = res_querydomainN(name, NULL, target, res); 251161877Sume if (ret > 0) 251261877Sume return (ret); 251361877Sume } 251461877Sume 251561877Sume /* 251661877Sume * if we got here, we didn't satisfy the search. 251761877Sume * if we did an initial full query, return that query's h_errno 251861877Sume * (note that we wouldn't be here if that query had succeeded). 251961877Sume * else if we ever got a nodata, send that back as the reason. 252061877Sume * else send back meaningless h_errno, that being the one from 252161877Sume * the last DNSRCH we did. 252261877Sume */ 2523156155Sumegiveup: 252461877Sume if (saved_herrno != -1) 2525156960Sume RES_SET_H_ERRNO(res, saved_herrno); 252661877Sume else if (got_nodata) 2527156960Sume RES_SET_H_ERRNO(res, NO_DATA); 252861877Sume else if (got_servfail) 2529156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 253061877Sume return (-1); 253161877Sume} 253261877Sume 253361877Sume/* 253461877Sume * Perform a call on res_query on the concatenation of name and domain, 253561877Sume * removing a trailing dot from name if domain is NULL. 253661877Sume */ 253761877Sumestatic int 2538157119Sumeres_querydomainN(const char *name, const char *domain, 2539157119Sume struct res_target *target, res_state res) 254061877Sume{ 254161877Sume char nbuf[MAXDNAME]; 254261877Sume const char *longname = nbuf; 254361877Sume size_t n, d; 254461877Sume 254561877Sume#ifdef DEBUG 2546156960Sume if (res->options & RES_DEBUG) 254761877Sume printf(";; res_querydomain(%s, %s)\n", 254861877Sume name, domain?domain:"<Nil>"); 254961877Sume#endif 255061877Sume if (domain == NULL) { 255161877Sume /* 255261877Sume * Check for trailing '.'; 255361877Sume * copy without '.' if present. 255461877Sume */ 255561877Sume n = strlen(name); 255661877Sume if (n >= MAXDNAME) { 2557156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 255861877Sume return (-1); 255961877Sume } 256061877Sume if (n > 0 && name[--n] == '.') { 256161877Sume strncpy(nbuf, name, n); 256261877Sume nbuf[n] = '\0'; 256361877Sume } else 256461877Sume longname = name; 256561877Sume } else { 256661877Sume n = strlen(name); 256761877Sume d = strlen(domain); 256861877Sume if (n + d + 1 >= MAXDNAME) { 2569156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 257061877Sume return (-1); 257161877Sume } 2572105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 257361877Sume } 2574156960Sume return (res_queryN(longname, target, res)); 257561877Sume} 2576