ares_parse_txt_reply.c revision 968bf19396ad404e89420f5d67900fce13f4186c
1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch/* Copyright 1998 by the Massachusetts Institute of Technology. 3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.com> 4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * 5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Permission to use, copy, modify, and distribute this 6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * software and its documentation for any purpose and without 7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * fee is hereby granted, provided that the above copyright 8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * notice appear in all copies and that both that copyright 9014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * notice and this permission notice appear in supporting 10 * documentation, and that the name of M.I.T. not be used in 11 * advertising or publicity pertaining to distribution of the 12 * software without specific, written prior permission. 13 * M.I.T. makes no representations about the suitability of 14 * this software for any purpose. It is provided "as is" 15 * without express or implied warranty. 16 */ 17 18#include "ares_setup.h" 19 20#ifdef HAVE_SYS_SOCKET_H 21# include <sys/socket.h> 22#endif 23#ifdef HAVE_NETINET_IN_H 24# include <netinet/in.h> 25#endif 26#ifdef HAVE_NETDB_H 27# include <netdb.h> 28#endif 29#ifdef HAVE_ARPA_INET_H 30# include <arpa/inet.h> 31#endif 32#ifdef HAVE_ARPA_NAMESER_H 33# include <arpa/nameser.h> 34#else 35# include "nameser.h" 36#endif 37#ifdef HAVE_ARPA_NAMESER_COMPAT_H 38# include <arpa/nameser_compat.h> 39#endif 40 41#ifdef HAVE_STRINGS_H 42# include <strings.h> 43#endif 44 45#include <stdlib.h> 46#include <string.h> 47 48#include "ares.h" 49#include "ares_dns.h" 50#include "ares_data.h" 51#include "ares_private.h" 52 53int 54ares_parse_txt_reply (const unsigned char *abuf, int alen, 55 struct ares_txt_reply **txt_out) 56{ 57 size_t substr_len, str_len; 58 unsigned int qdcount, ancount, i; 59 const unsigned char *aptr; 60 const unsigned char *strptr; 61 int status, rr_type, rr_class, rr_len; 62 long len; 63 char *hostname = NULL, *rr_name = NULL; 64 struct ares_txt_reply *txt_head = NULL; 65 struct ares_txt_reply *txt_last = NULL; 66 struct ares_txt_reply *txt_curr; 67 68 /* Set *txt_out to NULL for all failure cases. */ 69 *txt_out = NULL; 70 71 /* Give up if abuf doesn't have room for a header. */ 72 if (alen < HFIXEDSZ) 73 return ARES_EBADRESP; 74 75 /* Fetch the question and answer count from the header. */ 76 qdcount = DNS_HEADER_QDCOUNT (abuf); 77 ancount = DNS_HEADER_ANCOUNT (abuf); 78 if (qdcount != 1) 79 return ARES_EBADRESP; 80 if (ancount == 0) 81 return ARES_ENODATA; 82 83 /* Expand the name from the question, and skip past the question. */ 84 aptr = abuf + HFIXEDSZ; 85 status = ares_expand_name (aptr, abuf, alen, &hostname, &len); 86 if (status != ARES_SUCCESS) 87 return status; 88 89 if (aptr + len + QFIXEDSZ > abuf + alen) 90 { 91 free (hostname); 92 return ARES_EBADRESP; 93 } 94 aptr += len + QFIXEDSZ; 95 96 /* Examine each answer resource record (RR) in turn. */ 97 for (i = 0; i < ancount; i++) 98 { 99 /* Decode the RR up to the data field. */ 100 status = ares_expand_name (aptr, abuf, alen, &rr_name, &len); 101 if (status != ARES_SUCCESS) 102 { 103 break; 104 } 105 aptr += len; 106 if (aptr + RRFIXEDSZ > abuf + alen) 107 { 108 status = ARES_EBADRESP; 109 break; 110 } 111 rr_type = DNS_RR_TYPE (aptr); 112 rr_class = DNS_RR_CLASS (aptr); 113 rr_len = DNS_RR_LEN (aptr); 114 aptr += RRFIXEDSZ; 115 116 /* Check if we are really looking at a TXT record */ 117 if (rr_class == C_IN && rr_type == T_TXT) 118 { 119 /* Allocate storage for this TXT answer appending it to the list */ 120 txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY); 121 if (!txt_curr) 122 { 123 status = ARES_ENOMEM; 124 break; 125 } 126 if (txt_last) 127 { 128 txt_last->next = txt_curr; 129 } 130 else 131 { 132 txt_head = txt_curr; 133 } 134 txt_last = txt_curr; 135 136 /* 137 * There may be multiple substrings in a single TXT record. Each 138 * substring may be up to 255 characters in length, with a 139 * "length byte" indicating the size of the substring payload. 140 * RDATA contains both the length-bytes and payloads of all 141 * substrings contained therein. 142 */ 143 144 /* Compute total length to allow a single memory allocation */ 145 strptr = aptr; 146 while (strptr < (aptr + rr_len)) 147 { 148 substr_len = (unsigned char)*strptr; 149 txt_curr->length += substr_len; 150 strptr += substr_len + 1; 151 } 152 153 /* Including null byte */ 154 txt_curr->txt = malloc (txt_curr->length + 1); 155 if (txt_curr->txt == NULL) 156 { 157 status = ARES_ENOMEM; 158 break; 159 } 160 161 /* Step through the list of substrings, concatenating them */ 162 str_len = 0; 163 strptr = aptr; 164 while (strptr < (aptr + rr_len)) 165 { 166 substr_len = (unsigned char)*strptr; 167 strptr++; 168 memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len); 169 str_len += substr_len; 170 strptr += substr_len; 171 } 172 /* Make sure we NULL-terminate */ 173 *((char *) txt_curr->txt + txt_curr->length) = '\0'; 174 } 175 176 /* Don't lose memory in the next iteration */ 177 free (rr_name); 178 rr_name = NULL; 179 180 /* Move on to the next record */ 181 aptr += rr_len; 182 } 183 184 if (hostname) 185 free (hostname); 186 if (rr_name) 187 free (rr_name); 188 189 /* clean up on error */ 190 if (status != ARES_SUCCESS) 191 { 192 if (txt_head) 193 ares_free_data (txt_head); 194 return status; 195 } 196 197 /* everything looks fine, return the data */ 198 *txt_out = txt_head; 199 200 return ARES_SUCCESS; 201} 202