diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2009-11-27 09:39:41 +0100 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2009-12-09 10:05:18 -0500 |
commit | a3b55a024b03321be969a892cb0992bad14266af (patch) | |
tree | 9dfa66057df41bd5910ab9e09b14cfd4db4a0a2e /server/resolv/ares/ares_parse_txt_reply.c | |
parent | 2446a71baaae100bafee0589a2e18bb8a16dff1b (diff) | |
download | sssd-a3b55a024b03321be969a892cb0992bad14266af.tar.gz sssd-a3b55a024b03321be969a892cb0992bad14266af.tar.bz2 sssd-a3b55a024b03321be969a892cb0992bad14266af.zip |
Import ares 1.7.0 helpers
Diffstat (limited to 'server/resolv/ares/ares_parse_txt_reply.c')
-rw-r--r-- | server/resolv/ares/ares_parse_txt_reply.c | 119 |
1 files changed, 83 insertions, 36 deletions
diff --git a/server/resolv/ares/ares_parse_txt_reply.c b/server/resolv/ares/ares_parse_txt_reply.c index feb6af23..d710e8f9 100644 --- a/server/resolv/ares/ares_parse_txt_reply.c +++ b/server/resolv/ares/ares_parse_txt_reply.c @@ -50,21 +50,26 @@ #include "ares.h" /* this drags in some private macros c-ares uses */ #include "ares_dns.h" +#include "ares_data.h" #include "ares_parse_txt_reply.h" -int _ares_parse_txt_reply(const unsigned char* abuf, int alen, - struct txt_reply **txt_out, int *ntxtreply) +int _ares_parse_txt_reply (const unsigned char *abuf, int alen, + struct ares_txt_reply **txt_out) { - unsigned int qdcount, ancount; + size_t substr_len, str_len; + unsigned int qdcount, ancount, i; const unsigned char *aptr; - int status, i, rr_type, rr_class, rr_len; + const unsigned char *strptr; + int status, rr_type, rr_class, rr_len; long len; char *hostname = NULL, *rr_name = NULL; - struct txt_reply *txt = NULL; + struct ares_txt_reply *txt_head = NULL; + struct ares_txt_reply *txt_last = NULL; + struct ares_txt_reply *txt_curr; - if (txt_out) - *txt_out = NULL; + /* Set *txt_out to NULL for all failure cases. */ + *txt_out = NULL; /* Give up if abuf doesn't have room for a header. */ if (alen < HFIXEDSZ) @@ -91,29 +96,21 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen, } aptr += len + QFIXEDSZ; - /* Allocate txt_reply array; ancount gives an upper bound */ - txt = malloc ((ancount) * sizeof (struct txt_reply)); - if (!txt) - { - free (hostname); - return ARES_ENOMEM; - } - /* 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; - } + { + break; + } aptr += len; if (aptr + RRFIXEDSZ > abuf + alen) - { - status = ARES_EBADRESP; - break; - } + { + status = ARES_EBADRESP; + break; + } rr_type = DNS_RR_TYPE(aptr); rr_class = DNS_RR_CLASS(aptr); rr_len = DNS_RR_LEN(aptr); @@ -121,37 +118,87 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen, /* Check if we are really looking at a TXT record */ if (rr_class == C_IN && rr_type == T_TXT) - { - /* Grab the TXT payload */ - txt[i].length = rr_len; - txt[i].txt = malloc(sizeof(unsigned char) * rr_len); - if (txt[i].txt == NULL) + { + /* Allocate storage for this TXT answer appending it to the list */ + txt_curr = _ares_malloc_data(ARES_DATATYPE_TXT_REPLY); + if (!txt_curr) { status = ARES_ENOMEM; break; } - memcpy((void *) txt[i].txt, aptr+1, sizeof(unsigned char) * rr_len); - /* Move on to the next record */ - aptr += rr_len; + if (txt_last) + { + txt_last->next = txt_curr; + } + else + { + txt_head = txt_curr; + } + txt_last = txt_curr; + + /* + * 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. + */ + + /* Compute total length to allow a single memory allocation */ + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + txt_curr->length += substr_len; + strptr += substr_len + 1; + } + + /* Including null byte */ + txt_curr->txt = malloc (txt_curr->length + 1); + if (txt_curr->txt == NULL) + { + status = ARES_ENOMEM; + break; + } + + /* Step through the list of substrings, concatenating them */ + str_len = 0; + strptr = aptr; + while (strptr < (aptr + rr_len)) + { + substr_len = (unsigned char)*strptr; + strptr++; + memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len); + str_len += substr_len; + strptr += substr_len; + } + /* Make sure we NULL-terminate */ + *((char *) txt_curr->txt + txt_curr->length) = '\0'; } /* Don't lose memory in the next iteration */ free(rr_name); rr_name = NULL; + + /* Move on to the next record */ + aptr += rr_len; } - free(hostname); - free(rr_name); + if (hostname) + free (hostname); + if (rr_name) + free (rr_name); /* clean up on error */ if (status != ARES_SUCCESS) { - free (txt); + if (txt_head) + _ares_free_data (txt_head); return status; } /* everything looks fine, return the data */ - *txt_out = txt; - *ntxtreply = ancount; - return 0; + *txt_out = txt_head; + + return ARES_SUCCESS; } |