dns.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * DNS Support for Asterisk
  3. *
  4. * Written by Thorsten Lockert <tholo@trollphone.org>
  5. *
  6. * Funding provided by Troll Phone Networks AS
  7. *
  8. * This program is free software, distributed under the terms of
  9. * the GNU General Public License
  10. */
  11. #include <sys/types.h>
  12. #include <sys/socket.h>
  13. #include <netinet/in.h>
  14. #include <arpa/nameser.h>
  15. #include <resolv.h>
  16. #include <unistd.h>
  17. #include <asterisk/logger.h>
  18. #include <asterisk/channel.h>
  19. #include <asterisk/dns.h>
  20. #define MAX_SIZE 4096
  21. typedef struct {
  22. unsigned id :16; /* query identification number */
  23. #if BYTE_ORDER == BIG_ENDIAN
  24. /* fields in third byte */
  25. unsigned qr: 1; /* response flag */
  26. unsigned opcode: 4; /* purpose of message */
  27. unsigned aa: 1; /* authoritive answer */
  28. unsigned tc: 1; /* truncated message */
  29. unsigned rd: 1; /* recursion desired */
  30. /* fields in fourth byte */
  31. unsigned ra: 1; /* recursion available */
  32. unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
  33. unsigned ad: 1; /* authentic data from named */
  34. unsigned cd: 1; /* checking disabled by resolver */
  35. unsigned rcode :4; /* response code */
  36. #endif
  37. #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
  38. /* fields in third byte */
  39. unsigned rd :1; /* recursion desired */
  40. unsigned tc :1; /* truncated message */
  41. unsigned aa :1; /* authoritive answer */
  42. unsigned opcode :4; /* purpose of message */
  43. unsigned qr :1; /* response flag */
  44. /* fields in fourth byte */
  45. unsigned rcode :4; /* response code */
  46. unsigned cd: 1; /* checking disabled by resolver */
  47. unsigned ad: 1; /* authentic data from named */
  48. unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
  49. unsigned ra :1; /* recursion available */
  50. #endif
  51. /* remaining bytes */
  52. unsigned qdcount :16; /* number of question entries */
  53. unsigned ancount :16; /* number of answer entries */
  54. unsigned nscount :16; /* number of authority entries */
  55. unsigned arcount :16; /* number of resource entries */
  56. } dns_HEADER;
  57. struct dn_answer {
  58. unsigned short rtype;
  59. unsigned short class;
  60. unsigned int ttl;
  61. unsigned short size;
  62. } __attribute__ ((__packed__));
  63. static int skip_name(u_char *s, int len)
  64. {
  65. int x = 0;
  66. while (x < len) {
  67. if (*s == '\0') {
  68. s++;
  69. x++;
  70. break;
  71. }
  72. if ((*s & 0xc0) == 0xc0) {
  73. s += 2;
  74. x += 2;
  75. break;
  76. }
  77. x += *s + 1;
  78. s += *s + 1;
  79. }
  80. if (x >= len)
  81. return -1;
  82. return x;
  83. }
  84. static int dns_parse_answer(void *context,
  85. int class, int type, u_char *answer, int len,
  86. int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
  87. {
  88. u_char *fullanswer = answer;
  89. struct dn_answer *ans;
  90. dns_HEADER *h;
  91. int res;
  92. int x;
  93. h = (dns_HEADER *)answer;
  94. answer += sizeof(dns_HEADER);
  95. len -= sizeof(dns_HEADER);
  96. for (x = 0; x < ntohs(h->qdcount); x++) {
  97. if ((res = skip_name(answer, len)) < 0) {
  98. ast_log(LOG_WARNING, "Couldn't skip over name\n");
  99. return -1;
  100. }
  101. answer += res + 4; /* Skip name and QCODE / QCLASS */
  102. len -= res + 4;
  103. if (len < 0) {
  104. ast_log(LOG_WARNING, "Strange query size\n");
  105. return -1;
  106. }
  107. }
  108. for (x = 0; x < ntohs(h->ancount); x++) {
  109. if ((res = skip_name(answer, len)) < 0) {
  110. ast_log(LOG_WARNING, "Failed skipping name\n");
  111. return -1;
  112. }
  113. answer += res;
  114. len -= res;
  115. ans = (struct dn_answer *)answer;
  116. answer += sizeof(struct dn_answer);
  117. len -= sizeof(struct dn_answer);
  118. if (len < 0) {
  119. ast_log(LOG_WARNING, "Strange result size\n");
  120. return -1;
  121. }
  122. if (len < 0) {
  123. ast_log(LOG_WARNING, "Length exceeds frame\n");
  124. return -1;
  125. }
  126. if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
  127. if (callback) {
  128. if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
  129. ast_log(LOG_WARNING, "Failed to parse result\n");
  130. return -1;
  131. }
  132. if (res > 0)
  133. return 1;
  134. }
  135. }
  136. answer += ntohs(ans->size);
  137. len -= ntohs(ans->size);
  138. }
  139. return 0;
  140. }
  141. int ast_search_dns(void *context,
  142. const char *dname, int class, int type,
  143. int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
  144. {
  145. #ifdef linux
  146. struct __res_state dnsstate;
  147. #endif
  148. char answer[MAX_SIZE];
  149. int res, ret = -1;
  150. #ifdef linux
  151. res_ninit(&dnsstate);
  152. res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
  153. #else
  154. res_init();
  155. res = res_search(dname, class, type, answer, sizeof(answer));
  156. #endif
  157. if (res > 0) {
  158. if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
  159. ast_log(LOG_WARNING, "Parse error\n");
  160. ret = -1;
  161. }
  162. else if (ret == 0) {
  163. ast_log(LOG_DEBUG, "No matches found\n");
  164. ret = 0;
  165. }
  166. else
  167. ret = 1;
  168. }
  169. #if defined(linux)
  170. res_nclose(&dnsstate);
  171. #else
  172. #ifndef __APPLE__
  173. res_close();
  174. #endif
  175. #endif
  176. return ret;
  177. }