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
00023 #define MAX_SIZE 4096
00024
00025 typedef struct {
00026 unsigned id :16;
00027 #if BYTE_ORDER == BIG_ENDIAN
00028
00029 unsigned qr: 1;
00030 unsigned opcode: 4;
00031 unsigned aa: 1;
00032 unsigned tc: 1;
00033 unsigned rd: 1;
00034
00035 unsigned ra: 1;
00036 unsigned unused :1;
00037 unsigned ad: 1;
00038 unsigned cd: 1;
00039 unsigned rcode :4;
00040 #endif
00041 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00042
00043 unsigned rd :1;
00044 unsigned tc :1;
00045 unsigned aa :1;
00046 unsigned opcode :4;
00047 unsigned qr :1;
00048
00049 unsigned rcode :4;
00050 unsigned cd: 1;
00051 unsigned ad: 1;
00052 unsigned unused :1;
00053 unsigned ra :1;
00054 #endif
00055
00056 unsigned qdcount :16;
00057 unsigned ancount :16;
00058 unsigned nscount :16;
00059 unsigned arcount :16;
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;
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 }