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