Sat Nov 25 00:45:38 2006

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

Generated on Sat Nov 25 00:45:38 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6