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
34 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/nameser.h>
43 #include "asterisk/logger.h"
44 #include "asterisk/channel.h"
45 #include "asterisk/dns.h"
46 #include "asterisk/endian.h"
50 /* The dns_HEADER structure definition below originated
51 in the arpa/nameser.h header file distributed with ISC
52 BIND, which contains the following copyright and license
55 * ++Copyright++ 1983, 1989, 1993
57 * Copyright (c) 1983, 1989, 1993
58 * The Regents of the University of California. All rights reserved.
60 * Redistribution and use in source and binary forms, with or without
61 * modification, are permitted provided that the following conditions
63 * 1. Redistributions of source code must retain the above copyright
64 * notice, this list of conditions and the following disclaimer.
65 * 2. Redistributions in binary form must reproduce the above copyright
66 * notice, this list of conditions and the following disclaimer in the
67 * documentation and/or other materials provided with the distribution.
68 * 3. All advertising materials mentioning features or use of this software
69 * must display the following acknowledgement:
70 * This product includes software developed by the University of
71 * California, Berkeley and its contributors.
72 * 4. Neither the name of the University nor the names of its contributors
73 * may be used to endorse or promote products derived from this software
74 * without specific prior written permission.
76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
90 * Permission to use, copy, modify, and distribute this software for any
91 * purpose with or without fee is hereby granted, provided that the above
92 * copyright notice and this permission notice appear in all copies, and that
93 * the name of Digital Equipment Corporation not be used in advertising or
94 * publicity pertaining to distribution of the document or software without
95 * specific, written prior permission.
97 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
98 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
99 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
100 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
101 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
102 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
103 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
110 unsigned id
:16; /*!< query identification number */
111 #if __BYTE_ORDER == __BIG_ENDIAN
112 /* fields in third byte */
113 unsigned qr
:1; /*!< response flag */
114 unsigned opcode
:4; /*!< purpose of message */
115 unsigned aa
:1; /*!< authoritive answer */
116 unsigned tc
:1; /*!< truncated message */
117 unsigned rd
:1; /*!< recursion desired */
118 /* fields in fourth byte */
119 unsigned ra
:1; /*!< recursion available */
120 unsigned unused
:1; /*!< unused bits (MBZ as of 4.9.3a3) */
121 unsigned ad
:1; /*!< authentic data from named */
122 unsigned cd
:1; /*!< checking disabled by resolver */
123 unsigned rcode
:4; /*!< response code */
125 #if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
126 /* fields in third byte */
127 unsigned rd
:1; /*!< recursion desired */
128 unsigned tc
:1; /*!< truncated message */
129 unsigned aa
:1; /*!< authoritive answer */
130 unsigned opcode
:4; /*!< purpose of message */
131 unsigned qr
:1; /*!< response flag */
132 /* fields in fourth byte */
133 unsigned rcode
:4; /*!< response code */
134 unsigned cd
:1; /*!< checking disabled by resolver */
135 unsigned ad
:1; /*!< authentic data from named */
136 unsigned unused
:1; /*!< unused bits (MBZ as of 4.9.3a3) */
137 unsigned ra
:1; /*!< recursion available */
139 /* remaining bytes */
140 unsigned qdcount
:16; /*!< number of question entries */
141 unsigned ancount
:16; /*!< number of answer entries */
142 unsigned nscount
:16; /*!< number of authority entries */
143 unsigned arcount
:16; /*!< number of resource entries */
147 unsigned short rtype
;
148 unsigned short class;
151 } __attribute__ ((__packed__
));
153 static int skip_name(unsigned char *s
, int len
)
163 if ((*s
& 0xc0) == 0xc0) {
176 /*! \brief Parse DNS lookup result, call callback */
177 static int dns_parse_answer(void *context
,
178 int class, int type
, unsigned char *answer
, int len
,
179 int (*callback
)(void *context
, unsigned char *answer
, int len
, unsigned char *fullanswer
))
181 unsigned char *fullanswer
= answer
;
182 struct dn_answer
*ans
;
187 h
= (dns_HEADER
*)answer
;
188 answer
+= sizeof(dns_HEADER
);
189 len
-= sizeof(dns_HEADER
);
191 for (x
= 0; x
< ntohs(h
->qdcount
); x
++) {
192 if ((res
= skip_name(answer
, len
)) < 0) {
193 ast_log(LOG_WARNING
, "Couldn't skip over name\n");
196 answer
+= res
+ 4; /* Skip name and QCODE / QCLASS */
199 ast_log(LOG_WARNING
, "Strange query size\n");
204 for (x
= 0; x
< ntohs(h
->ancount
); x
++) {
205 if ((res
= skip_name(answer
, len
)) < 0) {
206 ast_log(LOG_WARNING
, "Failed skipping name\n");
211 ans
= (struct dn_answer
*)answer
;
212 answer
+= sizeof(struct dn_answer
);
213 len
-= sizeof(struct dn_answer
);
215 ast_log(LOG_WARNING
, "Strange result size\n");
219 ast_log(LOG_WARNING
, "Length exceeds frame\n");
223 if (ntohs(ans
->class) == class && ntohs(ans
->rtype
) == type
) {
225 if ((res
= callback(context
, answer
, ntohs(ans
->size
), fullanswer
)) < 0) {
226 ast_log(LOG_WARNING
, "Failed to parse result\n");
233 answer
+= ntohs(ans
->size
);
234 len
-= ntohs(ans
->size
);
239 #ifndef HAVE_RES_NINIT
240 AST_MUTEX_DEFINE_STATIC(res_lock
);
243 /*! \brief Lookup record in DNS
244 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
245 not work properly, Asterisk might not start properly or a channel may lock.
247 int ast_search_dns(void *context
,
248 const char *dname
, int class, int type
,
249 int (*callback
)(void *context
, unsigned char *answer
, int len
, unsigned char *fullanswer
))
251 #ifdef HAVE_RES_NINIT
252 struct __res_state dnsstate
;
254 unsigned char answer
[MAX_SIZE
];
257 #ifdef HAVE_RES_NINIT
258 memset(&dnsstate
, 0, sizeof(dnsstate
));
259 res_ninit(&dnsstate
);
260 res
= res_nsearch(&dnsstate
, dname
, class, type
, answer
, sizeof(answer
));
262 ast_mutex_lock(&res_lock
);
264 res
= res_search(dname
, class, type
, answer
, sizeof(answer
));
267 if ((res
= dns_parse_answer(context
, class, type
, answer
, res
, callback
)) < 0) {
268 ast_log(LOG_WARNING
, "DNS Parse error for %s\n", dname
);
272 ast_log(LOG_DEBUG
, "No matches found in DNS for %s\n", dname
);
278 #ifdef HAVE_RES_NINIT
279 #ifdef HAVE_RES_NDESTROY
280 res_ndestroy(&dnsstate
);
282 res_nclose(&dnsstate
);
288 ast_mutex_unlock(&res_lock
);