Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:47 2007

Asterisk developer's documentation :: Codename Pineapple


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: 44253 $")
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 #include "asterisk/options.h"
00048 
00049 #define MAX_SIZE 4096
00050 
00051 typedef struct {
00052    unsigned id:16;          /*!< query identification number */
00053 #if __BYTE_ORDER == __BIG_ENDIAN
00054          /* fields in third byte */
00055    unsigned qr:1;           /*!< response flag */
00056    unsigned opcode:4;       /*!< purpose of message */
00057    unsigned aa:1;           /*!< authoritive answer */
00058    unsigned tc:1;           /*!< truncated message */
00059    unsigned rd:1;           /*!< recursion desired */
00060          /* fields in fourth byte */
00061    unsigned ra:1;           /*!< recursion available */
00062    unsigned unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
00063    unsigned ad:1;           /*!< authentic data from named */
00064    unsigned cd:1;           /*!< checking disabled by resolver */
00065    unsigned rcode:4;        /*!< response code */
00066 #endif
00067 #if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
00068          /* fields in third byte */
00069    unsigned rd:1;           /*!< recursion desired */
00070    unsigned tc:1;           /*!< truncated message */
00071    unsigned aa:1;           /*!< authoritive answer */
00072    unsigned opcode:4;       /*!< purpose of message */
00073    unsigned qr:1;           /*!< response flag */
00074          /* fields in fourth byte */
00075    unsigned rcode:4;        /*!< response code */
00076    unsigned cd:1;           /*!< checking disabled by resolver */
00077    unsigned ad:1;           /*!< authentic data from named */
00078    unsigned unused:1;       /*!< unused bits (MBZ as of 4.9.3a3) */
00079    unsigned ra:1;           /*!< recursion available */
00080 #endif
00081          /* remaining bytes */
00082    unsigned qdcount:16;     /*!< number of question entries */
00083    unsigned ancount:16;     /*!< number of answer entries */
00084    unsigned nscount:16;     /*!< number of authority entries */
00085    unsigned arcount:16;     /*!< number of resource entries */
00086 } dns_HEADER;
00087 
00088 struct dn_answer {
00089    unsigned short rtype;
00090    unsigned short class;
00091    unsigned int ttl;
00092    unsigned short size;
00093 } __attribute__ ((__packed__));
00094 
00095 static int skip_name(unsigned char *s, int len)
00096 {
00097    int x = 0;
00098 
00099    while (x < len) {
00100       if (*s == '\0') {
00101          s++;
00102          x++;
00103          break;
00104       }
00105       if ((*s & 0xc0) == 0xc0) {
00106          s += 2;
00107          x += 2;
00108          break;
00109       }
00110       x += *s + 1;
00111       s += *s + 1;
00112    }
00113    if (x >= len)
00114       return -1;
00115    return x;
00116 }
00117 
00118 /*! \brief Parse DNS lookup result, call callback */
00119 static int dns_parse_answer(void *context,
00120    int class, int type, unsigned char *answer, int len,
00121    int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
00122 {
00123    unsigned char *fullanswer = answer;
00124    struct dn_answer *ans;
00125    dns_HEADER *h;
00126    int res;
00127    int x;
00128 
00129    h = (dns_HEADER *)answer;
00130    answer += sizeof(dns_HEADER);
00131    len -= sizeof(dns_HEADER);
00132 
00133    for (x = 0; x < ntohs(h->qdcount); x++) {
00134       if ((res = skip_name(answer, len)) < 0) {
00135          ast_log(LOG_WARNING, "Couldn't skip over name\n");
00136          return -1;
00137       }
00138       answer += res + 4;   /* Skip name and QCODE / QCLASS */
00139       len -= res + 4;
00140       if (len < 0) {
00141          ast_log(LOG_WARNING, "Strange query size\n");
00142          return -1;
00143       }
00144    }
00145 
00146    for (x = 0; x < ntohs(h->ancount); x++) {
00147       if ((res = skip_name(answer, len)) < 0) {
00148          ast_log(LOG_WARNING, "Failed skipping name\n");
00149          return -1;
00150       }
00151       answer += res;
00152       len -= res;
00153       ans = (struct dn_answer *)answer;
00154       answer += sizeof(struct dn_answer);
00155       len -= sizeof(struct dn_answer);
00156       if (len < 0) {
00157          ast_log(LOG_WARNING, "Strange result size\n");
00158          return -1;
00159       }
00160       if (len < 0) {
00161          ast_log(LOG_WARNING, "Length exceeds frame\n");
00162          return -1;
00163       }
00164 
00165       if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
00166          if (callback) {
00167             if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
00168                ast_log(LOG_WARNING, "Failed to parse result\n");
00169                return -1;
00170             }
00171             if (res > 0)
00172                return 1;
00173          }
00174       }
00175       answer += ntohs(ans->size);
00176       len -= ntohs(ans->size);
00177    }
00178    return 0;
00179 }
00180 
00181 #if !HAVE_RES_NINIT
00182 AST_MUTEX_DEFINE_STATIC(res_lock);
00183 #endif
00184 
00185 /*! \brief Lookup record in DNS 
00186 \note Asterisk DNS is synchronus at this time. This means that if your DNS does
00187 not work properly, Asterisk might not start properly or a channel may lock.
00188 */
00189 int ast_search_dns(void *context,
00190       const char *dname, int class, int type,
00191       int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
00192 {
00193 #if HAVE_RES_NINIT
00194    struct __res_state dnsstate;
00195 #endif
00196    unsigned char answer[MAX_SIZE];
00197    int res, ret = -1;
00198 
00199 #if HAVE_RES_NINIT
00200    res_ninit(&dnsstate);
00201    res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
00202 #else
00203    ast_mutex_lock(&res_lock);
00204    res_init();
00205    res = res_search(dname, class, type, answer, sizeof(answer));
00206 #endif
00207    if (res > 0) {
00208       if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
00209          ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
00210          ret = -1;
00211       }
00212       else if (ret == 0) {
00213          if (option_debug)
00214             ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
00215          ret = 0;
00216       }
00217       else
00218          ret = 1;
00219    }
00220 #if HAVE_RES_NINIT
00221    res_nclose(&dnsstate);
00222 #else
00223 #ifndef __APPLE__
00224    res_close();
00225 #endif
00226    ast_mutex_unlock(&res_lock);
00227 #endif
00228 
00229    return ret;
00230 }

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen