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

pull/1/head
Steinar H. Gunderson 17 years ago
parent 7cd35ce698
commit b4bdb6d4d7
  1. 23
      ares.h
  2. 4
      ares_gethostbyname.c
  3. 21
      ares_parse_a_reply.3
  4. 68
      ares_parse_a_reply.c
  5. 21
      ares_parse_aaaa_reply.3
  6. 70
      ares_parse_aaaa_reply.c

@ -240,10 +240,29 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
int alen, char **s, long *enclen); int alen, char **s, long *enclen);
int ares_expand_string(const unsigned char *encoded, const unsigned char *abuf, int ares_expand_string(const unsigned char *encoded, const unsigned char *abuf,
int alen, unsigned char **s, long *enclen); 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, 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, 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 ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr,
int addrlen, int family, struct hostent **host); int addrlen, int family, struct hostent **host);
int ares_parse_ns_reply(const unsigned char *abuf, int alen, int ares_parse_ns_reply(const unsigned char *abuf, int alen,

@ -160,13 +160,13 @@ static void host_callback(void *arg, int status, int timeouts,
{ {
if (hquery->family == AF_INET) 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) if (host && channel->nsort)
sort_addresses(host, channel->sortlist, channel->nsort); sort_addresses(host, channel->sortlist, channel->nsort);
} }
else if (hquery->family == AF_INET6) 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) if (host && channel->nsort)
sort6_addresses(host, channel->sortlist, channel->nsort); sort6_addresses(host, channel->sortlist, channel->nsort);
} }

@ -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> .B #include <ares.h>
.PP .PP
.B int ares_parse_a_reply(const unsigned char *\fIabuf\fP, int \fIalen\fP, .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 .fi
.SH DESCRIPTION .SH DESCRIPTION
The The
.B ares_parse_a_reply .B ares_parse_a_reply
function parses the response to a query of type A into a 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 The parameters
.I abuf .I abuf
and and
.I alen .I alen
give the contents of the response. The result is stored in allocated 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 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 It is the caller's responsibility to free the resulting host structure
using using
.BR ares_free_hostent (3) .BR ares_free_hostent (3)
when it is no longer needed. 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 .SH RETURN VALUES
.B ares_parse_a_reply .B ares_parse_a_reply
can return any of the following values: can return any of the following values:

@ -37,19 +37,26 @@
#include "ares_private.h" #include "ares_private.h"
int ares_parse_a_reply(const unsigned char *abuf, int alen, 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; 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; int naliases;
long len; long len;
const unsigned char *aptr; const unsigned char *aptr;
char *hostname, *rr_name, *rr_data, **aliases; char *hostname, *rr_name, *rr_data, **aliases;
struct in_addr *addrs; struct in_addr *addrs;
struct hostent *hostent; struct hostent *hostent;
const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
/* Set *host to NULL for all failure cases. */ /* Set *host to NULL for all failure cases. */
if (host)
*host = NULL; *host = NULL;
/* Same with *naddrttls. */
if (naddrttls)
*naddrttls = 0;
/* Give up if abuf doesn't have room for a header. */ /* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ) if (alen < HFIXEDSZ)
@ -73,6 +80,8 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
} }
aptr += len + QFIXEDSZ; aptr += len + QFIXEDSZ;
if (host)
{
/* Allocate addresses and aliases; ancount gives an upper bound for both. */ /* Allocate addresses and aliases; ancount gives an upper bound for both. */
addrs = malloc(ancount * sizeof(struct in_addr)); addrs = malloc(ancount * sizeof(struct in_addr));
if (!addrs) if (!addrs)
@ -87,6 +96,13 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
free(addrs); free(addrs);
return ARES_ENOMEM; return ARES_ENOMEM;
} }
}
else
{
addrs = NULL;
aliases = NULL;
}
naddrs = 0; naddrs = 0;
naliases = 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_type = DNS_RR_TYPE(aptr);
rr_class = DNS_RR_CLASS(aptr); rr_class = DNS_RR_CLASS(aptr);
rr_len = DNS_RR_LEN(aptr); rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ; aptr += RRFIXEDSZ;
if (rr_class == C_IN && rr_type == T_A if (rr_class == C_IN && rr_type == T_A
&& rr_len == sizeof(struct in_addr) && rr_len == sizeof(struct in_addr)
&& strcasecmp(rr_name, hostname) == 0) && 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)); 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++; naddrs++;
status = ARES_SUCCESS; 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) if (rr_class == C_IN && rr_type == T_CNAME)
{ {
/* Record the RR name as an alias. */ /* Record the RR name as an alias. */
if (aliases)
aliases[naliases] = rr_name; aliases[naliases] = rr_name;
else
free(rr_name);
naliases++; naliases++;
/* Decode the RR data and replace the hostname with it. */ /* 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; break;
free(hostname); free(hostname);
hostname = rr_data; 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 else
free(rr_name); free(rr_name);
@ -145,8 +188,23 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
status = ARES_ENODATA; status = ARES_ENODATA;
if (status == ARES_SUCCESS) 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; aliases[naliases] = NULL;
if (host)
{
/* Allocate memory to build the host entry. */
hostent = malloc(sizeof(struct hostent)); hostent = malloc(sizeof(struct hostent));
if (hostent) if (hostent)
{ {
@ -168,9 +226,13 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
} }
status = ARES_ENOMEM; status = ARES_ENOMEM;
} }
}
if (aliases)
{
for (i = 0; i < naliases; i++) for (i = 0; i < naliases; i++)
free(aliases[i]); free(aliases[i]);
free(aliases); free(aliases);
}
free(addrs); free(addrs);
free(hostname); free(hostname);
return status; return status;

@ -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> .B #include <ares.h>
.PP .PP
.B int ares_parse_aaaa_reply(const unsigned char *\fIabuf\fP, int \fIalen\fP, .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 .fi
.SH DESCRIPTION .SH DESCRIPTION
The The
.B ares_parse_aaaa_reply .B ares_parse_aaaa_reply
function parses the response to a query of type AAAA into a 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 The parameters
.I abuf .I abuf
and and
.I alen .I alen
give the contents of the response. The result is stored in allocated 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 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 It is the caller's responsibility to free the resulting host structure
using using
.BR ares_free_hostent (3) .BR ares_free_hostent (3)
when it is no longer needed. 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 .SH RETURN VALUES
.B ares_parse_aaaa_reply .B ares_parse_aaaa_reply
can return any of the following values: can return any of the following values:

@ -40,19 +40,26 @@
#include "ares_private.h" #include "ares_private.h"
int ares_parse_aaaa_reply(const unsigned char *abuf, int alen, int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
struct hostent **host) struct hostent **host, struct addr6ttl *addrttls,
int *naddrttls)
{ {
unsigned int qdcount, ancount; 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; int naliases;
long len; long len;
const unsigned char *aptr; const unsigned char *aptr;
char *hostname, *rr_name, *rr_data, **aliases; char *hostname, *rr_name, *rr_data, **aliases;
struct in6_addr *addrs; struct in6_addr *addrs;
struct hostent *hostent; struct hostent *hostent;
const int max_addr_ttls = (addrttls && naddrttls) ? *naddrttls : 0;
/* Set *host to NULL for all failure cases. */ /* Set *host to NULL for all failure cases. */
if (host)
*host = NULL; *host = NULL;
/* Same with *naddrttls. */
if (naddrttls)
*naddrttls = 0;
/* Give up if abuf doesn't have room for a header. */ /* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ) if (alen < HFIXEDSZ)
@ -77,6 +84,8 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
aptr += len + QFIXEDSZ; aptr += len + QFIXEDSZ;
/* Allocate addresses and aliases; ancount gives an upper bound for both. */ /* Allocate addresses and aliases; ancount gives an upper bound for both. */
if (host)
{
addrs = malloc(ancount * sizeof(struct in6_addr)); addrs = malloc(ancount * sizeof(struct in6_addr));
if (!addrs) if (!addrs)
{ {
@ -90,6 +99,12 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
free(addrs); free(addrs);
return ARES_ENOMEM; return ARES_ENOMEM;
} }
}
else
{
addrs = NULL;
aliases = NULL;
}
naddrs = 0; naddrs = 0;
naliases = 0; naliases = 0;
@ -109,13 +124,33 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
rr_type = DNS_RR_TYPE(aptr); rr_type = DNS_RR_TYPE(aptr);
rr_class = DNS_RR_CLASS(aptr); rr_class = DNS_RR_CLASS(aptr);
rr_len = DNS_RR_LEN(aptr); rr_len = DNS_RR_LEN(aptr);
rr_ttl = DNS_RR_TTL(aptr);
aptr += RRFIXEDSZ; aptr += RRFIXEDSZ;
if (rr_class == C_IN && rr_type == T_AAAA if (rr_class == C_IN && rr_type == T_AAAA
&& rr_len == sizeof(struct in6_addr) && rr_len == sizeof(struct in6_addr)
&& strcasecmp(rr_name, hostname) == 0) && strcasecmp(rr_name, hostname) == 0)
{ {
if (addrs)
{
if (aptr + sizeof(struct in6_addr) > abuf + alen)
{
status = ARES_EBADRESP;
break;
}
memcpy(&addrs[naddrs], aptr, sizeof(struct in6_addr)); memcpy(&addrs[naddrs], aptr, sizeof(struct in6_addr));
}
if (naddrs < max_addr_ttls)
{
struct addr6ttl * const at = &addrttls[naddrs];
if (aptr + sizeof(struct in6_addr) > abuf + alen)
{
status = ARES_EBADRESP;
break;
}
memcpy(&at->ip6addr, aptr, sizeof(struct in6_addr));
at->ttl = rr_ttl;
}
naddrs++; naddrs++;
status = ARES_SUCCESS; status = ARES_SUCCESS;
} }
@ -123,7 +158,10 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
if (rr_class == C_IN && rr_type == T_CNAME) if (rr_class == C_IN && rr_type == T_CNAME)
{ {
/* Record the RR name as an alias. */ /* Record the RR name as an alias. */
if (aliases)
aliases[naliases] = rr_name; aliases[naliases] = rr_name;
else
free(rr_name);
naliases++; naliases++;
/* Decode the RR data and replace the hostname with it. */ /* Decode the RR data and replace the hostname with it. */
@ -132,6 +170,10 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
break; break;
free(hostname); free(hostname);
hostname = rr_data; 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 else
free(rr_name); free(rr_name);
@ -148,8 +190,23 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
status = ARES_ENODATA; status = ARES_ENODATA;
if (status == ARES_SUCCESS) 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; aliases[naliases] = NULL;
if (host)
{
/* Allocate memory to build the host entry. */
hostent = malloc(sizeof(struct hostent)); hostent = malloc(sizeof(struct hostent));
if (hostent) if (hostent)
{ {
@ -171,6 +228,13 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
} }
status = ARES_ENOMEM; status = ARES_ENOMEM;
} }
}
if (aliases)
{
for (i = 0; i < naliases; i++)
free(aliases[i]);
free(aliases);
}
for (i = 0; i < naliases; i++) for (i = 0; i < naliases; i++)
free(aliases[i]); free(aliases[i]);
free(aliases); free(aliases);

Loading…
Cancel
Save