2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006 Thorsten Lockert
6 * Written by Thorsten Lockert <tholo@trollphone.org>
8 * Funding provided by Troll Phone Networks AS
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.
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.
23 * \brief DNS Support for Asterisk
25 * \author Thorsten Lockert <tholo@trollphone.org>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
37 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39 #include "asterisk/logger.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/dns.h"
42 #include "asterisk/endian.h"
47 unsigned id :16; /*!< query identification number */
48 #if __BYTE_ORDER == __BIG_ENDIAN
49 /* fields in third byte */
50 unsigned qr: 1; /*!< response flag */
51 unsigned opcode: 4; /*!< purpose of message */
52 unsigned aa: 1; /*!< authoritive answer */
53 unsigned tc: 1; /*!< truncated message */
54 unsigned rd: 1; /*!< recursion desired */
55 /* fields in fourth byte */
56 unsigned ra: 1; /*!< recursion available */
57 unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
58 unsigned ad: 1; /*!< authentic data from named */
59 unsigned cd: 1; /*!< checking disabled by resolver */
60 unsigned rcode :4; /*!< response code */
62 #if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
63 /* fields in third byte */
64 unsigned rd :1; /*!< recursion desired */
65 unsigned tc :1; /*!< truncated message */
66 unsigned aa :1; /*!< authoritive answer */
67 unsigned opcode :4; /*!< purpose of message */
68 unsigned qr :1; /*!< response flag */
69 /* fields in fourth byte */
70 unsigned rcode :4; /*!< response code */
71 unsigned cd: 1; /*!< checking disabled by resolver */
72 unsigned ad: 1; /*!< authentic data from named */
73 unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
74 unsigned ra :1; /*!< recursion available */
77 unsigned qdcount :16; /*!< number of question entries */
78 unsigned ancount :16; /*!< number of answer entries */
79 unsigned nscount :16; /*!< number of authority entries */
80 unsigned arcount :16; /*!< number of resource entries */
88 } __attribute__ ((__packed__));
90 static int skip_name(char *s, int len)
100 if ((*s & 0xc0) == 0xc0) {
113 /*! \brief Parse DNS lookup result, call callback */
114 static int dns_parse_answer(void *context,
115 int class, int type, char *answer, int len,
116 int (*callback)(void *context, char *answer, int len, char *fullanswer))
118 char *fullanswer = answer;
119 struct dn_answer *ans;
124 h = (dns_HEADER *)answer;
125 answer += sizeof(dns_HEADER);
126 len -= sizeof(dns_HEADER);
128 for (x = 0; x < ntohs(h->qdcount); x++) {
129 if ((res = skip_name(answer, len)) < 0) {
130 ast_log(LOG_WARNING, "Couldn't skip over name\n");
133 answer += res + 4; /* Skip name and QCODE / QCLASS */
136 ast_log(LOG_WARNING, "Strange query size\n");
141 for (x = 0; x < ntohs(h->ancount); x++) {
142 if ((res = skip_name(answer, len)) < 0) {
143 ast_log(LOG_WARNING, "Failed skipping name\n");
148 ans = (struct dn_answer *)answer;
149 answer += sizeof(struct dn_answer);
150 len -= sizeof(struct dn_answer);
152 ast_log(LOG_WARNING, "Strange result size\n");
156 ast_log(LOG_WARNING, "Length exceeds frame\n");
160 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
162 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
163 ast_log(LOG_WARNING, "Failed to parse result\n");
170 answer += ntohs(ans->size);
171 len -= ntohs(ans->size);
176 #if defined(res_ninit)
177 #define HAS_RES_NINIT
179 AST_MUTEX_DEFINE_STATIC(res_lock);
181 #warning "Warning, res_ninit is missing... Could have reentrancy issues"
185 /*! \brief Lookup record in DNS
186 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
187 not work properly, Asterisk might not start properly or a channel may lock.
189 int ast_search_dns(void *context,
190 const char *dname, int class, int type,
191 int (*callback)(void *context, char *answer, int len, char *fullanswer))
194 struct __res_state dnsstate;
196 char answer[MAX_SIZE];
200 #ifdef MAKE_VALGRIND_HAPPY
201 memset(&dnsstate, 0, sizeof(dnsstate));
203 res_ninit(&dnsstate);
204 res = res_nsearch(&dnsstate, dname, class, type, (unsigned char *)answer, sizeof(answer));
206 ast_mutex_lock(&res_lock);
208 res = res_search(dname, class, type, answer, sizeof(answer));
211 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
212 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
216 ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
223 res_nclose(&dnsstate);
228 ast_mutex_unlock(&res_lock);