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