From 53c2186e183c9749edb1b31507a6c4a5e30d5659 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 28 Mar 2014 00:14:59 +0400 Subject: [PATCH] txt: introduce `ares_parse_txt_reply_ext` Introduce `ares_txt_ext` structure with an extra `record_start` field, which indicates a start of a new TXT record, thus allowing to differentiate the chunks in the same record, from a chunks in a different record. Introduce a new API method: `ares_parse_txt_reply_ext` that works with this kind of struct. --- ares.h | 15 +++++++++++++ ares_data.c | 5 +++++ ares_data.h | 14 ++++++------ ares_parse_txt_reply.3 | 48 ++++++++++++++++++++++++++++++++++++++---- ares_parse_txt_reply.c | 36 +++++++++++++++++++++++-------- 5 files changed, 99 insertions(+), 19 deletions(-) diff --git a/ares.h b/ares.h index 8d4ab8c..fcbcecf 100644 --- a/ares.h +++ b/ares.h @@ -484,6 +484,17 @@ struct ares_txt_reply { size_t length; /* length excludes null termination */ }; +/* NOTE: This structure is a superset of ares_txt_reply + */ +struct ares_txt_ext { + struct ares_txt_ext *next; + unsigned char *txt; + size_t length; + /* 1 - if start of new record + * 0 - if a chunk in the same record */ + unsigned char record_start; +}; + struct ares_naptr_reply { struct ares_naptr_reply *next; unsigned char *flags; @@ -547,6 +558,10 @@ CARES_EXTERN int ares_parse_txt_reply(const unsigned char* abuf, int alen, struct ares_txt_reply** txt_out); +CARES_EXTERN int ares_parse_txt_reply_ext(const unsigned char* abuf, + int alen, + struct ares_txt_ext** txt_out); + CARES_EXTERN int ares_parse_naptr_reply(const unsigned char* abuf, int alen, struct ares_naptr_reply** naptr_out); diff --git a/ares_data.c b/ares_data.c index 2d2afeb..f891113 100644 --- a/ares_data.c +++ b/ares_data.c @@ -79,6 +79,7 @@ void ares_free_data(void *dataptr) break; case ARES_DATATYPE_TXT_REPLY: + case ARES_DATATYPE_TXT_EXT: if (ptr->data.txt_reply.next) ares_free_data(ptr->data.txt_reply.next); @@ -162,6 +163,10 @@ void *ares_malloc_data(ares_datatype type) ptr->data.srv_reply.port = 0; break; + case ARES_DATATYPE_TXT_EXT: + ptr->data.txt_ext.record_start = 0; + /* FALLTHROUGH */ + case ARES_DATATYPE_TXT_REPLY: ptr->data.txt_reply.next = NULL; ptr->data.txt_reply.txt = NULL; diff --git a/ares_data.h b/ares_data.h index bd4a951..ffee2be 100644 --- a/ares_data.h +++ b/ares_data.h @@ -18,6 +18,7 @@ typedef enum { ARES_DATATYPE_UNKNOWN = 1, /* unknown data type - introduced in 1.7.0 */ 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_TXT_EXT, /* struct ares_txt_ext - introduced in 1.11.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 */ ARES_DATATYPE_NAPTR_REPLY,/* struct ares_naptr_reply - introduced in 1.7.6 */ @@ -56,13 +57,14 @@ struct ares_data { ares_datatype type; /* Actual data type identifier. */ unsigned int mark; /* Private ares_data signature. */ union { - struct ares_txt_reply txt_reply; - struct ares_srv_reply srv_reply; - struct ares_addr_node addr_node; + struct ares_txt_reply txt_reply; + struct ares_txt_ext txt_ext; + struct ares_srv_reply srv_reply; + struct ares_addr_node addr_node; struct ares_addr_port_node addr_port_node; - struct ares_mx_reply mx_reply; - struct ares_naptr_reply naptr_reply; - struct ares_soa_reply soa_reply; + struct ares_mx_reply mx_reply; + struct ares_naptr_reply naptr_reply; + struct ares_soa_reply soa_reply; } data; }; diff --git a/ares_parse_txt_reply.3 b/ares_parse_txt_reply.3 index 063b3ff..e15d0ea 100644 --- a/ares_parse_txt_reply.3 +++ b/ares_parse_txt_reply.3 @@ -22,13 +22,16 @@ ares_parse_txt_reply \- Parse a reply to a DNS query of type TXT .PP .B int ares_parse_txt_reply(const unsigned char* \fIabuf\fP, int \fIalen\fP, .B struct ares_txt_reply **\fItxt_out\fP); +.PP +.B int ares_parse_txt_reply_ext(const unsigned char* \fIabuf\fP, int \fIalen\fP, +.B struct ares_txt_ext **\fItxt_out\fP); .fi .SH DESCRIPTION The -.B ares_parse_txt_reply +.BR "ares_parse_txt_reply" " (" "ares_parse_txt_reply_ext" ")" function parses the response to a query of type TXT into a linked list (one element per sub-string) of -.I struct ares_txt_reply +.IR "struct ares_txt_reply" " (" "struct ares_txt_ext" ")" The parameters .I abuf and @@ -55,8 +58,44 @@ struct ares_txt_reply { .fi .in .PP +The structure +.I ares_txt_ext +contains the following fields: +.sp +.in +4n +.nf +struct ares_txt_ext { + struct ares_txt_ext *next; + unsigned int length; + unsigned char *txt; + unsigned char record_start; +}; +.fi +.in +.PP +The +.I record_start +field in +.I struct ares_txt_ext +is 1 if this structure is a start of a TXT record, and 0 if the structure is a +continuation of a previous record. The linked list of the +.I struct ares_txt_ext +will have at least one item with +.I record_start +equal to 1, and may have some items with +.I record_start +equal to 0 between them. +.PP +These sequences of +.I struct ares_txt_ext +(starting from the item with +.I record_start +equal to 1, and ending right before the record start item) may be treated as +either components of a single TXT record or as a multi-parted TXT record, +depending on particular use case. +.PP .SH RETURN VALUES -.B ares_parse_txt_reply +.BR "ares_parse_txt_reply" " (" "ares_parse_txt_reply_ext" ")" can return any of the following values: .TP 15 .B ARES_SUCCESS @@ -77,4 +116,5 @@ This function was first introduced in c-ares version 1.7.0. .BR ares_free_data (3) .SH AUTHOR Written by Jakub Hrozek , on behalf of Red Hat, Inc http://www.redhat.com - +.PP +Amended by Fedor Indutny , on behalf of PayPal, Inc https://www.paypal.com diff --git a/ares_parse_txt_reply.c b/ares_parse_txt_reply.c index ed95eb1..4856b4c 100644 --- a/ares_parse_txt_reply.c +++ b/ares_parse_txt_reply.c @@ -44,9 +44,9 @@ #include "ares_data.h" #include "ares_private.h" -int -ares_parse_txt_reply (const unsigned char *abuf, int alen, - struct ares_txt_reply **txt_out) +static int +ares__parse_txt_reply (const unsigned char *abuf, int alen, + int ex, void **txt_out) { size_t substr_len; unsigned int qdcount, ancount, i; @@ -55,9 +55,9 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen, int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; - struct ares_txt_reply *txt_head = NULL; - struct ares_txt_reply *txt_last = NULL; - struct ares_txt_reply *txt_curr; + struct ares_txt_ext *txt_head = NULL; + struct ares_txt_ext *txt_last = NULL; + struct ares_txt_ext *txt_curr; /* Set *txt_out to NULL for all failure cases. */ *txt_out = NULL; @@ -133,10 +133,9 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen, break; } - ++strptr; - /* Allocate storage for this TXT answer appending it to the list */ - txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY); + txt_curr = ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT : + ARES_DATATYPE_TXT_REPLY); if (!txt_curr) { status = ARES_ENOMEM; @@ -152,6 +151,8 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen, } txt_last = txt_curr; + if (ex) + txt_curr->record_start = (strptr == aptr); txt_curr->length = substr_len; txt_curr->txt = ares_malloc (substr_len + 1/* Including null byte */); if (txt_curr->txt == NULL) @@ -159,6 +160,8 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen, status = ARES_ENOMEM; break; } + + ++strptr; memcpy ((char *) txt_curr->txt, strptr, substr_len); /* Make sure we NULL-terminate */ @@ -200,3 +203,18 @@ ares_parse_txt_reply (const unsigned char *abuf, int alen, return ARES_SUCCESS; } + +int +ares_parse_txt_reply (const unsigned char *abuf, int alen, + struct ares_txt_reply **txt_out) +{ + return ares__parse_txt_reply(abuf, alen, 0, (void **) txt_out); +} + + +int +ares_parse_txt_reply_ext (const unsigned char *abuf, int alen, + struct ares_txt_ext **txt_out) +{ + return ares__parse_txt_reply(abuf, alen, 1, (void **) txt_out); +}