Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

dns.c

Go to the documentation of this file.
00001 /* 00002 * DNS Support for Asterisk 00003 * 00004 * Written by Thorsten Lockert <tholo@trollphone.org> 00005 * 00006 * Funding provided by Troll Phone Networks AS 00007 * 00008 * This program is free software, distributed under the terms of 00009 * the GNU General Public License 00010 */ 00011 00012 #include <sys/types.h> 00013 #include <sys/socket.h> 00014 #include <netinet/in.h> 00015 #include <arpa/nameser.h> 00016 #include <resolv.h> 00017 #include <unistd.h> 00018 00019 #include <asterisk/logger.h> 00020 #include <asterisk/channel.h> 00021 #include <asterisk/dns.h> 00022 00023 #define MAX_SIZE 4096 00024 00025 typedef struct { 00026 unsigned id :16; /* query identification number */ 00027 #if BYTE_ORDER == BIG_ENDIAN 00028 /* fields in third byte */ 00029 unsigned qr: 1; /* response flag */ 00030 unsigned opcode: 4; /* purpose of message */ 00031 unsigned aa: 1; /* authoritive answer */ 00032 unsigned tc: 1; /* truncated message */ 00033 unsigned rd: 1; /* recursion desired */ 00034 /* fields in fourth byte */ 00035 unsigned ra: 1; /* recursion available */ 00036 unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ 00037 unsigned ad: 1; /* authentic data from named */ 00038 unsigned cd: 1; /* checking disabled by resolver */ 00039 unsigned rcode :4; /* response code */ 00040 #endif 00041 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN 00042 /* fields in third byte */ 00043 unsigned rd :1; /* recursion desired */ 00044 unsigned tc :1; /* truncated message */ 00045 unsigned aa :1; /* authoritive answer */ 00046 unsigned opcode :4; /* purpose of message */ 00047 unsigned qr :1; /* response flag */ 00048 /* fields in fourth byte */ 00049 unsigned rcode :4; /* response code */ 00050 unsigned cd: 1; /* checking disabled by resolver */ 00051 unsigned ad: 1; /* authentic data from named */ 00052 unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ 00053 unsigned ra :1; /* recursion available */ 00054 #endif 00055 /* remaining bytes */ 00056 unsigned qdcount :16; /* number of question entries */ 00057 unsigned ancount :16; /* number of answer entries */ 00058 unsigned nscount :16; /* number of authority entries */ 00059 unsigned arcount :16; /* number of resource entries */ 00060 } dns_HEADER; 00061 00062 struct dn_answer { 00063 unsigned short rtype; 00064 unsigned short class; 00065 unsigned int ttl; 00066 unsigned short size; 00067 } __attribute__ ((__packed__)); 00068 00069 static int skip_name(u_char *s, int len) 00070 { 00071 int x = 0; 00072 00073 while (x < len) { 00074 if (*s == '\0') { 00075 s++; 00076 x++; 00077 break; 00078 } 00079 if ((*s & 0xc0) == 0xc0) { 00080 s += 2; 00081 x += 2; 00082 break; 00083 } 00084 x += *s + 1; 00085 s += *s + 1; 00086 } 00087 if (x >= len) 00088 return -1; 00089 return x; 00090 } 00091 00092 static int dns_parse_answer(void *context, 00093 int class, int type, u_char *answer, int len, 00094 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer)) 00095 { 00096 u_char *fullanswer = answer; 00097 struct dn_answer *ans; 00098 dns_HEADER *h; 00099 int res; 00100 int x; 00101 00102 h = (dns_HEADER *)answer; 00103 answer += sizeof(dns_HEADER); 00104 len -= sizeof(dns_HEADER); 00105 00106 for (x = 0; x < ntohs(h->qdcount); x++) { 00107 if ((res = skip_name(answer, len)) < 0) { 00108 ast_log(LOG_WARNING, "Couldn't skip over name\n"); 00109 return -1; 00110 } 00111 answer += res + 4; /* Skip name and QCODE / QCLASS */ 00112 len -= res + 4; 00113 if (len < 0) { 00114 ast_log(LOG_WARNING, "Strange query size\n"); 00115 return -1; 00116 } 00117 } 00118 00119 for (x = 0; x < ntohs(h->ancount); x++) { 00120 if ((res = skip_name(answer, len)) < 0) { 00121 ast_log(LOG_WARNING, "Failed skipping name\n"); 00122 return -1; 00123 } 00124 answer += res; 00125 len -= res; 00126 ans = (struct dn_answer *)answer; 00127 answer += sizeof(struct dn_answer); 00128 len -= sizeof(struct dn_answer); 00129 if (len < 0) { 00130 ast_log(LOG_WARNING, "Strange result size\n"); 00131 return -1; 00132 } 00133 if (len < 0) { 00134 ast_log(LOG_WARNING, "Length exceeds frame\n"); 00135 return -1; 00136 } 00137 00138 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) { 00139 if (callback) { 00140 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) { 00141 ast_log(LOG_WARNING, "Failed to parse result\n"); 00142 return -1; 00143 } 00144 if (res > 0) 00145 return 1; 00146 } 00147 } 00148 answer += ntohs(ans->size); 00149 len -= ntohs(ans->size); 00150 } 00151 return 0; 00152 } 00153 00154 #if defined(res_ninit) 00155 #define HAS_RES_NINIT 00156 #else 00157 AST_MUTEX_DEFINE_STATIC(res_lock); 00158 #if 0 00159 #warning "Warning, res_ninit is missing... Could have reentrancy issues" 00160 #endif 00161 #endif 00162 00163 int ast_search_dns(void *context, 00164 const char *dname, int class, int type, 00165 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer)) 00166 { 00167 #ifdef HAS_RES_NINIT 00168 struct __res_state dnsstate; 00169 #endif 00170 char answer[MAX_SIZE]; 00171 int res, ret = -1; 00172 00173 #ifdef HAS_RES_NINIT 00174 res_ninit(&dnsstate); 00175 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer)); 00176 #else 00177 ast_mutex_lock(&res_lock); 00178 res_init(); 00179 res = res_search(dname, class, type, answer, sizeof(answer)); 00180 #endif 00181 if (res > 0) { 00182 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) { 00183 ast_log(LOG_WARNING, "Parse error\n"); 00184 ret = -1; 00185 } 00186 else if (ret == 0) { 00187 ast_log(LOG_DEBUG, "No matches found\n"); 00188 ret = 0; 00189 } 00190 else 00191 ret = 1; 00192 } 00193 #ifdef HAS_RES_NINIT 00194 res_nclose(&dnsstate); 00195 #else 00196 #ifndef __APPLE__ 00197 res_close(); 00198 #endif 00199 ast_mutex_unlock(&res_lock); 00200 #endif 00201 return ret; 00202 }

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7