2 * DNS Support for Asterisk
4 * Written by Thorsten Lockert <tholo@trollphone.org>
6 * Funding provided by Troll Phone Networks AS
8 * This program is free software, distributed under the terms of
9 * the GNU General Public License
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/nameser.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/dns.h>
26 unsigned id :16; /* query identification number */
27 #if BYTE_ORDER == BIG_ENDIAN
28 /* fields in third byte */
29 unsigned qr: 1; /* response flag */
30 unsigned opcode: 4; /* purpose of message */
31 unsigned aa: 1; /* authoritive answer */
32 unsigned tc: 1; /* truncated message */
33 unsigned rd: 1; /* recursion desired */
34 /* fields in fourth byte */
35 unsigned ra: 1; /* recursion available */
36 unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
37 unsigned ad: 1; /* authentic data from named */
38 unsigned cd: 1; /* checking disabled by resolver */
39 unsigned rcode :4; /* response code */
41 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
42 /* fields in third byte */
43 unsigned rd :1; /* recursion desired */
44 unsigned tc :1; /* truncated message */
45 unsigned aa :1; /* authoritive answer */
46 unsigned opcode :4; /* purpose of message */
47 unsigned qr :1; /* response flag */
48 /* fields in fourth byte */
49 unsigned rcode :4; /* response code */
50 unsigned cd: 1; /* checking disabled by resolver */
51 unsigned ad: 1; /* authentic data from named */
52 unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
53 unsigned ra :1; /* recursion available */
56 unsigned qdcount :16; /* number of question entries */
57 unsigned ancount :16; /* number of answer entries */
58 unsigned nscount :16; /* number of authority entries */
59 unsigned arcount :16; /* number of resource entries */
67 } __attribute__ ((__packed__));
69 static int skip_name(u_char *s, int len)
79 if ((*s & 0xc0) == 0xc0) {
92 static int dns_parse_answer(void *context,
93 int class, int type, u_char *answer, int len,
94 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
96 u_char *fullanswer = answer;
97 struct dn_answer *ans;
102 h = (dns_HEADER *)answer;
103 answer += sizeof(dns_HEADER);
104 len -= sizeof(dns_HEADER);
106 for (x = 0; x < ntohs(h->qdcount); x++) {
107 if ((res = skip_name(answer, len)) < 0) {
108 ast_log(LOG_WARNING, "Couldn't skip over name\n");
111 answer += res + 4; /* Skip name and QCODE / QCLASS */
114 ast_log(LOG_WARNING, "Strange query size\n");
119 for (x = 0; x < ntohs(h->ancount); x++) {
120 if ((res = skip_name(answer, len)) < 0) {
121 ast_log(LOG_WARNING, "Failed skipping name\n");
126 ans = (struct dn_answer *)answer;
127 answer += sizeof(struct dn_answer);
128 len -= sizeof(struct dn_answer);
130 ast_log(LOG_WARNING, "Strange result size\n");
134 ast_log(LOG_WARNING, "Length exceeds frame\n");
138 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
140 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
141 ast_log(LOG_WARNING, "Failed to parse result\n");
148 answer += ntohs(ans->size);
149 len -= ntohs(ans->size);
154 int ast_search_dns(void *context,
155 const char *dname, int class, int type,
156 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
159 struct __res_state dnsstate;
161 char answer[MAX_SIZE];
165 res_ninit(&dnsstate);
166 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
169 res = res_search(dname, class, type, answer, sizeof(answer));
172 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
173 ast_log(LOG_WARNING, "Parse error\n");
177 ast_log(LOG_DEBUG, "No matches found\n");
183 #if defined(__Linux__)
184 res_nclose(&dnsstate);