getaddrinfo.c revision 56627
1155192Srwatson/* 2155192Srwatson * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3155192Srwatson * All rights reserved. 4155192Srwatson * 5155192Srwatson * Redistribution and use in source and binary forms, with or without 6155192Srwatson * modification, are permitted provided that the following conditions 7155192Srwatson * are met: 8155192Srwatson * 1. Redistributions of source code must retain the above copyright 9155192Srwatson * notice, this list of conditions and the following disclaimer. 10155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11155192Srwatson * notice, this list of conditions and the following disclaimer in the 12155192Srwatson * documentation and/or other materials provided with the distribution. 13155192Srwatson * 3. Neither the name of the project nor the names of its contributors 14155192Srwatson * may be used to endorse or promote products derived from this software 15155192Srwatson * without specific prior written permission. 16155192Srwatson * 17155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20155192Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27155192Srwatson * SUCH DAMAGE. 28155192Srwatson * 29155192Srwatson * $FreeBSD: head/lib/libc/net/getaddrinfo.c 56627 2000-01-26 08:37:29Z shin $ 30155192Srwatson */ 31155192Srwatson 32168933Srwatson/* 33168933Srwatson * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 34155192Srwatson * 35159318Srwatson * Issues to be discussed: 36155192Srwatson * - Thread safe-ness must be checked. 37164033Srwatson * - Return values. There are nonstandard return values defined and used 38155192Srwatson * in the source code. This is because RFC2553 is silent about which error 39155192Srwatson * code must be returned for which situation. 40155192Srwatson * Note: 41155192Srwatson * - We use getipnodebyname() just for thread-safeness. There's no intent 42163207Scsjp * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 43155192Srwatson * getipnodebyname(). 44155192Srwatson * - The code filters out AFs that are not supported by the kernel, 45155192Srwatson * when globbing NULL hostname (to loopback, or wildcard). Is it the right 46168933Srwatson * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 47155192Srwatson * in ai_flags? 48155192Srwatson */ 49168933Srwatson 50155192Srwatson#include <sys/types.h> 51155192Srwatson#include <sys/param.h> 52155192Srwatson#include <sys/socket.h> 53155192Srwatson#include <net/if.h> 54156889Srwatson#include <netinet/in.h> 55170127Srwatson#include <arpa/inet.h> 56156889Srwatson#include <arpa/nameser.h> 57155192Srwatson#include <netdb.h> 58156889Srwatson#include <resolv.h> 59156889Srwatson#include <string.h> 60156889Srwatson#include <stdlib.h> 61155192Srwatson#include <stddef.h> 62155192Srwatson#include <ctype.h> 63155192Srwatson#include <unistd.h> 64155192Srwatson#include <stdio.h> 65155192Srwatson 66155192Srwatson#if defined(__KAME__) && defined(INET6) 67155192Srwatson# define FAITH 68155192Srwatson#endif 69155192Srwatson 70163207Scsjp#define SUCCESS 0 71163207Scsjp#define ANY 0 72164033Srwatson#define YES 1 73155192Srwatson#define NO 0 74155192Srwatson 75155192Srwatsonstatic const char in_addrany[] = { 0, 0, 0, 0 }; 76155192Srwatsonstatic const char in6_addrany[] = { 77155192Srwatson 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 78155192Srwatson}; 79155192Srwatsonstatic const char in_loopback[] = { 127, 0, 0, 1 }; 80155192Srwatsonstatic const char in6_loopback[] = { 81156889Srwatson 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 82156889Srwatson}; 83155192Srwatson 84155192Srwatsonstatic const struct afd { 85155192Srwatson int a_af; 86155192Srwatson int a_addrlen; 87156889Srwatson int a_socklen; 88156889Srwatson int a_off; 89156889Srwatson const char *a_addrany; 90156889Srwatson const char *a_loopback; 91155192Srwatson int a_scoped; 92155192Srwatson} afdl [] = { 93155192Srwatson#ifdef INET6 94155192Srwatson#define N_INET6 0 95155192Srwatson {PF_INET6, sizeof(struct in6_addr), 96155192Srwatson sizeof(struct sockaddr_in6), 97155192Srwatson offsetof(struct sockaddr_in6, sin6_addr), 98155192Srwatson in6_addrany, in6_loopback, 1}, 99155192Srwatson#define N_INET 1 100155192Srwatson#else 101156889Srwatson#define N_INET 0 102155192Srwatson#endif 103155192Srwatson {PF_INET, sizeof(struct in_addr), 104155192Srwatson sizeof(struct sockaddr_in), 105155192Srwatson offsetof(struct sockaddr_in, sin_addr), 106155192Srwatson in_addrany, in_loopback, 0}, 107155192Srwatson {0, 0, 0, 0, NULL, NULL, 0}, 108155192Srwatson}; 109155192Srwatson 110156889Srwatsonstruct explore { 111155192Srwatson int e_af; 112155192Srwatson int e_socktype; 113155192Srwatson int e_protocol; 114155192Srwatson const char *e_protostr; 115155192Srwatson int e_wild; 116168933Srwatson#define WILD_AF(ex) ((ex)->e_wild & 0x01) 117172930Srwatson#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 118168933Srwatson#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 119168933Srwatson}; 120168933Srwatson 121168933Srwatsonstatic const struct explore explore[] = { 122156889Srwatson#ifdef INET6 123170127Srwatson { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 124155192Srwatson { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 125155192Srwatson { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 126155192Srwatson#endif 127155192Srwatson { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 128155192Srwatson { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 129155192Srwatson { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 130155192Srwatson { -1, 0, 0, NULL, 0 }, 131155192Srwatson}; 132155192Srwatson 133162380Scsjp#ifdef INET6 134162380Scsjp#define PTON_MAX 16 135162380Scsjp#else 136170127Srwatson#define PTON_MAX 4 137162380Scsjp#endif 138162380Scsjp 139162380Scsjp 140162380Scsjpstatic int str_isnumber __P((const char *)); 141155192Srwatsonstatic int explore_fqdn __P((const struct addrinfo *, const char *, 142155192Srwatson const char *, struct addrinfo **)); 143155192Srwatsonstatic int explore_null __P((const struct addrinfo *, const char *, 144156889Srwatson const char *, struct addrinfo **)); 145156889Srwatsonstatic int explore_numeric __P((const struct addrinfo *, const char *, 146156889Srwatson const char *, struct addrinfo **)); 147155192Srwatsonstatic int explore_numeric_scope __P((const struct addrinfo *, const char *, 148155192Srwatson const char *, struct addrinfo **)); 149155192Srwatsonstatic int get_canonname __P((const struct addrinfo *, 150155192Srwatson struct addrinfo *, const char *)); 151155192Srwatsonstatic struct addrinfo *get_ai __P((const struct addrinfo *, 152155192Srwatson const struct afd *, const char *)); 153155192Srwatsonstatic int get_portmatch __P((const struct addrinfo *, const char *)); 154155192Srwatsonstatic int get_port __P((struct addrinfo *, const char *, int)); 155155192Srwatsonstatic const struct afd *find_afd __P((int)); 156155192Srwatson 157155192Srwatsonstatic char *ai_errlist[] = { 158155192Srwatson "Success", 159170407Srwatson "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 160155192Srwatson "Temporary failure in name resolution", /* EAI_AGAIN */ 161155192Srwatson "Invalid value for ai_flags", /* EAI_BADFLAGS */ 162155192Srwatson "Non-recoverable failure in name resolution", /* EAI_FAIL */ 163155192Srwatson "ai_family not supported", /* EAI_FAMILY */ 164163207Scsjp "Memory allocation failure", /* EAI_MEMORY */ 165163207Scsjp "No address associated with hostname", /* EAI_NODATA */ 166155192Srwatson "hostname nor servname provided, or not known", /* EAI_NONAME */ 167168933Srwatson "servname not supported for ai_socktype", /* EAI_SERVICE */ 168168933Srwatson "ai_socktype not supported", /* EAI_SOCKTYPE */ 169172930Srwatson "System error returned in errno", /* EAI_SYSTEM */ 170168933Srwatson "Invalid value for hints", /* EAI_BADHINTS */ 171168933Srwatson "Resolved protocol is unknown", /* EAI_PROTOCOL */ 172168933Srwatson "Argument res is NULL", /* EAI_RESNULL */ 173168933Srwatson "Unknown error", /* EAI_MAX */ 174164033Srwatson}; 175155192Srwatson 176155192Srwatson/* XXX macros that make external reference is BAD. */ 177155192Srwatson 178155192Srwatson#define GET_AI(ai, afd, addr) \ 179155192Srwatsondo { \ 180155192Srwatson /* external reference: pai, error, and label free */ \ 181155192Srwatson (ai) = get_ai(pai, (afd), (addr)); \ 182155192Srwatson if ((ai) == NULL) { \ 183156889Srwatson error = EAI_MEMORY; \ 184156889Srwatson goto free; \ 185156889Srwatson } \ 186155192Srwatson} while (0) 187155192Srwatson 188155192Srwatson#define GET_PORT(ai, serv) \ 189155192Srwatsondo { \ 190155192Srwatson /* external reference: error and label free */ \ 191155192Srwatson error = get_port((ai), (serv), 0); \ 192155192Srwatson if (error != 0) \ 193155192Srwatson goto free; \ 194155192Srwatson} while (0) 195155192Srwatson 196155192Srwatson#define GET_CANONNAME(ai, str) \ 197155192Srwatsondo { \ 198155192Srwatson /* external reference: pai, error and label free */ \ 199155192Srwatson error = get_canonname(pai, (ai), (str)); \ 200155192Srwatson if (error != 0) \ 201155192Srwatson goto free; \ 202155192Srwatson} while (0) 203155192Srwatson 204155192Srwatson#define ERR(err) \ 205155192Srwatsondo { \ 206155192Srwatson /* external reference: error, and label bad */ \ 207155192Srwatson error = (err); \ 208155192Srwatson goto bad; \ 209156889Srwatson} while (0) 210155192Srwatson 211155192Srwatson#define MATCH_FAMILY(x, y, w) \ 212155192Srwatson ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 213155192Srwatson#define MATCH(x, y, w) \ 214155192Srwatson ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY))) 215155192Srwatson 216155192Srwatsonchar * 217155192Srwatsongai_strerror(ecode) 218161813Swsalamon int ecode; 219161813Swsalamon{ 220161813Swsalamon if (ecode < 0 || ecode > EAI_MAX) 221161813Swsalamon ecode = EAI_MAX; 222155192Srwatson return ai_errlist[ecode]; 223155192Srwatson} 224155192Srwatson 225161813Swsalamonvoid 226161813Swsalamonfreeaddrinfo(ai) 227155192Srwatson struct addrinfo *ai; 228155192Srwatson{ 229155192Srwatson struct addrinfo *next; 230155192Srwatson 231155192Srwatson do { 232155192Srwatson next = ai->ai_next; 233161813Swsalamon if (ai->ai_canonname) 234161813Swsalamon free(ai->ai_canonname); 235155192Srwatson /* no need to free(ai->ai_addr) */ 236155192Srwatson free(ai); 237155192Srwatson } while ((ai = next) != NULL); 238155192Srwatson} 239155192Srwatson 240155192Srwatsonstatic int 241155192Srwatsonstr_isnumber(p) 242155192Srwatson const char *p; 243155192Srwatson{ 244155192Srwatson char *q = (char *)p; 245155192Srwatson while (*q) { 246155192Srwatson if (! isdigit(*q)) 247155192Srwatson return NO; 248155192Srwatson q++; 249155192Srwatson } 250155192Srwatson return YES; 251155192Srwatson} 252155192Srwatson 253155192Srwatsonint 254155192Srwatsongetaddrinfo(hostname, servname, hints, res) 255155192Srwatson const char *hostname, *servname; 256155192Srwatson const struct addrinfo *hints; 257155192Srwatson struct addrinfo **res; 258155192Srwatson{ 259155192Srwatson struct addrinfo sentinel; 260155192Srwatson struct addrinfo *cur; 261155192Srwatson int error = 0; 262155192Srwatson struct addrinfo ai; 263155192Srwatson struct addrinfo ai0; 264155192Srwatson struct addrinfo *pai; 265155192Srwatson const struct afd *afd; 266155192Srwatson const struct explore *ex; 267155192Srwatson 268155192Srwatson sentinel.ai_next = NULL; 269155192Srwatson cur = &sentinel; 270155192Srwatson pai = &ai; 271155192Srwatson pai->ai_flags = 0; 272155192Srwatson pai->ai_family = PF_UNSPEC; 273155192Srwatson pai->ai_socktype = ANY; 274155192Srwatson pai->ai_protocol = ANY; 275155192Srwatson pai->ai_addrlen = 0; 276155192Srwatson pai->ai_canonname = NULL; 277155192Srwatson pai->ai_addr = NULL; 278155192Srwatson pai->ai_next = NULL; 279155192Srwatson 280155192Srwatson if (hostname == NULL && servname == NULL) 281155192Srwatson return EAI_NONAME; 282155192Srwatson if (res == NULL) 283155192Srwatson return EAI_RESNULL; /* xxx */ 284155192Srwatson if (hints) { 285155192Srwatson /* error check for hints */ 286155192Srwatson if (hints->ai_addrlen || hints->ai_canonname || 287155192Srwatson hints->ai_addr || hints->ai_next) 288155192Srwatson ERR(EAI_BADHINTS); /* xxx */ 289155192Srwatson if (hints->ai_flags & ~AI_MASK) 290155192Srwatson ERR(EAI_BADFLAGS); 291155192Srwatson switch (hints->ai_family) { 292155192Srwatson case PF_UNSPEC: 293155192Srwatson case PF_INET: 294156889Srwatson#ifdef INET6 295155192Srwatson case PF_INET6: 296156889Srwatson#endif 297155192Srwatson break; 298155192Srwatson default: 299155192Srwatson ERR(EAI_FAMILY); 300155192Srwatson } 301155192Srwatson memcpy(pai, hints, sizeof(*pai)); 302155192Srwatson 303155192Srwatson /* 304155192Srwatson * if both socktype/protocol are specified, check if they 305156889Srwatson * are meaningful combination. 306156889Srwatson */ 307155192Srwatson if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 308155192Srwatson int matched = 0; 309155192Srwatson 310155192Srwatson for (ex = explore; ex->e_af >= 0; ex++) { 311156889Srwatson if (pai->ai_family != ex->e_af) 312155192Srwatson continue; 313155192Srwatson if (ex->e_socktype == ANY) 314155192Srwatson continue; 315156889Srwatson if (ex->e_protocol == ANY) 316155192Srwatson continue; 317155192Srwatson if (pai->ai_socktype == ex->e_socktype 318155192Srwatson && pai->ai_protocol == ex->e_protocol) 319165624Srwatson matched = 1; 320165624Srwatson else 321165624Srwatson continue; 322165624Srwatson if (matched == 0) 323170407Srwatson ERR(EAI_BADHINTS); 324168688Scsjp } 325168688Scsjp } 326168688Scsjp } 327170407Srwatson 328170407Srwatson /* backup original pai contents */ 329156889Srwatson ai0 = *pai; 330170407Srwatson 331156889Srwatson /* 332170407Srwatson * special cases check for inet and inet6 sockets. 333156889Srwatson * (1) servname is disallowed for raw sockets. 334170407Srwatson * (2) numeric servname is disallowed if socktype/protocol is left 335168688Scsjp * unspecified. 336170407Srwatson */ 337170407Srwatson if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 338170407Srwatson#ifdef INET6 339155192Srwatson || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 340155192Srwatson#endif 341155192Srwatson ) { 342155192Srwatson *pai = ai0; 343156889Srwatson 344155192Srwatson if (pai->ai_family == PF_UNSPEC) 345170407Srwatson#ifdef INET6 346170407Srwatson pai->ai_family = PF_INET6; 347170407Srwatson#else 348155192Srwatson pai->ai_family = PF_INET; 349170407Srwatson#endif 350165624Srwatson error = get_portmatch(pai, servname); 351165624Srwatson if (error) 352170407Srwatson ERR(error); 353165624Srwatson } 354165624Srwatson 355170407Srwatson /* NULL hostname, or numeric hostname */ 356170407Srwatson for (ex = explore; ex->e_af >= 0; ex++) { 357170407Srwatson *pai = ai0; 358156889Srwatson 359170407Srwatson if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 360156889Srwatson continue; 361170407Srwatson if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 362155192Srwatson continue; 363170407Srwatson if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 364155192Srwatson continue; 365155192Srwatson 366155192Srwatson if (pai->ai_family == PF_UNSPEC) 367155192Srwatson pai->ai_family = ex->e_af; 368155192Srwatson if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 369155192Srwatson pai->ai_socktype = ex->e_socktype; 370155192Srwatson if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 371155192Srwatson pai->ai_protocol = ex->e_protocol; 372155192Srwatson 373155192Srwatson if (hostname == NULL) 374155192Srwatson error = explore_null(pai, hostname, servname, &cur->ai_next); 375155192Srwatson else 376155192Srwatson error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 377155192Srwatson 378155192Srwatson if (error) 379168688Scsjp goto free; 380168688Scsjp 381168688Scsjp while (cur && cur->ai_next) 382168688Scsjp cur = cur->ai_next; 383170407Srwatson } 384170407Srwatson 385168688Scsjp /* 386170407Srwatson * XXX 387168688Scsjp * If numreic representation of AF1 can be interpreted as FQDN 388170407Srwatson * representation of AF2, we need to think again about the code below. 389170407Srwatson */ 390170407Srwatson if (sentinel.ai_next) 391170407Srwatson goto good; 392170407Srwatson 393168688Scsjp if (pai->ai_flags & AI_NUMERICHOST) 394155192Srwatson ERR(EAI_NONAME); 395155192Srwatson if (hostname == NULL) 396155192Srwatson ERR(EAI_NONAME); 397155192Srwatson 398155192Srwatson /* 399155192Srwatson * hostname as alphabetical name. 400155192Srwatson * we would like to prefer AF_INET6 than AF_INET, so we'll make a 401155192Srwatson * outer loop by AFs. 402155192Srwatson */ 403155192Srwatson for (afd = afdl; afd->a_af; afd++) { 404155192Srwatson *pai = ai0; 405155192Srwatson 406155192Srwatson if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 407155192Srwatson continue; 408156845Srwatson 409155192Srwatson for (ex = explore; ex->e_af >= 0; ex++) { 410156889Srwatson *pai = ai0; 411156889Srwatson 412156889Srwatson if (pai->ai_family == PF_UNSPEC) 413156889Srwatson pai->ai_family = afd->a_af; 414155192Srwatson 415155192Srwatson if (!MATCH_FAMILY(pai->ai_family, ex->e_af, 416155192Srwatson WILD_AF(ex))) 417155192Srwatson continue; 418155192Srwatson if (!MATCH(pai->ai_socktype, ex->e_socktype, 419155192Srwatson WILD_SOCKTYPE(ex))) { 420155192Srwatson continue; 421155192Srwatson } 422155192Srwatson if (!MATCH(pai->ai_protocol, ex->e_protocol, 423155192Srwatson WILD_PROTOCOL(ex))) { 424155192Srwatson continue; 425155192Srwatson } 426155192Srwatson 427155192Srwatson if (pai->ai_family == PF_UNSPEC) 428155192Srwatson pai->ai_family = ex->e_af; 429155192Srwatson if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 430155192Srwatson pai->ai_socktype = ex->e_socktype; 431155192Srwatson if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 432155192Srwatson pai->ai_protocol = ex->e_protocol; 433155192Srwatson 434155192Srwatson error = explore_fqdn(pai, hostname, servname, 435155192Srwatson &cur->ai_next); 436156889Srwatson 437155192Srwatson while (cur && cur->ai_next) 438155192Srwatson cur = cur->ai_next; 439155192Srwatson } 440155192Srwatson } 441155192Srwatson 442155192Srwatson /* XXX: if any addrinfo found, SUCCESS return even if (error != 0) */ 443155192Srwatson if (sentinel.ai_next) { 444155192Srwatson good: 445163207Scsjp *res = sentinel.ai_next; 446163207Scsjp return SUCCESS; 447164033Srwatson } 448155192Srwatson /* else, failed */ 449155192Srwatson free: 450170407Srwatson bad: 451170407Srwatson if (error == 0) 452155192Srwatson error = EAI_FAIL; 453155192Srwatson if (sentinel.ai_next) 454155192Srwatson freeaddrinfo(sentinel.ai_next); 455155192Srwatson *res = NULL; 456155192Srwatson return error; 457155192Srwatson} 458170407Srwatson 459170407Srwatson/* 460155192Srwatson * FQDN hostname, DNS lookup 461155192Srwatson */ 462163207Scsjpstatic int 463163207Scsjpexplore_fqdn(pai, hostname, servname, res) 464155192Srwatson const struct addrinfo *pai; 465155192Srwatson const char *hostname; 466155192Srwatson const char *servname; 467155192Srwatson struct addrinfo **res; 468170407Srwatson{ 469170407Srwatson struct hostent *hp; 470170407Srwatson int h_error; 471170407Srwatson int af; 472168933Srwatson char *ap; 473172930Srwatson struct addrinfo sentinel, *cur; 474168933Srwatson int i; 475170407Srwatson const struct afd *afd; 476168933Srwatson int error; 477170407Srwatson 478170407Srwatson *res = NULL; 479170407Srwatson sentinel.ai_next = NULL; 480170407Srwatson cur = &sentinel; 481170407Srwatson 482155192Srwatson /* 483170407Srwatson * if the servname does not match socktype/protocol, ignore it. 484155192Srwatson */ 485170407Srwatson if (get_portmatch(pai, servname) != 0) 486170407Srwatson return 0; 487170407Srwatson 488170407Srwatson afd = find_afd(pai->ai_family); 489155192Srwatson if (afd == NULL) 490155192Srwatson return 0; 491155192Srwatson 492156889Srwatson hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, 493155192Srwatson &h_error); 494155192Srwatson if (hp == NULL) { 495155192Srwatson switch (h_error) { 496155192Srwatson case HOST_NOT_FOUND: 497155192Srwatson case NO_DATA: 498155192Srwatson error = EAI_NODATA; 499155192Srwatson break; 500155192Srwatson case TRY_AGAIN: 501163207Scsjp error = EAI_AGAIN; 502163207Scsjp break; 503164033Srwatson case NO_RECOVERY: 504155192Srwatson case NETDB_INTERNAL: 505155192Srwatson default: 506171066Scsjp error = EAI_FAIL; 507171066Scsjp break; 508168688Scsjp } 509170407Srwatson } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) 510170407Srwatson || (hp->h_addr_list[0] == NULL)) { 511170407Srwatson freehostent(hp); 512170407Srwatson hp = NULL; 513170407Srwatson error = EAI_FAIL; 514171066Scsjp } 515155192Srwatson 516155192Srwatson if (hp == NULL) 517155192Srwatson goto free; 518155192Srwatson 519155192Srwatson for (i = 0; hp->h_addr_list[i] != NULL; i++) { 520155192Srwatson af = hp->h_addrtype; 521170407Srwatson ap = hp->h_addr_list[i]; 522155192Srwatson 523155192Srwatson if (af != pai->ai_family) 524155192Srwatson continue; 525163207Scsjp 526163207Scsjp GET_AI(cur->ai_next, afd, ap); 527155192Srwatson GET_PORT(cur->ai_next, servname); 528155192Srwatson if ((pai->ai_flags & AI_CANONNAME) != 0) { 529155192Srwatson /* 530155192Srwatson * RFC2553 says that ai_canonname will be set only for 531170407Srwatson * the first element. we do it for all the elements, 532170407Srwatson * just for convenience. 533170407Srwatson */ 534170407Srwatson GET_CANONNAME(cur->ai_next, hp->h_name); 535168933Srwatson } 536172930Srwatson 537168933Srwatson while (cur && cur->ai_next) 538170407Srwatson cur = cur->ai_next; 539168933Srwatson } 540170407Srwatson 541170407Srwatson *res = sentinel.ai_next; 542170407Srwatson return 0; 543170407Srwatson 544170407Srwatsonfree: 545170407Srwatson if (hp) 546170407Srwatson freehostent(hp); 547170407Srwatson if (sentinel.ai_next) 548170407Srwatson freeaddrinfo(sentinel.ai_next); 549170407Srwatson return error; 550170407Srwatson} 551155192Srwatson 552170407Srwatson/* 553155192Srwatson * hostname == NULL. 554170407Srwatson * passive socket -> anyaddr (0.0.0.0 or ::) 555170407Srwatson * non-passive socket -> localhost (127.0.0.1 or ::1) 556170407Srwatson */ 557170407Srwatsonstatic int 558155192Srwatsonexplore_null(pai, hostname, servname, res) 559155192Srwatson const struct addrinfo *pai; 560155192Srwatson const char *hostname; 561155192Srwatson const char *servname; 562155192Srwatson struct addrinfo **res; 563155192Srwatson{ 564155192Srwatson int s; 565155192Srwatson const struct afd *afd; 566163207Scsjp struct addrinfo *cur; 567163207Scsjp struct addrinfo sentinel; 568170407Srwatson int error; 569170407Srwatson 570164033Srwatson *res = NULL; 571155192Srwatson sentinel.ai_next = NULL; 572155192Srwatson cur = &sentinel; 573170407Srwatson 574170407Srwatson /* 575155192Srwatson * filter out AFs that are not supported by the kernel 576155192Srwatson * XXX errno? 577155192Srwatson */ 578155192Srwatson s = socket(pai->ai_family, SOCK_DGRAM, 0); 579155192Srwatson if (s < 0) 580155192Srwatson return 0; 581170407Srwatson _libc_close(s); 582168688Scsjp afd = find_afd(pai->ai_family); 583155192Srwatson if (afd == NULL) 584155192Srwatson return 0; 585163207Scsjp 586163207Scsjp GET_AI(cur->ai_next, afd, 587170407Srwatson (pai->ai_flags & AI_PASSIVE) ? afd->a_addrany : afd->a_loopback 588155192Srwatson ); 589155192Srwatson /* xxx meaningless? 590171066Scsjp * GET_CANONNAME(cur->ai_next, "anyaddr"); 591171066Scsjp * or 592171066Scsjp * GET_CANONNAME(cur->ai_next, "localhost"); 593171066Scsjp */ 594170407Srwatson /* if the servname does not match socktype/protocol, ignored */ 595170407Srwatson GET_PORT(cur->ai_next, servname); 596170407Srwatson 597170407Srwatson *res = sentinel.ai_next; 598168933Srwatson return 0; 599172930Srwatson 600168933Srwatsonfree: 601170407Srwatson if (sentinel.ai_next) 602168933Srwatson freeaddrinfo(sentinel.ai_next); 603170407Srwatson return error; 604168688Scsjp} 605170407Srwatson 606170407Srwatson/* 607170407Srwatson * numeric hostname 608168688Scsjp */ 609170407Srwatsonstatic int 610170407Srwatsonexplore_numeric(pai, hostname, servname, res) 611170407Srwatson const struct addrinfo *pai; 612170777Srwatson const char *hostname; 613170407Srwatson const char *servname; 614168688Scsjp struct addrinfo **res; 615155192Srwatson{ 616155192Srwatson const struct afd *afd; 617155192Srwatson struct addrinfo *cur; 618155192Srwatson struct addrinfo sentinel; 619155192Srwatson int error; 620155192Srwatson char pton[PTON_MAX]; 621155192Srwatson int flags; 622155192Srwatson 623155192Srwatson *res = NULL; 624155192Srwatson sentinel.ai_next = NULL; 625155192Srwatson cur = &sentinel; 626155192Srwatson 627155192Srwatson /* 628159318Srwatson * if the servname does not match socktype/protocol, ignore it. 629155192Srwatson */ 630163207Scsjp if (get_portmatch(pai, servname) != 0) 631163207Scsjp return 0; 632164033Srwatson 633155192Srwatson afd = find_afd(pai->ai_family); 634155192Srwatson if (afd == NULL) 635155192Srwatson return 0; 636155192Srwatson flags = pai->ai_flags; 637155192Srwatson 638155192Srwatson if (inet_pton(afd->a_af, hostname, pton) == 1) { 639155192Srwatson if (pai->ai_family == afd->a_af || 640155192Srwatson pai->ai_family == PF_UNSPEC /*?*/) { 641155192Srwatson GET_AI(cur->ai_next, afd, pton); 642155192Srwatson GET_PORT(cur->ai_next, servname); 643155192Srwatson while (cur && cur->ai_next) 644165624Srwatson cur = cur->ai_next; 645155192Srwatson } else 646155192Srwatson ERR(EAI_FAMILY); /*xxx*/ 647155192Srwatson } 648155192Srwatson 649162944Srwatson *res = sentinel.ai_next; 650162944Srwatson return 0; 651155192Srwatson 652170183Skibfree: 653159318Srwatsonbad: 654159318Srwatson if (sentinel.ai_next) 655159318Srwatson freeaddrinfo(sentinel.ai_next); 656155192Srwatson return error; 657168933Srwatson} 658172930Srwatson 659175294Sattilio/* 660168933Srwatson * numeric hostname with scope 661168933Srwatson */ 662168933Srwatsonstatic int 663168933Srwatsonexplore_numeric_scope(pai, hostname, servname, res) 664168933Srwatson const struct addrinfo *pai; 665168933Srwatson const char *hostname; 666175294Sattilio const char *servname; 667168933Srwatson struct addrinfo **res; 668162944Srwatson{ 669155192Srwatson#ifndef SCOPE_DELIMITER 670155192Srwatson return explore_numeric(pai, hostname, servname, res); 671159318Srwatson#else 672159318Srwatson const struct afd *afd; 673155192Srwatson struct addrinfo *cur; 674159318Srwatson int error; 675155192Srwatson char *cp, *hostname2 = NULL; 676155192Srwatson int scope; 677155192Srwatson#ifdef INET6 678155192Srwatson struct sockaddr_in6 *sin6; 679155192Srwatson#endif 680155192Srwatson 681155192Srwatson /* 682155192Srwatson * if the servname does not match socktype/protocol, ignore it. 683155192Srwatson */ 684155192Srwatson if (get_portmatch(pai, servname) != 0) 685155192Srwatson return 0; 686155192Srwatson 687155192Srwatson afd = find_afd(pai->ai_family); 688155192Srwatson if (afd == NULL) 689155192Srwatson return 0; 690155192Srwatson if (!afd->a_scoped) 691155192Srwatson return explore_numeric(pai, hostname, servname, res); 692155192Srwatson 693155192Srwatson cp = strchr(hostname, SCOPE_DELIMITER); 694155192Srwatson if (cp == NULL) 695155192Srwatson return explore_numeric(pai, hostname, servname, res); 696155192Srwatson 697155192Srwatson /* 698155192Srwatson * Handle special case of <scoped_address><delimiter><scope id> 699155192Srwatson */ 700155192Srwatson hostname2 = strdup(hostname); 701155192Srwatson if (hostname2 == NULL) 702155192Srwatson return EAI_MEMORY; 703155192Srwatson /* terminate at the delimiter */ 704155192Srwatson hostname2[cp - hostname] = '\0'; 705155192Srwatson 706155192Srwatson cp++; 707155192Srwatson switch (pai->ai_family) { 708155192Srwatson#ifdef INET6 709155192Srwatson case AF_INET6: 710155192Srwatson scope = if_nametoindex(cp); 711155192Srwatson if (scope == 0) { 712155192Srwatson error = EAI_SYSTEM; 713155192Srwatson goto free; 714155192Srwatson } 715155192Srwatson break; 716155192Srwatson#endif 717155192Srwatson } 718155192Srwatson 719155192Srwatson error = explore_numeric(pai, hostname2, servname, res); 720155192Srwatson if (error == 0) { 721155192Srwatson for (cur = *res; cur; cur = cur->ai_next) { 722155192Srwatson#ifdef INET6 723155192Srwatson if (cur->ai_family != AF_INET6) 724155192Srwatson continue; 725155192Srwatson sin6 = (struct sockaddr_in6 *)cur->ai_addr; 726155192Srwatson if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 727155192Srwatson IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) 728155192Srwatson sin6->sin6_scope_id = scope; 729155192Srwatson#endif 730155192Srwatson } 731155192Srwatson } 732155192Srwatson 733155192Srwatson#ifdef INET6 734155192Srwatsonfree: 735155192Srwatson#endif 736155192Srwatson free(hostname2); 737155192Srwatson 738155192Srwatson return error; 739155192Srwatson#endif 740155192Srwatson} 741155192Srwatson 742155192Srwatsonstatic int 743155192Srwatsonget_canonname(pai, ai, str) 744155192Srwatson const struct addrinfo *pai; 745155192Srwatson struct addrinfo *ai; 746155192Srwatson const char *str; 747155192Srwatson{ 748155192Srwatson if ((pai->ai_flags & AI_CANONNAME) != 0) { 749155192Srwatson ai->ai_canonname = (char *)malloc(strlen(str) + 1); 750155192Srwatson if (ai->ai_canonname == NULL) 751155192Srwatson return EAI_MEMORY; 752155192Srwatson strcpy(ai->ai_canonname, str); 753155192Srwatson } 754 return 0; 755} 756 757static struct addrinfo * 758get_ai(pai, afd, addr) 759 const struct addrinfo *pai; 760 const struct afd *afd; 761 const char *addr; 762{ 763 char *p; 764 struct addrinfo *ai; 765#ifdef FAITH 766 struct in6_addr faith_prefix; 767 char *fp_str; 768 int translate = 0; 769#endif 770 771#ifdef FAITH 772 /* 773 * Transfrom an IPv4 addr into a special IPv6 addr format for 774 * IPv6->IPv4 translation gateway. (only TCP is supported now) 775 * 776 * +-----------------------------------+------------+ 777 * | faith prefix part (12 bytes) | embedded | 778 * | | IPv4 addr part (4 bytes) 779 * +-----------------------------------+------------+ 780 * 781 * faith prefix part is specified as ascii IPv6 addr format 782 * in environmental variable GAI. 783 * For FAITH to work correctly, routing to faith prefix must be 784 * setup toward a machine where a FAITH daemon operates. 785 * Also, the machine must enable some mechanizm 786 * (e.g. faith interface hack) to divert those packet with 787 * faith prefixed destination addr to user-land FAITH daemon. 788 */ 789 fp_str = getenv("GAI"); 790 if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && 791 afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { 792 u_int32_t v4a; 793 u_int8_t v4a_top; 794 795 memcpy(&v4a, addr, sizeof v4a); 796 v4a_top = v4a >> IN_CLASSA_NSHIFT; 797 if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && 798 v4a_top != 0 && v4a != IN_LOOPBACKNET) { 799 afd = &afdl[N_INET6]; 800 memcpy(&faith_prefix.s6_addr[12], addr, 801 sizeof(struct in_addr)); 802 translate = 1; 803 } 804 } 805#endif 806 807 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 808 + (afd->a_socklen)); 809 if (ai == NULL) 810 return NULL; 811 812 memcpy(ai, pai, sizeof(struct addrinfo)); 813 ai->ai_addr = (struct sockaddr *)(ai + 1); 814 memset(ai->ai_addr, 0, afd->a_socklen); 815 ai->ai_addr->sa_len = afd->a_socklen; 816 ai->ai_addrlen = afd->a_socklen; 817 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 818 p = (char *)(ai->ai_addr); 819#ifdef FAITH 820 if (translate == 1) 821 memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen); 822 else 823#endif 824 memcpy(p + afd->a_off, addr, afd->a_addrlen); 825 826 return ai; 827} 828 829static int 830get_portmatch(ai, servname) 831 const struct addrinfo *ai; 832 const char *servname; 833{ 834 /* get_port does not touch first argument. when matchonly == 1. */ 835 return get_port((struct addrinfo *)ai, servname, 1); 836} 837 838static int 839get_port(ai, servname, matchonly) 840 struct addrinfo *ai; 841 const char *servname; 842 int matchonly; 843{ 844 const char *proto; 845 struct servent *sp; 846 int port; 847 int allownumeric; 848 849 if (servname == NULL) 850 return 0; 851 if (ai->ai_family != AF_INET 852#ifdef INET6 853 && ai->ai_family != AF_INET6 854#endif 855 ) 856 return 0; 857 858 switch (ai->ai_socktype) { 859 case SOCK_RAW: 860 return EAI_SERVICE; 861 case SOCK_DGRAM: 862 case SOCK_STREAM: 863 allownumeric = 1; 864 break; 865 case ANY: 866 allownumeric = 0; 867 break; 868 default: 869 return EAI_SOCKTYPE; 870 } 871 872 if (str_isnumber(servname)) { 873 if (!allownumeric) 874 return EAI_SERVICE; 875 port = htons(atoi(servname)); 876 if (port < 0 || port > 65535) 877 return EAI_SERVICE; 878 } else { 879 switch (ai->ai_socktype) { 880 case SOCK_DGRAM: 881 proto = "udp"; 882 break; 883 case SOCK_STREAM: 884 proto = "tcp"; 885 break; 886 default: 887 proto = NULL; 888 break; 889 } 890 891 if ((sp = getservbyname(servname, proto)) == NULL) 892 return EAI_SERVICE; 893 port = sp->s_port; 894 } 895 896 if (!matchonly) { 897 switch (ai->ai_family) { 898 case AF_INET: 899 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port; 900 break; 901#ifdef INET6 902 case AF_INET6: 903 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port; 904 break; 905#endif 906 } 907 } 908 909 return 0; 910} 911 912static const struct afd * 913find_afd(af) 914 int af; 915{ 916 const struct afd *afd; 917 918 if (af == PF_UNSPEC) 919 return NULL; 920 for (afd = afdl; afd->a_af; afd++) { 921 if (afd->a_af == af) 922 return afd; 923 } 924 return NULL; 925} 926