Newer
Older
* Asterisk -- An open source telephony toolkit.
*
*
* Written by Thorsten Lockert <tholo@trollphone.org>
*
* Funding provided by Troll Phone Networks AS
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief DNS Support for Asterisk
*
* \author Thorsten Lockert <tholo@trollphone.org>
*
* \par Reference
* - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <unistd.h>
Kevin P. Fleming
committed
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/dns.h"
#include "asterisk/endian.h"
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned qr: 1; /*!< response flag */
unsigned opcode: 4; /*!< purpose of message */
unsigned aa: 1; /*!< authoritive answer */
unsigned tc: 1; /*!< truncated message */
unsigned rd: 1; /*!< recursion desired */
unsigned ra: 1; /*!< recursion available */
unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
unsigned ad: 1; /*!< authentic data from named */
unsigned cd: 1; /*!< checking disabled by resolver */
unsigned rcode :4; /*!< response code */
#if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN
unsigned rd :1; /*!< recursion desired */
unsigned tc :1; /*!< truncated message */
unsigned aa :1; /*!< authoritive answer */
unsigned opcode :4; /*!< purpose of message */
unsigned qr :1; /*!< response flag */
unsigned rcode :4; /*!< response code */
unsigned cd: 1; /*!< checking disabled by resolver */
unsigned ad: 1; /*!< authentic data from named */
unsigned unused :1; /*!< unused bits (MBZ as of 4.9.3a3) */
unsigned ra :1; /*!< recursion available */
unsigned qdcount :16; /*!< number of question entries */
unsigned ancount :16; /*!< number of answer entries */
unsigned nscount :16; /*!< number of authority entries */
unsigned arcount :16; /*!< number of resource entries */
} dns_HEADER;
struct dn_answer {
unsigned short rtype;
unsigned short class;
unsigned int ttl;
unsigned short size;
} __attribute__ ((__packed__));
{
int x = 0;
while (x < len) {
if (*s == '\0') {
s++;
x++;
break;
}
if ((*s & 0xc0) == 0xc0) {
s += 2;
x += 2;
break;
}
x += *s + 1;
s += *s + 1;
}
if (x >= len)
return -1;
return x;
}
int class, int type, char *answer, int len,
int (*callback)(void *context, char *answer, int len, char *fullanswer))
struct dn_answer *ans;
dns_HEADER *h;
int res;
int x;
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
answer += sizeof(dns_HEADER);
len -= sizeof(dns_HEADER);
for (x = 0; x < ntohs(h->qdcount); x++) {
if ((res = skip_name(answer, len)) < 0) {
ast_log(LOG_WARNING, "Couldn't skip over name\n");
return -1;
}
answer += res + 4; /* Skip name and QCODE / QCLASS */
len -= res + 4;
if (len < 0) {
ast_log(LOG_WARNING, "Strange query size\n");
return -1;
}
}
for (x = 0; x < ntohs(h->ancount); x++) {
if ((res = skip_name(answer, len)) < 0) {
ast_log(LOG_WARNING, "Failed skipping name\n");
return -1;
}
answer += res;
len -= res;
ans = (struct dn_answer *)answer;
answer += sizeof(struct dn_answer);
len -= sizeof(struct dn_answer);
if (len < 0) {
ast_log(LOG_WARNING, "Strange result size\n");
return -1;
}
if (len < 0) {
ast_log(LOG_WARNING, "Length exceeds frame\n");
return -1;
}
if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
if (callback) {
if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
return -1;
}
if (res > 0)
return 1;
}
}
answer += ntohs(ans->size);
len -= ntohs(ans->size);
}
return 0;
}
#if defined(res_ninit)
#define HAS_RES_NINIT
#else
AST_MUTEX_DEFINE_STATIC(res_lock);
#warning "Warning, res_ninit is missing... Could have reentrancy issues"
#endif
/*! \brief Lookup record in DNS
\note Asterisk DNS is synchronus at this time. This means that if your DNS does
not work properly, Asterisk might not start properly or a channel may lock.
*/
const char *dname, int class, int type,
int (*callback)(void *context, char *answer, int len, char *fullanswer))
struct __res_state dnsstate;
#endif
char answer[MAX_SIZE];
int res, ret = -1;
Mark Spencer
committed
#ifdef MAKE_VALGRIND_HAPPY
memset(&dnsstate, 0, sizeof(dnsstate));
#endif
res = res_nsearch(&dnsstate, dname, class, type, (unsigned char *)answer, sizeof(answer));
res_init();
res = res_search(dname, class, type, answer, sizeof(answer));
#endif
if (res > 0) {
if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname);
#ifdef HAS_RES_NINIT
res_nclose(&dnsstate);
ast_mutex_unlock(&res_lock);