ares_parse_mx_reply.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* Copyright 1998 by the Massachusetts Institute of Technology.
  2. * Copyright (C) 2010 Jeremy Lal <kapouer@melix.org>
  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. #include "ares.h"
  35. #include "ares_dns.h"
  36. #include "ares_data.h"
  37. #include "ares_private.h"
  38. int
  39. ares_parse_mx_reply (const unsigned char *abuf, int alen,
  40. struct ares_mx_reply **mx_out)
  41. {
  42. unsigned int qdcount, ancount, i;
  43. const unsigned char *aptr, *vptr;
  44. int status, rr_type, rr_class, rr_len, rr_ttl;
  45. long len;
  46. char *hostname = NULL, *rr_name = NULL;
  47. struct ares_mx_reply *mx_head = NULL;
  48. struct ares_mx_reply *mx_last = NULL;
  49. struct ares_mx_reply *mx_curr;
  50. /* Set *mx_out to NULL for all failure cases. */
  51. *mx_out = NULL;
  52. /* Give up if abuf doesn't have room for a header. */
  53. if (alen < HFIXEDSZ)
  54. return ARES_EBADRESP;
  55. /* Fetch the question and answer count from the header. */
  56. qdcount = DNS_HEADER_QDCOUNT (abuf);
  57. ancount = DNS_HEADER_ANCOUNT (abuf);
  58. if (qdcount != 1)
  59. return ARES_EBADRESP;
  60. if (ancount == 0)
  61. return ARES_ENODATA;
  62. /* Expand the name from the question, and skip past the question. */
  63. aptr = abuf + HFIXEDSZ;
  64. status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
  65. if (status != ARES_SUCCESS)
  66. return status;
  67. if (aptr + len + QFIXEDSZ > abuf + alen)
  68. {
  69. ares_free (hostname);
  70. return ARES_EBADRESP;
  71. }
  72. aptr += len + QFIXEDSZ;
  73. /* Examine each answer resource record (RR) in turn. */
  74. for (i = 0; i < ancount; i++)
  75. {
  76. /* Decode the RR up to the data field. */
  77. status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
  78. if (status != ARES_SUCCESS)
  79. {
  80. break;
  81. }
  82. aptr += len;
  83. if (aptr + RRFIXEDSZ > abuf + alen)
  84. {
  85. status = ARES_EBADRESP;
  86. break;
  87. }
  88. rr_type = DNS_RR_TYPE (aptr);
  89. rr_class = DNS_RR_CLASS (aptr);
  90. rr_len = DNS_RR_LEN (aptr);
  91. rr_ttl = DNS_RR_TTL (aptr);
  92. aptr += RRFIXEDSZ;
  93. if (aptr + rr_len > abuf + alen)
  94. {
  95. status = ARES_EBADRESP;
  96. break;
  97. }
  98. /* Check if we are really looking at a MX record */
  99. if (rr_class == C_IN && rr_type == T_MX)
  100. {
  101. /* parse the MX record itself */
  102. if (rr_len < 2)
  103. {
  104. status = ARES_EBADRESP;
  105. break;
  106. }
  107. /* Allocate storage for this MX answer appending it to the list */
  108. mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY);
  109. if (!mx_curr)
  110. {
  111. status = ARES_ENOMEM;
  112. break;
  113. }
  114. if (mx_last)
  115. {
  116. mx_last->next = mx_curr;
  117. }
  118. else
  119. {
  120. mx_head = mx_curr;
  121. }
  122. mx_last = mx_curr;
  123. vptr = aptr;
  124. mx_curr->priority = DNS__16BIT(vptr);
  125. mx_curr->ttl = rr_ttl;
  126. vptr += sizeof(unsigned short);
  127. status = ares_expand_name (vptr, abuf, alen, &mx_curr->host, &len);
  128. if (status != ARES_SUCCESS)
  129. break;
  130. }
  131. /* Don't lose memory in the next iteration */
  132. ares_free (rr_name);
  133. rr_name = NULL;
  134. /* Move on to the next record */
  135. aptr += rr_len;
  136. }
  137. if (hostname)
  138. ares_free (hostname);
  139. if (rr_name)
  140. ares_free (rr_name);
  141. /* clean up on error */
  142. if (status != ARES_SUCCESS)
  143. {
  144. if (mx_head)
  145. ares_free_data (mx_head);
  146. return status;
  147. }
  148. /* everything looks fine, return the data */
  149. *mx_out = mx_head;
  150. return ARES_SUCCESS;
  151. }