X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/b8037ee9610ca42e2f6a9f4f71ccaa45f058475f..8f94d68a09e1103353cc7d1133d6dfdf7d5a920d:/missing/getaddrinfo.c diff --git a/missing/getaddrinfo.c b/missing/getaddrinfo.c index 59568c2c..458fe014 100644 --- a/missing/getaddrinfo.c +++ b/missing/getaddrinfo.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +13,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,12 +35,24 @@ * - Return values. There are nonstandard return values defined and used * in the source code. This is because RFC2553 is silent about which error * code must be returned for which situation. - * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. + * Note: + * - We use getipnodebyname() just for thread-safeness. There's no intent + * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to + * getipnodebyname(). + * - The code filters out AFs that are not supported by the kernel, + * when globbing NULL hostname (to loopback, or wildcard). Is it the right + * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG + * in ai_flags? */ #ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include +#endif + +#ifndef lint +static const char rcsid[] = + "@(#) $Header: /tcpdump/master/tcpdump/missing/getaddrinfo.c,v 1.11 2002-06-11 17:13:37 itojun Exp $"; +#endif #include #include @@ -60,22 +72,17 @@ #include #include #include +#include -#ifndef HAVE_PORTABLE_PROTOTYPE -#include "cdecl_ext.h" -#endif - -#if 0 #ifndef HAVE_U_INT32_T #include "bittypes.h" -#endif #endif #ifndef HAVE_SOCKADDR_STORAGE #include "sockstorage.h" -#endif +#endif -#ifndef HAVE_ADDRINFO +#ifdef NEED_ADDRINFO_H #include "addrinfo.h" #endif @@ -97,7 +104,7 @@ static const char in_addrany[] = { 0, 0, 0, 0 }; static const char in6_addrany[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in_loopback[] = { 127, 0, 0, 1 }; static const char in6_loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; @@ -115,7 +122,7 @@ static const struct afd { int a_socklen; int a_off; const char *a_addrany; - const char *a_loopback; + const char *a_loopback; int a_scoped; } afdl [] = { #ifdef INET6 @@ -164,24 +171,24 @@ static const struct explore explore[] = { #endif -static int str_isnumber __P((const char *)); -static int explore_fqdn __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int explore_null __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int explore_numeric __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int explore_numeric_scope __P((const struct addrinfo *, const char *, - const char *, struct addrinfo **)); -static int get_name __P((const char *, const struct afd *, struct addrinfo **, - char *, const struct addrinfo *, const char *)); -static int get_canonname __P((const struct addrinfo *, - struct addrinfo *, const char *)); -static struct addrinfo *get_ai __P((const struct addrinfo *, - const struct afd *, const char *)); -static int get_portmatch __P((const struct addrinfo *, const char *)); -static int get_port __P((struct addrinfo *, const char *, int)); -static const struct afd *find_afd __P((int)); +static int str_isnumber (const char *); +static int explore_fqdn (const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int explore_null (const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int explore_numeric (const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int explore_numeric_scope (const struct addrinfo *, const char *, + const char *, struct addrinfo **); +static int get_name (const char *, const struct afd *, struct addrinfo **, + char *, const struct addrinfo *, const char *); +static int get_canonname (const struct addrinfo *, + struct addrinfo *, const char *); +static struct addrinfo *get_ai (const struct addrinfo *, + const struct afd *, const char *); +static int get_portmatch (const struct addrinfo *, const char *); +static int get_port (struct addrinfo *, const char *, int); +static const struct afd *find_afd (int); static char *ai_errlist[] = { "Success", @@ -316,7 +323,7 @@ getaddrinfo(hostname, servname, hints, res) pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; - + if (hostname == NULL && servname == NULL) return EAI_NONAME; if (hints) { @@ -364,11 +371,19 @@ getaddrinfo(hostname, servname, hints, res) * for raw and other inet{,6} sockets. */ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) - || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)) { +#ifdef PF_INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { ai0 = *pai; - if (pai->ai_family == PF_UNSPEC) + if (pai->ai_family == PF_UNSPEC) { +#ifdef PF_INET6 pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + } error = get_portmatch(pai, servname); if (error) ERR(error); @@ -496,13 +511,16 @@ explore_fqdn(pai, hostname, servname, res) const char *servname; struct addrinfo **res; { - int s; struct hostent *hp; int h_error; int af; + char **aplist = NULL, *apbuf = NULL; char *ap; struct addrinfo sentinel, *cur; int i; +#ifndef USE_GETIPNODEBY + int naddrs; +#endif const struct afd *afd; int error; @@ -511,13 +529,10 @@ explore_fqdn(pai, hostname, servname, res) cur = &sentinel; /* - * filter out AFs that are not supported by the kernel - * XXX errno? + * Do not filter unsupported AFs here. We need to honor content of + * databases (/etc/hosts, DNS and others). Otherwise we cannot + * replace gethostbyname() by getaddrinfo(). */ - s = socket(pai->ai_family, SOCK_DGRAM, 0); - if (s < 0) - return 0; - close(s); /* * if the servname does not match socktype/protocol, ignore it. @@ -527,12 +542,27 @@ explore_fqdn(pai, hostname, servname, res) afd = find_afd(pai->ai_family); + /* + * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG) + * rather than hardcoding it. we may need to add AI_ADDRCONFIG + * handling code by ourselves in case we don't have getipnodebyname(). + */ #ifdef USE_GETIPNODEBY hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error); #else +#ifdef HAVE_GETHOSTBYNAME2 hp = gethostbyname2(hostname, pai->ai_family); +#else + if (pai->ai_family != AF_INET) + return 0; + hp = gethostbyname(hostname); +#ifdef HAVE_H_ERRNO h_error = h_errno; +#else + h_error = EINVAL; #endif +#endif /*HAVE_GETHOSTBYNAME2*/ +#endif /*USE_GETIPNODEBY*/ if (hp == NULL) { switch (h_error) { @@ -561,10 +591,38 @@ explore_fqdn(pai, hostname, servname, res) if (hp == NULL) goto free; - for (i = 0; hp->h_addr_list[i] != NULL; i++) { +#ifdef USE_GETIPNODEBY + aplist = hp->h_addr_list; +#else + /* + * hp will be overwritten if we use gethostbyname2(). + * always deep copy for simplification. + */ + for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++) + ; + naddrs++; + aplist = (char **)malloc(sizeof(aplist[0]) * naddrs); + apbuf = (char *)malloc(hp->h_length * naddrs); + if (aplist == NULL || apbuf == NULL) { + error = EAI_MEMORY; + goto free; + } + memset(aplist, 0, sizeof(aplist[0]) * naddrs); + for (i = 0; i < naddrs; i++) { + if (hp->h_addr_list[i] == NULL) { + aplist[i] = NULL; + continue; + } + memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i], + hp->h_length); + aplist[i] = &apbuf[i * hp->h_length]; + } +#endif + + for (i = 0; aplist[i] != NULL; i++) { af = hp->h_addrtype; - ap = hp->h_addr_list[i]; -#ifdef INET6 + ap = aplist[i]; +#ifdef AF_INET6 if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { af = AF_INET; @@ -606,6 +664,10 @@ free: if (hp) freehostent(hp); #endif + if (aplist) + free(aplist); + if (apbuf) + free(apbuf); if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error; @@ -638,9 +700,11 @@ explore_null(pai, hostname, servname, res) * XXX errno? */ s = socket(pai->ai_family, SOCK_DGRAM, 0); - if (s < 0) - return 0; - close(s); + if (s < 0) { + if (errno != EMFILE) + return 0; + } else + close(s); /* * if the servname does not match socktype/protocol, ignore it. @@ -749,7 +813,7 @@ explore_numeric(pai, hostname, servname, res) } while (cur && cur->ai_next) cur = cur->ai_next; - } else + } else ERR(EAI_FAMILY); /*xxx*/ } @@ -811,6 +875,10 @@ explore_numeric_scope(pai, hostname, servname, res) #ifdef INET6 case AF_INET6: scope = if_nametoindex(cp); + if (scope == 0) { + free(hostname2); + return (EAI_NONAME); + } break; #endif } @@ -842,9 +910,10 @@ get_name(addr, afd, res, numaddr, pai, servname) const struct addrinfo *pai; const char *servname; { - struct hostent *hp; - struct addrinfo *cur; + struct hostent *hp = NULL; + struct addrinfo *cur = NULL; int error = 0; + char *ap = NULL, *cn = NULL; #ifdef USE_GETIPNODEBY int h_error; @@ -853,14 +922,33 @@ get_name(addr, afd, res, numaddr, pai, servname) hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); #endif if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { +#ifdef USE_GETIPNODEBY GET_AI(cur, afd, hp->h_addr_list[0]); GET_PORT(cur, servname); GET_CANONNAME(cur, hp->h_name); +#else + /* hp will be damaged if we use gethostbyaddr() */ + if ((ap = (char *)malloc(hp->h_length)) == NULL) { + error = EAI_MEMORY; + goto free; + } + memcpy(ap, hp->h_addr_list[0], hp->h_length); + if ((cn = strdup(hp->h_name)) == NULL) { + error = EAI_MEMORY; + goto free; + } + + GET_AI(cur, afd, ap); + GET_PORT(cur, servname); + GET_CANONNAME(cur, cn); + free(ap); ap = NULL; + free(cn); cn = NULL; +#endif } else { GET_AI(cur, afd, numaddr); GET_PORT(cur, servname); } - + #ifdef USE_GETIPNODEBY if (hp) freehostent(hp); @@ -870,11 +958,14 @@ get_name(addr, afd, res, numaddr, pai, servname) free: if (cur) freeaddrinfo(cur); + if (ap) + free(ap); + if (cn) + free(cn); #ifdef USE_GETIPNODEBY if (hp) freehostent(hp); #endif - /* bad: */ *res = NULL; return error; } @@ -926,6 +1017,7 @@ get_portmatch(ai, servname) const struct addrinfo *ai; const char *servname; { + /* get_port does not touch first argument. when matchonly == 1. */ return get_port((struct addrinfo *)ai, servname, 1); } @@ -943,8 +1035,15 @@ get_port(ai, servname, matchonly) if (servname == NULL) return 0; - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + break; + default: return 0; + } switch (ai->ai_socktype) { case SOCK_RAW: