Mon May 14 04:42:58 2007

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

Generated on Mon May 14 04:42:58 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1