Sat Aug 6 00:39:28 2011

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

Generated on Sat Aug 6 00:39:28 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7