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 int ast_search_dns(void *context,
00155 const char *dname, int class, int type,
00156 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
00157 {
00158 #ifdef linux
00159 struct __res_state dnsstate;
00160 #endif
00161 char answer[MAX_SIZE];
00162 int res, ret = -1;
00163
00164 #ifdef linux
00165 res_ninit(&dnsstate);
00166 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
00167 #else
00168 res_init();
00169 res = res_search(dname, class, type, answer, sizeof(answer));
00170 #endif
00171 if (res > 0) {
00172 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
00173 ast_log(LOG_WARNING, "Parse error\n");
00174 ret = -1;
00175 }
00176 else if (ret == 0) {
00177 ast_log(LOG_DEBUG, "No matches found\n");
00178 ret = 0;
00179 }
00180 else
00181 ret = 1;
00182 }
00183 #if defined(linux)
00184 res_nclose(&dnsstate);
00185 #else
00186 #ifndef __APPLE__
00187 res_close();
00188 #endif
00189 #endif
00190 return ret;
00191 }