getaddrinfo.c revision 188316
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 * - Return values. There are nonstandard return values defined and used 3755163Sshin * in the source code. This is because RFC2553 is silent about which error 3855163Sshin * code must be returned for which situation. 3961877Sume * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 40105940Sume * invalid. current code - SEGV on freeaddrinfo(NULL) 41105940Sume * 4256627Sshin * Note: 4356627Sshin * - The code filters out AFs that are not supported by the kernel, 4456627Sshin * when globbing NULL hostname (to loopback, or wildcard). Is it the right 4556627Sshin * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 4656627Sshin * in ai_flags? 4761877Sume * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 4861877Sume * (1) what should we do against numeric hostname (2) what should we do 4961877Sume * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 5061877Sume * non-loopback address configured? global address configured? 51105940Sume * 52105940Sume * OS specific notes for freebsd4: 53105940Sume * - FreeBSD supported $GAI. The code does not. 5455163Sshin */ 5555163Sshin 5692986Sobrien#include <sys/cdefs.h> 5792986Sobrien__FBSDID("$FreeBSD: head/lib/libc/net/getaddrinfo.c 188316 2009-02-08 16:58:05Z ume $"); 5892986Sobrien 5971579Sdeischen#include "namespace.h" 6055163Sshin#include <sys/types.h> 6155163Sshin#include <sys/param.h> 6255163Sshin#include <sys/socket.h> 6355163Sshin#include <net/if.h> 6455163Sshin#include <netinet/in.h> 65121747Sume#include <sys/queue.h> 66121747Sume#ifdef INET6 67121747Sume#include <net/if_var.h> 68121747Sume#include <sys/sysctl.h> 69129901Sume#include <sys/ioctl.h> 70121747Sume#include <netinet6/in6_var.h> /* XXX */ 71121747Sume#endif 7255163Sshin#include <arpa/inet.h> 7355163Sshin#include <arpa/nameser.h> 74121474Sume#include <rpc/rpc.h> 75121474Sume#include <rpcsvc/yp_prot.h> 76121474Sume#include <rpcsvc/ypclnt.h> 7755163Sshin#include <netdb.h> 7855163Sshin#include <resolv.h> 7955163Sshin#include <string.h> 8055163Sshin#include <stdlib.h> 8155163Sshin#include <stddef.h> 8255163Sshin#include <ctype.h> 8355163Sshin#include <unistd.h> 8455163Sshin#include <stdio.h> 8561877Sume#include <errno.h> 86102237Spirzyk 87102237Spirzyk#include "res_config.h" 88102237Spirzyk 8978012Sume#ifdef DEBUG 9078012Sume#include <syslog.h> 9178012Sume#endif 9255163Sshin 9365532Snectar#include <stdarg.h> 9465532Snectar#include <nsswitch.h> 9571579Sdeischen#include "un-namespace.h" 96111618Snectar#include "libc_private.h" 97158115Sume#ifdef NS_CACHING 98158115Sume#include "nscache.h" 99158115Sume#endif 10065532Snectar 10155163Sshin#if defined(__KAME__) && defined(INET6) 10255163Sshin# define FAITH 10355163Sshin#endif 10455163Sshin 105105940Sume#define SUCCESS 0 106105940Sume#define ANY 0 107105940Sume#define YES 1 108105940Sume#define NO 0 10955163Sshin 11055163Sshinstatic const char in_addrany[] = { 0, 0, 0, 0 }; 111105940Sumestatic const char in_loopback[] = { 127, 0, 0, 1 }; 112105940Sume#ifdef INET6 11355163Sshinstatic const char in6_addrany[] = { 11455163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 11555163Sshin}; 11655163Sshinstatic const char in6_loopback[] = { 11755163Sshin 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 11855163Sshin}; 119105940Sume#endif 12055163Sshin 121121747Sumestruct policyqueue { 122121747Sume TAILQ_ENTRY(policyqueue) pc_entry; 123121747Sume#ifdef INET6 124121747Sume struct in6_addrpolicy pc_policy; 125121747Sume#endif 126121747Sume}; 127121747SumeTAILQ_HEAD(policyhead, policyqueue); 128121747Sume 12955163Sshinstatic const struct afd { 13055163Sshin int a_af; 13155163Sshin int a_addrlen; 132146244Sume socklen_t a_socklen; 13355163Sshin int a_off; 13455163Sshin const char *a_addrany; 13573665Sobrien const char *a_loopback; 13655163Sshin int a_scoped; 13755163Sshin} afdl [] = { 13855163Sshin#ifdef INET6 13955163Sshin#define N_INET6 0 14055163Sshin {PF_INET6, sizeof(struct in6_addr), 14155163Sshin sizeof(struct sockaddr_in6), 14255163Sshin offsetof(struct sockaddr_in6, sin6_addr), 14355163Sshin in6_addrany, in6_loopback, 1}, 14455163Sshin#define N_INET 1 14555163Sshin#else 14655163Sshin#define N_INET 0 14755163Sshin#endif 14855163Sshin {PF_INET, sizeof(struct in_addr), 14955163Sshin sizeof(struct sockaddr_in), 15055163Sshin offsetof(struct sockaddr_in, sin_addr), 15155163Sshin in_addrany, in_loopback, 0}, 15255163Sshin {0, 0, 0, 0, NULL, NULL, 0}, 15355163Sshin}; 15455163Sshin 15555163Sshinstruct explore { 15661877Sume int e_af; 15755163Sshin int e_socktype; 15855163Sshin int e_protocol; 15955163Sshin const char *e_protostr; 16055163Sshin int e_wild; 161105940Sume#define WILD_AF(ex) ((ex)->e_wild & 0x01) 162105940Sume#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 163105940Sume#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 16455163Sshin}; 16555163Sshin 16655163Sshinstatic const struct explore explore[] = { 16761877Sume#if 0 168121474Sume { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 16961877Sume#endif 17061877Sume#ifdef INET6 171121474Sume { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 172121474Sume { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 173121474Sume { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 17461877Sume#endif 175121474Sume { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 176121474Sume { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 177121474Sume { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 178121474Sume { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 179121474Sume { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 180121474Sume { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 18161877Sume { -1, 0, 0, NULL, 0 }, 18255163Sshin}; 18355163Sshin 18455163Sshin#ifdef INET6 185105940Sume#define PTON_MAX 16 18655163Sshin#else 187105940Sume#define PTON_MAX 4 18855163Sshin#endif 18955163Sshin 190121747Sume#define AIO_SRCFLAG_DEPRECATED 0x1 191121747Sume 192121747Sumestruct ai_order { 193121747Sume union { 194121747Sume struct sockaddr_storage aiou_ss; 195121747Sume struct sockaddr aiou_sa; 196121747Sume } aio_src_un; 197121747Sume#define aio_srcsa aio_src_un.aiou_sa 198121747Sume u_int32_t aio_srcflag; 199121747Sume int aio_srcscope; 200121747Sume int aio_dstscope; 201121747Sume struct policyqueue *aio_srcpolicy; 202121747Sume struct policyqueue *aio_dstpolicy; 203121747Sume struct addrinfo *aio_ai; 204121747Sume int aio_matchlen; 205121747Sume}; 206121747Sume 20765532Snectarstatic const ns_src default_dns_files[] = { 20865532Snectar { NSSRC_FILES, NS_SUCCESS }, 20965532Snectar { NSSRC_DNS, NS_SUCCESS }, 21065532Snectar { 0 } 21165532Snectar}; 21265532Snectar 21361877Sumestruct res_target { 21461877Sume struct res_target *next; 21561877Sume const char *name; /* domain name */ 21662614Sitojun int qclass, qtype; /* class and type of query */ 21761877Sume u_char *answer; /* buffer to put answer */ 21861877Sume int anslen; /* size of answer buffer */ 21961877Sume int n; /* result length */ 22061877Sume}; 22161877Sume 222121426Sume#define MAXPACKET (64*1024) 223121426Sume 224121426Sumetypedef union { 225121426Sume HEADER hdr; 226121426Sume u_char buf[MAXPACKET]; 227121426Sume} querybuf; 228121426Sume 229160593Sumestatic int str2number(const char *, int *); 23092941Sobrienstatic int explore_null(const struct addrinfo *, 23192941Sobrien const char *, struct addrinfo **); 23292941Sobrienstatic int explore_numeric(const struct addrinfo *, const char *, 233140906Sume const char *, struct addrinfo **, const char *); 23492941Sobrienstatic int explore_numeric_scope(const struct addrinfo *, const char *, 23592941Sobrien const char *, struct addrinfo **); 23692941Sobrienstatic int get_canonname(const struct addrinfo *, 23792941Sobrien struct addrinfo *, const char *); 23892941Sobrienstatic struct addrinfo *get_ai(const struct addrinfo *, 23992941Sobrien const struct afd *, const char *); 24092905Sobrienstatic int get_portmatch(const struct addrinfo *, const char *); 24192905Sobrienstatic int get_port(struct addrinfo *, const char *, int); 24292905Sobrienstatic const struct afd *find_afd(int); 243121474Sumestatic int addrconfig(struct addrinfo *); 244129901Sumestatic void set_source(struct ai_order *, struct policyhead *); 245121747Sumestatic int comp_dst(const void *, const void *); 24661877Sume#ifdef INET6 247105943Sumestatic int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *); 24861877Sume#endif 249121747Sumestatic int gai_addr2scopetype(struct sockaddr *); 25055163Sshin 251121426Sumestatic int explore_fqdn(const struct addrinfo *, const char *, 252121426Sume const char *, struct addrinfo **); 253121426Sume 254121747Sumestatic int reorder(struct addrinfo *); 255121747Sumestatic int get_addrselectpolicy(struct policyhead *); 256121747Sumestatic void free_addrselectpolicy(struct policyhead *); 257121747Sumestatic struct policyqueue *match_addrselectpolicy(struct sockaddr *, 258121747Sume struct policyhead *); 259129901Sumestatic int matchlen(struct sockaddr *, struct sockaddr *); 260121747Sume 26192941Sobrienstatic struct addrinfo *getanswer(const querybuf *, int, const char *, int, 262156960Sume const struct addrinfo *, res_state); 263121426Sume#if defined(RESOLVSORT) 264156960Sumestatic int addr4sort(struct addrinfo *, res_state); 265121426Sume#endif 266105943Sumestatic int _dns_getaddrinfo(void *, void *, va_list); 267144634Sumestatic void _sethtent(FILE **); 268144634Sumestatic void _endhtent(FILE **); 269144634Sumestatic struct addrinfo *_gethtent(FILE **, const char *, 270144634Sume const struct addrinfo *); 27192905Sobrienstatic int _files_getaddrinfo(void *, void *, va_list); 27261877Sume#ifdef YP 27392905Sobrienstatic struct addrinfo *_yphostent(char *, const struct addrinfo *); 27492905Sobrienstatic int _yp_getaddrinfo(void *, void *, va_list); 27561877Sume#endif 276158115Sume#ifdef NS_CACHING 277158115Sumestatic int addrinfo_id_func(char *, size_t *, va_list, void *); 278158115Sumestatic int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *); 279158115Sumestatic int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *); 280158115Sume#endif 28161877Sume 282156960Sumestatic int res_queryN(const char *, struct res_target *, res_state); 283156960Sumestatic int res_searchN(const char *, struct res_target *, res_state); 28492941Sobrienstatic int res_querydomainN(const char *, const char *, 285156960Sume struct res_target *, res_state); 28661877Sume 28755163Sshin/* XXX macros that make external reference is BAD. */ 28855163Sshin 289105940Sume#define GET_AI(ai, afd, addr) \ 29055163Sshindo { \ 29155163Sshin /* external reference: pai, error, and label free */ \ 29255163Sshin (ai) = get_ai(pai, (afd), (addr)); \ 29355163Sshin if ((ai) == NULL) { \ 29455163Sshin error = EAI_MEMORY; \ 29555163Sshin goto free; \ 29655163Sshin } \ 29761877Sume} while (/*CONSTCOND*/0) 29855163Sshin 299105940Sume#define GET_PORT(ai, serv) \ 30055163Sshindo { \ 30155163Sshin /* external reference: error and label free */ \ 30255163Sshin error = get_port((ai), (serv), 0); \ 30355163Sshin if (error != 0) \ 30455163Sshin goto free; \ 30561877Sume} while (/*CONSTCOND*/0) 30655163Sshin 307105940Sume#define GET_CANONNAME(ai, str) \ 30855163Sshindo { \ 30955163Sshin /* external reference: pai, error and label free */ \ 31055163Sshin error = get_canonname(pai, (ai), (str)); \ 31155163Sshin if (error != 0) \ 31255163Sshin goto free; \ 31361877Sume} while (/*CONSTCOND*/0) 31455163Sshin 315105940Sume#define ERR(err) \ 31655163Sshindo { \ 31755163Sshin /* external reference: error, and label bad */ \ 31855163Sshin error = (err); \ 31955163Sshin goto bad; \ 32061877Sume /*NOTREACHED*/ \ 32161877Sume} while (/*CONSTCOND*/0) 32255163Sshin 323105940Sume#define MATCH_FAMILY(x, y, w) \ 32461877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 325105940Sume#define MATCH(x, y, w) \ 32661877Sume ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 32755163Sshin 32855163Sshinvoid 329157119Sumefreeaddrinfo(struct addrinfo *ai) 33055163Sshin{ 33155163Sshin struct addrinfo *next; 33255163Sshin 33355163Sshin do { 33455163Sshin next = ai->ai_next; 33555163Sshin if (ai->ai_canonname) 33655163Sshin free(ai->ai_canonname); 33755163Sshin /* no need to free(ai->ai_addr) */ 33855163Sshin free(ai); 33961877Sume ai = next; 34061877Sume } while (ai); 34155163Sshin} 34255163Sshin 34355163Sshinstatic int 344160593Sumestr2number(const char *p, int *portp) 34555163Sshin{ 34662836Sitojun char *ep; 347140908Sume unsigned long v; 34862836Sitojun 34962836Sitojun if (*p == '\0') 350140908Sume return -1; 35162836Sitojun ep = NULL; 352105943Sume errno = 0; 353140908Sume v = strtoul(p, &ep, 10); 354160593Sume if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) { 355160593Sume *portp = v; 356160593Sume return 0; 357160593Sume } 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 * check for special cases. (1) numeric servname is disallowed if 42961877Sume * socktype/protocol are left unspecified. (2) servname is disallowed 43061877Sume * for raw and other inet{,6} sockets. 43155163Sshin */ 43255163Sshin if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 43361877Sume#ifdef PF_INET6 434121474Sume || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 43555163Sshin#endif 43655163Sshin ) { 43761877Sume ai0 = *pai; /* backup *pai */ 43855163Sshin 43961877Sume if (pai->ai_family == PF_UNSPEC) { 44061877Sume#ifdef PF_INET6 44155163Sshin pai->ai_family = PF_INET6; 44255163Sshin#else 44355163Sshin pai->ai_family = PF_INET; 44455163Sshin#endif 44561877Sume } 44655163Sshin error = get_portmatch(pai, servname); 44755163Sshin if (error) 44855163Sshin ERR(error); 44961877Sume 45061877Sume *pai = ai0; 45155163Sshin } 45255163Sshin 45361877Sume ai0 = *pai; 45461877Sume 455121474Sume /* NULL hostname, or numeric hostname */ 456121474Sume for (ex = explore; ex->e_af >= 0; ex++) { 45755163Sshin *pai = ai0; 45855163Sshin 459121474Sume /* PF_UNSPEC entries are prepared for DNS queries only */ 460121474Sume if (ex->e_af == PF_UNSPEC) 46155163Sshin continue; 46261877Sume 463121474Sume if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 464121474Sume continue; 465121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 466121474Sume continue; 467121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 468121474Sume continue; 469121474Sume 47055163Sshin if (pai->ai_family == PF_UNSPEC) 471121474Sume pai->ai_family = ex->e_af; 472121474Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 473121474Sume pai->ai_socktype = ex->e_socktype; 474121474Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 475121474Sume pai->ai_protocol = ex->e_protocol; 47655163Sshin 477121474Sume if (hostname == NULL) 478121474Sume error = explore_null(pai, servname, &cur->ai_next); 479121474Sume else 480140906Sume error = explore_numeric_scope(pai, hostname, servname, 481140906Sume &cur->ai_next); 48255163Sshin 483121474Sume if (error) 484121474Sume goto free; 485121474Sume 486121474Sume while (cur && cur->ai_next) 487121474Sume cur = cur->ai_next; 48855163Sshin } 48955163Sshin 490121474Sume /* 491121474Sume * XXX 492121474Sume * If numreic representation of AF1 can be interpreted as FQDN 493121474Sume * representation of AF2, we need to think again about the code below. 494121474Sume */ 495121747Sume if (sentinel.ai_next) { 496121747Sume numeric = 1; 497121474Sume goto good; 498121747Sume } 499121474Sume 500121425Sume if (hostname == NULL) 501121425Sume ERR(EAI_NONAME); /* used to be EAI_NODATA */ 50255163Sshin if (pai->ai_flags & AI_NUMERICHOST) 50390053Sroam ERR(EAI_NONAME); 50455163Sshin 505121474Sume if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0)) 506121474Sume ERR(EAI_FAIL); 507121474Sume 50861877Sume /* 50961877Sume * hostname as alphabetical name. 510121474Sume * we would like to prefer AF_INET6 than AF_INET, so we'll make a 511121474Sume * outer loop by AFs. 51261877Sume */ 51361877Sume for (ex = explore; ex->e_af >= 0; ex++) { 51461877Sume *pai = ai0; 51555163Sshin 516121474Sume /* require exact match for family field */ 517121474Sume if (pai->ai_family != ex->e_af) 51861877Sume continue; 51955163Sshin 520121474Sume if (!MATCH(pai->ai_socktype, ex->e_socktype, 521121474Sume WILD_SOCKTYPE(ex))) { 52261877Sume continue; 523121474Sume } 524121474Sume if (!MATCH(pai->ai_protocol, ex->e_protocol, 525121474Sume WILD_PROTOCOL(ex))) { 52661877Sume continue; 527121474Sume } 52855163Sshin 52961877Sume if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 53061877Sume pai->ai_socktype = ex->e_socktype; 53161877Sume if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 53261877Sume pai->ai_protocol = ex->e_protocol; 53361877Sume 534121474Sume error = explore_fqdn(pai, hostname, servname, 535121474Sume &cur->ai_next); 53661877Sume 53761877Sume while (cur && cur->ai_next) 53861877Sume cur = cur->ai_next; 53955163Sshin } 54055163Sshin 541121747Sume /* XXX inhibit errors if we have the result */ 54261877Sume if (sentinel.ai_next) 54361877Sume error = 0; 54461877Sume 545121747Sumegood: 546121747Sume /* 547121747Sume * ensure we return either: 548121747Sume * - error == 0, non-NULL *res 549121747Sume * - error != 0, NULL *res 550121747Sume */ 55161877Sume if (error == 0) { 55261877Sume if (sentinel.ai_next) { 553121747Sume /* 554121747Sume * If the returned entry is for an active connection, 555121747Sume * and the given name is not numeric, reorder the 556121747Sume * list, so that the application would try the list 557172052Sjinmei * in the most efficient order. Since the head entry 558172052Sjinmei * of the original list may contain ai_canonname and 559172052Sjinmei * that entry may be moved elsewhere in the new list, 560172052Sjinmei * we keep the pointer and will restore it in the new 561172052Sjinmei * head entry. (Note that RFC3493 requires the head 562172052Sjinmei * entry store it when requested by the caller). 563121747Sume */ 564121747Sume if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) { 565172052Sjinmei if (!numeric) { 566172052Sjinmei char *canonname; 567172052Sjinmei 568172052Sjinmei canonname = 569172052Sjinmei sentinel.ai_next->ai_canonname; 570172052Sjinmei sentinel.ai_next->ai_canonname = NULL; 571121747Sume (void)reorder(&sentinel); 572172052Sjinmei if (sentinel.ai_next->ai_canonname == 573172052Sjinmei NULL) { 574172052Sjinmei sentinel.ai_next->ai_canonname 575172052Sjinmei = canonname; 576172052Sjinmei } else if (canonname != NULL) 577172052Sjinmei free(canonname); 578172052Sjinmei } 579121747Sume } 58061877Sume *res = sentinel.ai_next; 581121474Sume return SUCCESS; 58261877Sume } else 58361877Sume error = EAI_FAIL; 58455163Sshin } 585121747Sumefree: 586121747Sumebad: 587121474Sume if (sentinel.ai_next) 588121474Sume freeaddrinfo(sentinel.ai_next); 589121474Sume *res = NULL; 59055163Sshin return error; 59155163Sshin} 59255163Sshin 593121747Sumestatic int 594157119Sumereorder(struct addrinfo *sentinel) 595121747Sume{ 596121747Sume struct addrinfo *ai, **aip; 597121747Sume struct ai_order *aio; 598121747Sume int i, n; 599121747Sume struct policyhead policyhead; 600121747Sume 601121747Sume /* count the number of addrinfo elements for sorting. */ 602121747Sume for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++) 603121747Sume ; 604121747Sume 605121747Sume /* 606121747Sume * If the number is small enough, we can skip the reordering process. 607121747Sume */ 608121747Sume if (n <= 1) 609121747Sume return(n); 610121747Sume 611121747Sume /* allocate a temporary array for sort and initialization of it. */ 612121747Sume if ((aio = malloc(sizeof(*aio) * n)) == NULL) 613121747Sume return(n); /* give up reordering */ 614121747Sume memset(aio, 0, sizeof(*aio) * n); 615121747Sume 616121747Sume /* retrieve address selection policy from the kernel */ 617121747Sume TAILQ_INIT(&policyhead); 618121747Sume if (!get_addrselectpolicy(&policyhead)) { 619121747Sume /* no policy is installed into kernel, we don't sort. */ 620121747Sume free(aio); 621121747Sume return (n); 622121747Sume } 623121747Sume 624121747Sume for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) { 625121747Sume aio[i].aio_ai = ai; 626121747Sume aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr); 627121747Sume aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr, 628121747Sume &policyhead); 629129901Sume set_source(&aio[i], &policyhead); 630121747Sume } 631121747Sume 632121747Sume /* perform sorting. */ 633121747Sume qsort(aio, n, sizeof(*aio), comp_dst); 634121747Sume 635121747Sume /* reorder the addrinfo chain. */ 636121747Sume for (i = 0, aip = &sentinel->ai_next; i < n; i++) { 637121747Sume *aip = aio[i].aio_ai; 638121747Sume aip = &aio[i].aio_ai->ai_next; 639121747Sume } 640121747Sume *aip = NULL; 641121747Sume 642121747Sume /* cleanup and return */ 643121747Sume free(aio); 644121747Sume free_addrselectpolicy(&policyhead); 645121747Sume return(n); 646121747Sume} 647121747Sume 648121747Sumestatic int 649157119Sumeget_addrselectpolicy(struct policyhead *head) 650121747Sume{ 651121747Sume#ifdef INET6 652121747Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY }; 653121747Sume size_t l; 654121747Sume char *buf; 655121747Sume struct in6_addrpolicy *pol, *ep; 656121747Sume 657121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) 658121747Sume return (0); 659121747Sume if ((buf = malloc(l)) == NULL) 660121747Sume return (0); 661121747Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 662121747Sume free(buf); 663121747Sume return (0); 664121747Sume } 665121747Sume 666121747Sume ep = (struct in6_addrpolicy *)(buf + l); 667121747Sume for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) { 668121747Sume struct policyqueue *new; 669121747Sume 670121747Sume if ((new = malloc(sizeof(*new))) == NULL) { 671121747Sume free_addrselectpolicy(head); /* make the list empty */ 672121747Sume break; 673121747Sume } 674121747Sume new->pc_policy = *pol; 675121747Sume TAILQ_INSERT_TAIL(head, new, pc_entry); 676121747Sume } 677121747Sume 678121747Sume free(buf); 679121747Sume return (1); 680121747Sume#else 681121747Sume return (0); 682121747Sume#endif 683121747Sume} 684121747Sume 685121747Sumestatic void 686157119Sumefree_addrselectpolicy(struct policyhead *head) 687121747Sume{ 688121747Sume struct policyqueue *ent, *nent; 689121747Sume 690121747Sume for (ent = TAILQ_FIRST(head); ent; ent = nent) { 691121747Sume nent = TAILQ_NEXT(ent, pc_entry); 692121747Sume TAILQ_REMOVE(head, ent, pc_entry); 693121747Sume free(ent); 694121747Sume } 695121747Sume} 696121747Sume 697121747Sumestatic struct policyqueue * 698157119Sumematch_addrselectpolicy(struct sockaddr *addr, struct policyhead *head) 699121747Sume{ 700121747Sume#ifdef INET6 701121747Sume struct policyqueue *ent, *bestent = NULL; 702121747Sume struct in6_addrpolicy *pol; 703121747Sume int matchlen, bestmatchlen = -1; 704121747Sume u_char *mp, *ep, *k, *p, m; 705121747Sume struct sockaddr_in6 key; 706121747Sume 707121747Sume switch(addr->sa_family) { 708121747Sume case AF_INET6: 709121747Sume key = *(struct sockaddr_in6 *)addr; 710121747Sume break; 711121747Sume case AF_INET: 712121747Sume /* convert the address into IPv4-mapped IPv6 address. */ 713121747Sume memset(&key, 0, sizeof(key)); 714121747Sume key.sin6_family = AF_INET6; 715121747Sume key.sin6_len = sizeof(key); 716121747Sume key.sin6_addr.s6_addr[10] = 0xff; 717121747Sume key.sin6_addr.s6_addr[11] = 0xff; 718121747Sume memcpy(&key.sin6_addr.s6_addr[12], 719121747Sume &((struct sockaddr_in *)addr)->sin_addr, 4); 720121747Sume break; 721121747Sume default: 722121747Sume return(NULL); 723121747Sume } 724121747Sume 725121747Sume for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) { 726121747Sume pol = &ent->pc_policy; 727121747Sume matchlen = 0; 728121747Sume 729121747Sume mp = (u_char *)&pol->addrmask.sin6_addr; 730121747Sume ep = mp + 16; /* XXX: scope field? */ 731121747Sume k = (u_char *)&key.sin6_addr; 732121747Sume p = (u_char *)&pol->addr.sin6_addr; 733121747Sume for (; mp < ep && *mp; mp++, k++, p++) { 734121747Sume m = *mp; 735121747Sume if ((*k & m) != *p) 736121747Sume goto next; /* not match */ 737121747Sume if (m == 0xff) /* short cut for a typical case */ 738121747Sume matchlen += 8; 739121747Sume else { 740121747Sume while (m >= 0x80) { 741121747Sume matchlen++; 742121747Sume m <<= 1; 743121747Sume } 744121747Sume } 745121747Sume } 746121747Sume 747121747Sume /* matched. check if this is better than the current best. */ 748121747Sume if (matchlen > bestmatchlen) { 749121747Sume bestent = ent; 750121747Sume bestmatchlen = matchlen; 751121747Sume } 752121747Sume 753121747Sume next: 754121747Sume continue; 755121747Sume } 756121747Sume 757121747Sume return(bestent); 758121747Sume#else 759121747Sume return(NULL); 760121747Sume#endif 761121747Sume 762121747Sume} 763121747Sume 764129901Sumestatic void 765157119Sumeset_source(struct ai_order *aio, struct policyhead *ph) 766129901Sume{ 767129901Sume struct addrinfo ai = *aio->aio_ai; 768129901Sume struct sockaddr_storage ss; 769145786Sume socklen_t srclen; 770145786Sume int s; 771129901Sume 772129901Sume /* set unspec ("no source is available"), just in case */ 773129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 774129901Sume aio->aio_srcscope = -1; 775129901Sume 776129901Sume switch(ai.ai_family) { 777129901Sume case AF_INET: 778129901Sume#ifdef INET6 779129901Sume case AF_INET6: 780129901Sume#endif 781129901Sume break; 782129901Sume default: /* ignore unsupported AFs explicitly */ 783129901Sume return; 784129901Sume } 785129901Sume 786129901Sume /* XXX: make a dummy addrinfo to call connect() */ 787129901Sume ai.ai_socktype = SOCK_DGRAM; 788129901Sume ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */ 789129901Sume ai.ai_next = NULL; 790129901Sume memset(&ss, 0, sizeof(ss)); 791129901Sume memcpy(&ss, ai.ai_addr, ai.ai_addrlen); 792129901Sume ai.ai_addr = (struct sockaddr *)&ss; 793129901Sume get_port(&ai, "1", 0); 794129901Sume 795129901Sume /* open a socket to get the source address for the given dst */ 796129901Sume if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) 797129901Sume return; /* give up */ 798129901Sume if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) 799129901Sume goto cleanup; 800129901Sume srclen = ai.ai_addrlen; 801129901Sume if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) { 802129901Sume aio->aio_srcsa.sa_family = AF_UNSPEC; 803129901Sume goto cleanup; 804129901Sume } 805129901Sume aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa); 806129901Sume aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph); 807129901Sume aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr); 808129901Sume#ifdef INET6 809129901Sume if (ai.ai_family == AF_INET6) { 810129901Sume struct in6_ifreq ifr6; 811129901Sume u_int32_t flags6; 812129901Sume 813129901Sume /* XXX: interface name should not be hardcoded */ 814129901Sume strncpy(ifr6.ifr_name, "lo0", sizeof(ifr6.ifr_name)); 815129901Sume memset(&ifr6, 0, sizeof(ifr6)); 816129901Sume memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen); 817129901Sume if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) { 818129901Sume flags6 = ifr6.ifr_ifru.ifru_flags6; 819129901Sume if ((flags6 & IN6_IFF_DEPRECATED)) 820129901Sume aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED; 821129901Sume } 822129901Sume } 823129901Sume#endif 824129901Sume 825129901Sume cleanup: 826129901Sume _close(s); 827129901Sume return; 828129901Sume} 829129901Sume 830121747Sumestatic int 831157119Sumematchlen(struct sockaddr *src, struct sockaddr *dst) 832129901Sume{ 833129901Sume int match = 0; 834129901Sume u_char *s, *d; 835129901Sume u_char *lim, r; 836129901Sume int addrlen; 837129901Sume 838129901Sume switch (src->sa_family) { 839129901Sume#ifdef INET6 840129901Sume case AF_INET6: 841129901Sume s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr; 842129901Sume d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr; 843129901Sume addrlen = sizeof(struct in6_addr); 844129901Sume lim = s + addrlen; 845129901Sume break; 846129901Sume#endif 847129901Sume case AF_INET: 848146222Sgnn s = (u_char *)&((struct sockaddr_in *)src)->sin_addr; 849146222Sgnn d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr; 850129901Sume addrlen = sizeof(struct in_addr); 851129901Sume lim = s + addrlen; 852129901Sume break; 853129901Sume default: 854129901Sume return(0); 855129901Sume } 856129901Sume 857129901Sume while (s < lim) 858129901Sume if ((r = (*d++ ^ *s++)) != 0) { 859129901Sume while (r < addrlen * 8) { 860129901Sume match++; 861129901Sume r <<= 1; 862129901Sume } 863129901Sume break; 864129901Sume } else 865129901Sume match += 8; 866129901Sume return(match); 867129901Sume} 868129901Sume 869129901Sumestatic int 870157119Sumecomp_dst(const void *arg1, const void *arg2) 871121747Sume{ 872121747Sume const struct ai_order *dst1 = arg1, *dst2 = arg2; 873121747Sume 874121747Sume /* 875121747Sume * Rule 1: Avoid unusable destinations. 876121747Sume * XXX: we currently do not consider if an appropriate route exists. 877121747Sume */ 878121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 879121747Sume dst2->aio_srcsa.sa_family == AF_UNSPEC) { 880121747Sume return(-1); 881121747Sume } 882121747Sume if (dst1->aio_srcsa.sa_family == AF_UNSPEC && 883121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 884121747Sume return(1); 885121747Sume } 886121747Sume 887121747Sume /* Rule 2: Prefer matching scope. */ 888121747Sume if (dst1->aio_dstscope == dst1->aio_srcscope && 889121747Sume dst2->aio_dstscope != dst2->aio_srcscope) { 890121747Sume return(-1); 891121747Sume } 892121747Sume if (dst1->aio_dstscope != dst1->aio_srcscope && 893121747Sume dst2->aio_dstscope == dst2->aio_srcscope) { 894121747Sume return(1); 895121747Sume } 896121747Sume 897121747Sume /* Rule 3: Avoid deprecated addresses. */ 898121747Sume if (dst1->aio_srcsa.sa_family != AF_UNSPEC && 899121747Sume dst2->aio_srcsa.sa_family != AF_UNSPEC) { 900121747Sume if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 901121747Sume (dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 902121747Sume return(-1); 903121747Sume } 904121747Sume if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) && 905121747Sume !(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) { 906121747Sume return(1); 907121747Sume } 908121747Sume } 909121747Sume 910121747Sume /* Rule 4: Prefer home addresses. */ 911121747Sume /* XXX: not implemented yet */ 912121747Sume 913121747Sume /* Rule 5: Prefer matching label. */ 914121747Sume#ifdef INET6 915121747Sume if (dst1->aio_srcpolicy && dst1->aio_dstpolicy && 916121747Sume dst1->aio_srcpolicy->pc_policy.label == 917121747Sume dst1->aio_dstpolicy->pc_policy.label && 918121747Sume (dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL || 919121747Sume dst2->aio_srcpolicy->pc_policy.label != 920121747Sume dst2->aio_dstpolicy->pc_policy.label)) { 921121747Sume return(-1); 922121747Sume } 923121747Sume if (dst2->aio_srcpolicy && dst2->aio_dstpolicy && 924121747Sume dst2->aio_srcpolicy->pc_policy.label == 925121747Sume dst2->aio_dstpolicy->pc_policy.label && 926121747Sume (dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL || 927121747Sume dst1->aio_srcpolicy->pc_policy.label != 928121747Sume dst1->aio_dstpolicy->pc_policy.label)) { 929121747Sume return(1); 930121747Sume } 931121747Sume#endif 932121747Sume 933121747Sume /* Rule 6: Prefer higher precedence. */ 934121747Sume#ifdef INET6 935121747Sume if (dst1->aio_dstpolicy && 936121747Sume (dst2->aio_dstpolicy == NULL || 937121747Sume dst1->aio_dstpolicy->pc_policy.preced > 938121747Sume dst2->aio_dstpolicy->pc_policy.preced)) { 939121747Sume return(-1); 940121747Sume } 941121747Sume if (dst2->aio_dstpolicy && 942121747Sume (dst1->aio_dstpolicy == NULL || 943121747Sume dst2->aio_dstpolicy->pc_policy.preced > 944121747Sume dst1->aio_dstpolicy->pc_policy.preced)) { 945121747Sume return(1); 946121747Sume } 947121747Sume#endif 948121747Sume 949121747Sume /* Rule 7: Prefer native transport. */ 950121747Sume /* XXX: not implemented yet */ 951121747Sume 952121747Sume /* Rule 8: Prefer smaller scope. */ 953121747Sume if (dst1->aio_dstscope >= 0 && 954121747Sume dst1->aio_dstscope < dst2->aio_dstscope) { 955121747Sume return(-1); 956121747Sume } 957121747Sume if (dst2->aio_dstscope >= 0 && 958121747Sume dst2->aio_dstscope < dst1->aio_dstscope) { 959121747Sume return(1); 960121747Sume } 961121747Sume 962121747Sume /* 963121747Sume * Rule 9: Use longest matching prefix. 964121747Sume * We compare the match length in a same AF only. 965121747Sume */ 966121747Sume if (dst1->aio_ai->ai_addr->sa_family == 967121747Sume dst2->aio_ai->ai_addr->sa_family) { 968121747Sume if (dst1->aio_matchlen > dst2->aio_matchlen) { 969121747Sume return(-1); 970121747Sume } 971121747Sume if (dst1->aio_matchlen < dst2->aio_matchlen) { 972121747Sume return(1); 973121747Sume } 974121747Sume } 975121747Sume 976121747Sume /* Rule 10: Otherwise, leave the order unchanged. */ 977121747Sume return(-1); 978121747Sume} 979121747Sume 98055163Sshin/* 981121747Sume * Copy from scope.c. 982121747Sume * XXX: we should standardize the functions and link them as standard 983121747Sume * library. 984121747Sume */ 985121747Sumestatic int 986157119Sumegai_addr2scopetype(struct sockaddr *sa) 987121747Sume{ 988121747Sume#ifdef INET6 989121747Sume struct sockaddr_in6 *sa6; 990121747Sume#endif 991121747Sume struct sockaddr_in *sa4; 992121747Sume 993121747Sume switch(sa->sa_family) { 994121747Sume#ifdef INET6 995121747Sume case AF_INET6: 996121747Sume sa6 = (struct sockaddr_in6 *)sa; 997121747Sume if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) { 998121747Sume /* just use the scope field of the multicast address */ 999121747Sume return(sa6->sin6_addr.s6_addr[2] & 0x0f); 1000121747Sume } 1001121747Sume /* 1002121747Sume * Unicast addresses: map scope type to corresponding scope 1003121747Sume * value defined for multcast addresses. 1004121747Sume * XXX: hardcoded scope type values are bad... 1005121747Sume */ 1006121747Sume if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) 1007121747Sume return(1); /* node local scope */ 1008121747Sume if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) 1009121747Sume return(2); /* link-local scope */ 1010121747Sume if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr)) 1011121747Sume return(5); /* site-local scope */ 1012121747Sume return(14); /* global scope */ 1013121747Sume break; 1014121747Sume#endif 1015121747Sume case AF_INET: 1016121747Sume /* 1017121747Sume * IPv4 pseudo scoping according to RFC 3484. 1018121747Sume */ 1019121747Sume sa4 = (struct sockaddr_in *)sa; 1020121747Sume /* IPv4 autoconfiguration addresses have link-local scope. */ 1021121747Sume if (((u_char *)&sa4->sin_addr)[0] == 169 && 1022121747Sume ((u_char *)&sa4->sin_addr)[1] == 254) 1023121747Sume return(2); 1024121747Sume /* Private addresses have site-local scope. */ 1025121747Sume if (((u_char *)&sa4->sin_addr)[0] == 10 || 1026121747Sume (((u_char *)&sa4->sin_addr)[0] == 172 && 1027121747Sume (((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) || 1028121747Sume (((u_char *)&sa4->sin_addr)[0] == 192 && 1029121747Sume ((u_char *)&sa4->sin_addr)[1] == 168)) 1030129905Sume return(14); /* XXX: It should be 5 unless NAT */ 1031121747Sume /* Loopback addresses have link-local scope. */ 1032121747Sume if (((u_char *)&sa4->sin_addr)[0] == 127) 1033121747Sume return(2); 1034121747Sume return(14); 1035121747Sume break; 1036121747Sume default: 1037121747Sume errno = EAFNOSUPPORT; /* is this a good error? */ 1038121747Sume return(-1); 1039121747Sume } 1040121747Sume} 1041121747Sume 1042121747Sume/* 104355163Sshin * hostname == NULL. 104455163Sshin * passive socket -> anyaddr (0.0.0.0 or ::) 104555163Sshin * non-passive socket -> localhost (127.0.0.1 or ::1) 104655163Sshin */ 104755163Sshinstatic int 1048157119Sumeexplore_null(const struct addrinfo *pai, const char *servname, 1049157119Sume struct addrinfo **res) 105055163Sshin{ 1051121474Sume int s; 105255163Sshin const struct afd *afd; 1053160551Sume struct addrinfo *ai; 105455163Sshin int error; 105555163Sshin 105655163Sshin *res = NULL; 1057160551Sume ai = NULL; 105855163Sshin 105955163Sshin /* 1060121474Sume * filter out AFs that are not supported by the kernel 1061121474Sume * XXX errno? 1062121474Sume */ 1063121474Sume s = _socket(pai->ai_family, SOCK_DGRAM, 0); 1064121474Sume if (s < 0) { 1065121474Sume if (errno != EMFILE) 1066121474Sume return 0; 1067121474Sume } else 1068121474Sume _close(s); 1069121474Sume 1070121474Sume /* 107161877Sume * if the servname does not match socktype/protocol, ignore it. 107261877Sume */ 107361877Sume if (get_portmatch(pai, servname) != 0) 107455163Sshin return 0; 107561877Sume 107655163Sshin afd = find_afd(pai->ai_family); 107755163Sshin if (afd == NULL) 107855163Sshin return 0; 107955163Sshin 108061877Sume if (pai->ai_flags & AI_PASSIVE) { 1081160551Sume GET_AI(ai, afd, afd->a_addrany); 1082160551Sume GET_PORT(ai, servname); 108361877Sume } else { 1084160551Sume GET_AI(ai, afd, afd->a_loopback); 1085160551Sume GET_PORT(ai, servname); 108661877Sume } 108755163Sshin 1088160551Sume *res = ai; 108955163Sshin return 0; 109055163Sshin 109155163Sshinfree: 1092160551Sume if (ai != NULL) 1093160551Sume freeaddrinfo(ai); 109455163Sshin return error; 109555163Sshin} 109655163Sshin 109755163Sshin/* 109855163Sshin * numeric hostname 109955163Sshin */ 110055163Sshinstatic int 1101157119Sumeexplore_numeric(const struct addrinfo *pai, const char *hostname, 1102157119Sume const char *servname, struct addrinfo **res, const char *canonname) 110355163Sshin{ 110455163Sshin const struct afd *afd; 1105160551Sume struct addrinfo *ai; 110655163Sshin int error; 110755163Sshin char pton[PTON_MAX]; 110855163Sshin 110955163Sshin *res = NULL; 1110160551Sume ai = NULL; 111155163Sshin 1112121474Sume /* 1113121474Sume * if the servname does not match socktype/protocol, ignore it. 1114121474Sume */ 1115121474Sume if (get_portmatch(pai, servname) != 0) 1116121474Sume return 0; 1117121474Sume 111855163Sshin afd = find_afd(pai->ai_family); 111955163Sshin if (afd == NULL) 112055163Sshin return 0; 112155163Sshin 112262614Sitojun switch (afd->a_af) { 112362614Sitojun case AF_INET: 1124160552Sume /* 1125160552Sume * RFC3493 requires getaddrinfo() to accept AF_INET formats 1126160552Sume * that are accepted by inet_addr() and its family. The 1127160552Sume * accepted forms includes the "classful" one, which inet_pton 1128160552Sume * does not accept. So we need to separate the case for 1129160552Sume * AF_INET. 1130160552Sume */ 1131160553Sume if (inet_aton(hostname, (struct in_addr *)pton) != 1) 1132160553Sume return 0; 113362614Sitojun break; 113462614Sitojun default: 1135160553Sume if (inet_pton(afd->a_af, hostname, pton) != 1) 1136160553Sume return 0; 113762614Sitojun break; 113855163Sshin } 113955163Sshin 1140160553Sume if (pai->ai_family == afd->a_af) { 1141160553Sume GET_AI(ai, afd, pton); 1142160553Sume GET_PORT(ai, servname); 1143160553Sume if ((pai->ai_flags & AI_CANONNAME)) { 1144160553Sume /* 1145160553Sume * Set the numeric address itself as the canonical 1146160553Sume * name, based on a clarification in RFC3493. 1147160553Sume */ 1148160553Sume GET_CANONNAME(ai, canonname); 1149160553Sume } 1150160553Sume } else { 1151160553Sume /* 1152160553Sume * XXX: This should not happen since we already matched the AF 1153160553Sume * by find_afd. 1154160553Sume */ 1155160553Sume ERR(EAI_FAMILY); 1156160553Sume } 1157160553Sume 1158160551Sume *res = ai; 115955163Sshin return 0; 116055163Sshin 116155163Sshinfree: 116255163Sshinbad: 1163160551Sume if (ai != NULL) 1164160551Sume freeaddrinfo(ai); 116555163Sshin return error; 116655163Sshin} 116755163Sshin 116855163Sshin/* 116955163Sshin * numeric hostname with scope 117055163Sshin */ 117155163Sshinstatic int 1172157119Sumeexplore_numeric_scope(const struct addrinfo *pai, const char *hostname, 1173157119Sume const char *servname, struct addrinfo **res) 117455163Sshin{ 117561877Sume#if !defined(SCOPE_DELIMITER) || !defined(INET6) 1176140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 117755163Sshin#else 117855163Sshin const struct afd *afd; 117955163Sshin struct addrinfo *cur; 118055163Sshin int error; 118161877Sume char *cp, *hostname2 = NULL, *scope, *addr; 118255163Sshin struct sockaddr_in6 *sin6; 118355163Sshin 1184121474Sume /* 1185121474Sume * if the servname does not match socktype/protocol, ignore it. 1186121474Sume */ 1187121474Sume if (get_portmatch(pai, servname) != 0) 1188121474Sume return 0; 1189121474Sume 119055163Sshin afd = find_afd(pai->ai_family); 119155163Sshin if (afd == NULL) 119255163Sshin return 0; 119365532Snectar 119455163Sshin if (!afd->a_scoped) 1195140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 119655163Sshin 119755163Sshin cp = strchr(hostname, SCOPE_DELIMITER); 119855163Sshin if (cp == NULL) 1199140906Sume return explore_numeric(pai, hostname, servname, res, hostname); 120055163Sshin 120155163Sshin /* 120255163Sshin * Handle special case of <scoped_address><delimiter><scope id> 120355163Sshin */ 120455163Sshin hostname2 = strdup(hostname); 120555163Sshin if (hostname2 == NULL) 120655163Sshin return EAI_MEMORY; 120755163Sshin /* terminate at the delimiter */ 120855163Sshin hostname2[cp - hostname] = '\0'; 120961877Sume addr = hostname2; 121061877Sume scope = cp + 1; 121155163Sshin 1212140906Sume error = explore_numeric(pai, addr, servname, res, hostname); 121361877Sume if (error == 0) { 1214105943Sume u_int32_t scopeid; 121555163Sshin 121655163Sshin for (cur = *res; cur; cur = cur->ai_next) { 121755163Sshin if (cur->ai_family != AF_INET6) 121855163Sshin continue; 121961877Sume sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 1220105943Sume if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) { 122161877Sume free(hostname2); 1222121425Sume return(EAI_NONAME); /* XXX: is return OK? */ 122361877Sume } 122461877Sume sin6->sin6_scope_id = scopeid; 122555163Sshin } 122655163Sshin } 122755163Sshin 122855163Sshin free(hostname2); 122955163Sshin 123055163Sshin return error; 123155163Sshin#endif 123255163Sshin} 123355163Sshin 123455163Sshinstatic int 1235157119Sumeget_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 123655163Sshin{ 123755163Sshin if ((pai->ai_flags & AI_CANONNAME) != 0) { 1238140947Sume ai->ai_canonname = strdup(str); 123955163Sshin if (ai->ai_canonname == NULL) 124055163Sshin return EAI_MEMORY; 124155163Sshin } 124255163Sshin return 0; 124355163Sshin} 124455163Sshin 124555163Sshinstatic struct addrinfo * 1246157119Sumeget_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 124755163Sshin{ 124855163Sshin char *p; 124955163Sshin struct addrinfo *ai; 125055163Sshin#ifdef FAITH 125155163Sshin struct in6_addr faith_prefix; 125255163Sshin char *fp_str; 125355163Sshin int translate = 0; 125455163Sshin#endif 125555163Sshin 125655163Sshin#ifdef FAITH 125755163Sshin /* 125855163Sshin * Transfrom an IPv4 addr into a special IPv6 addr format for 125955163Sshin * IPv6->IPv4 translation gateway. (only TCP is supported now) 126055163Sshin * 126155163Sshin * +-----------------------------------+------------+ 126255163Sshin * | faith prefix part (12 bytes) | embedded | 126355163Sshin * | | IPv4 addr part (4 bytes) 126455163Sshin * +-----------------------------------+------------+ 126555163Sshin * 126655163Sshin * faith prefix part is specified as ascii IPv6 addr format 126755163Sshin * in environmental variable GAI. 126855163Sshin * For FAITH to work correctly, routing to faith prefix must be 126955163Sshin * setup toward a machine where a FAITH daemon operates. 127055163Sshin * Also, the machine must enable some mechanizm 127155163Sshin * (e.g. faith interface hack) to divert those packet with 127255163Sshin * faith prefixed destination addr to user-land FAITH daemon. 127355163Sshin */ 127455163Sshin fp_str = getenv("GAI"); 127555163Sshin if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 127655163Sshin afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 127755163Sshin u_int32_t v4a; 127855163Sshin u_int8_t v4a_top; 127955163Sshin 128055163Sshin memcpy(&v4a, addr, sizeof v4a); 128155163Sshin v4a_top = v4a >> IN_CLASSA_NSHIFT; 128255163Sshin if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 128355163Sshin v4a_top != 0 && v4a != IN_LOOPBACKNET) { 128455163Sshin afd = &afdl[N_INET6]; 128555163Sshin memcpy(&faith_prefix.s6_addr[12], addr, 128655163Sshin sizeof(struct in_addr)); 128755163Sshin translate = 1; 128855163Sshin } 128955163Sshin } 129055163Sshin#endif 129155163Sshin 129255163Sshin ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 129355163Sshin + (afd->a_socklen)); 129455163Sshin if (ai == NULL) 129555163Sshin return NULL; 129655163Sshin 129755163Sshin memcpy(ai, pai, sizeof(struct addrinfo)); 129861877Sume ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 129961877Sume memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 130055163Sshin ai->ai_addr->sa_len = afd->a_socklen; 130155163Sshin ai->ai_addrlen = afd->a_socklen; 130255163Sshin ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 130365532Snectar p = (char *)(void *)(ai->ai_addr); 130455163Sshin#ifdef FAITH 130555163Sshin if (translate == 1) 130665532Snectar memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); 130755163Sshin else 130855163Sshin#endif 130965532Snectar memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 131055163Sshin return ai; 131155163Sshin} 131255163Sshin 131355163Sshinstatic int 1314157119Sumeget_portmatch(const struct addrinfo *ai, const char *servname) 131555163Sshin{ 131661877Sume 1317140908Sume /* get_port does not touch first argument when matchonly == 1. */ 131861877Sume /* LINTED const cast */ 131955163Sshin return get_port((struct addrinfo *)ai, servname, 1); 132055163Sshin} 132155163Sshin 132255163Sshinstatic int 1323157119Sumeget_port(struct addrinfo *ai, const char *servname, int matchonly) 132455163Sshin{ 132555163Sshin const char *proto; 132655163Sshin struct servent *sp; 1327160593Sume int port, error; 132855163Sshin int allownumeric; 132955163Sshin 133055163Sshin if (servname == NULL) 133155163Sshin return 0; 133261877Sume switch (ai->ai_family) { 133361877Sume case AF_INET: 133461877Sume#ifdef AF_INET6 133561877Sume case AF_INET6: 133655163Sshin#endif 133761877Sume break; 133861877Sume default: 133955163Sshin return 0; 134061877Sume } 134155163Sshin 134255163Sshin switch (ai->ai_socktype) { 134355163Sshin case SOCK_RAW: 134455163Sshin return EAI_SERVICE; 134555163Sshin case SOCK_DGRAM: 134655163Sshin case SOCK_STREAM: 134755163Sshin allownumeric = 1; 134855163Sshin break; 134955163Sshin case ANY: 135055163Sshin allownumeric = 0; 135155163Sshin break; 135255163Sshin default: 135355163Sshin return EAI_SOCKTYPE; 135455163Sshin } 135555163Sshin 1356160593Sume error = str2number(servname, &port); 1357160593Sume if (error == 0) { 135855163Sshin if (!allownumeric) 135955163Sshin return EAI_SERVICE; 136055163Sshin if (port < 0 || port > 65535) 136155163Sshin return EAI_SERVICE; 1362105940Sume port = htons(port); 136355163Sshin } else { 1364140908Sume if (ai->ai_flags & AI_NUMERICSERV) 1365140908Sume return EAI_NONAME; 1366121474Sume switch (ai->ai_socktype) { 1367121474Sume case SOCK_DGRAM: 136855163Sshin proto = "udp"; 136955163Sshin break; 1370121474Sume case SOCK_STREAM: 137155163Sshin proto = "tcp"; 137255163Sshin break; 137355163Sshin default: 137455163Sshin proto = NULL; 137555163Sshin break; 137655163Sshin } 137755163Sshin 1378145118Sume if ((sp = getservbyname(servname, proto)) == NULL) 137955163Sshin return EAI_SERVICE; 138055163Sshin port = sp->s_port; 138155163Sshin } 138255163Sshin 138355163Sshin if (!matchonly) { 138455163Sshin switch (ai->ai_family) { 138555163Sshin case AF_INET: 138661877Sume ((struct sockaddr_in *)(void *) 138761877Sume ai->ai_addr)->sin_port = port; 138855163Sshin break; 138955163Sshin#ifdef INET6 139055163Sshin case AF_INET6: 139161877Sume ((struct sockaddr_in6 *)(void *) 139261877Sume ai->ai_addr)->sin6_port = port; 139355163Sshin break; 139455163Sshin#endif 139555163Sshin } 139655163Sshin } 139755163Sshin 139855163Sshin return 0; 139955163Sshin} 140055163Sshin 140155163Sshinstatic const struct afd * 1402157119Sumefind_afd(int af) 140355163Sshin{ 140455163Sshin const struct afd *afd; 140555163Sshin 140655163Sshin if (af == PF_UNSPEC) 140755163Sshin return NULL; 140855163Sshin for (afd = afdl; afd->a_af; afd++) { 140955163Sshin if (afd->a_af == af) 141055163Sshin return afd; 141155163Sshin } 141255163Sshin return NULL; 141355163Sshin} 141461877Sume 141561877Sume/* 141661877Sume * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 141761877Sume * will take care of it. 141861877Sume * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 141961877Sume * if the code is right or not. 1420121474Sume * 1421121474Sume * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with 1422121474Sume * _dns_getaddrinfo. 142361877Sume */ 142461877Sumestatic int 1425157119Sumeaddrconfig(struct addrinfo *pai) 142661877Sume{ 1427121474Sume int s, af; 142861877Sume 1429121474Sume /* 1430121474Sume * TODO: 1431121474Sume * Note that implementation dependent test for address 1432121474Sume * configuration should be done everytime called 1433121474Sume * (or apropriate interval), 1434121474Sume * because addresses will be dynamically assigned or deleted. 1435121474Sume */ 1436121474Sume af = pai->ai_family; 1437121474Sume if (af == AF_UNSPEC) { 1438121474Sume if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1439121474Sume af = AF_INET; 1440121474Sume else { 1441121474Sume _close(s); 1442121474Sume if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1443121474Sume af = AF_INET6; 1444121474Sume else 1445121474Sume _close(s); 1446121474Sume } 1447121474Sume } 1448121474Sume if (af != AF_UNSPEC) { 1449121474Sume if ((s = _socket(af, SOCK_DGRAM, 0)) < 0) 145061877Sume return 0; 1451121474Sume _close(s); 1452121474Sume } 1453121474Sume pai->ai_family = af; 145461877Sume return 1; 145561877Sume} 145661877Sume 145761877Sume#ifdef INET6 145861877Sume/* convert a string to a scope identifier. XXX: IPv6 specific */ 145961877Sumestatic int 1460157119Sumeip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid) 146161877Sume{ 1462105943Sume u_long lscopeid; 1463121474Sume struct in6_addr *a6; 146461877Sume char *ep; 146561877Sume 1466121474Sume a6 = &sin6->sin6_addr; 1467121474Sume 146862836Sitojun /* empty scopeid portion is invalid */ 146962836Sitojun if (*scope == '\0') 147062836Sitojun return -1; 147162836Sitojun 1472121474Sume if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 147361877Sume /* 147461877Sume * We currently assume a one-to-one mapping between links 147561877Sume * and interfaces, so we simply use interface indices for 147661877Sume * like-local scopes. 147761877Sume */ 1478105943Sume *scopeid = if_nametoindex(scope); 1479105943Sume if (*scopeid == 0) 148061877Sume goto trynumeric; 1481105943Sume return 0; 148261877Sume } 148361877Sume 148461877Sume /* still unclear about literal, allow numeric only - placeholder */ 148561877Sume if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 148661877Sume goto trynumeric; 148761877Sume if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 148861877Sume goto trynumeric; 148961877Sume else 149061877Sume goto trynumeric; /* global */ 149161877Sume 149261877Sume /* try to convert to a numeric id as a last resort */ 1493121474Sume trynumeric: 1494105943Sume errno = 0; 1495105943Sume lscopeid = strtoul(scope, &ep, 10); 1496105943Sume *scopeid = (u_int32_t)(lscopeid & 0xffffffffUL); 1497105943Sume if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid) 1498105943Sume return 0; 149961877Sume else 150061877Sume return -1; 150161877Sume} 150261877Sume#endif 150361877Sume 1504158115Sume 1505158115Sume#ifdef NS_CACHING 1506158115Sumestatic int 1507158115Sumeaddrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap, 1508158115Sume void *cache_mdata) 1509158115Sume{ 1510158115Sume res_state statp; 1511158115Sume u_long res_options; 1512158115Sume 1513158115Sume const int op_id = 0; /* identifies the getaddrinfo for the cache */ 1514158115Sume char *hostname; 1515158115Sume struct addrinfo *hints; 1516158115Sume 1517158115Sume char *p; 1518158115Sume int ai_flags, ai_family, ai_socktype, ai_protocol; 1519158115Sume size_t desired_size, size; 1520158115Sume 1521158115Sume statp = __res_state(); 1522158115Sume res_options = statp->options & (RES_RECURSE | RES_DEFNAMES | 1523158115Sume RES_DNSRCH | RES_NOALIASES | RES_USE_INET6); 1524158115Sume 1525158115Sume hostname = va_arg(ap, char *); 1526158115Sume hints = va_arg(ap, struct addrinfo *); 1527158115Sume 1528158115Sume desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4; 1529158115Sume if (hostname != NULL) { 1530158115Sume size = strlen(hostname); 1531158115Sume desired_size += size + 1; 1532158115Sume } else 1533158115Sume size = 0; 1534158115Sume 1535158115Sume if (desired_size > *buffer_size) { 1536158115Sume *buffer_size = desired_size; 1537158115Sume return (NS_RETURN); 1538158115Sume } 1539158115Sume 1540158115Sume if (hints == NULL) 1541158115Sume ai_flags = ai_family = ai_socktype = ai_protocol = 0; 1542158115Sume else { 1543158115Sume ai_flags = hints->ai_flags; 1544158115Sume ai_family = hints->ai_family; 1545158115Sume ai_socktype = hints->ai_socktype; 1546158115Sume ai_protocol = hints->ai_protocol; 1547158115Sume } 1548158115Sume 1549158115Sume p = buffer; 1550158115Sume memcpy(p, &res_options, sizeof(res_options)); 1551158115Sume p += sizeof(res_options); 1552158115Sume 1553158115Sume memcpy(p, &op_id, sizeof(int)); 1554158115Sume p += sizeof(int); 1555158115Sume 1556158115Sume memcpy(p, &ai_flags, sizeof(int)); 1557158115Sume p += sizeof(int); 1558158115Sume 1559158115Sume memcpy(p, &ai_family, sizeof(int)); 1560158115Sume p += sizeof(int); 1561158115Sume 1562158115Sume memcpy(p, &ai_socktype, sizeof(int)); 1563158115Sume p += sizeof(int); 1564158115Sume 1565158115Sume memcpy(p, &ai_protocol, sizeof(int)); 1566158115Sume p += sizeof(int); 1567158115Sume 1568158115Sume if (hostname != NULL) 1569158115Sume memcpy(p, hostname, size); 1570158115Sume 1571158115Sume *buffer_size = desired_size; 1572158115Sume return (NS_SUCCESS); 1573158115Sume} 1574158115Sume 1575158115Sumestatic int 1576158115Sumeaddrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval, 1577158115Sume va_list ap, void *cache_mdata) 1578158115Sume{ 1579158115Sume struct addrinfo *ai, *cai; 1580158115Sume char *p; 1581158115Sume size_t desired_size, size, ai_size; 1582158115Sume 1583158115Sume ai = *((struct addrinfo **)retval); 1584158115Sume 1585158115Sume desired_size = sizeof(size_t); 1586158115Sume ai_size = 0; 1587158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1588158115Sume desired_size += sizeof(struct addrinfo) + cai->ai_addrlen; 1589158115Sume if (cai->ai_canonname != NULL) 1590158115Sume desired_size += sizeof(size_t) + 1591158115Sume strlen(cai->ai_canonname); 1592158115Sume ++ai_size; 1593158115Sume } 1594158115Sume 1595158115Sume if (desired_size > *buffer_size) { 1596158115Sume /* this assignment is here for future use */ 1597158115Sume errno = ERANGE; 1598158115Sume *buffer_size = desired_size; 1599158115Sume return (NS_RETURN); 1600158115Sume } 1601158115Sume 1602158115Sume memset(buffer, 0, desired_size); 1603158115Sume p = buffer; 1604158115Sume 1605158115Sume memcpy(p, &ai_size, sizeof(size_t)); 1606158115Sume p += sizeof(size_t); 1607158115Sume for (cai = ai; cai != NULL; cai = cai->ai_next) { 1608158115Sume memcpy(p, cai, sizeof(struct addrinfo)); 1609158115Sume p += sizeof(struct addrinfo); 1610158115Sume 1611158115Sume memcpy(p, cai->ai_addr, cai->ai_addrlen); 1612158115Sume p += cai->ai_addrlen; 1613158115Sume 1614158115Sume if (cai->ai_canonname != NULL) { 1615158115Sume size = strlen(cai->ai_canonname); 1616158115Sume memcpy(p, &size, sizeof(size_t)); 1617158115Sume p += sizeof(size_t); 1618158115Sume 1619158115Sume memcpy(p, cai->ai_canonname, size); 1620158115Sume p += size; 1621158115Sume } 1622158115Sume } 1623158115Sume 1624158115Sume return (NS_SUCCESS); 1625158115Sume} 1626158115Sume 1627158115Sumestatic int 1628158115Sumeaddrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval, 1629158115Sume va_list ap, void *cache_mdata) 1630158115Sume{ 1631158115Sume struct addrinfo new_ai, *result, *sentinel, *lasts; 1632158115Sume 1633158115Sume char *p; 1634158115Sume size_t ai_size, ai_i, size; 1635158115Sume 1636158115Sume p = buffer; 1637158115Sume memcpy(&ai_size, p, sizeof(size_t)); 1638158115Sume p += sizeof(size_t); 1639158115Sume 1640158115Sume result = NULL; 1641158115Sume lasts = NULL; 1642158115Sume for (ai_i = 0; ai_i < ai_size; ++ai_i) { 1643158115Sume memcpy(&new_ai, p, sizeof(struct addrinfo)); 1644158115Sume p += sizeof(struct addrinfo); 1645158115Sume size = new_ai.ai_addrlen + sizeof(struct addrinfo) + 1646158115Sume _ALIGNBYTES; 1647158115Sume 1648158115Sume sentinel = (struct addrinfo *)malloc(size); 1649158115Sume memset(sentinel, 0, size); 1650158115Sume 1651158115Sume memcpy(sentinel, &new_ai, sizeof(struct addrinfo)); 1652158115Sume sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel + 1653158115Sume sizeof(struct addrinfo)); 1654158115Sume 1655158115Sume memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen); 1656158115Sume p += new_ai.ai_addrlen; 1657158115Sume 1658158115Sume if (new_ai.ai_canonname != NULL) { 1659158115Sume memcpy(&size, p, sizeof(size_t)); 1660158115Sume p += sizeof(size_t); 1661158115Sume 1662158115Sume sentinel->ai_canonname = (char *)malloc(size + 1); 1663158115Sume memset(sentinel->ai_canonname, 0, size + 1); 1664158115Sume 1665158115Sume memcpy(sentinel->ai_canonname, p, size); 1666158115Sume p += size; 1667158115Sume } 1668158115Sume 1669158115Sume if (result == NULL) { 1670158115Sume result = sentinel; 1671158115Sume lasts = sentinel; 1672158115Sume } else { 1673158115Sume lasts->ai_next = sentinel; 1674158115Sume lasts = sentinel; 1675158115Sume } 1676158115Sume } 1677158115Sume 1678158115Sume *((struct addrinfo **)retval) = result; 1679158115Sume return (NS_SUCCESS); 1680158115Sume} 1681158115Sume#endif /* NS_CACHING */ 1682158115Sume 1683121426Sume/* 1684121426Sume * FQDN hostname, DNS lookup 1685121426Sume */ 1686102237Spirzykstatic int 1687157119Sumeexplore_fqdn(const struct addrinfo *pai, const char *hostname, 1688157119Sume const char *servname, struct addrinfo **res) 1689102237Spirzyk{ 1690121426Sume struct addrinfo *result; 1691121426Sume struct addrinfo *cur; 1692121426Sume int error = 0; 1693158115Sume 1694158115Sume#ifdef NS_CACHING 1695158115Sume static const nss_cache_info cache_info = 1696158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 1697158115Sume hosts, NULL, addrinfo_id_func, addrinfo_marshal_func, 1698158115Sume addrinfo_unmarshal_func); 1699158115Sume#endif 1700121426Sume static const ns_dtab dtab[] = { 1701121426Sume NS_FILES_CB(_files_getaddrinfo, NULL) 1702121426Sume { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 1703121426Sume NS_NIS_CB(_yp_getaddrinfo, NULL) 1704158115Sume#ifdef NS_CACHING 1705158115Sume NS_CACHE_CB(&cache_info) 1706158115Sume#endif 1707121426Sume { 0 } 1708121426Sume }; 1709102237Spirzyk 1710121426Sume result = NULL; 1711121426Sume 1712121426Sume /* 1713121426Sume * if the servname does not match socktype/protocol, ignore it. 1714121426Sume */ 1715126243Sgreen if (get_portmatch(pai, servname) != 0) 1716102237Spirzyk return 0; 1717102237Spirzyk 1718121426Sume switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 1719121426Sume default_dns_files, hostname, pai)) { 1720121426Sume case NS_TRYAGAIN: 1721121426Sume error = EAI_AGAIN; 1722121426Sume goto free; 1723121426Sume case NS_UNAVAIL: 1724121426Sume error = EAI_FAIL; 1725121426Sume goto free; 1726121426Sume case NS_NOTFOUND: 1727121426Sume error = EAI_NONAME; 1728121426Sume goto free; 1729121426Sume case NS_SUCCESS: 1730121426Sume error = 0; 1731121426Sume for (cur = result; cur; cur = cur->ai_next) { 1732121426Sume GET_PORT(cur, servname); 1733121426Sume /* canonname should be filled already */ 1734121426Sume } 1735121426Sume break; 1736102237Spirzyk } 1737102237Spirzyk 1738121426Sume *res = result; 1739121426Sume 1740102237Spirzyk return 0; 1741121426Sume 1742121426Sumefree: 1743121426Sume if (result) 1744121426Sume freeaddrinfo(result); 1745121426Sume return error; 1746102237Spirzyk} 1747102237Spirzyk 174861877Sume#ifdef DEBUG 174961877Sumestatic const char AskedForGot[] = 175061877Sume "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 175161877Sume#endif 175261877Sume 175361877Sumestatic struct addrinfo * 1754157119Sumegetanswer(const querybuf *answer, int anslen, const char *qname, int qtype, 1755157119Sume const struct addrinfo *pai, res_state res) 175661877Sume{ 175761877Sume struct addrinfo sentinel, *cur; 175861877Sume struct addrinfo ai; 175961877Sume const struct afd *afd; 176061877Sume char *canonname; 176161877Sume const HEADER *hp; 176261877Sume const u_char *cp; 176361877Sume int n; 176461877Sume const u_char *eom; 1765105940Sume char *bp, *ep; 1766105940Sume int type, class, ancount, qdcount; 176761877Sume int haveanswer, had_error; 176861877Sume char tbuf[MAXDNAME]; 176992905Sobrien int (*name_ok)(const char *); 177061877Sume char hostbuf[8*1024]; 177161877Sume 177261877Sume memset(&sentinel, 0, sizeof(sentinel)); 177361877Sume cur = &sentinel; 177461877Sume 177561877Sume canonname = NULL; 177661877Sume eom = answer->buf + anslen; 177761877Sume switch (qtype) { 177861877Sume case T_A: 177961877Sume case T_AAAA: 178061877Sume case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 178161877Sume name_ok = res_hnok; 178261877Sume break; 178361877Sume default: 178461877Sume return (NULL); /* XXX should be abort(); */ 178561877Sume } 178661877Sume /* 178761877Sume * find first satisfactory answer 178861877Sume */ 178961877Sume hp = &answer->hdr; 179061877Sume ancount = ntohs(hp->ancount); 179161877Sume qdcount = ntohs(hp->qdcount); 179261877Sume bp = hostbuf; 1793105940Sume ep = hostbuf + sizeof hostbuf; 179461877Sume cp = answer->buf + HFIXEDSZ; 179561877Sume if (qdcount != 1) { 1796156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 179761877Sume return (NULL); 179861877Sume } 1799105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 180061877Sume if ((n < 0) || !(*name_ok)(bp)) { 1801156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 180261877Sume return (NULL); 180361877Sume } 180461877Sume cp += n + QFIXEDSZ; 180561877Sume if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 180661877Sume /* res_send() has already verified that the query name is the 180761877Sume * same as the one we sent; this just gets the expanded name 180861877Sume * (i.e., with the succeeding search-domain tacked on). 180961877Sume */ 181061877Sume n = strlen(bp) + 1; /* for the \0 */ 181161877Sume if (n >= MAXHOSTNAMELEN) { 1812156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 181361877Sume return (NULL); 181461877Sume } 181561877Sume canonname = bp; 181661877Sume bp += n; 181761877Sume /* The qname can be abbreviated, but h_name is now absolute. */ 181861877Sume qname = canonname; 181961877Sume } 182061877Sume haveanswer = 0; 182161877Sume had_error = 0; 182261877Sume while (ancount-- > 0 && cp < eom && !had_error) { 1823105940Sume n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 182461877Sume if ((n < 0) || !(*name_ok)(bp)) { 182561877Sume had_error++; 182661877Sume continue; 182761877Sume } 182861877Sume cp += n; /* name */ 182961877Sume type = _getshort(cp); 183061877Sume cp += INT16SZ; /* type */ 183161877Sume class = _getshort(cp); 183261877Sume cp += INT16SZ + INT32SZ; /* class, TTL */ 183361877Sume n = _getshort(cp); 183461877Sume cp += INT16SZ; /* len */ 183561877Sume if (class != C_IN) { 183661877Sume /* XXX - debug? syslog? */ 183761877Sume cp += n; 183861877Sume continue; /* XXX - had_error++ ? */ 183961877Sume } 184061877Sume if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 184161877Sume type == T_CNAME) { 184261877Sume n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 184361877Sume if ((n < 0) || !(*name_ok)(tbuf)) { 184461877Sume had_error++; 184561877Sume continue; 184661877Sume } 184761877Sume cp += n; 184861877Sume /* Get canonical name. */ 184961877Sume n = strlen(tbuf) + 1; /* for the \0 */ 1850105940Sume if (n > ep - bp || n >= MAXHOSTNAMELEN) { 185161877Sume had_error++; 185261877Sume continue; 185361877Sume } 1854114443Snectar strlcpy(bp, tbuf, ep - bp); 185561877Sume canonname = bp; 185661877Sume bp += n; 185761877Sume continue; 185861877Sume } 185961877Sume if (qtype == T_ANY) { 186061877Sume if (!(type == T_A || type == T_AAAA)) { 186161877Sume cp += n; 186261877Sume continue; 186361877Sume } 186461877Sume } else if (type != qtype) { 186561877Sume#ifdef DEBUG 1866188316Sume if (type != T_KEY && type != T_SIG && 1867188316Sume type != ns_t_dname) 186861877Sume syslog(LOG_NOTICE|LOG_AUTH, 186961877Sume "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 187061877Sume qname, p_class(C_IN), p_type(qtype), 187161877Sume p_type(type)); 187261877Sume#endif 187361877Sume cp += n; 187461877Sume continue; /* XXX - had_error++ ? */ 187561877Sume } 187661877Sume switch (type) { 187761877Sume case T_A: 187861877Sume case T_AAAA: 187961877Sume if (strcasecmp(canonname, bp) != 0) { 188061877Sume#ifdef DEBUG 188161877Sume syslog(LOG_NOTICE|LOG_AUTH, 188261877Sume AskedForGot, canonname, bp); 188361877Sume#endif 188461877Sume cp += n; 188561877Sume continue; /* XXX - had_error++ ? */ 188661877Sume } 188761877Sume if (type == T_A && n != INADDRSZ) { 188861877Sume cp += n; 188961877Sume continue; 189061877Sume } 189161877Sume if (type == T_AAAA && n != IN6ADDRSZ) { 189261877Sume cp += n; 189361877Sume continue; 189461877Sume } 189561877Sume#ifdef FILTER_V4MAPPED 189661877Sume if (type == T_AAAA) { 189761877Sume struct in6_addr in6; 189861877Sume memcpy(&in6, cp, sizeof(in6)); 189961877Sume if (IN6_IS_ADDR_V4MAPPED(&in6)) { 190061877Sume cp += n; 190161877Sume continue; 190261877Sume } 190361877Sume } 190461877Sume#endif 190561877Sume if (!haveanswer) { 190661877Sume int nn; 190761877Sume 190861877Sume canonname = bp; 190961877Sume nn = strlen(bp) + 1; /* for the \0 */ 191061877Sume bp += nn; 191161877Sume } 191261877Sume 191361877Sume /* don't overwrite pai */ 191461877Sume ai = *pai; 191561877Sume ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 191661877Sume afd = find_afd(ai.ai_family); 191761877Sume if (afd == NULL) { 191861877Sume cp += n; 191961877Sume continue; 192061877Sume } 192161877Sume cur->ai_next = get_ai(&ai, afd, (const char *)cp); 192261877Sume if (cur->ai_next == NULL) 192361877Sume had_error++; 192461877Sume while (cur && cur->ai_next) 192561877Sume cur = cur->ai_next; 192661877Sume cp += n; 192761877Sume break; 192861877Sume default: 192961877Sume abort(); 193061877Sume } 193161877Sume if (!had_error) 193261877Sume haveanswer++; 193361877Sume } 193461877Sume if (haveanswer) { 1935102237Spirzyk#if defined(RESOLVSORT) 1936102237Spirzyk /* 1937102237Spirzyk * We support only IPv4 address for backward 1938102237Spirzyk * compatibility against gethostbyname(3). 1939102237Spirzyk */ 1940156960Sume if (res->nsort && qtype == T_A) { 1941156960Sume if (addr4sort(&sentinel, res) < 0) { 1942102237Spirzyk freeaddrinfo(sentinel.ai_next); 1943156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 1944102237Spirzyk return NULL; 1945102237Spirzyk } 1946102237Spirzyk } 1947102237Spirzyk#endif /*RESOLVSORT*/ 194861877Sume if (!canonname) 194961877Sume (void)get_canonname(pai, sentinel.ai_next, qname); 195061877Sume else 195161877Sume (void)get_canonname(pai, sentinel.ai_next, canonname); 1952156960Sume RES_SET_H_ERRNO(res, NETDB_SUCCESS); 195361877Sume return sentinel.ai_next; 195461877Sume } 195561877Sume 1956156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 195761877Sume return NULL; 195861877Sume} 195961877Sume 1960121426Sume#ifdef RESOLVSORT 1961121426Sumestruct addr_ptr { 1962121426Sume struct addrinfo *ai; 1963121426Sume int aval; 1964121426Sume}; 1965121426Sume 1966121426Sumestatic int 1967156960Sumeaddr4sort(struct addrinfo *sentinel, res_state res) 1968121426Sume{ 1969121426Sume struct addrinfo *ai; 1970121426Sume struct addr_ptr *addrs, addr; 1971121426Sume struct sockaddr_in *sin; 1972121426Sume int naddrs, i, j; 1973121426Sume int needsort = 0; 1974121426Sume 1975121426Sume if (!sentinel) 1976121426Sume return -1; 1977121426Sume naddrs = 0; 1978121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) 1979121426Sume naddrs++; 1980121426Sume if (naddrs < 2) 1981121426Sume return 0; /* We don't need sorting. */ 1982121426Sume if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL) 1983121426Sume return -1; 1984121426Sume i = 0; 1985121426Sume for (ai = sentinel->ai_next; ai; ai = ai->ai_next) { 1986121426Sume sin = (struct sockaddr_in *)ai->ai_addr; 1987156960Sume for (j = 0; (unsigned)j < res->nsort; j++) { 1988157119Sume if (res->sort_list[j].addr.s_addr == 1989156960Sume (sin->sin_addr.s_addr & res->sort_list[j].mask)) 1990121426Sume break; 1991121426Sume } 1992121426Sume addrs[i].ai = ai; 1993121426Sume addrs[i].aval = j; 1994121426Sume if (needsort == 0 && i > 0 && j < addrs[i - 1].aval) 1995121426Sume needsort = i; 1996121426Sume i++; 1997121426Sume } 1998121426Sume if (!needsort) { 1999121426Sume free(addrs); 2000121426Sume return 0; 2001121426Sume } 2002121426Sume 2003121426Sume while (needsort < naddrs) { 2004157371Sume for (j = needsort - 1; j >= 0; j--) { 2005157371Sume if (addrs[j].aval > addrs[j+1].aval) { 2006157371Sume addr = addrs[j]; 2007157371Sume addrs[j] = addrs[j + 1]; 2008157371Sume addrs[j + 1] = addr; 2009157371Sume } else 2010157371Sume break; 2011157371Sume } 2012157371Sume needsort++; 2013121426Sume } 2014121426Sume 2015121426Sume ai = sentinel; 2016121426Sume for (i = 0; i < naddrs; ++i) { 2017121426Sume ai->ai_next = addrs[i].ai; 2018121426Sume ai = ai->ai_next; 2019121426Sume } 2020121426Sume ai->ai_next = NULL; 2021121426Sume free(addrs); 2022121426Sume return 0; 2023121426Sume} 2024121426Sume#endif /*RESOLVSORT*/ 2025121426Sume 202661877Sume/*ARGSUSED*/ 202761877Sumestatic int 2028157119Sume_dns_getaddrinfo(void *rv, void *cb_data, va_list ap) 202961877Sume{ 203061877Sume struct addrinfo *ai; 2031103357Sume querybuf *buf, *buf2; 2032130600Sume const char *hostname; 203365532Snectar const struct addrinfo *pai; 203461877Sume struct addrinfo sentinel, *cur; 203561877Sume struct res_target q, q2; 2036156960Sume res_state res; 203761877Sume 2038130600Sume hostname = va_arg(ap, char *); 203965532Snectar pai = va_arg(ap, const struct addrinfo *); 204065532Snectar 2041156946Sdelphij memset(&q, 0, sizeof(q)); 204261877Sume memset(&q2, 0, sizeof(q2)); 204361877Sume memset(&sentinel, 0, sizeof(sentinel)); 204461877Sume cur = &sentinel; 204561877Sume 2046103357Sume buf = malloc(sizeof(*buf)); 2047103357Sume if (!buf) { 2048156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2049103357Sume return NS_NOTFOUND; 2050103357Sume } 2051103357Sume buf2 = malloc(sizeof(*buf2)); 2052103357Sume if (!buf2) { 2053103357Sume free(buf); 2054156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2055103357Sume return NS_NOTFOUND; 2056103357Sume } 2057103357Sume 205861877Sume switch (pai->ai_family) { 205961877Sume case AF_UNSPEC: 2060130600Sume q.name = hostname; 206162614Sitojun q.qclass = C_IN; 2062140896Sume q.qtype = T_A; 2063103357Sume q.answer = buf->buf; 2064103357Sume q.anslen = sizeof(buf->buf); 206561877Sume q.next = &q2; 2066130600Sume q2.name = hostname; 206762614Sitojun q2.qclass = C_IN; 2068140896Sume q2.qtype = T_AAAA; 2069103357Sume q2.answer = buf2->buf; 2070103357Sume q2.anslen = sizeof(buf2->buf); 207161877Sume break; 207261877Sume case AF_INET: 2073130600Sume q.name = hostname; 207462614Sitojun q.qclass = C_IN; 207562614Sitojun q.qtype = T_A; 2076103357Sume q.answer = buf->buf; 2077103357Sume q.anslen = sizeof(buf->buf); 207861877Sume break; 207961877Sume case AF_INET6: 2080130600Sume q.name = hostname; 208162614Sitojun q.qclass = C_IN; 208262614Sitojun q.qtype = T_AAAA; 2083103357Sume q.answer = buf->buf; 2084103357Sume q.anslen = sizeof(buf->buf); 208561877Sume break; 208661877Sume default: 2087103357Sume free(buf); 2088103357Sume free(buf2); 208965532Snectar return NS_UNAVAIL; 209061877Sume } 2091156960Sume 2092156960Sume res = __res_state(); 2093156960Sume if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) { 2094156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2095103357Sume free(buf); 2096103357Sume free(buf2); 209765532Snectar return NS_NOTFOUND; 2098103357Sume } 2099156960Sume 2100156960Sume if (res_searchN(hostname, &q, res) < 0) { 2101156960Sume free(buf); 2102156960Sume free(buf2); 2103156960Sume return NS_NOTFOUND; 2104156960Sume } 2105140896Sume /* prefer IPv6 */ 210661877Sume if (q.next) { 2107156960Sume ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res); 2108140896Sume if (ai) { 210961877Sume cur->ai_next = ai; 2110140896Sume while (cur && cur->ai_next) 2111140896Sume cur = cur->ai_next; 2112140896Sume } 211361877Sume } 2114156960Sume ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); 2115140896Sume if (ai) 2116140896Sume cur->ai_next = ai; 2117103357Sume free(buf); 2118103357Sume free(buf2); 211961877Sume if (sentinel.ai_next == NULL) 2120156960Sume switch (res->res_h_errno) { 212161877Sume case HOST_NOT_FOUND: 212265532Snectar return NS_NOTFOUND; 212361877Sume case TRY_AGAIN: 212465532Snectar return NS_TRYAGAIN; 212561877Sume default: 212665532Snectar return NS_UNAVAIL; 212761877Sume } 212865532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 212965532Snectar return NS_SUCCESS; 213061877Sume} 213161877Sume 213265532Snectarstatic void 2133144634Sume_sethtent(FILE **hostf) 213465532Snectar{ 2135144634Sume if (!*hostf) 2136144634Sume *hostf = fopen(_PATH_HOSTS, "r"); 213765532Snectar else 2138144634Sume rewind(*hostf); 213965532Snectar} 214065532Snectar 214165532Snectarstatic void 2142144634Sume_endhtent(FILE **hostf) 214365532Snectar{ 2144144634Sume if (*hostf) { 2145144634Sume (void) fclose(*hostf); 2146144634Sume *hostf = NULL; 214765532Snectar } 214865532Snectar} 214965532Snectar 215061877Sumestatic struct addrinfo * 2151144634Sume_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai) 215261877Sume{ 215361877Sume char *p; 215461877Sume char *cp, *tname, *cname; 215561877Sume struct addrinfo hints, *res0, *res; 215661877Sume int error; 215761877Sume const char *addr; 215861877Sume char hostbuf[8*1024]; 215961877Sume 2160144634Sume if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "r"))) 216165532Snectar return (NULL); 2162105940Sumeagain: 2163144634Sume if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf))) 216461877Sume return (NULL); 216561877Sume if (*p == '#') 216661877Sume goto again; 2167139612Ssobomax cp = strpbrk(p, "#\n"); 2168139612Ssobomax if (cp != NULL) 2169139612Ssobomax *cp = '\0'; 217061877Sume if (!(cp = strpbrk(p, " \t"))) 217161877Sume goto again; 217261877Sume *cp++ = '\0'; 217361877Sume addr = p; 217461877Sume cname = NULL; 217561877Sume /* if this is not something we're looking for, skip it. */ 217661877Sume while (cp && *cp) { 217761877Sume if (*cp == ' ' || *cp == '\t') { 217861877Sume cp++; 217961877Sume continue; 218061877Sume } 218161877Sume tname = cp; 218261877Sume if (cname == NULL) 218361877Sume cname = cp; 218461877Sume if ((cp = strpbrk(cp, " \t")) != NULL) 218561877Sume *cp++ = '\0'; 218661877Sume if (strcasecmp(name, tname) == 0) 218761877Sume goto found; 218861877Sume } 218961877Sume goto again; 219061877Sume 219161877Sumefound: 2192105940Sume /* we should not glob socktype/protocol here */ 2193105940Sume memset(&hints, 0, sizeof(hints)); 2194105940Sume hints.ai_family = pai->ai_family; 2195105940Sume hints.ai_socktype = SOCK_DGRAM; 2196105940Sume hints.ai_protocol = 0; 219761877Sume hints.ai_flags = AI_NUMERICHOST; 2198105940Sume error = getaddrinfo(addr, "0", &hints, &res0); 219961877Sume if (error) 220061877Sume goto again; 220161877Sume#ifdef FILTER_V4MAPPED 220261877Sume /* XXX should check all items in the chain */ 220361877Sume if (res0->ai_family == AF_INET6 && 220461877Sume IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) { 220561877Sume freeaddrinfo(res0); 220661877Sume goto again; 220761877Sume } 220861877Sume#endif 220961877Sume for (res = res0; res; res = res->ai_next) { 221061877Sume /* cover it up */ 221161877Sume res->ai_flags = pai->ai_flags; 2212105940Sume res->ai_socktype = pai->ai_socktype; 2213105940Sume res->ai_protocol = pai->ai_protocol; 221461877Sume 221561877Sume if (pai->ai_flags & AI_CANONNAME) { 221661877Sume if (get_canonname(pai, res, cname) != 0) { 221761877Sume freeaddrinfo(res0); 221861877Sume goto again; 221961877Sume } 222061877Sume } 222161877Sume } 222261877Sume return res0; 222361877Sume} 222461877Sume 222561877Sume/*ARGSUSED*/ 222661877Sumestatic int 2227157119Sume_files_getaddrinfo(void *rv, void *cb_data, va_list ap) 222865532Snectar{ 222965532Snectar const char *name; 223061877Sume const struct addrinfo *pai; 223161877Sume struct addrinfo sentinel, *cur; 223261877Sume struct addrinfo *p; 2233144634Sume FILE *hostf = NULL; 223461877Sume 223565532Snectar name = va_arg(ap, char *); 223665532Snectar pai = va_arg(ap, struct addrinfo *); 223765532Snectar 223865532Snectar memset(&sentinel, 0, sizeof(sentinel)); 223961877Sume cur = &sentinel; 224061877Sume 2241144634Sume _sethtent(&hostf); 2242144634Sume while ((p = _gethtent(&hostf, name, pai)) != NULL) { 224361877Sume cur->ai_next = p; 224461877Sume while (cur && cur->ai_next) 224561877Sume cur = cur->ai_next; 224661877Sume } 2247144634Sume _endhtent(&hostf); 224861877Sume 224965532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 225065532Snectar if (sentinel.ai_next == NULL) 225165532Snectar return NS_NOTFOUND; 225265532Snectar return NS_SUCCESS; 225361877Sume} 225461877Sume 225561877Sume#ifdef YP 225661877Sume/*ARGSUSED*/ 225765532Snectarstatic struct addrinfo * 2258157119Sume_yphostent(char *line, const struct addrinfo *pai) 225961877Sume{ 226061877Sume struct addrinfo sentinel, *cur; 226165532Snectar struct addrinfo hints, *res, *res0; 226261877Sume int error; 226365532Snectar char *p = line; 226465532Snectar const char *addr, *canonname; 226565532Snectar char *nextline; 226665532Snectar char *cp; 226761877Sume 226865532Snectar addr = canonname = NULL; 226965532Snectar 227065532Snectar memset(&sentinel, 0, sizeof(sentinel)); 227161877Sume cur = &sentinel; 227261877Sume 227365532Snectarnextline: 227465532Snectar /* terminate line */ 227565532Snectar cp = strchr(p, '\n'); 227665532Snectar if (cp) { 227765532Snectar *cp++ = '\0'; 227865532Snectar nextline = cp; 227965532Snectar } else 228065532Snectar nextline = NULL; 228161877Sume 228265532Snectar cp = strpbrk(p, " \t"); 228365532Snectar if (cp == NULL) { 228465532Snectar if (canonname == NULL) 228565532Snectar return (NULL); 228665532Snectar else 228765532Snectar goto done; 228861877Sume } 228965532Snectar *cp++ = '\0'; 229061877Sume 229165532Snectar addr = p; 229261877Sume 229365532Snectar while (cp && *cp) { 229465532Snectar if (*cp == ' ' || *cp == '\t') { 229565532Snectar cp++; 229661877Sume continue; 229765532Snectar } 229865532Snectar if (!canonname) 229965532Snectar canonname = cp; 230065532Snectar if ((cp = strpbrk(cp, " \t")) != NULL) 230165532Snectar *cp++ = '\0'; 230265532Snectar } 230361877Sume 2304121474Sume hints = *pai; 230565532Snectar hints.ai_flags = AI_NUMERICHOST; 2306121474Sume error = getaddrinfo(addr, NULL, &hints, &res0); 230765532Snectar if (error == 0) { 230865532Snectar for (res = res0; res; res = res->ai_next) { 230965532Snectar /* cover it up */ 231065532Snectar res->ai_flags = pai->ai_flags; 231161877Sume 231265532Snectar if (pai->ai_flags & AI_CANONNAME) 231365532Snectar (void)get_canonname(pai, res, canonname); 231461877Sume } 231565532Snectar } else 231665532Snectar res0 = NULL; 231765532Snectar if (res0) { 231865532Snectar cur->ai_next = res0; 231961877Sume while (cur && cur->ai_next) 232061877Sume cur = cur->ai_next; 232161877Sume } 232261877Sume 232365532Snectar if (nextline) { 232465532Snectar p = nextline; 232565532Snectar goto nextline; 232665532Snectar } 232761877Sume 232865532Snectardone: 232965532Snectar return sentinel.ai_next; 233061877Sume} 233165532Snectar 233265532Snectar/*ARGSUSED*/ 233365532Snectarstatic int 2334157119Sume_yp_getaddrinfo(void *rv, void *cb_data, va_list ap) 233565532Snectar{ 233665532Snectar struct addrinfo sentinel, *cur; 233765532Snectar struct addrinfo *ai = NULL; 2338144679Sume char *ypbuf; 2339144679Sume int ypbuflen, r; 234065532Snectar const char *name; 234165532Snectar const struct addrinfo *pai; 2342144679Sume char *ypdomain; 234365532Snectar 2344144679Sume if (_yp_check(&ypdomain) == 0) 2345144679Sume return NS_UNAVAIL; 2346144679Sume 234765532Snectar name = va_arg(ap, char *); 234865532Snectar pai = va_arg(ap, const struct addrinfo *); 234965532Snectar 235065532Snectar memset(&sentinel, 0, sizeof(sentinel)); 235165532Snectar cur = &sentinel; 235265532Snectar 235365532Snectar /* hosts.byname is only for IPv4 (Solaris8) */ 235465532Snectar if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 2355144679Sume r = yp_match(ypdomain, "hosts.byname", name, 2356144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 235765532Snectar if (r == 0) { 235865532Snectar struct addrinfo ai4; 235965532Snectar 236065532Snectar ai4 = *pai; 236165532Snectar ai4.ai_family = AF_INET; 2362144679Sume ai = _yphostent(ypbuf, &ai4); 236365532Snectar if (ai) { 236465532Snectar cur->ai_next = ai; 236565532Snectar while (cur && cur->ai_next) 236665532Snectar cur = cur->ai_next; 236765532Snectar } 2368146190Sume free(ypbuf); 236965532Snectar } 237065532Snectar } 237165532Snectar 237265532Snectar /* ipnodes.byname can hold both IPv4/v6 */ 2373144679Sume r = yp_match(ypdomain, "ipnodes.byname", name, 2374144679Sume (int)strlen(name), &ypbuf, &ypbuflen); 237565532Snectar if (r == 0) { 2376144679Sume ai = _yphostent(ypbuf, pai); 2377144679Sume if (ai) 237865532Snectar cur->ai_next = ai; 2379144679Sume free(ypbuf); 238065532Snectar } 238165532Snectar 238265532Snectar if (sentinel.ai_next == NULL) { 2383156960Sume RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); 238465532Snectar return NS_NOTFOUND; 238565532Snectar } 238665532Snectar *((struct addrinfo **)rv) = sentinel.ai_next; 238765532Snectar return NS_SUCCESS; 238865532Snectar} 238961877Sume#endif 239061877Sume 239161877Sume/* resolver logic */ 239261877Sume 239361877Sume/* 239461877Sume * Formulate a normal query, send, and await answer. 239561877Sume * Returned answer is placed in supplied buffer "answer". 239661877Sume * Perform preliminary check of answer, returning success only 239761877Sume * if no error is indicated and the answer count is nonzero. 239861877Sume * Return the size of the response on success, -1 on error. 239961877Sume * Error number is left in h_errno. 240061877Sume * 240161877Sume * Caller must parse answer and determine whether it answers the question. 240261877Sume */ 240361877Sumestatic int 2404157119Sumeres_queryN(const char *name, struct res_target *target, res_state res) 240561877Sume{ 2406103357Sume u_char *buf; 240761877Sume HEADER *hp; 240861877Sume int n; 2409157203Sume u_int oflags; 241061877Sume struct res_target *t; 241161877Sume int rcode; 241261877Sume int ancount; 241361877Sume 241461877Sume rcode = NOERROR; 241561877Sume ancount = 0; 241661877Sume 2417103357Sume buf = malloc(MAXPACKET); 2418103357Sume if (!buf) { 2419156960Sume RES_SET_H_ERRNO(res, NETDB_INTERNAL); 2420103357Sume return -1; 2421103357Sume } 2422103357Sume 242361877Sume for (t = target; t; t = t->next) { 242461877Sume int class, type; 242561877Sume u_char *answer; 242661877Sume int anslen; 242761877Sume 242861877Sume hp = (HEADER *)(void *)t->answer; 242961877Sume 243061877Sume /* make it easier... */ 243162614Sitojun class = t->qclass; 243262614Sitojun type = t->qtype; 243361877Sume answer = t->answer; 243461877Sume anslen = t->anslen; 2435157203Sume 2436157203Sume oflags = res->_flags; 2437157203Sume 2438157203Sumeagain: 2439157203Sume hp->rcode = NOERROR; /* default */ 2440157203Sume 244161877Sume#ifdef DEBUG 2442156960Sume if (res->options & RES_DEBUG) 244361877Sume printf(";; res_query(%s, %d, %d)\n", name, class, type); 244461877Sume#endif 244561877Sume 2446156960Sume n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL, 2447103357Sume buf, MAXPACKET); 2448157203Sume if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 && 2449157203Sume (res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U) 2450156960Sume n = res_nopt(res, n, buf, MAXPACKET, anslen); 245161877Sume if (n <= 0) { 245261877Sume#ifdef DEBUG 2453156960Sume if (res->options & RES_DEBUG) 245461877Sume printf(";; res_query: mkquery failed\n"); 245561877Sume#endif 2456103357Sume free(buf); 2457156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 245861877Sume return (n); 245961877Sume } 2460156960Sume n = res_nsend(res, buf, n, answer, anslen); 246161877Sume if (n < 0) { 2462157203Sume /* 2463157203Sume * if the query choked with EDNS0, retry 2464157203Sume * without EDNS0 2465157203Sume */ 2466157203Sume if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) 2467157203Sume != 0U && 2468157203Sume ((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) { 2469157203Sume res->_flags |= RES_F_EDNS0ERR; 2470157203Sume if (res->options & RES_DEBUG) 2471157203Sume printf(";; res_nquery: retry without EDNS0\n"); 2472157203Sume goto again; 2473157203Sume } 2474157203Sume rcode = hp->rcode; /* record most recent error */ 247561877Sume#ifdef DEBUG 2476156960Sume if (res->options & RES_DEBUG) 247761877Sume printf(";; res_query: send error\n"); 247861877Sume#endif 2479157203Sume continue; 248061877Sume } 248161877Sume 2482157081Sume if (n > anslen) 2483103350Snectar hp->rcode = FORMERR; /* XXX not very informative */ 2484157203Sume if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 248561877Sume rcode = hp->rcode; /* record most recent error */ 248661877Sume#ifdef DEBUG 2487156960Sume if (res->options & RES_DEBUG) 2488105940Sume printf(";; rcode = %u, ancount=%u\n", hp->rcode, 248961877Sume ntohs(hp->ancount)); 249061877Sume#endif 249161877Sume continue; 249261877Sume } 249361877Sume 249461877Sume ancount += ntohs(hp->ancount); 249561877Sume 249661877Sume t->n = n; 249761877Sume } 249861877Sume 2499103357Sume free(buf); 2500103357Sume 250161877Sume if (ancount == 0) { 250261877Sume switch (rcode) { 250361877Sume case NXDOMAIN: 2504156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); 250561877Sume break; 250661877Sume case SERVFAIL: 2507156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 250861877Sume break; 250961877Sume case NOERROR: 2510156960Sume RES_SET_H_ERRNO(res, NO_DATA); 251161877Sume break; 251261877Sume case FORMERR: 251361877Sume case NOTIMP: 251461877Sume case REFUSED: 251561877Sume default: 2516156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 251761877Sume break; 251861877Sume } 251961877Sume return (-1); 252061877Sume } 252161877Sume return (ancount); 252261877Sume} 252361877Sume 252461877Sume/* 252561877Sume * Formulate a normal query, send, and retrieve answer in supplied buffer. 252661877Sume * Return the size of the response on success, -1 on error. 252761877Sume * If enabled, implement search rules until answer or unrecoverable failure 252861877Sume * is detected. Error code, if any, is left in h_errno. 252961877Sume */ 253061877Sumestatic int 2531157119Sumeres_searchN(const char *name, struct res_target *target, res_state res) 253261877Sume{ 253361877Sume const char *cp, * const *domain; 253461877Sume HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 253561877Sume u_int dots; 253661877Sume int trailing_dot, ret, saved_herrno; 2537155983Sume int got_nodata = 0, got_servfail = 0, root_on_list = 0; 2538155983Sume int tried_as_is = 0; 2539155983Sume int searched = 0; 2540145113Sume char abuf[MAXDNAME]; 254161877Sume 254261877Sume errno = 0; 2543156960Sume RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */ 254461877Sume dots = 0; 254561877Sume for (cp = name; *cp; cp++) 254661877Sume dots += (*cp == '.'); 254761877Sume trailing_dot = 0; 254861877Sume if (cp > name && *--cp == '.') 254961877Sume trailing_dot++; 255061877Sume 255161877Sume /* 255261877Sume * if there aren't any dots, it could be a user-level alias 255361877Sume */ 2554156960Sume if (!dots && 2555156960Sume (cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL) 2556156960Sume return (res_queryN(cp, target, res)); 255761877Sume 255861877Sume /* 2559155983Sume * If there are enough dots in the name, let's just give it a 2560155983Sume * try 'as is'. The threshold can be set with the "ndots" option. 2561155983Sume * Also, query 'as is', if there is a trailing dot in the name. 256261877Sume */ 256361877Sume saved_herrno = -1; 2564156960Sume if (dots >= res->ndots || trailing_dot) { 2565156960Sume ret = res_querydomainN(name, NULL, target, res); 2566155983Sume if (ret > 0 || trailing_dot) 256761877Sume return (ret); 2568156155Sume if (errno == ECONNREFUSED) { 2569156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 2570156155Sume return (-1); 2571156155Sume } 2572156960Sume switch (res->res_h_errno) { 2573156155Sume case NO_DATA: 2574156155Sume case HOST_NOT_FOUND: 2575156155Sume break; 2576157093Sume case TRY_AGAIN: 2577157093Sume if (hp->rcode == SERVFAIL) 2578157093Sume break; 2579157093Sume /* FALLTHROUGH */ 2580156155Sume default: 2581156155Sume return (-1); 2582156155Sume } 2583156960Sume saved_herrno = res->res_h_errno; 258461877Sume tried_as_is++; 258561877Sume } 258661877Sume 258761877Sume /* 258861877Sume * We do at least one level of search if 258961877Sume * - there is no dot and RES_DEFNAME is set, or 259061877Sume * - there is at least one dot, there is no trailing dot, 259161877Sume * and RES_DNSRCH is set. 259261877Sume */ 2593156960Sume if ((!dots && (res->options & RES_DEFNAMES)) || 2594156960Sume (dots && !trailing_dot && (res->options & RES_DNSRCH))) { 259561877Sume int done = 0; 259661877Sume 2597156960Sume for (domain = (const char * const *)res->dnsrch; 259861877Sume *domain && !done; 259961877Sume domain++) { 2600155983Sume searched = 1; 260161877Sume 2602155983Sume if (domain[0][0] == '\0' || 2603155983Sume (domain[0][0] == '.' && domain[0][1] == '\0')) 2604155983Sume root_on_list++; 2605155983Sume 2606155983Sume if (root_on_list && tried_as_is) 2607155983Sume continue; 2608155983Sume 2609156960Sume ret = res_querydomainN(name, *domain, target, res); 261061877Sume if (ret > 0) 261161877Sume return (ret); 261261877Sume 261361877Sume /* 261461877Sume * If no server present, give up. 261561877Sume * If name isn't found in this domain, 261661877Sume * keep trying higher domains in the search list 261761877Sume * (if that's enabled). 261861877Sume * On a NO_DATA error, keep trying, otherwise 261961877Sume * a wildcard entry of another type could keep us 262061877Sume * from finding this entry higher in the domain. 262161877Sume * If we get some other error (negative answer or 262261877Sume * server failure), then stop searching up, 262361877Sume * but try the input name below in case it's 262461877Sume * fully-qualified. 262561877Sume */ 262661877Sume if (errno == ECONNREFUSED) { 2627156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 262861877Sume return (-1); 262961877Sume } 263061877Sume 2631156960Sume switch (res->res_h_errno) { 263261877Sume case NO_DATA: 263361877Sume got_nodata++; 263461877Sume /* FALLTHROUGH */ 263561877Sume case HOST_NOT_FOUND: 263661877Sume /* keep trying */ 263761877Sume break; 263861877Sume case TRY_AGAIN: 2639157093Sume got_servfail++; 264061877Sume if (hp->rcode == SERVFAIL) { 264161877Sume /* try next search element, if any */ 264261877Sume break; 264361877Sume } 264461877Sume /* FALLTHROUGH */ 264561877Sume default: 264661877Sume /* anything else implies that we're done */ 264761877Sume done++; 264861877Sume } 264961877Sume /* 265061877Sume * if we got here for some reason other than DNSRCH, 265161877Sume * we only wanted one iteration of the loop, so stop. 265261877Sume */ 2653156960Sume if (!(res->options & RES_DNSRCH)) 265461877Sume done++; 265561877Sume } 265661877Sume } 265761877Sume 2658156960Sume switch (res->res_h_errno) { 2659156155Sume case NO_DATA: 2660156155Sume case HOST_NOT_FOUND: 2661156155Sume break; 2662157093Sume case TRY_AGAIN: 2663157093Sume if (hp->rcode == SERVFAIL) 2664157093Sume break; 2665157093Sume /* FALLTHROUGH */ 2666156155Sume default: 2667156155Sume goto giveup; 2668156155Sume } 2669156155Sume 267061877Sume /* 2671155983Sume * If the query has not already been tried as is then try it 2672155983Sume * unless RES_NOTLDQUERY is set and there were no dots. 267361877Sume */ 2674156960Sume if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) && 2675155983Sume !(tried_as_is || root_on_list)) { 2676156960Sume ret = res_querydomainN(name, NULL, target, res); 267761877Sume if (ret > 0) 267861877Sume return (ret); 267961877Sume } 268061877Sume 268161877Sume /* 268261877Sume * if we got here, we didn't satisfy the search. 268361877Sume * if we did an initial full query, return that query's h_errno 268461877Sume * (note that we wouldn't be here if that query had succeeded). 268561877Sume * else if we ever got a nodata, send that back as the reason. 268661877Sume * else send back meaningless h_errno, that being the one from 268761877Sume * the last DNSRCH we did. 268861877Sume */ 2689156155Sumegiveup: 269061877Sume if (saved_herrno != -1) 2691156960Sume RES_SET_H_ERRNO(res, saved_herrno); 269261877Sume else if (got_nodata) 2693156960Sume RES_SET_H_ERRNO(res, NO_DATA); 269461877Sume else if (got_servfail) 2695156960Sume RES_SET_H_ERRNO(res, TRY_AGAIN); 269661877Sume return (-1); 269761877Sume} 269861877Sume 269961877Sume/* 270061877Sume * Perform a call on res_query on the concatenation of name and domain, 270161877Sume * removing a trailing dot from name if domain is NULL. 270261877Sume */ 270361877Sumestatic int 2704157119Sumeres_querydomainN(const char *name, const char *domain, 2705157119Sume struct res_target *target, res_state res) 270661877Sume{ 270761877Sume char nbuf[MAXDNAME]; 270861877Sume const char *longname = nbuf; 270961877Sume size_t n, d; 271061877Sume 271161877Sume#ifdef DEBUG 2712156960Sume if (res->options & RES_DEBUG) 271361877Sume printf(";; res_querydomain(%s, %s)\n", 271461877Sume name, domain?domain:"<Nil>"); 271561877Sume#endif 271661877Sume if (domain == NULL) { 271761877Sume /* 271861877Sume * Check for trailing '.'; 271961877Sume * copy without '.' if present. 272061877Sume */ 272161877Sume n = strlen(name); 272261877Sume if (n >= MAXDNAME) { 2723156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 272461877Sume return (-1); 272561877Sume } 272661877Sume if (n > 0 && name[--n] == '.') { 272761877Sume strncpy(nbuf, name, n); 272861877Sume nbuf[n] = '\0'; 272961877Sume } else 273061877Sume longname = name; 273161877Sume } else { 273261877Sume n = strlen(name); 273361877Sume d = strlen(domain); 273461877Sume if (n + d + 1 >= MAXDNAME) { 2735156960Sume RES_SET_H_ERRNO(res, NO_RECOVERY); 273661877Sume return (-1); 273761877Sume } 2738105940Sume snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain); 273961877Sume } 2740156960Sume return (res_queryN(longname, target, res)); 274161877Sume} 2742