Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:53 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# dns.c

Go to the documentation of this file.

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