![]() |
Home page |
Mailing list |
Docs
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 }