This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: one more bug in getaddrinfo()


Arkadiusz Miskiewicz <misiek@misiek.eu.org> writes:

> But I found another bug in getaddrinfo() (tested on 2.1.2):

Thanks for the test cases.  I think I fixed all the bugs.  Please give
the appended patch a try.

One of your test cases was wrong, though.  The RFC draft I have says
about the servname argument of getaddrinfo():

	A non-NULL servname string can be either a service name
	or a decimal port number.

Therefore it cannot have the form "514/udp" which you used in the last
test.

-- 
---------------.      drepper at gnu.org  ,-.   1325 Chesapeake Terrace
Ulrich Drepper  \    ,-------------------'   \  Sunnyvale, CA 94089 USA
Cygnus Solutions `--' drepper at cygnus.com   `------------------------

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Index: sysdeps/posix/getaddrinfo.c
===================================================================
RCS file: /glibc/cvsfiles/libc/sysdeps/posix/getaddrinfo.c,v
retrieving revision 1.19
retrieving revision 1.15.2.4
diff -u -u -r1.19 -r1.15.2.4
--- getaddrinfo.c	1999/09/05 00:07:06	1.19
+++ getaddrinfo.c	1999/09/12 19:17:09	1.15.2.4
@@ -120,7 +120,7 @@
   struct utsname utsname;
 
   if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
-    if (uname(&utsname))
+    if (uname (&utsname))
       return -EAI_SYSTEM;
 
   if (name != NULL)
@@ -132,7 +132,23 @@
 	return GAIH_OKIFUNSPEC | -EAI_NONAME;
     }
 
-  *pai = malloc (sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
+  if (req->ai_protocol || req->ai_socktype)
+    {
+      struct gaih_typeproto *tp = gaih_inet_typeproto;
+
+      for (tp++; tp->name &&
+	     ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
+	     ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
+      if (tp->name == NULL)
+	{
+	  if (req->ai_socktype)
+	    return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+	  else
+	    return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+	}
+    }
+
+  *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
 		 + ((req->ai_flags & AI_CANONNAME)
 		    ? (strlen(utsname.nodename) + 1): 0));
   if (*pai == NULL)
@@ -143,8 +159,8 @@
   (*pai)->ai_family = AF_LOCAL;
   (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
   (*pai)->ai_protocol = req->ai_protocol;
-  (*pai)->ai_addrlen = sizeof(struct sockaddr_un);
-  (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
+  (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
+  (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
 
 #if SALEN
   ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
@@ -181,8 +197,9 @@
     }
 
   if (req->ai_flags & AI_CANONNAME)
-    strcpy ((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) +
-	    sizeof(struct sockaddr_un), utsname.nodename);
+    (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
+				   + sizeof (struct sockaddr_un),
+				   utsname.nodename);
   else
     (*pai)->ai_canonname = NULL;
   return 0;
@@ -201,14 +218,12 @@
   do
     {
       tmpbuf = __alloca (tmpbuflen);
-      if (tmpbuf == NULL)
-	return -EAI_MEMORY;
 
       r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
 			     &s);
-      if (r || s == NULL)
+      if (r != 0 || s == NULL)
 	{
-	  if (errno == ERANGE)
+	  if (r == ERANGE)
 	    tmpbuflen *= 2;
 	  else
 	    return GAIH_OKIFUNSPEC | -EAI_SERVICE;
@@ -234,12 +249,10 @@
   do {								\
     tmpbuflen *= 2;						\
     tmpbuf = __alloca (tmpbuflen);				\
-    if (tmpbuf == NULL)						\
-      return -EAI_MEMORY;					\
     rc = __gethostbyname2_r (name, _family, &th, tmpbuf,	\
          tmpbuflen, &h, &herrno);				\
   } while (rc == ERANGE && herrno == NETDB_INTERNAL);		\
-  if ((rc != 0) && (herrno == NETDB_INTERNAL))			\
+  if (rc != 0 && herrno == NETDB_INTERNAL)			\
     {								\
       __set_h_errno (herrno);					\
       return -EAI_SYSTEM;					\
@@ -249,11 +262,7 @@
       for (i = 0; h->h_addr_list[i]; i++)			\
 	{							\
 	  if (*pat == NULL)					\
-	    {							\
-	      *pat = __alloca (sizeof(struct gaih_addrtuple));	\
-	      if (*pat == NULL)					\
-		return -EAI_MEMORY;				\
-	    }							\
+	    *pat = __alloca (sizeof(struct gaih_addrtuple));	\
 	  (*pat)->next = NULL;					\
 	  (*pat)->family = _family;				\
 	  memcpy ((*pat)->addr, h->h_addr_list[i],		\
@@ -261,6 +270,7 @@
 	  pat = &((*pat)->next);				\
 	}							\
     }								\
+  no_data = rc != 0 && herrno == NO_DATA;			\
  }
 
 static int
@@ -322,10 +332,7 @@
 	}
       else
 	{
-	  st = __alloca (sizeof(struct gaih_servtuple));
-	  if (st == NULL)
-	    return -EAI_MEMORY;
-
+	  st = __alloca (sizeof (struct gaih_servtuple));
 	  st->next = NULL;
 	  st->socktype = tp->socktype;
 	  st->protocol = tp->protocol;
@@ -335,45 +342,58 @@
 
   if (name != NULL)
     {
-      at = __alloca (sizeof(struct gaih_addrtuple));
+      at = __alloca (sizeof (struct gaih_addrtuple));
 
-      at->family = 0;
+      at->family = AF_UNSPEC;
       at->next = NULL;
 
-      if (req->ai_family == 0 || req->ai_family == AF_INET)
-	if (inet_pton (AF_INET, name, at->addr) > 0)
-	  at->family = AF_INET;
+      if (inet_pton (AF_INET, name, at->addr) > 0)
+	{
+	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
+	    at->family = AF_INET;
+	  else
+	    return -EAI_ADDRFAMILY;
+	}
 
-      if (!at->family && (req->ai_family == 0 || req->ai_family == AF_INET6))
-	if (inet_pton (AF_INET6, name, at->addr) > 0)
-	  at->family = AF_INET6;
+      if (at->family == AF_UNSPEC && inet_pton (AF_INET6, name, at->addr) > 0)
+	{
+	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+	    at->family = AF_INET6;
+	  else
+	    return -EAI_ADDRFAMILY;
+	}
 
       if (at->family == AF_UNSPEC)
 	{
 	  struct hostent *h;
 	  struct gaih_addrtuple **pat = &at;
+	  int no_data = 0;
 
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
 	    gethosts (AF_INET6, struct in6_addr);
 
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
 	    gethosts (AF_INET, struct in_addr);
+
+	  if (no_data != 0)
+	    /* We made requests but they turned out no data.  The name
+	       is known, though.  */
+	    return (GAIH_OKIFUNSPEC | -EAI_NODATA);
 	}
 
       if (at->family == AF_UNSPEC)
 	return (GAIH_OKIFUNSPEC | -EAI_NONAME);
-
     }
   else
     {
       struct gaih_addrtuple *atr;
-      atr = at = __alloca (sizeof(struct gaih_addrtuple));
-      memset (at, 0, sizeof(struct gaih_addrtuple));
+      atr = at = __alloca (sizeof (struct gaih_addrtuple));
+      memset (at, '\0', sizeof (struct gaih_addrtuple));
 
       if (req->ai_family == 0)
 	{
-	  at->next = __alloca (sizeof(struct gaih_addrtuple));
-	  memset (at->next, 0, sizeof(struct gaih_addrtuple));
+	  at->next = __alloca (sizeof (struct gaih_addrtuple));
+	  memset (at->next, '\0', sizeof (struct gaih_addrtuple));
 	}
 
       if (req->ai_family == 0 || req->ai_family == AF_INET6)
@@ -433,10 +453,9 @@
 					&h, &herrno);
 
 	      }
-	    while ((rc != 0) && (herrno == NETDB_INTERNAL)
-		   && (errno == ERANGE));
+	    while (rc == errno && herrno == NETDB_INTERNAL);
 
-	    if ((rc != 0) && (herrno == NETDB_INTERNAL))
+	    if (rc != 0 && herrno == NETDB_INTERNAL)
 	      {
 		__set_h_errno (herrno);
 		return -EAI_SYSTEM;
@@ -527,7 +546,7 @@
 getaddrinfo (const char *name, const char *service,
 	     const struct addrinfo *hints, struct addrinfo **pai)
 {
-  int i = 0, j = 0;
+  int i = 0, j = 0, last_i = 0;
   struct addrinfo *p = NULL, **end;
   struct gaih *g = gaih, *pg = NULL;
   struct gaih_service gaih_service, *pservice;
@@ -583,6 +602,11 @@
 	      i = g->gaih (name, pservice, hints, end);
 	      if (i != 0)
 		{
+		  /* EAI_NODATA is a more specific result as it says that
+		     we found a result but it is not usable.  */
+		  if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
+		    last_i = i;
+
 		  if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
 		    continue;
 
@@ -607,13 +631,13 @@
       return 0;
     }
 
-  if (pai == NULL && i == 0)
+  if (pai == NULL && last_i == 0)
     return 0;
 
   if (p)
     freeaddrinfo (p);
 
-  return i ? -(i & GAIH_EAI) : EAI_NONAME;
+  return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
 }
 
 void
Index: resolv/nss_dns/dns-host.c
===================================================================
RCS file: /glibc/cvsfiles/libc/resolv/nss_dns/dns-host.c,v
retrieving revision 1.19
retrieving revision 1.14.2.3
diff -u -u -r1.19 -r1.14.2.3
--- dns-host.c	1999/08/15 20:22:35	1.19
+++ dns-host.c	1999/09/12 19:11:49	1.14.2.3
@@ -163,7 +163,7 @@
   if (n < 0)
     {
       *h_errnop = h_errno;
-      *errnop = errno;
+      *errnop = *h_errnop == TRY_AGAIN ? EAGAIN : ENOENT;
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
@@ -342,6 +342,7 @@
       name_ok = res_dnok;
       break;
     default:
+      *errnop = ENOENT;
       return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
     }
 
@@ -356,6 +357,7 @@
   if (qdcount != 1)
     {
       *h_errnop = NO_RECOVERY;
+      *errnop = ENOENT;
       return NSS_STATUS_UNAVAIL;
     }
 
@@ -390,6 +392,7 @@
       if (n >= MAXHOSTNAMELEN)
 	{
 	  *h_errnop = NO_RECOVERY;
+	  *errnop = ENOENT;
 	  return NSS_STATUS_TRYAGAIN;
 	}
       result->h_name = bp;
@@ -660,5 +663,6 @@
     }
  no_recovery:
   *h_errnop = NO_RECOVERY;
+  *errnop = ENOENT;
   return NSS_STATUS_TRYAGAIN;
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]