Jakub Hrozek added ares_parse_txt_reply() for TXT parsing

This commit is contained in:
Daniel Stenberg 2009-10-29 08:59:40 +00:00
parent 982e655c07
commit 950a034895
6 changed files with 270 additions and 1 deletions

View File

@ -1,5 +1,8 @@
Changelog for the c-ares project
* October 29, 2009 (Daniel Stenberg)
- Jakub Hrozek added ares_parse_txt_reply() for TXT parsing
* October 23, 2009 (Yang Tse)
- John Engelhart noticed an unreleased problem relative to a duplicate
ARES_ECANCELLED error code value and missing error code description.

View File

@ -23,6 +23,8 @@ CSOURCES = ares__close_sockets.c \
ares_parse_ns_reply.c \
ares_parse_ptr_reply.c \
ares_parse_srv_reply.c \
ares_parse_txt_reply.c \
ares_free_txt_reply.c \
ares_process.c \
ares_query.c \
ares_search.c \

View File

@ -1,4 +1,4 @@
This is what's new and changed in the c-ares 1.6.1 release:
This is what's new and changed in the c-ares 1.7.0 release:
Changed:
@ -11,6 +11,7 @@ Changed:
o new --enable-curldebug configure option
o ARES_ECANCELLED is now sent as reason for ares_cancel()
o added ares_parse_srv_reply()
o added ares_parse_txt_reply()
Fixed:

View File

@ -436,6 +436,11 @@ struct ares_srv_reply {
char *host;
};
struct ares_txt_reply {
unsigned int length;
unsigned char *txt;
};
/*
** 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.
@ -472,6 +477,11 @@ CARES_EXTERN int ares_parse_srv_reply(const unsigned char* abuf,
struct ares_srv_reply** srv_out,
int *nsrvreply);
CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf,
int alen,
struct ares_txt_reply** txt_out,
int *nsrvreply);
CARES_EXTERN void ares_free_string(void *str);
CARES_EXTERN void ares_free_hostent(struct hostent *host);

View File

@ -0,0 +1,77 @@
.\"
.\" Copyright 1998 by the Massachusetts Institute of Technology.
.\"
.\" Permission to use, copy, modify, and distribute this
.\" software and its documentation for any purpose and without
.\" fee is hereby granted, provided that the above copyright
.\" notice appear in all copies and that both that copyright
.\" notice and this permission notice appear in supporting
.\" documentation, and that the name of M.I.T. not be used in
.\" advertising or publicity pertaining to distribution of the
.\" software without specific, written prior permission.
.\" M.I.T. makes no representations about the suitability of
.\" this software for any purpose. It is provided "as is"
.\" without express or implied warranty.
.\"
.TH ARES_PARSE_TXT_REPLY 3 "27 October 2009"
.SH NAME
ares_parse_txt_reply \- Parse a reply to a DNS query of type TXT into a
struct ares_txt_reply
.SH SYNOPSIS
.nf
.B #include <ares.h>
.PP
.B int ares_parse_txt_reply(const unsigned char* \fIabuf\fP, int \fIalen\fP,
.B struct ares_txt_reply **\fItxt_out\fP, int *\fIntxtreply\fP);
.fi
.SH DESCRIPTION
The
.B ares_parse_txt_reply
function parses the response to a query of type TXT into a
.I struct ares_txt_reply
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 txt_out .
The number of responses is stored into the variable pointed to by
.IR ntxtreply .
It is the caller's responsibility to free the resulting
.IR txt_out
structure when it is no longer needed.
.PP
The structure
.I ares_txt_reply
contains the following fields:
.sp
.in +4n
.nf
struct ares_txt_reply {
unsigned int length;
unsigned char *txt;
};
.fi
.in
.PP
.SH RETURN VALUES
.B ares_parse_txt_reply
can return any of the following values:
.TP 15
.B ARES_SUCCESS
The response was successfully parsed.
.TP 15
.B ARES_EBADRESP
The response was malformatted.
.TP 15
.B ARES_ENODATA
The response did not contain an answer to the query.
.TP 15
.B ARES_ENOMEM
Memory was exhausted.
.SH SEE ALSO
.BR ares_query (3)
.SH AUTHOR
Written by Jakub Hrozek <jhrozek@redhat.com>, on behalf of Red Hat, Inc http://www.redhat.com

176
ares/ares_parse_txt_reply.c Normal file
View File

@ -0,0 +1,176 @@
/* Copyright (C) 2009 Jakub Hrozek <jhrozek@redhat.com>
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
#include "setup.h"
#if defined(WIN32) && !defined(WATT32)
#include "nameser.h"
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <arpa/nameser.h>
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
#include <arpa/nameser_compat.h>
#endif
#endif
#include <stdlib.h>
#include <string.h>
#include "ares.h"
#include "ares_dns.h"
#include "ares_private.h"
int
ares_parse_txt_reply (const unsigned char *abuf, int alen,
struct ares_txt_reply **txt_out, int *ntxtreply)
{
unsigned char substr_len = 0;
unsigned char str_len = 0;
unsigned int qdcount, ancount;
const unsigned char *aptr;
const unsigned char *strptr;
int status, i, rr_type, rr_class, rr_len;
long len;
char *hostname = NULL, *rr_name = NULL;
struct ares_txt_reply *txt = NULL;
*txt_out = NULL;
/* Give up if abuf doesn't have room for a header. */
if (alen < HFIXEDSZ)
return ARES_EBADRESP;
/* Fetch the question and answer count from the header. */
qdcount = DNS_HEADER_QDCOUNT (abuf);
ancount = DNS_HEADER_ANCOUNT (abuf);
if (qdcount != 1)
return ARES_EBADRESP;
if (ancount == 0)
return ARES_ENODATA;
/* Expand the name from the question, and skip past the question. */
aptr = abuf + HFIXEDSZ;
status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
if (status != ARES_SUCCESS)
return status;
if (aptr + len + QFIXEDSZ > abuf + alen)
{
free (hostname);
return ARES_EBADRESP;
}
aptr += len + QFIXEDSZ;
/* Allocate ares_txt_reply array; ancount gives an upper bound */
txt = malloc ((ancount) * sizeof (struct ares_txt_reply));
if (!txt)
{
free (hostname);
return ARES_ENOMEM;
}
/* Zero out so we can safely free txt.txt even if NULL */
memset(txt, 0, ancount * sizeof (struct ares_txt_reply));
/* Examine each answer resource record (RR) in turn. */
for (i = 0; i < (int) ancount; i++)
{
/* Decode the RR up to the data field. */
status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
if (status != ARES_SUCCESS)
{
break;
}
aptr += len;
if (aptr + RRFIXEDSZ > abuf + alen)
{
status = ARES_EBADRESP;
break;
}
rr_type = DNS_RR_TYPE (aptr);
rr_class = DNS_RR_CLASS (aptr);
rr_len = DNS_RR_LEN (aptr);
aptr += RRFIXEDSZ;
/* Check if we are really looking at a TXT record */
if (rr_class == C_IN && rr_type == T_TXT)
{
/*
* There may be multiple substrings in a single TXT record. Each
* substring may be up to 255 characters in length, with a
* "length byte" indicating the size of the substring payload.
* RDATA contains both the length-bytes and payloads of all
* substrings contained therein.
*/
/* Realloc would be expensive, compute the total length */
txt[i].length = 0;
strptr = aptr;
while (strptr < (aptr + rr_len))
{
memcpy ((void *) &substr_len, strptr, sizeof (unsigned char));
txt[i].length += substr_len;
strptr += substr_len + 1;
}
/* Including null byte */
txt[i].txt = malloc (sizeof (unsigned char) * (txt[i].length + 1));
if (txt[i].txt == NULL)
{
status = ARES_ENOMEM;
break;
}
/* Step through the list of substrings, concatenating them */
substr_len = 0;
str_len = 0;
strptr = aptr;
while (strptr < (aptr + rr_len))
{
memcpy ((void *) &substr_len, strptr, sizeof (unsigned char));
strptr++;
memcpy ((void *) txt[i].txt + str_len, strptr,
sizeof (unsigned char) * substr_len);
str_len += substr_len;
strptr += substr_len;
}
/* Make sure we NULL-terminate */
txt[i].txt[txt[i].length] = '\0';
/* Move on to the next record */
aptr += rr_len;
}
/* Don't lose memory in the next iteration */
free (rr_name);
rr_name = NULL;
}
free (hostname);
free (rr_name);
/* clean up on error */
if (status != ARES_SUCCESS)
{
ares_free_txt_reply(txt, ancount);
return status;
}
/* everything looks fine, return the data */
*txt_out = txt;
*ntxtreply = ancount;
return 0;
}