summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérémy Lal <kapouer@melix.org>2010-04-18 00:29:26 +0200
committerDaniel Stenberg <daniel@haxx.se>2010-04-18 00:29:26 +0200
commit63918fca7667a03b310c5f8486636a896be7ac72 (patch)
treed403f6919268eaa232ed5b513125d848a8af96df
parentf28874d3233adad18f4c25df8d9437d0c9e7c3eb (diff)
downloadc-ares-63918fca7667a03b310c5f8486636a896be7ac72.tar.gz
c-ares-63918fca7667a03b310c5f8486636a896be7ac72.tar.bz2
c-ares-63918fca7667a03b310c5f8486636a896be7ac72.zip
added ares_parse_mx_reply
-rw-r--r--Makefile.inc4
-rw-r--r--ares.h10
-rw-r--r--ares_data.c14
-rw-r--r--ares_data.h2
-rw-r--r--ares_free_data.37
-rw-r--r--ares_parse_mx_reply.379
-rw-r--r--ares_parse_mx_reply.c170
7 files changed, 286 insertions, 0 deletions
diff --git a/Makefile.inc b/Makefile.inc
index cef828a..bc211f8 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -23,6 +23,7 @@ CSOURCES = ares__close_sockets.c \
ares_options.c \
ares_parse_a_reply.c \
ares_parse_aaaa_reply.c \
+ ares_parse_mx_reply.c \
ares_parse_ns_reply.c \
ares_parse_ptr_reply.c \
ares_parse_srv_reply.c \
@@ -86,6 +87,7 @@ MANPAGES = ares_cancel.3 \
ares_mkquery.3 \
ares_parse_a_reply.3 \
ares_parse_aaaa_reply.3 \
+ ares_parse_mx_reply.3 \
ares_parse_ns_reply.3 \
ares_parse_ptr_reply.3 \
ares_parse_srv_reply.3 \
@@ -124,6 +126,7 @@ HTMLPAGES = ares_cancel.html \
ares_mkquery.html \
ares_parse_a_reply.html \
ares_parse_aaaa_reply.html \
+ ares_parse_mx_reply.html \
ares_parse_ns_reply.html \
ares_parse_ptr_reply.html \
ares_parse_srv_reply.html \
@@ -162,6 +165,7 @@ PDFPAGES = ares_cancel.pdf \
ares_mkquery.pdf \
ares_parse_a_reply.pdf \
ares_parse_aaaa_reply.pdf \
+ ares_parse_mx_reply.pdf \
ares_parse_ns_reply.pdf \
ares_parse_ptr_reply.pdf \
ares_parse_srv_reply.pdf \
diff --git a/ares.h b/ares.h
index 31c862a..368c73a 100644
--- a/ares.h
+++ b/ares.h
@@ -433,6 +433,12 @@ struct ares_srv_reply {
unsigned short port;
};
+struct ares_mx_reply {
+ struct ares_mx_reply *next;
+ char *host;
+ unsigned short priority;
+};
+
struct ares_txt_reply {
struct ares_txt_reply *next;
unsigned char *txt;
@@ -474,6 +480,10 @@ CARES_EXTERN int ares_parse_srv_reply(const unsigned char* abuf,
int alen,
struct ares_srv_reply** srv_out);
+CARES_EXTERN int ares_parse_mx_reply(const unsigned char* abuf,
+ int alen,
+ struct ares_mx_reply** mx_out);
+
CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf,
int alen,
struct ares_txt_reply** txt_out);
diff --git a/ares_data.c b/ares_data.c
index 59fe449..6b6fae8 100644
--- a/ares_data.c
+++ b/ares_data.c
@@ -62,6 +62,14 @@ void ares_free_data(void *dataptr)
switch (ptr->type)
{
+ case ARES_DATATYPE_MX_REPLY:
+
+ if (ptr->data.mx_reply.next)
+ ares_free_data(ptr->data.mx_reply.next);
+ if (ptr->data.mx_reply.host)
+ free(ptr->data.mx_reply.host);
+ break;
+
case ARES_DATATYPE_SRV_REPLY:
if (ptr->data.srv_reply.next)
@@ -113,6 +121,12 @@ void *ares_malloc_data(ares_datatype type)
switch (type)
{
+ case ARES_DATATYPE_MX_REPLY:
+ ptr->data.mx_reply.next = NULL;
+ ptr->data.mx_reply.host = NULL;
+ ptr->data.mx_reply.priority = 0;
+ break;
+
case ARES_DATATYPE_SRV_REPLY:
ptr->data.srv_reply.next = NULL;
ptr->data.srv_reply.host = NULL;
diff --git a/ares_data.h b/ares_data.h
index 193c179..de1608b 100644
--- a/ares_data.h
+++ b/ares_data.h
@@ -19,6 +19,7 @@ typedef enum {
ARES_DATATYPE_SRV_REPLY, /* struct ares_srv_reply - introduced in 1.7.0 */
ARES_DATATYPE_TXT_REPLY, /* struct ares_txt_reply - introduced in 1.7.0 */
ARES_DATATYPE_ADDR_NODE, /* struct ares_addr_node - introduced in 1.7.1 */
+ ARES_DATATYPE_MX_REPLY, /* struct ares_mx_reply - introduced in 1.7.2 */
#if 0
ARES_DATATYPE_ADDR6TTL, /* struct ares_addrttl */
ARES_DATATYPE_ADDRTTL, /* struct ares_addr6ttl */
@@ -55,6 +56,7 @@ struct ares_data {
struct ares_txt_reply txt_reply;
struct ares_srv_reply srv_reply;
struct ares_addr_node addr_node;
+ struct ares_mx_reply mx_reply;
} data;
};
diff --git a/ares_free_data.3 b/ares_free_data.3
index b783fd0..c6cadd5 100644
--- a/ares_free_data.3
+++ b/ares_free_data.3
@@ -44,6 +44,12 @@ will free the whole linked list of ares_srv_reply structures returned
by ares_parse_srv_reply(3), along with any additional storage
associated with those structures.
.TP
+.B ares_parse_mx_reply(3)
+When used to free the data returned by ares_parse_mx_reply(3) this
+will free the whole linked list of ares_mx_reply structures returned
+by ares_parse_mx_reply(3), along with any additional storage
+associated with those structures.
+.TP
.B ares_parse_txt_reply(3)
When used to free the data returned by ares_parse_txt_reply(3) this
will free the whole linked list of ares_txt_reply structures returned
@@ -56,6 +62,7 @@ This function was first introduced in c-ares version 1.7.0.
.SH SEE ALSO
.BR ares_get_servers(3),
.BR ares_parse_srv_reply(3),
+.BR ares_parse_mx_reply(3),
.BR ares_parse_txt_reply(3)
.SH AUTHOR
Yang Tse
diff --git a/ares_parse_mx_reply.3 b/ares_parse_mx_reply.3
new file mode 100644
index 0000000..87df459
--- /dev/null
+++ b/ares_parse_mx_reply.3
@@ -0,0 +1,79 @@
+.\"
+.\" 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_MX_REPLY 3 "4 August 2009"
+.SH NAME
+ares_parse_mx_reply \- Parse a reply to a DNS query of type MX
+.SH SYNOPSIS
+.nf
+.B #include <ares.h>
+.PP
+.B int ares_parse_mx_reply(const unsigned char* \fIabuf\fP, int \fIalen\fP,
+.B struct ares_mx_reply** \fImx_out\fP);
+.fi
+.SH DESCRIPTION
+The
+.B ares_parse_mx_reply
+function parses the response to a query of type MX into a
+linked list of
+.I struct ares_mx_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 mx_out .
+It is the caller's responsibility to free the resulting
+.IR mx_out
+structure when it is no longer needed using the function
+.B ares_free_data
+.PP
+The structure
+.I ares_mx_reply
+contains the following fields:
+.sp
+.in +4n
+.nf
+struct ares_mx_reply {
+ struct ares_mx_reply *next;
+ char *host;
+ unsigned short priority;
+};
+.fi
+.in
+.PP
+.SH RETURN VALUES
+.B ares_parse_mx_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 AVAILABILITY
+This function was first introduced in c-ares version 1.7.2.
+.SH SEE ALSO
+.BR ares_query (3)
+.BR ares_free_data (3)
+.SH AUTHOR
+Written by Jeremy Lal <kapouer@melix.org>
diff --git a/ares_parse_mx_reply.c b/ares_parse_mx_reply.c
new file mode 100644
index 0000000..186ddd3
--- /dev/null
+++ b/ares_parse_mx_reply.c
@@ -0,0 +1,170 @@
+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2010 Jeremy Lal <kapouer@melix.org>
+ *
+ * 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 "ares_setup.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#else
+# include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+# include <arpa/nameser_compat.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+int
+ares_parse_mx_reply (const unsigned char *abuf, int alen,
+ struct ares_mx_reply **mx_out)
+{
+ unsigned int qdcount, ancount, i;
+ const unsigned char *aptr, *vptr;
+ int status, rr_type, rr_class, rr_len;
+ long len;
+ char *hostname = NULL, *rr_name = NULL;
+ struct ares_mx_reply *mx_head = NULL;
+ struct ares_mx_reply *mx_last = NULL;
+ struct ares_mx_reply *mx_curr;
+
+ /* Set *mx_out to NULL for all failure cases. */
+ *mx_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;
+
+ /* Examine each answer resource record (RR) in turn. */
+ for (i = 0; i < 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 MX record */
+ if (rr_class == C_IN && rr_type == T_MX)
+ {
+ /* parse the MX record itself */
+ if (rr_len < 2)
+ {
+ status = ARES_EBADRESP;
+ break;
+ }
+
+ /* Allocate storage for this MX answer appending it to the list */
+ mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY);
+ if (!mx_curr)
+ {
+ status = ARES_ENOMEM;
+ break;
+ }
+ if (mx_last)
+ {
+ mx_last->next = mx_curr;
+ }
+ else
+ {
+ mx_head = mx_curr;
+ }
+ mx_last = mx_curr;
+
+ vptr = aptr;
+ mx_curr->priority = ntohs (*((unsigned short *)vptr));
+ vptr += sizeof(unsigned short);
+
+ status = ares_expand_name (vptr, abuf, alen, &mx_curr->host, &len);
+ if (status != ARES_SUCCESS)
+ break;
+ }
+
+ /* Don't lose memory in the next iteration */
+ free (rr_name);
+ rr_name = NULL;
+
+ /* Move on to the next record */
+ aptr += rr_len;
+ }
+
+ if (hostname)
+ free (hostname);
+ if (rr_name)
+ free (rr_name);
+
+ /* clean up on error */
+ if (status != ARES_SUCCESS)
+ {
+ if (mx_head)
+ ares_free_data (mx_head);
+ return status;
+ }
+
+ /* everything looks fine, return the data */
+ *mx_out = mx_head;
+
+ return ARES_SUCCESS;
+}