Merged revisions 140563 via svnmerge from
[asterisk-bristuff.git] / main / dns.c
blobad1673830d4ce62f1623a57b39f9f64a8b716cdc
1 /*
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.
21 /*! \file
23 * \brief DNS Support for Asterisk
25 * \author Thorsten Lockert <tholo@trollphone.org>
27 * \par Reference
28 * - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt
32 #include "asterisk.h"
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36 #include "asterisk/network.h"
37 #include <arpa/nameser.h> /* res_* functions */
38 #include <resolv.h>
40 #include "asterisk/channel.h"
41 #include "asterisk/dns.h"
42 #include "asterisk/endian.h"
44 #define MAX_SIZE 4096
46 #ifdef __PDP_ENDIAN
47 #if __BYTE_ORDER == __PDP_ENDIAN
48 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
49 #endif
50 #endif
51 #if __BYTE_ORDER == __BIG_ENDIAN
52 #define DETERMINED_BYTE_ORDER __BIG_ENDIAN
53 #endif
54 #if __BYTE_ORDER == __LITTLE_ENDIAN
55 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
56 #endif
58 /* The dns_HEADER structure definition below originated
59 in the arpa/nameser.h header file distributed with ISC
60 BIND, which contains the following copyright and license
61 notices:
63 * ++Copyright++ 1983, 1989, 1993
64 * -
65 * Copyright (c) 1983, 1989, 1993
66 * The Regents of the University of California. All rights reserved.
68 * Redistribution and use in source and binary forms, with or without
69 * modification, are permitted provided that the following conditions
70 * are met:
71 * 1. Redistributions of source code must retain the above copyright
72 * notice, this list of conditions and the following disclaimer.
73 * 2. Redistributions in binary form must reproduce the above copyright
74 * notice, this list of conditions and the following disclaimer in the
75 * documentation and/or other materials provided with the distribution.
76 * 3. All advertising materials mentioning features or use of this software
77 * must display the following acknowledgement:
78 * This product includes software developed by the University of
79 * California, Berkeley and its contributors.
80 * 4. Neither the name of the University nor the names of its contributors
81 * may be used to endorse or promote products derived from this software
82 * without specific prior written permission.
84 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94 * SUCH DAMAGE.
95 * -
96 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
98 * Permission to use, copy, modify, and distribute this software for any
99 * purpose with or without fee is hereby granted, provided that the above
100 * copyright notice and this permission notice appear in all copies, and that
101 * the name of Digital Equipment Corporation not be used in advertising or
102 * publicity pertaining to distribution of the document or software without
103 * specific, written prior permission.
105 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
106 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
107 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
108 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
109 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
110 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
111 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
112 * SOFTWARE.
114 * --Copyright--
117 typedef struct {
118 unsigned id:16; /*!< query identification number */
119 #if DETERMINED_BYTE_ORDER == __BIG_ENDIAN
120 /* fields in third byte */
121 unsigned qr:1; /*!< response flag */
122 unsigned opcode:4; /*!< purpose of message */
123 unsigned aa:1; /*!< authoritive answer */
124 unsigned tc:1; /*!< truncated message */
125 unsigned rd:1; /*!< recursion desired */
126 /* fields in fourth byte */
127 unsigned ra:1; /*!< recursion available */
128 unsigned unused:1; /*!< unused bits (MBZ as of 4.9.3a3) */
129 unsigned ad:1; /*!< authentic data from named */
130 unsigned cd:1; /*!< checking disabled by resolver */
131 unsigned rcode:4; /*!< response code */
132 #endif
133 #if DETERMINED_BYTE_ORDER == __LITTLE_ENDIAN
134 /* fields in third byte */
135 unsigned rd:1; /*!< recursion desired */
136 unsigned tc:1; /*!< truncated message */
137 unsigned aa:1; /*!< authoritive answer */
138 unsigned opcode:4; /*!< purpose of message */
139 unsigned qr:1; /*!< response flag */
140 /* fields in fourth byte */
141 unsigned rcode:4; /*!< response code */
142 unsigned cd:1; /*!< checking disabled by resolver */
143 unsigned ad:1; /*!< authentic data from named */
144 unsigned unused:1; /*!< unused bits (MBZ as of 4.9.3a3) */
145 unsigned ra:1; /*!< recursion available */
146 #endif
147 /* remaining bytes */
148 unsigned qdcount:16; /*!< number of question entries */
149 unsigned ancount:16; /*!< number of answer entries */
150 unsigned nscount:16; /*!< number of authority entries */
151 unsigned arcount:16; /*!< number of resource entries */
152 } dns_HEADER;
154 struct dn_answer {
155 unsigned short rtype;
156 unsigned short class;
157 unsigned int ttl;
158 unsigned short size;
159 } __attribute__ ((__packed__));
161 static int skip_name(unsigned char *s, int len)
163 int x = 0;
165 while (x < len) {
166 if (*s == '\0') {
167 s++;
168 x++;
169 break;
171 if ((*s & 0xc0) == 0xc0) {
172 s += 2;
173 x += 2;
174 break;
176 x += *s + 1;
177 s += *s + 1;
179 if (x >= len)
180 return -1;
181 return x;
184 /*! \brief Parse DNS lookup result, call callback */
185 static int dns_parse_answer(void *context,
186 int class, int type, unsigned char *answer, int len,
187 int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
189 unsigned char *fullanswer = answer;
190 struct dn_answer *ans;
191 dns_HEADER *h;
192 int ret = 0;
193 int res;
194 int x;
196 h = (dns_HEADER *)answer;
197 answer += sizeof(dns_HEADER);
198 len -= sizeof(dns_HEADER);
200 for (x = 0; x < ntohs(h->qdcount); x++) {
201 if ((res = skip_name(answer, len)) < 0) {
202 ast_log(LOG_WARNING, "Couldn't skip over name\n");
203 return -1;
205 answer += res + 4; /* Skip name and QCODE / QCLASS */
206 len -= res + 4;
207 if (len < 0) {
208 ast_log(LOG_WARNING, "Strange query size\n");
209 return -1;
213 for (x = 0; x < ntohs(h->ancount); x++) {
214 if ((res = skip_name(answer, len)) < 0) {
215 ast_log(LOG_WARNING, "Failed skipping name\n");
216 return -1;
218 answer += res;
219 len -= res;
220 ans = (struct dn_answer *)answer;
221 answer += sizeof(struct dn_answer);
222 len -= sizeof(struct dn_answer);
223 if (len < 0) {
224 ast_log(LOG_WARNING, "Strange result size\n");
225 return -1;
227 if (len < 0) {
228 ast_log(LOG_WARNING, "Length exceeds frame\n");
229 return -1;
232 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
233 if (callback) {
234 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
235 ast_log(LOG_WARNING, "Failed to parse result\n");
236 return -1;
238 ret = 1;
241 answer += ntohs(ans->size);
242 len -= ntohs(ans->size);
244 return ret;
247 #ifndef HAVE_RES_NINIT
248 AST_MUTEX_DEFINE_STATIC(res_lock);
249 #endif
251 /*! \brief Lookup record in DNS
252 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
253 not work properly, Asterisk might not start properly or a channel may lock.
255 int ast_search_dns(void *context,
256 const char *dname, int class, int type,
257 int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
259 #ifdef HAVE_RES_NINIT
260 struct __res_state dnsstate;
261 #endif
262 unsigned char answer[MAX_SIZE];
263 int res, ret = -1;
265 #ifdef HAVE_RES_NINIT
266 memset(&dnsstate, 0, sizeof(dnsstate));
267 res_ninit(&dnsstate);
268 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
269 #else
270 ast_mutex_lock(&res_lock);
271 res_init();
272 res = res_search(dname, class, type, answer, sizeof(answer));
273 #endif
274 if (res > 0) {
275 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
276 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
277 ret = -1;
278 } else if (res == 0) {
279 ast_debug(1, "No matches found in DNS for %s\n", dname);
280 ret = 0;
281 } else
282 ret = 1;
284 #ifdef HAVE_RES_NINIT
285 #ifdef HAVE_RES_NDESTROY
286 res_ndestroy(&dnsstate);
287 #else
288 res_nclose(&dnsstate);
289 #endif
290 #else
291 #ifndef __APPLE__
292 res_close();
293 #endif
294 ast_mutex_unlock(&res_lock);
295 #endif
297 return ret;