]> The Tcpdump Group git mirrors - tcpdump/blobdiff - missing/getaddrinfo.c
Pointers into packet data should usually be pointers to unsigned 1-byte
[tcpdump] / missing / getaddrinfo.c
index 9da09cbb03323b6ce6044626fff399cab9ffa190..f59b2c4ef36570126997c40ce42df44adc0b335a 100644 (file)
@@ -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
  * - 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
 
@@ -95,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
 };
@@ -113,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
@@ -162,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",
@@ -314,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) {
@@ -362,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);
@@ -494,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;
 
@@ -509,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.
@@ -525,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) {
@@ -559,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;
@@ -604,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;
@@ -636,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.
@@ -747,7 +813,7 @@ explore_numeric(pai, hostname, servname, res)
                        }
                        while (cur && cur->ai_next)
                                cur = cur->ai_next;
-               } else 
+               } else
                        ERR(EAI_FAMILY);        /*xxx*/
        }
 
@@ -809,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
        }
@@ -840,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;
 
@@ -851,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);
@@ -868,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;
 }
@@ -924,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);
 }
@@ -941,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: