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 * - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/nameser.h>
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/dns.h"
46 #include "asterisk/endian.h"
51 unsigned id :16; /*!< query identification number */
52 #if __BYTE_ORDER == __BIG_ENDIAN
53 /* fields in third byte */
54 unsigned qr: 1; /*!< response flag */
55 unsigned opcode: 4; /*!< purpose of message */
56 unsigned aa: 1; /*!< authoritive answer */
57 unsigned tc: 1; /*!< truncated message */
58 unsigned rd: 1; /*!< recursion desired */
59 /* fields in fourth byte */
60 unsigned ra: 1; /*!< recursion available */
61 unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
62 unsigned ad: 1; /*!< authentic data from named */
63 unsigned cd: 1; /*!< checking disabled by resolver */
64 unsigned rcode :4; /*!< response code */
66 #if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
67 /* fields in third byte */
68 unsigned rd :1; /*!< recursion desired */
69 unsigned tc :1; /*!< truncated message */
70 unsigned aa :1; /*!< authoritive answer */
71 unsigned opcode :4; /*!< purpose of message */
72 unsigned qr :1; /*!< response flag */
73 /* fields in fourth byte */
74 unsigned rcode :4; /*!< response code */
75 unsigned cd: 1; /*!< checking disabled by resolver */
76 unsigned ad: 1; /*!< authentic data from named */
77 unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
78 unsigned ra :1; /*!< recursion available */
81 unsigned qdcount :16; /*!< number of question entries */
82 unsigned ancount :16; /*!< number of answer entries */
83 unsigned nscount :16; /*!< number of authority entries */
84 unsigned arcount :16; /*!< number of resource entries */
92 } __attribute__ ((__packed__));
94 static int skip_name(char *s, int len)
104 if ((*s & 0xc0) == 0xc0) {
117 /*! \brief Parse DNS lookup result, call callback */
118 static int dns_parse_answer(void *context,
119 int class, int type, char *answer, int len,
120 int (*callback)(void *context, char *answer, int len, char *fullanswer))
122 char *fullanswer = answer;
123 struct dn_answer *ans;
128 h = (dns_HEADER *)answer;
129 answer += sizeof(dns_HEADER);
130 len -= sizeof(dns_HEADER);
132 for (x = 0; x < ntohs(h->qdcount); x++) {
133 if ((res = skip_name(answer, len)) < 0) {
134 ast_log(LOG_WARNING, "Couldn't skip over name\n");
137 answer += res + 4; /* Skip name and QCODE / QCLASS */
140 ast_log(LOG_WARNING, "Strange query size\n");
145 for (x = 0; x < ntohs(h->ancount); x++) {
146 if ((res = skip_name(answer, len)) < 0) {
147 ast_log(LOG_WARNING, "Failed skipping name\n");
152 ans = (struct dn_answer *)answer;
153 answer += sizeof(struct dn_answer);
154 len -= sizeof(struct dn_answer);
156 ast_log(LOG_WARNING, "Strange result size\n");
160 ast_log(LOG_WARNING, "Length exceeds frame\n");
164 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
166 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
167 ast_log(LOG_WARNING, "Failed to parse result\n");
174 answer += ntohs(ans->size);
175 len -= ntohs(ans->size);
180 #if defined(res_ninit)
181 #define HAS_RES_NINIT
183 AST_MUTEX_DEFINE_STATIC(res_lock);
185 #warning "Warning, res_ninit is missing... Could have reentrancy issues"
189 /*! \brief Lookup record in DNS
190 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
191 not work properly, Asterisk might not start properly or a channel may lock.
193 int ast_search_dns(void *context,
194 const char *dname, int class, int type,
195 int (*callback)(void *context, char *answer, int len, char *fullanswer))
198 struct __res_state dnsstate;
200 char answer[MAX_SIZE];
204 #ifdef MAKE_VALGRIND_HAPPY
205 memset(&dnsstate, 0, sizeof(dnsstate));
207 res_ninit(&dnsstate);
208 res = res_nsearch(&dnsstate, dname, class, type, (unsigned char *)answer, sizeof(answer));
210 ast_mutex_lock(&res_lock);
212 res = res_search(dname, class, type, answer, sizeof(answer));
215 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
216 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
220 ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
227 res_nclose(&dnsstate);
232 ast_mutex_unlock(&res_lock);