Replace most uses of ast_register_atexit with ast_register_cleanup.
[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 /*** MODULEINFO
33         <support_level>core</support_level>
34  ***/
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/network.h"
41 #include <arpa/nameser.h>       /* res_* functions */
42 #include <resolv.h>
43
44 #include "asterisk/channel.h"
45 #include "asterisk/dns.h"
46 #include "asterisk/endian.h"
47
48 #define MAX_SIZE 4096
49
50 #ifdef __PDP_ENDIAN
51 #if __BYTE_ORDER == __PDP_ENDIAN
52 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
53 #endif
54 #endif
55 #if __BYTE_ORDER == __BIG_ENDIAN
56 #define DETERMINED_BYTE_ORDER __BIG_ENDIAN
57 #endif
58 #if __BYTE_ORDER == __LITTLE_ENDIAN
59 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
60 #endif
61
62 /* The dns_HEADER structure definition below originated
63    in the arpa/nameser.h header file distributed with ISC
64    BIND, which contains the following copyright and license
65    notices:
66
67  * ++Copyright++ 1983, 1989, 1993
68  * -
69  * Copyright (c) 1983, 1989, 1993
70  *    The Regents of the University of California.  All rights reserved.
71  *
72  * Redistribution and use in source and binary forms, with or without
73  * modification, are permitted provided that the following conditions
74  * are met:
75  * 1. Redistributions of source code must retain the above copyright
76  *    notice, this list of conditions and the following disclaimer.
77  * 2. Redistributions in binary form must reproduce the above copyright
78  *    notice, this list of conditions and the following disclaimer in the
79  *    documentation and/or other materials provided with the distribution.
80  * 3. All advertising materials mentioning features or use of this software
81  *    must display the following acknowledgement:
82  *      This product includes software developed by the University of
83  *      California, Berkeley and its contributors.
84  * 4. Neither the name of the University nor the names of its contributors
85  *    may be used to endorse or promote products derived from this software
86  *    without specific prior written permission.
87  *
88  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
89  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
92  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98  * SUCH DAMAGE.
99  * -
100  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
101  *
102  * Permission to use, copy, modify, and distribute this software for any
103  * purpose with or without fee is hereby granted, provided that the above
104  * copyright notice and this permission notice appear in all copies, and that
105  * the name of Digital Equipment Corporation not be used in advertising or
106  * publicity pertaining to distribution of the document or software without
107  * specific, written prior permission.
108  *
109  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
110  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
111  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
112  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
113  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
114  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
115  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
116  * SOFTWARE.
117  * -
118  * --Copyright--
119  */
120
121 typedef struct {
122         unsigned        id:16;          /*!< query identification number */
123 #if DETERMINED_BYTE_ORDER == __BIG_ENDIAN
124                         /* fields in third byte */
125         unsigned        qr:1;           /*!< response flag */
126         unsigned        opcode:4;       /*!< purpose of message */
127         unsigned        aa:1;           /*!< authoritive answer */
128         unsigned        tc:1;           /*!< truncated message */
129         unsigned        rd:1;           /*!< recursion desired */
130                         /* fields in fourth byte */
131         unsigned        ra:1;           /*!< recursion available */
132         unsigned        unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
133         unsigned        ad:1;           /*!< authentic data from named */
134         unsigned        cd:1;           /*!< checking disabled by resolver */
135         unsigned        rcode:4;        /*!< response code */
136 #endif
137 #if DETERMINED_BYTE_ORDER == __LITTLE_ENDIAN
138                         /* fields in third byte */
139         unsigned        rd:1;           /*!< recursion desired */
140         unsigned        tc:1;           /*!< truncated message */
141         unsigned        aa:1;           /*!< authoritive answer */
142         unsigned        opcode:4;       /*!< purpose of message */
143         unsigned        qr:1;           /*!< response flag */
144                         /* fields in fourth byte */
145         unsigned        rcode:4;        /*!< response code */
146         unsigned        cd:1;           /*!< checking disabled by resolver */
147         unsigned        ad:1;           /*!< authentic data from named */
148         unsigned        unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
149         unsigned        ra:1;           /*!< recursion available */
150 #endif
151                         /* remaining bytes */
152         unsigned        qdcount:16;     /*!< number of question entries */
153         unsigned        ancount:16;     /*!< number of answer entries */
154         unsigned        nscount:16;     /*!< number of authority entries */
155         unsigned        arcount:16;     /*!< number of resource entries */
156 } dns_HEADER;
157
158 struct dn_answer {
159         unsigned short rtype;
160         unsigned short class;
161         unsigned int ttl;
162         unsigned short size;
163 } __attribute__((__packed__));
164
165 static int skip_name(unsigned char *s, int len)
166 {
167         int x = 0;
168
169         while (x < len) {
170                 if (*s == '\0') {
171                         s++;
172                         x++;
173                         break;
174                 }
175                 if ((*s & 0xc0) == 0xc0) {
176                         s += 2;
177                         x += 2;
178                         break;
179                 }
180                 x += *s + 1;
181                 s += *s + 1;
182         }
183         if (x >= len)
184                 return -1;
185         return x;
186 }
187
188 /*! \brief Parse DNS lookup result, call callback */
189 static int dns_parse_answer(void *context,
190         int class, int type, unsigned char *answer, int len,
191         int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
192 {
193         unsigned char *fullanswer = answer;
194         struct dn_answer *ans;
195         dns_HEADER *h;
196         int ret = 0;
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, "Length of DNS answer 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 }
299
300 struct ao2_container *ast_dns_get_nameservers(void)
301 {
302 #ifdef HAVE_RES_NINIT
303         struct __res_state dnsstate;
304 #endif
305         struct __res_state *state;
306         struct ao2_container *nameservers;
307         int i;
308
309         nameservers = ast_str_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 3);
310         if (!nameservers) {
311                 return NULL;
312         }
313
314 #ifdef HAVE_RES_NINIT
315         memset(&dnsstate, 0, sizeof(dnsstate));
316         res_ninit(&dnsstate);
317         state = &dnsstate;
318 #else
319         ast_mutex_lock(&res_lock);
320         res_init();
321         state = &_res;
322 #endif
323
324         for (i = 0; i < state->nscount; i++) {
325                 ast_str_container_add(nameservers, ast_inet_ntoa(state->nsaddr_list[i].sin_addr));
326         }
327
328 #ifdef HAVE_RES_NINIT
329 #ifdef HAVE_RES_NDESTROY
330         res_ndestroy(&dnsstate);
331 #else
332         res_nclose(&dnsstate);
333 #endif
334 #else
335 #ifdef HAVE_RES_CLOSE
336         res_close();
337 #endif
338         ast_mutex_unlock(&res_lock);
339 #endif
340
341         return nameservers;
342 }
343