/*
* 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:
* 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
* - 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 <config.h>
+#endif
+
+#ifndef lint
+static const char rcsid[] _U_ =
+ "@(#) $Header: /tcpdump/master/tcpdump/missing/getaddrinfo.c,v 1.13 2003-11-16 09:36:48 guy Exp $";
+#endif
#include <sys/types.h>
#include <sys/param.h>
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
-
-#ifndef HAVE_PORTABLE_PROTOTYPE
-#include "cdecl_ext.h"
-#endif
+#include <errno.h>
#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
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
};
int a_socklen;
int a_off;
const char *a_addrany;
- const char *a_loopback;
+ const char *a_loopback;
int a_scoped;
} afdl [] = {
#ifdef INET6
#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",
pai->ai_canonname = NULL;
pai->ai_addr = NULL;
pai->ai_next = NULL;
-
+
if (hostname == NULL && servname == NULL)
return EAI_NONAME;
if (hints) {
* 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);
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;
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.
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) {
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;
if (hp)
freehostent(hp);
#endif
+ if (aplist)
+ free(aplist);
+ if (apbuf)
+ free(apbuf);
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return error;
* 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.
}
while (cur && cur->ai_next)
cur = cur->ai_next;
- } else
+ } else
ERR(EAI_FAMILY); /*xxx*/
}
#ifdef INET6
case AF_INET6:
scope = if_nametoindex(cp);
+ if (scope == 0) {
+ free(hostname2);
+ return (EAI_NONAME);
+ }
break;
#endif
}
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;
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);
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;
}
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);
}
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: