Thu Apr 28 2011 16:56:46

Asterisk developer's documentation


dns.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006 Thorsten Lockert
00005  *
00006  * Written by Thorsten Lockert <tholo@trollphone.org>
00007  *
00008  * Funding provided by Troll Phone Networks AS
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief DNS Support for Asterisk
00024  *
00025  * \author Thorsten Lockert <tholo@trollphone.org>
00026  *
00027  * \par Reference
00028  * - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt
00029  *
00030  */
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 159818 $")
00035 
00036 #include "asterisk/network.h"
00037 #include <arpa/nameser.h>  /* res_* functions */
00038 #include <resolv.h>
00039 
00040 #include "asterisk/channel.h"
00041 #include "asterisk/dns.h"
00042 #include "asterisk/endian.h"
00043 
00044 #define MAX_SIZE 4096
00045 
00046 #ifdef __PDP_ENDIAN
00047 #if __BYTE_ORDER == __PDP_ENDIAN
00048 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
00049 #endif
00050 #endif
00051 #if __BYTE_ORDER == __BIG_ENDIAN
00052 #define DETERMINED_BYTE_ORDER __BIG_ENDIAN
00053 #endif
00054 #if __BYTE_ORDER == __LITTLE_ENDIAN
00055 #define DETERMINED_BYTE_ORDER __LITTLE_ENDIAN
00056 #endif
00057 
00058 /* The dns_HEADER structure definition below originated
00059    in the arpa/nameser.h header file distributed with ISC
00060    BIND, which contains the following copyright and license
00061    notices:
00062 
00063  * ++Copyright++ 1983, 1989, 1993
00064  * -
00065  * Copyright (c) 1983, 1989, 1993
00066  *    The Regents of the University of California.  All rights reserved.
00067  * 
00068  * Redistribution and use in source and binary forms, with or without
00069  * modification, are permitted provided that the following conditions
00070  * are met:
00071  * 1. Redistributions of source code must retain the above copyright
00072  *    notice, this list of conditions and the following disclaimer.
00073  * 2. Redistributions in binary form must reproduce the above copyright
00074  *    notice, this list of conditions and the following disclaimer in the
00075  *    documentation and/or other materials provided with the distribution.
00076  * 3. All advertising materials mentioning features or use of this software
00077  *    must display the following acknowledgement:
00078  *    This product includes software developed by the University of
00079  *    California, Berkeley and its contributors.
00080  * 4. Neither the name of the University nor the names of its contributors
00081  *    may be used to endorse or promote products derived from this software
00082  *    without specific prior written permission.
00083  * 
00084  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00085  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00086  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00087  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00088  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00089  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00090  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00091  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00092  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00093  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00094  * SUCH DAMAGE.
00095  * -
00096  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00097  * 
00098  * Permission to use, copy, modify, and distribute this software for any
00099  * purpose with or without fee is hereby granted, provided that the above
00100  * copyright notice and this permission notice appear in all copies, and that
00101  * the name of Digital Equipment Corporation not be used in advertising or
00102  * publicity pertaining to distribution of the document or software without
00103  * specific, written prior permission.
00104  * 
00105  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00106  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00107  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00108  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00109  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00110  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00111  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00112  * SOFTWARE.
00113  * -
00114  * --Copyright--
00115  */
00116 
00117 typedef struct {
00118    unsigned id:16;          /*!< query identification number */
00119 #if DETERMINED_BYTE_ORDER == __BIG_ENDIAN
00120          /* fields in third byte */
00121    unsigned qr:1;           /*!< response flag */
00122    unsigned opcode:4;       /*!< purpose of message */
00123    unsigned aa:1;           /*!< authoritive answer */
00124    unsigned tc:1;           /*!< truncated message */
00125    unsigned rd:1;           /*!< recursion desired */
00126          /* fields in fourth byte */
00127    unsigned ra:1;           /*!< recursion available */
00128    unsigned unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
00129    unsigned ad:1;           /*!< authentic data from named */
00130    unsigned cd:1;           /*!< checking disabled by resolver */
00131    unsigned rcode:4;        /*!< response code */
00132 #endif
00133 #if DETERMINED_BYTE_ORDER == __LITTLE_ENDIAN
00134          /* fields in third byte */
00135    unsigned rd:1;           /*!< recursion desired */
00136    unsigned tc:1;           /*!< truncated message */
00137    unsigned aa:1;           /*!< authoritive answer */
00138    unsigned opcode:4;       /*!< purpose of message */
00139    unsigned qr:1;           /*!< response flag */
00140          /* fields in fourth byte */
00141    unsigned rcode:4;        /*!< response code */
00142    unsigned cd:1;           /*!< checking disabled by resolver */
00143    unsigned ad:1;           /*!< authentic data from named */
00144    unsigned unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
00145    unsigned ra:1;           /*!< recursion available */
00146 #endif
00147          /* remaining bytes */
00148    unsigned qdcount:16;     /*!< number of question entries */
00149    unsigned ancount:16;     /*!< number of answer entries */
00150    unsigned nscount:16;     /*!< number of authority entries */
00151    unsigned arcount:16;     /*!< number of resource entries */
00152 } dns_HEADER;
00153 
00154 struct dn_answer {
00155    unsigned short rtype;
00156    unsigned short class;
00157    unsigned int ttl;
00158    unsigned short size;
00159 } __attribute__((__packed__));
00160 
00161 static int skip_name(unsigned char *s, int len)
00162 {
00163    int x = 0;
00164 
00165    while (x < len) {
00166       if (*s == '\0') {
00167          s++;
00168          x++;
00169          break;
00170       }
00171       if ((*s & 0xc0) == 0xc0) {
00172          s += 2;
00173          x += 2;
00174          break;
00175       }
00176       x += *s + 1;
00177       s += *s + 1;
00178    }
00179    if (x >= len)
00180       return -1;
00181    return x;
00182 }
00183 
00184 /*! \brief Parse DNS lookup result, call callback */
00185 static int dns_parse_answer(void *context,
00186    int class, int type, unsigned char *answer, int len,
00187    int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
00188 {
00189    unsigned char *fullanswer = answer;
00190    struct dn_answer *ans;
00191    dns_HEADER *h;
00192    int ret = 0;
00193    int res;
00194    int x;
00195 
00196    h = (dns_HEADER *)answer;
00197    answer += sizeof(dns_HEADER);
00198    len -= sizeof(dns_HEADER);
00199 
00200    for (x = 0; x < ntohs(h->qdcount); x++) {
00201       if ((res = skip_name(answer, len)) < 0) {
00202          ast_log(LOG_WARNING, "Couldn't skip over name\n");
00203          return -1;
00204       }
00205       answer += res + 4;   /* Skip name and QCODE / QCLASS */
00206       len -= res + 4;
00207       if (len < 0) {
00208          ast_log(LOG_WARNING, "Strange query size\n");
00209          return -1;
00210       }
00211    }
00212 
00213    for (x = 0; x < ntohs(h->ancount); x++) {
00214       if ((res = skip_name(answer, len)) < 0) {
00215          ast_log(LOG_WARNING, "Failed skipping name\n");
00216          return -1;
00217       }
00218       answer += res;
00219       len -= res;
00220       ans = (struct dn_answer *)answer;
00221       answer += sizeof(struct dn_answer);
00222       len -= sizeof(struct dn_answer);
00223       if (len < 0) {
00224          ast_log(LOG_WARNING, "Strange result size\n");
00225          return -1;
00226       }
00227       if (len < 0) {
00228          ast_log(LOG_WARNING, "Length exceeds frame\n");
00229          return -1;
00230       }
00231 
00232       if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
00233          if (callback) {
00234             if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
00235                ast_log(LOG_WARNING, "Failed to parse result\n");
00236                return -1;
00237             }
00238             ret = 1;
00239          }
00240       }
00241       answer += ntohs(ans->size);
00242       len -= ntohs(ans->size);
00243    }
00244    return ret;
00245 }
00246 
00247 #ifndef HAVE_RES_NINIT
00248 AST_MUTEX_DEFINE_STATIC(res_lock);
00249 #endif
00250 
00251 /*! \brief Lookup record in DNS 
00252 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
00253 not work properly, Asterisk might not start properly or a channel may lock.
00254 */
00255 int ast_search_dns(void *context,
00256       const char *dname, int class, int type,
00257       int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
00258 {
00259 #ifdef HAVE_RES_NINIT
00260    struct __res_state dnsstate;
00261 #endif
00262    unsigned char answer[MAX_SIZE];
00263    int res, ret = -1;
00264 
00265 #ifdef HAVE_RES_NINIT
00266    memset(&dnsstate, 0, sizeof(dnsstate));
00267    res_ninit(&dnsstate);
00268    res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
00269 #else
00270    ast_mutex_lock(&res_lock);
00271    res_init();
00272    res = res_search(dname, class, type, answer, sizeof(answer));
00273 #endif
00274    if (res > 0) {
00275       if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
00276          ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
00277          ret = -1;
00278       } else if (res == 0) {
00279          ast_debug(1, "No matches found in DNS for %s\n", dname);
00280          ret = 0;
00281       } else
00282          ret = 1;
00283    }
00284 #ifdef HAVE_RES_NINIT
00285 #ifdef HAVE_RES_NDESTROY
00286    res_ndestroy(&dnsstate);
00287 #else
00288    res_nclose(&dnsstate);
00289 #endif
00290 #else
00291 #ifndef __APPLE__
00292    res_close();
00293 #endif
00294    ast_mutex_unlock(&res_lock);
00295 #endif
00296 
00297    return ret;
00298 }