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]

[PATCH] Fix dns lookup for AF_UNSPEC when response for T_A exceedsbuffer size


Hi,

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.

Regards,
Siddhesh

----

ChangeLog:

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

	* 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


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