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