ares_parse_txt_reply.c 6.0 KB

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