dns.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005 Thorsten Lockert
  5. *
  6. * Written by Thorsten Lockert <tholo@trollphone.org>
  7. *
  8. * Funding provided by Troll Phone Networks AS
  9. *
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2. See the LICENSE file
  18. * at the top of the source tree.
  19. */
  20. /*! \file
  21. *
  22. * \brief DNS Support for Asterisk
  23. *
  24. * \author Thorsten Lockert <tholo@trollphone.org>
  25. */
  26. #include <sys/types.h>
  27. #include <sys/socket.h>
  28. #include <netinet/in.h>
  29. #include <arpa/nameser.h>
  30. #include <resolv.h>
  31. #include <unistd.h>
  32. #include "asterisk.h"
  33. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  34. #include "asterisk/logger.h"
  35. #include "asterisk/channel.h"
  36. #include "asterisk/dns.h"
  37. #include "asterisk/endian.h"
  38. #define MAX_SIZE 4096
  39. typedef struct {
  40. unsigned id :16; /* query identification number */
  41. #if __BYTE_ORDER == __BIG_ENDIAN
  42. /* fields in third byte */
  43. unsigned qr: 1; /* response flag */
  44. unsigned opcode: 4; /* purpose of message */
  45. unsigned aa: 1; /* authoritive answer */
  46. unsigned tc: 1; /* truncated message */
  47. unsigned rd: 1; /* recursion desired */
  48. /* fields in fourth byte */
  49. unsigned ra: 1; /* recursion available */
  50. unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
  51. unsigned ad: 1; /* authentic data from named */
  52. unsigned cd: 1; /* checking disabled by resolver */
  53. unsigned rcode :4; /* response code */
  54. #endif
  55. #if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
  56. /* fields in third byte */
  57. unsigned rd :1; /* recursion desired */
  58. unsigned tc :1; /* truncated message */
  59. unsigned aa :1; /* authoritive answer */
  60. unsigned opcode :4; /* purpose of message */
  61. unsigned qr :1; /* response flag */
  62. /* fields in fourth byte */
  63. unsigned rcode :4; /* response code */
  64. unsigned cd: 1; /* checking disabled by resolver */
  65. unsigned ad: 1; /* authentic data from named */
  66. unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
  67. unsigned ra :1; /* recursion available */
  68. #endif
  69. /* remaining bytes */
  70. unsigned qdcount :16; /* number of question entries */
  71. unsigned ancount :16; /* number of answer entries */
  72. unsigned nscount :16; /* number of authority entries */
  73. unsigned arcount :16; /* number of resource entries */
  74. } dns_HEADER;
  75. struct dn_answer {
  76. unsigned short rtype;
  77. unsigned short class;
  78. unsigned int ttl;
  79. unsigned short size;
  80. } __attribute__ ((__packed__));
  81. static int skip_name(char *s, int len)
  82. {
  83. int x = 0;
  84. while (x < len) {
  85. if (*s == '\0') {
  86. s++;
  87. x++;
  88. break;
  89. }
  90. if ((*s & 0xc0) == 0xc0) {
  91. s += 2;
  92. x += 2;
  93. break;
  94. }
  95. x += *s + 1;
  96. s += *s + 1;
  97. }
  98. if (x >= len)
  99. return -1;
  100. return x;
  101. }
  102. /*--- dns_parse_answer: Parse DNS lookup result, call callback */
  103. static int dns_parse_answer(void *context,
  104. int class, int type, char *answer, int len,
  105. int (*callback)(void *context, char *answer, int len, char *fullanswer))
  106. {
  107. char *fullanswer = answer;
  108. struct dn_answer *ans;
  109. dns_HEADER *h;
  110. int res;
  111. int x;
  112. h = (dns_HEADER *)answer;
  113. answer += sizeof(dns_HEADER);
  114. len -= sizeof(dns_HEADER);
  115. for (x = 0; x < ntohs(h->qdcount); x++) {
  116. if ((res = skip_name(answer, len)) < 0) {
  117. ast_log(LOG_WARNING, "Couldn't skip over name\n");
  118. return -1;
  119. }
  120. answer += res + 4; /* Skip name and QCODE / QCLASS */
  121. len -= res + 4;
  122. if (len < 0) {
  123. ast_log(LOG_WARNING, "Strange query size\n");
  124. return -1;
  125. }
  126. }
  127. for (x = 0; x < ntohs(h->ancount); x++) {
  128. if ((res = skip_name(answer, len)) < 0) {
  129. ast_log(LOG_WARNING, "Failed skipping name\n");
  130. return -1;
  131. }
  132. answer += res;
  133. len -= res;
  134. ans = (struct dn_answer *)answer;
  135. answer += sizeof(struct dn_answer);
  136. len -= sizeof(struct dn_answer);
  137. if (len < 0) {
  138. ast_log(LOG_WARNING, "Strange result size\n");
  139. return -1;
  140. }
  141. if (len < 0) {
  142. ast_log(LOG_WARNING, "Length exceeds frame\n");
  143. return -1;
  144. }
  145. if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
  146. if (callback) {
  147. if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
  148. ast_log(LOG_WARNING, "Failed to parse result\n");
  149. return -1;
  150. }
  151. if (res > 0)
  152. return 1;
  153. }
  154. }
  155. answer += ntohs(ans->size);
  156. len -= ntohs(ans->size);
  157. }
  158. return 0;
  159. }
  160. #if defined(res_ninit)
  161. #define HAS_RES_NINIT
  162. #else
  163. AST_MUTEX_DEFINE_STATIC(res_lock);
  164. #if 0
  165. #warning "Warning, res_ninit is missing... Could have reentrancy issues"
  166. #endif
  167. #endif
  168. /*--- ast_search_dns: Lookup record in DNS */
  169. int ast_search_dns(void *context,
  170. const char *dname, int class, int type,
  171. int (*callback)(void *context, char *answer, int len, char *fullanswer))
  172. {
  173. #ifdef HAS_RES_NINIT
  174. struct __res_state dnsstate;
  175. #endif
  176. char answer[MAX_SIZE];
  177. int res, ret = -1;
  178. #ifdef HAS_RES_NINIT
  179. #ifdef MAKE_VALGRIND_HAPPY
  180. memset(&dnsstate, 0, sizeof(dnsstate));
  181. #endif
  182. res_ninit(&dnsstate);
  183. res = res_nsearch(&dnsstate, dname, class, type, (unsigned char *)answer, sizeof(answer));
  184. #else
  185. ast_mutex_lock(&res_lock);
  186. res_init();
  187. res = res_search(dname, class, type, answer, sizeof(answer));
  188. #endif
  189. if (res > 0) {
  190. if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
  191. ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
  192. ret = -1;
  193. }
  194. else if (ret == 0) {
  195. ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
  196. ret = 0;
  197. }
  198. else
  199. ret = 1;
  200. }
  201. #ifdef HAS_RES_NINIT
  202. res_nclose(&dnsstate);
  203. #else
  204. #ifndef __APPLE__
  205. res_close();
  206. #endif
  207. ast_mutex_unlock(&res_lock);
  208. #endif
  209. return ret;
  210. }