Let ExtensionState resolve dynamic hints.
[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/channel.h"
41 #include "asterisk/dns.h"
42 #include "asterisk/endian.h"
43
44 #define MAX_SIZE 4096
45
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
57
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:
62
63  * ++Copyright++ 1983, 1989, 1993
64  * -
65  * Copyright (c) 1983, 1989, 1993
66  *    The Regents of the University of California.  All rights reserved.
67  * 
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.
83  * 
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.
97  * 
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.
104  * 
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.
113  * -
114  * --Copyright--
115  */
116
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;
153
154 struct dn_answer {
155         unsigned short rtype;
156         unsigned short class;
157         unsigned int ttl;
158         unsigned short size;
159 } __attribute__((__packed__));
160
161 static int skip_name(unsigned char *s, int len)
162 {
163         int x = 0;
164
165         while (x < len) {
166                 if (*s == '\0') {
167                         s++;
168                         x++;
169                         break;
170                 }
171                 if ((*s & 0xc0) == 0xc0) {
172                         s += 2;
173                         x += 2;
174                         break;
175                 }
176                 x += *s + 1;
177                 s += *s + 1;
178         }
179         if (x >= len)
180                 return -1;
181         return x;
182 }
183
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))
188 {
189         unsigned char *fullanswer = answer;
190         struct dn_answer *ans;
191         dns_HEADER *h;
192         int ret = 0;
193         int res;
194         int x;
195
196         h = (dns_HEADER *)answer;
197         answer += sizeof(dns_HEADER);
198         len -= sizeof(dns_HEADER);
199
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;
204                 }
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;
210                 }
211         }
212
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;
217                 }
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;
226                 }
227                 if (len < 0) {
228                         ast_log(LOG_WARNING, "Length exceeds frame\n");
229                         return -1;
230                 }
231
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;
237                                 }
238                                 ret = 1;
239                         }
240                 }
241                 answer += ntohs(ans->size);
242                 len -= ntohs(ans->size);
243         }
244         return ret;
245 }
246
247 #ifndef HAVE_RES_NINIT
248 AST_MUTEX_DEFINE_STATIC(res_lock);
249 #endif
250
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.
254 */
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))
258 {
259 #ifdef HAVE_RES_NINIT
260         struct __res_state dnsstate;
261 #endif
262         unsigned char answer[MAX_SIZE];
263         int res, ret = -1;
264
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;
283         }
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 #ifdef HAVE_RES_CLOSE
292         res_close();
293 #endif
294         ast_mutex_unlock(&res_lock);
295 #endif
296
297         return ret;
298 }