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

Generated on Fri Feb 27 12:19:42 2004 for Asterisk by doxygen 1.3.5