From 979bf951d3436bf7e86e690de26a174b39a081f8 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Fri, 15 Jun 2012 13:29:03 +0200 Subject: [PATCH] SOA parser added I need to do SOA queries, so here is a parser for them. - ares_soa_reply: new struct - ares_malloc_data/ares_free_soa: ARES_DATATYPE_SOA_REPLY - ares_parse_soa_reply: actual function --- Makefile.inc | 4 ++ ares.h | 16 +++++ ares_data.c | 17 ++++++ ares_data.h | 2 + ares_free_data.3 | 8 ++- ares_parse_soa_reply.3 | 80 ++++++++++++++++++++++++ ares_parse_soa_reply.c | 135 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 ares_parse_soa_reply.3 create mode 100644 ares_parse_soa_reply.c diff --git a/Makefile.inc b/Makefile.inc index def54cb..ec0cba4 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -28,6 +28,7 @@ CSOURCES = ares__close_sockets.c \ ares_parse_naptr_reply.c \ ares_parse_ns_reply.c \ ares_parse_ptr_reply.c \ + ares_parse_soa_reply.c \ ares_parse_srv_reply.c \ ares_parse_txt_reply.c \ ares_platform.c \ @@ -97,6 +98,7 @@ MANPAGES = ares_cancel.3 \ ares_parse_naptr_reply.3 \ ares_parse_ns_reply.3 \ ares_parse_ptr_reply.3 \ + ares_parse_soa_reply.3 \ ares_parse_srv_reply.3 \ ares_parse_txt_reply.3 \ ares_process.3 \ @@ -136,6 +138,7 @@ HTMLPAGES = ares_cancel.html \ ares_parse_mx_reply.html \ ares_parse_ns_reply.html \ ares_parse_ptr_reply.html \ + ares_parse_soa_reply.html \ ares_parse_srv_reply.html \ ares_parse_txt_reply.html \ ares_process.html \ @@ -175,6 +178,7 @@ PDFPAGES = ares_cancel.pdf \ ares_parse_mx_reply.pdf \ ares_parse_ns_reply.pdf \ ares_parse_ptr_reply.pdf \ + ares_parse_soa_reply.pdf \ ares_parse_srv_reply.pdf \ ares_parse_txt_reply.pdf \ ares_process.pdf \ diff --git a/ares.h b/ares.h index a4a119e..c5e4069 100644 --- a/ares.h +++ b/ares.h @@ -476,6 +476,16 @@ struct ares_naptr_reply { unsigned short preference; }; +struct ares_soa_reply { + char *nsname; + char *hostmaster; + unsigned int serial; + unsigned int refresh; + unsigned int retry; + unsigned int expire; + unsigned int minttl; +}; + /* ** 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. @@ -523,10 +533,16 @@ CARES_EXTERN int ares_parse_naptr_reply(const unsigned char* abuf, int alen, struct ares_naptr_reply** naptr_out); +CARES_EXTERN int ares_parse_soa_reply(const unsigned char* abuf, + int alen, + struct ares_soa_reply** soa_out); + CARES_EXTERN void ares_free_string(void *str); CARES_EXTERN void ares_free_hostent(struct hostent *host); +CARES_EXTERN void ares_free_soa(struct ares_soa_reply *soa); + CARES_EXTERN void ares_free_data(void *dataptr); CARES_EXTERN const char *ares_strerror(int code); diff --git a/ares_data.c b/ares_data.c index 0e43ddd..7c04650 100644 --- a/ares_data.c +++ b/ares_data.c @@ -106,6 +106,13 @@ void ares_free_data(void *dataptr) free(ptr->data.naptr_reply.replacement); break; + case ARES_DATATYPE_SOA_REPLY: + if (ptr->data.soa_reply.nsname) + free(ptr->data.soa_reply.nsname); + if (ptr->data.soa_reply.hostmaster) + free(ptr->data.soa_reply.hostmaster); + break; + default: return; } @@ -172,6 +179,16 @@ void *ares_malloc_data(ares_datatype type) ptr->data.naptr_reply.preference = 0; break; + case ARES_DATATYPE_SOA_REPLY: + ptr->data.soa_reply.nsname = NULL; + ptr->data.soa_reply.hostmaster = NULL; + ptr->data.soa_reply.serial = 0; + ptr->data.soa_reply.refresh = 0; + ptr->data.soa_reply.retry = 0; + ptr->data.soa_reply.expire = 0; + ptr->data.soa_reply.minttl = 0; + break; + default: free(ptr); return NULL; diff --git a/ares_data.h b/ares_data.h index a6acd20..fbfc496 100644 --- a/ares_data.h +++ b/ares_data.h @@ -21,6 +21,7 @@ typedef enum { 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 */ ARES_DATATYPE_NAPTR_REPLY,/* struct ares_naptr_reply - introduced in 1.7.6 */ + ARES_DATATYPE_SOA_REPLY, /* struct ares_soa_reply - introduced in 1.x.x */ #if 0 ARES_DATATYPE_ADDR6TTL, /* struct ares_addrttl */ ARES_DATATYPE_ADDRTTL, /* struct ares_addr6ttl */ @@ -59,6 +60,7 @@ struct ares_data { struct ares_addr_node addr_node; struct ares_mx_reply mx_reply; struct ares_naptr_reply naptr_reply; + struct ares_soa_reply soa_reply; } data; }; diff --git a/ares_free_data.3 b/ares_free_data.3 index c6cadd5..f8a65b9 100644 --- a/ares_free_data.3 +++ b/ares_free_data.3 @@ -55,6 +55,11 @@ 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 by ares_parse_txt_reply(3), along with any additional storage associated with those structures. +.TP +.B ares_parse_soa_reply(3) +When used to free the data returned by ares_parse_soa_reply(3) this +will free the ares_soa_reply structure, along with any additional storage +associated with those structure. .SH RETURN VALUE The ares_free_data() function does not return a value. .SH AVAILABILITY @@ -63,7 +68,8 @@ This function was first introduced in c-ares version 1.7.0. .BR ares_get_servers(3), .BR ares_parse_srv_reply(3), .BR ares_parse_mx_reply(3), -.BR ares_parse_txt_reply(3) +.BR ares_parse_txt_reply(3), +.BR ares_parse_soa_reply(3) .SH AUTHOR Yang Tse .PP diff --git a/ares_parse_soa_reply.3 b/ares_parse_soa_reply.3 new file mode 100644 index 0000000..1c4456f --- /dev/null +++ b/ares_parse_soa_reply.3 @@ -0,0 +1,80 @@ +.\" +.\" 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_SOA_REPLY 3 "29 May 2012" +.SH NAME +ares_parse_soa_reply \- Parse a reply to a DNS query of type SOA +.SH SYNOPSIS +.nf +.B #include +.PP +.B int ares_parse_soa_reply(const unsigned char* \fIabuf\fP, int \fIalen\fP, +.B struct ares_soa_reply** \fIsoa_out\fP); +.fi +.SH DESCRIPTION +The +.B ares_parse_soa_reply +function parses the response to a query of type SOA into a +.IR struct\ ares_soa_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 soa_out . +It is the caller's responsibility to free the resulting +.IR soa_out +structure when it is no longer needed using the function +.B ares_free_data +.PP +The structure +.I ares_soa_reply +contains the following fields: +.sp +.in +4n +.nf +struct ares_soa_reply { + char *nsname; + char *hostmaster; + unsigned int serial; + unsigned int refresh; + unsigned int retry; + unsigned int expire; + unsigned int minttl; +}; +.fi +.in +.PP +.SH RETURN VALUES +.B ares_parse_soa_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.9.0. +.SH SEE ALSO +.BR ares_query (3) +.BR ares_free_data (3) diff --git a/ares_parse_soa_reply.c b/ares_parse_soa_reply.c new file mode 100644 index 0000000..b811954 --- /dev/null +++ b/ares_parse_soa_reply.c @@ -0,0 +1,135 @@ + +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2012 Marko Kreen + * + * 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 +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#else +# include "nameser.h" +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#include +#include "ares.h" +#include "ares_dns.h" +#include "ares_data.h" +#include "ares_private.h" + +int +ares_parse_soa_reply(const unsigned char *abuf, int alen, + struct ares_soa_reply **soa_out) +{ + const unsigned char *aptr; + long len; + char *qname = NULL, *rr_name = NULL; + struct ares_soa_reply *soa = NULL; + int qdcount, ancount; + int status; + + if (alen < HFIXEDSZ) + return ARES_EBADRESP; + + /* parse message header */ + qdcount = DNS_HEADER_QDCOUNT(abuf); + ancount = DNS_HEADER_ANCOUNT(abuf); + if (qdcount != 1 || ancount != 1) + return ARES_EBADRESP; + aptr = abuf + HFIXEDSZ; + + /* query name */ + status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len); + if (status != ARES_SUCCESS) + goto failed_stat; + aptr += len; + + /* skip qtype & qclass */ + if (aptr + QFIXEDSZ > abuf + alen) + goto failed; + aptr += QFIXEDSZ; + + /* rr_name */ + status = ares__expand_name_for_response(aptr, abuf, alen, &rr_name, &len); + if (status != ARES_SUCCESS) + goto failed_stat; + aptr += len; + + /* skip rr_type, rr_class, rr_ttl, rr_rdlen */ + if (aptr + RRFIXEDSZ > abuf + alen) + goto failed; + aptr += RRFIXEDSZ; + + /* allocate result struct */ + soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY); + if (!soa) + return ARES_ENOMEM; + + /* nsname */ + status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname, &len); + if (status != ARES_SUCCESS) + goto failed_stat; + aptr += len; + + /* hostmaster */ + status = ares__expand_name_for_response(aptr, abuf, alen, &soa->hostmaster, &len); + if (status != ARES_SUCCESS) + goto failed_stat; + aptr += len; + + /* integer fields */ + if (aptr + 5 * 4 > abuf + alen) + goto failed; + soa->serial = DNS__32BIT(aptr + 0 * 4); + soa->refresh = DNS__32BIT(aptr + 1 * 4); + soa->retry = DNS__32BIT(aptr + 2 * 4); + soa->expire = DNS__32BIT(aptr + 3 * 4); + soa->minttl = DNS__32BIT(aptr + 4 * 4); + + free(qname); + free(rr_name); + + *soa_out = soa; + + return ARES_SUCCESS; + +failed: + status = ARES_EBADRESP; + +failed_stat: + ares_free_data(soa); + if (qname) + free(qname); + if (rr_name) + free(rr_name); + return status; +} +