dns_system_resolver.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2015, Digium, Inc.
  5. *
  6. * Ashley Sanders <asanders@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief The default DNS resolver for Asterisk.
  21. *
  22. * \arg See also \ref res_resolver_unbound.c
  23. *
  24. * \author Ashley Sanders <asanders@digium.com>
  25. */
  26. #include "asterisk.h"
  27. #include "asterisk/_private.h"
  28. #include "asterisk/astobj2.h"
  29. #include "asterisk/dns.h"
  30. #include "asterisk/dns_core.h"
  31. #include "asterisk/dns_resolver.h"
  32. #include "asterisk/linkedlists.h"
  33. #include "asterisk/taskprocessor.h"
  34. #include "asterisk/utils.h"
  35. /*! \brief The consideration priority for this resolver implementation. */
  36. #define DNS_SYSTEM_RESOLVER_PRIORITY INT_MAX
  37. /*! \brief Resolver return code upon success. */
  38. #define DNS_SYSTEM_RESOLVER_SUCCESS 0
  39. /*! \brief Resolver return code upon failure. */
  40. #define DNS_SYSTEM_RESOLVER_FAILURE -1
  41. static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl);
  42. static int dns_system_resolver_cancel(struct ast_dns_query *query);
  43. static void dns_system_resolver_destroy(void);
  44. static int dns_system_resolver_process_query(void *data);
  45. static int dns_system_resolver_resolve(struct ast_dns_query *query);
  46. static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode);
  47. /*! \brief The task processor to use for making DNS searches asynchronous. */
  48. static struct ast_taskprocessor *dns_system_resolver_tp;
  49. /*! \brief The base definition for the dns_system_resolver */
  50. struct ast_dns_resolver dns_system_resolver_base = {
  51. .name = "system",
  52. .priority = DNS_SYSTEM_RESOLVER_PRIORITY,
  53. .resolve = dns_system_resolver_resolve,
  54. .cancel = dns_system_resolver_cancel,
  55. };
  56. /*!
  57. * \brief Callback to handle processing resource records.
  58. *
  59. * \details Adds an individual resource record discovered with ast_search_dns_ex to the
  60. * ast_dns_query currently being resolved.
  61. *
  62. * \internal
  63. *
  64. * \param context A void pointer to the ast_dns_query being processed.
  65. * \param record An individual resource record discovered during the DNS search.
  66. * \param record_len The length of the resource record.
  67. * \param ttl The resource record's expiration time limit (time to live).
  68. *
  69. * \retval 0 on success
  70. * \retval -1 on failure
  71. */
  72. static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl)
  73. {
  74. struct ast_dns_query *query = context;
  75. /* Add the record to the query.*/
  76. return ast_dns_resolver_add_record(query,
  77. ast_dns_query_get_rr_type(query),
  78. ast_dns_query_get_rr_class(query),
  79. ttl,
  80. (const char*) record,
  81. record_len);
  82. }
  83. /*!
  84. * \brief Cancels processing resolution for a given query.
  85. *
  86. * \note The system API calls block so there is no way to cancel them. Therefore, this function always
  87. * returns failure when invoked.
  88. *
  89. * \internal
  90. *
  91. * \param query The ast_dns_query to cancel.
  92. *
  93. * \retval 0 on success
  94. * \retval -1 on failure
  95. */
  96. static int dns_system_resolver_cancel(struct ast_dns_query *query)
  97. {
  98. return DNS_SYSTEM_RESOLVER_FAILURE;
  99. }
  100. /*!
  101. * \brief Destructor.
  102. *
  103. * \internal
  104. */
  105. static void dns_system_resolver_destroy(void)
  106. {
  107. /* Unreference the task processor */
  108. dns_system_resolver_tp = ast_taskprocessor_unreference(dns_system_resolver_tp);
  109. /* Unregister the base resolver */
  110. ast_dns_resolver_unregister(&dns_system_resolver_base);
  111. }
  112. /*!
  113. * \brief Callback to handle processing the query from the ast_taskprocessor instance.
  114. *
  115. * \internal
  116. *
  117. * \param data A void pointer to the ast_dns_query being processed.
  118. *
  119. * \retval -1 on search failure
  120. * \retval 0 on no records found
  121. * \retval 1 on success
  122. */
  123. static int dns_system_resolver_process_query(void *data)
  124. {
  125. struct ast_dns_query *query = data;
  126. /* Perform the DNS search */
  127. enum ast_dns_search_result res = ast_search_dns_ex(query,
  128. ast_dns_query_get_name(query),
  129. ast_dns_query_get_rr_class(query),
  130. ast_dns_query_get_rr_type(query),
  131. dns_system_resolver_set_response,
  132. dns_system_resolver_add_record);
  133. /* Handle the possible return values from the DNS search */
  134. if (res == AST_DNS_SEARCH_FAILURE) {
  135. ast_debug(1, "DNS search failed for query: '%s'\n",
  136. ast_dns_query_get_name(query));
  137. } else if (res == AST_DNS_SEARCH_NO_RECORDS) {
  138. ast_debug(1, "DNS search failed to yield any results for query: '%s'\n",
  139. ast_dns_query_get_name(query));
  140. }
  141. /* Mark the query as complete */
  142. ast_dns_resolver_completed(query);
  143. /* Reduce the reference count on the query object */
  144. ao2_ref(query, -1);
  145. return res;
  146. }
  147. /*!
  148. * \brief Resolves a DNS query.
  149. *
  150. * \internal
  151. *
  152. * \param query The ast_dns_query to resolve.
  153. *
  154. * \retval 0 on successful load of query handler to the ast_taskprocessor instance
  155. * \retval -1 on failure to load the query handler to the ast_taskprocessor instance
  156. */
  157. static int dns_system_resolver_resolve(struct ast_dns_query *query)
  158. {
  159. /* Add query processing handler to the task processor */
  160. int res = ast_taskprocessor_push(dns_system_resolver_tp,
  161. dns_system_resolver_process_query,
  162. ao2_bump(query));
  163. /* The query processing handler was not added to the task processor */
  164. if (res < 0) {
  165. ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n",
  166. ast_dns_query_get_name(query));
  167. ao2_ref(query, -1);
  168. }
  169. /* Return the result of adding the query processing handler to the task processor */
  170. return res;
  171. }
  172. /*!
  173. * \brief Callback to handle initializing the results field.
  174. *
  175. * \internal
  176. *
  177. * \param context A void pointer to the ast_dns_query being processed.
  178. * \param dns_response The full DNS response.
  179. * \param dns_response_len The length of the full DNS response.
  180. * \param rcode The DNS response code.
  181. *
  182. * \retval 0 on success
  183. * \retval -1 on failure
  184. */
  185. static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode)
  186. {
  187. struct ast_dns_query *query = context;
  188. int res;
  189. /* Instantiate the query's result field (if necessary). */
  190. if (!ast_dns_query_get_result(query)) {
  191. res = ast_dns_resolver_set_result(query,
  192. 0,
  193. 0,
  194. rcode,
  195. ast_dns_query_get_name(query),
  196. (const char*) dns_response,
  197. dns_response_len);
  198. if (res) {
  199. /* There was a problem instantiating the results field. */
  200. ast_log(LOG_ERROR, "Could not instantiate the results field for query: '%s'\n",
  201. ast_dns_query_get_name(query));
  202. }
  203. } else {
  204. res = DNS_SYSTEM_RESOLVER_SUCCESS;
  205. }
  206. return res;
  207. }
  208. /*!
  209. * \brief Initializes the resolver.
  210. *
  211. * \retval 0 on success
  212. * \retval -1 on failure
  213. */
  214. int ast_dns_system_resolver_init(void)
  215. {
  216. /* Register the base resolver */
  217. int res = ast_dns_resolver_register(&dns_system_resolver_base);
  218. if (res) {
  219. return DNS_SYSTEM_RESOLVER_FAILURE;
  220. }
  221. /* Instantiate the task processor */
  222. dns_system_resolver_tp = ast_taskprocessor_get("dns_system_resolver_tp",
  223. TPS_REF_DEFAULT);
  224. /* Return error if the task processor failed to instantiate */
  225. if (!dns_system_resolver_tp) {
  226. return DNS_SYSTEM_RESOLVER_FAILURE;
  227. }
  228. /* Register the cleanup function */
  229. ast_register_cleanup(dns_system_resolver_destroy);
  230. return DNS_SYSTEM_RESOLVER_SUCCESS;
  231. }