Commit 17fde12f authored by Steinar H. Gunderson's avatar Steinar H. Gunderson
Browse files

Return TTL data from ares_parse_{a,aaaa}_reply, if the user is so inclined....

Return TTL data from ares_parse_{a,aaaa}_reply, if the user is so inclined. Patch from the Google tree.
parent 5c8b973d
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -240,10 +240,29 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
                     int alen, char **s, long *enclen);
int ares_expand_string(const unsigned char *encoded, const unsigned char *abuf,
                     int alen, unsigned char **s, long *enclen);

struct addrttl {
  struct in_addr ipaddr;
  int            ttl;
};
struct addr6ttl {
  struct in6_addr ip6addr;
  int             ttl;
};

/*
** Parse the buffer, starting at *abuf and of length alen bytes, previously
** obtained from an ares_search call.  Put the results in *host, if nonnull.
** Also, if addrttls is nonnull, put up to *naddrttls IPv4 addresses along with
** their TTLs in that array, and set *naddrttls to the number of addresses
** so written.
*/
int ares_parse_a_reply(const unsigned char *abuf, int alen,
                       struct hostent **host);
                       struct hostent **host,
                       struct addrttl *addrttls, int *naddrttls);
int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
                       struct hostent **host);
                       struct hostent **host,
                       struct addr6ttl *addrttls, int *naddrttls);
int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
                         int addrlen, int family, struct hostent **host);
int ares_parse_ns_reply(const unsigned char *abuf, int alen,
+2 −2
Original line number Diff line number Diff line
@@ -160,13 +160,13 @@ static void host_callback(void *arg, int status, int timeouts,
    {
      if (hquery->family == AF_INET)
        {
          status = ares_parse_a_reply(abuf, alen, &host);
          status = ares_parse_a_reply(abuf, alen, &host, NULL, NULL);
          if (host && channel->nsort)
            sort_addresses(host, channel->sortlist, channel->nsort);
        }
      else if (hquery->family == AF_INET6)
        {
          status = ares_parse_aaaa_reply(abuf, alen, &host);
          status = ares_parse_aaaa_reply(abuf, alen, &host, NULL, NULL);
          if (host && channel->nsort)
            sort6_addresses(host, channel->sortlist, channel->nsort);
        }
+18 −3
Original line number Diff line number Diff line
@@ -22,24 +22,39 @@ ares_parse_a_reply \- Parse a reply to a DNS query of type A into a hostent
.B #include <ares.h>
.PP
.B int ares_parse_a_reply(const unsigned char *\fIabuf\fP, int \fIalen\fP,
.B 	struct hostent **\fIhost\fP);
.B 	struct hostent **\fIhost\fP,
.B      struct addrttl *\fIaddrttls\fB, int *\fInaddrttls\fB);
.fi
.SH DESCRIPTION
The
.B ares_parse_a_reply
function parses the response to a query of type A into a
.BR "struct hostent" .
.BR "struct hostent"
and/or an array of
.BR "struct addrttls" . 
The parameters
.I abuf
and
.I alen
give the contents of the response.  The result is stored in allocated
memory and a pointer to it stored into the variable pointed to by
.IR host .
.IR host ,
if host is nonnull.
It is the caller's responsibility to free the resulting host structure
using
.BR ares_free_hostent (3)
when it is no longer needed.
.PP
If
.IR addrttls
and
.IR naddrttls
are both nonnull,
then up to *naddrttls
.BR "struct addrttl"
records are stored in the array pointed to by addrttls,
and then *naddrttls is set to the number of records so stored.
Note that the memory for these records is supplied by the caller.
.SH RETURN VALUES
.B ares_parse_a_reply
can return any of the following values:
+98 −36
Original line number Diff line number Diff line
@@ -37,19 +37,26 @@
#include "ares_private.h"

int ares_parse_a_reply(const unsigned char *abuf, int alen,
                       struct hostent **host)
                       struct hostent **host,
                       struct addrttl *addrttls, int *naddrttls)
{
  unsigned int qdcount, ancount;
  int status, i, rr_type, rr_class, rr_len, naddrs;
  int status, i, rr_type, rr_class, rr_len, rr_ttl, naddrs;
  int cname_ttl = INT_MAX;  /* the TTL imposed by the CNAME chain */
  int naliases;
  long len;
  const unsigned char *aptr;
  char *hostname, *rr_name, *rr_data, **aliases;
  struct in_addr *addrs;
  struct hostent *hostent;
  const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;

  /* Set *host to NULL for all failure cases. */
  if (host)
    *host = NULL;
  /* Same with *naddrttls. */
  if (naddrttls)
    *naddrttls = 0;

  /* Give up if abuf doesn't have room for a header. */
  if (alen < HFIXEDSZ)
@@ -73,6 +80,8 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
    }
  aptr += len + QFIXEDSZ;

  if (host)
    {
      /* Allocate addresses and aliases; ancount gives an upper bound for both. */
      addrs = malloc(ancount * sizeof(struct in_addr));
      if (!addrs)
@@ -87,6 +96,13 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
          free(addrs);
          return ARES_ENOMEM;
        }
    }
  else
    {
      addrs = NULL;
      aliases = NULL;
    }
  
  naddrs = 0;
  naliases = 0;

@@ -106,13 +122,33 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
      rr_type = DNS_RR_TYPE(aptr);
      rr_class = DNS_RR_CLASS(aptr);
      rr_len = DNS_RR_LEN(aptr);
      rr_ttl = DNS_RR_TTL(aptr);
      aptr += RRFIXEDSZ;

      if (rr_class == C_IN && rr_type == T_A
          && rr_len == sizeof(struct in_addr)
          && strcasecmp(rr_name, hostname) == 0)
        {
          if (addrs)
            {
              if (aptr + sizeof(struct in_addr) > abuf + alen)
              {
                status = ARES_EBADRESP;
                break;
              }
              memcpy(&addrs[naddrs], aptr, sizeof(struct in_addr));
            }
          if (naddrs < max_addr_ttls)
            {
              struct addrttl * const at = &addrttls[naddrs];
              if (aptr + sizeof(struct in_addr) > abuf + alen)
              {
                status = ARES_EBADRESP;
                break;
              }
              memcpy(&at->ipaddr, aptr,  sizeof(struct in_addr));
              at->ttl = rr_ttl;
            }
          naddrs++;
          status = ARES_SUCCESS;
        }
@@ -120,7 +156,10 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
      if (rr_class == C_IN && rr_type == T_CNAME)
        {
          /* Record the RR name as an alias. */
          if (aliases)
            aliases[naliases] = rr_name;
          else
            free(rr_name);
          naliases++;

          /* Decode the RR data and replace the hostname with it. */
@@ -129,6 +168,10 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
            break;
          free(hostname);
          hostname = rr_data;

          /* Take the min of the TTLs we see in the CNAME chain. */
          if (cname_ttl > rr_ttl)
            cname_ttl = rr_ttl;
        }
      else
        free(rr_name);
@@ -145,8 +188,23 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
    status = ARES_ENODATA;
  if (status == ARES_SUCCESS)
    {
      /* We got our answer.  Allocate memory to build the host entry. */
      /* We got our answer. */
      if (naddrttls)
        {
          const int n = naddrs < max_addr_ttls ? naddrs : max_addr_ttls;
          for (i = 0; i < n; i++)
            {
              /* Ensure that each A TTL is no larger than the CNAME TTL. */
              if (addrttls[i].ttl > cname_ttl)
                addrttls[i].ttl = cname_ttl;
            }
          *naddrttls = n;
        }
      if (aliases)
        aliases[naliases] = NULL;
      if (host)
        {
          /* Allocate memory to build the host entry. */
          hostent = malloc(sizeof(struct hostent));
          if (hostent)
            {
@@ -168,9 +226,13 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
            }
          status = ARES_ENOMEM;
        }
     }
  if (aliases)
    {
      for (i = 0; i < naliases; i++)
        free(aliases[i]);
      free(aliases);
    }
  free(addrs);
  free(hostname);
  return status;
+18 −3
Original line number Diff line number Diff line
@@ -22,24 +22,39 @@ ares_parse_aaaa_reply \- Parse a reply to a DNS query of type AAAA into a hosten
.B #include <ares.h>
.PP
.B int ares_parse_aaaa_reply(const unsigned char *\fIabuf\fP, int \fIalen\fP,
.B 	struct hostent **\fIhost\fP);
.B 	struct hostent **\fIhost\fP,         
.B      struct addrttl *\fIaddrttls\fB, int *\fInaddrttls\fB);
.fi
.SH DESCRIPTION
The
.B ares_parse_aaaa_reply
function parses the response to a query of type AAAA into a
.BR "struct hostent" .
.BR "struct hostent"
and/or an array of
.BR "struct addrttls" . 
The parameters
.I abuf
and
.I alen
give the contents of the response.  The result is stored in allocated
memory and a pointer to it stored into the variable pointed to by
.IR host .
.IR host ,
if host is nonnull.
It is the caller's responsibility to free the resulting host structure
using
.BR ares_free_hostent (3)
when it is no longer needed.
.PP
If
.IR addrttls
and
.IR naddrttls
are both nonnull,
then up to *naddrttls
.BR "struct addr6ttl"
records are stored in the array pointed to by addrttls,
and then *naddrttls is set to the number of records so stored.
Note that the memory for these records is supplied by the caller.
.SH RETURN VALUES
.B ares_parse_aaaa_reply
can return any of the following values:
Loading