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 /*--- dns_parse_answer: Parse DNS lookup result, call callback */
93 static int dns_parse_answer(void *context,
94 int class, int type, u_char *answer, int len,
95 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
97 u_char *fullanswer = answer;
98 struct dn_answer *ans;
103 h = (dns_HEADER *)answer;
104 answer += sizeof(dns_HEADER);
105 len -= sizeof(dns_HEADER);
107 for (x = 0; x < ntohs(h->qdcount); x++) {
108 if ((res = skip_name(answer, len)) < 0) {
109 ast_log(LOG_WARNING, "Couldn't skip over name\n");
112 answer += res + 4; /* Skip name and QCODE / QCLASS */
115 ast_log(LOG_WARNING, "Strange query size\n");
120 for (x = 0; x < ntohs(h->ancount); x++) {
121 if ((res = skip_name(answer, len)) < 0) {
122 ast_log(LOG_WARNING, "Failed skipping name\n");
127 ans = (struct dn_answer *)answer;
128 answer += sizeof(struct dn_answer);
129 len -= sizeof(struct dn_answer);
131 ast_log(LOG_WARNING, "Strange result size\n");
135 ast_log(LOG_WARNING, "Length exceeds frame\n");
139 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
141 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
142 ast_log(LOG_WARNING, "Failed to parse result\n");
149 answer += ntohs(ans->size);
150 len -= ntohs(ans->size);
155 #if defined(res_ninit)
156 #define HAS_RES_NINIT
158 AST_MUTEX_DEFINE_STATIC(res_lock);
160 #warning "Warning, res_ninit is missing... Could have reentrancy issues"
164 /*--- ast_search_dns: Lookup record in DNS */
165 int ast_search_dns(void *context,
166 const char *dname, int class, int type,
167 int (*callback)(void *context, u_char *answer, int len, u_char *fullanswer))
170 struct __res_state dnsstate;
172 char answer[MAX_SIZE];
176 res_ninit(&dnsstate);
177 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
179 ast_mutex_lock(&res_lock);
181 res = res_search(dname, class, type, answer, sizeof(answer));
184 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
185 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
189 ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
196 res_nclose(&dnsstate);
201 ast_mutex_unlock(&res_lock);