00001
00002
00003
00004
00005
00006
00007
00008
00009
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 #include "asterisk/endian.h"
00023
00024 #define MAX_SIZE 4096
00025
00026 typedef struct {
00027 unsigned id :16;
00028 #if BYTE_ORDER == BIG_ENDIAN
00029
00030 unsigned qr: 1;
00031 unsigned opcode: 4;
00032 unsigned aa: 1;
00033 unsigned tc: 1;
00034 unsigned rd: 1;
00035
00036 unsigned ra: 1;
00037 unsigned unused :1;
00038 unsigned ad: 1;
00039 unsigned cd: 1;
00040 unsigned rcode :4;
00041 #endif
00042 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00043
00044 unsigned rd :1;
00045 unsigned tc :1;
00046 unsigned aa :1;
00047 unsigned opcode :4;
00048 unsigned qr :1;
00049
00050 unsigned rcode :4;
00051 unsigned cd: 1;
00052 unsigned ad: 1;
00053 unsigned unused :1;
00054 unsigned ra :1;
00055 #endif
00056
00057 unsigned qdcount :16;
00058 unsigned ancount :16;
00059 unsigned nscount :16;
00060 unsigned arcount :16;
00061 } dns_HEADER;
00062
00063 struct dn_answer {
00064 unsigned short rtype;
00065 unsigned short class;
00066 unsigned int ttl;
00067 unsigned short size;
00068 } __attribute__ ((__packed__));
00069
00070 static int skip_name(u_char *s, int len)
00071 {
00072 int x = 0;
00073
00074 while (x < len) {
00075 if (*s == '\0') {
00076 s++;
00077 x++;
00078 break;
00079 }
00080 if ((*s & 0xc0) == 0xc0) {
00081 s += 2;
00082 x += 2;
00083 break;
00084 }
00085 x += *s + 1;
00086 s += *s + 1;
00087 }
00088 if (x >= len)
00089 return -1;
00090 return x;
00091 }
00092
00093 static int dns_parse_answer(void *context,
00094 int class, int type, u_char *answer, int len,
00095 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
00096 {
00097 u_char *fullanswer = answer;
00098 struct dn_answer *ans;
00099 dns_HEADER *h;
00100 int res;
00101 int x;
00102
00103 h = (dns_HEADER *)answer;
00104 answer += sizeof(dns_HEADER);
00105 len -= sizeof(dns_HEADER);
00106
00107 for (x = 0; x < ntohs(h->qdcount); x++) {
00108 if ((res = skip_name(answer, len)) < 0) {
00109 ast_log(LOG_WARNING, "Couldn't skip over name\n");
00110 return -1;
00111 }
00112 answer += res + 4;
00113 len -= res + 4;
00114 if (len < 0) {
00115 ast_log(LOG_WARNING, "Strange query size\n");
00116 return -1;
00117 }
00118 }
00119
00120 for (x = 0; x < ntohs(h->ancount); x++) {
00121 if ((res = skip_name(answer, len)) < 0) {
00122 ast_log(LOG_WARNING, "Failed skipping name\n");
00123 return -1;
00124 }
00125 answer += res;
00126 len -= res;
00127 ans = (struct dn_answer *)answer;
00128 answer += sizeof(struct dn_answer);
00129 len -= sizeof(struct dn_answer);
00130 if (len < 0) {
00131 ast_log(LOG_WARNING, "Strange result size\n");
00132 return -1;
00133 }
00134 if (len < 0) {
00135 ast_log(LOG_WARNING, "Length exceeds frame\n");
00136 return -1;
00137 }
00138
00139 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
00140 if (callback) {
00141 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
00142 ast_log(LOG_WARNING, "Failed to parse result\n");
00143 return -1;
00144 }
00145 if (res > 0)
00146 return 1;
00147 }
00148 }
00149 answer += ntohs(ans->size);
00150 len -= ntohs(ans->size);
00151 }
00152 return 0;
00153 }
00154
00155 #if defined(res_ninit)
00156 #define HAS_RES_NINIT
00157 #else
00158 AST_MUTEX_DEFINE_STATIC(res_lock);
00159 #if 0
00160 #warning "Warning, res_ninit is missing... Could have reentrancy issues"
00161 #endif
00162 #endif
00163
00164 int ast_search_dns(void *context,
00165 const char *dname, int class, int type,
00166 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
00167 {
00168 #ifdef HAS_RES_NINIT
00169 struct __res_state dnsstate;
00170 #endif
00171 char answer[MAX_SIZE];
00172 int res, ret = -1;
00173
00174 #ifdef HAS_RES_NINIT
00175 res_ninit(&dnsstate);
00176 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
00177 #else
00178 ast_mutex_lock(&res_lock);
00179 res_init();
00180 res = res_search(dname, class, type, answer, sizeof(answer));
00181 #endif
00182 if (res > 0) {
00183 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
00184 ast_log(LOG_WARNING, "Parse error\n");
00185 ret = -1;
00186 }
00187 else if (ret == 0) {
00188 ast_log(LOG_DEBUG, "No matches found\n");
00189 ret = 0;
00190 }
00191 else
00192 ret = 1;
00193 }
00194 #ifdef HAS_RES_NINIT
00195 res_nclose(&dnsstate);
00196 #else
00197 #ifndef __APPLE__
00198 res_close();
00199 #endif
00200 ast_mutex_unlock(&res_lock);
00201 #endif
00202 return ret;
00203 }