This is the mail archive of the libc-alpha@sourceware.org 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]
Other format: [Raw text]

[RESEND][PATCH][BZ #13760] Fix dns lookup for AF_UNSPEC whenresponse for T_A exceeds buffer size


ping.

--
Siddhesh
--- Begin Message ---
On Mon, Feb 27, 2012 at 11:25:53AM +0530, Siddhesh Poyarekar wrote:
> On Fri, Feb 24, 2012 at 07:44:21PM -0500, Carlos O'Donell wrote:
> > Could you please file an issue in bugzilla for this bug?
> > 
> 
> Also updated ChangeLog that I missed in my last email:

Ping, can this please be reviewed?

Thanks,
Siddhesh

When a dns lookup is made for a host that returns a large number of
results for A (over 28 records in my test) and a finite number for
AAAA, getaddrinfo ends up returning only the AAAA records. This is
because the check that decides whether to process the second response
or just drop it (resulting in a retry with a larger buffer) is broken.

The current check looks for the ERANGE error in 'errno' when it should
be looking for it in *errnop (where gaih_getanswer_slice sets
it). Also, we should discard the second response and retry the query
in case of NSS_STATUS_TRYAGAIN and ERANGE (buffer too small) only when
the response error is recoverable. The only condition in which this
currently occurs (buffer too small and h_errno is NO_RECOVERY) is when
the hostname returned by the query is longer than MAXHOSTNAMELEN.

To reproduce the problem, set up a hostname with more than 28 A
records and at least one AAAA record and then compile and run the
following program. It shows that only the AAAA records are returned in
getaddrinfo:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
int main(void)
{
  struct addrinfo *result;
  struct addrinfo *res;
  int error;
  const char *domain = "my.foo.com";
  error = getaddrinfo(domain, NULL, NULL, &result);
  if (error != 0)
    {
      fprintf(stderr, "error in getaddrinfo: %s\n", gaistrerror(error));
      return 1;
    }
  /* print the domain name */
  printf("%s:\n", domain);
  /* loop over all returned results and print the addresses */
  for (res = result; res != NULL; res = res->ainext)
    {
      void *addr;
      char address[64] = "";
      if (res->aifamily == AFINET) {
    addr = &((struct sockaddrin *)(res->aiaddr))->sinaddr;
      } else if (res->aifamily == AFINET6) {
    addr = &((struct sockaddrin6 *)(res->aiaddr))->sin6addr;
      }
      inetntop(res->aiaddr->safamily, addr, address, 64);
      printf("  %s\n", address);
    }
  freeaddrinfo(result);
  return EXITSUCCESS;
}

Attached patch fixes this.

----


ChangeLog:

2012-02-22  Siddhesh Poyarekar  <siddhesh@redhat.com>

	[BZ #13760]
	* resolv/nss_dns/dns-host.c (gaih_getanswer): Look for errno
	in the right place. Discard and retry query if response is
	larger than input buffer size.

Attachment: glibc-dns-tryagain.patch
Description: Text document


--- End Message ---

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