diff options
Diffstat (limited to 'main/dns.c')
-rw-r--r-- | main/dns.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/main/dns.c b/main/dns.c new file mode 100644 index 000000000..dc0d3c818 --- /dev/null +++ b/main/dns.c @@ -0,0 +1,292 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006 Thorsten Lockert + * + * 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. + */ + +/*! \file + * + * \brief DNS Support for Asterisk + * + * \author Thorsten Lockert <tholo@trollphone.org> + * + * \par Reference + * - DNR SRV records http://www.ietf.org/rfc/rfc2782.txt + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <unistd.h> + +#include "asterisk/logger.h" +#include "asterisk/channel.h" +#include "asterisk/dns.h" +#include "asterisk/endian.h" + +#define MAX_SIZE 4096 + +/* The dns_HEADER structure definition below originated + in the arpa/nameser.h header file distributed with ISC + BIND, which contains the following copyright and license + notices: + + * ++Copyright++ 1983, 1989, 1993 + * - + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +typedef struct { + unsigned id:16; /*!< query identification number */ +#if __BYTE_ORDER == __BIG_ENDIAN + /* fields in third byte */ + 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 */ + /* fields in fourth byte */ + 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 */ +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __PDP_ENDIAN + /* fields in third byte */ + 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 */ + /* fields in fourth byte */ + 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 */ +#endif + /* remaining bytes */ + 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__)); + +static int skip_name(unsigned char *s, int len) +{ + 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; +} + +/*! \brief Parse DNS lookup result, call callback */ +static int dns_parse_answer(void *context, + int class, int type, unsigned char *answer, int len, + int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer)) +{ + unsigned char *fullanswer = answer; + struct dn_answer *ans; + dns_HEADER *h; + int res; + int x; + + h = (dns_HEADER *)answer; + 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) { + ast_log(LOG_WARNING, "Failed to parse result\n"); + return -1; + } + if (res > 0) + return 1; + } + } + answer += ntohs(ans->size); + len -= ntohs(ans->size); + } + return 0; +} + +#ifndef HAVE_RES_NINIT +AST_MUTEX_DEFINE_STATIC(res_lock); +#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. +*/ +int ast_search_dns(void *context, + const char *dname, int class, int type, + int (*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer)) +{ +#ifdef HAVE_RES_NINIT + struct __res_state dnsstate; +#endif + unsigned char answer[MAX_SIZE]; + int res, ret = -1; + +#ifdef HAVE_RES_NINIT + memset(&dnsstate, 0, sizeof(dnsstate)); + res_ninit(&dnsstate); + res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer)); +#else + ast_mutex_lock(&res_lock); + 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); + ret = -1; + } + else if (res == 0) { + ast_log(LOG_DEBUG, "No matches found in DNS for %s\n", dname); + ret = 0; + } + else + ret = 1; + } +#ifdef HAVE_RES_NINIT +#ifdef HAVE_RES_NDESTROY + res_ndestroy(&dnsstate); +#else + res_nclose(&dnsstate); +#endif +#else +#ifndef __APPLE__ + res_close(); +#endif + ast_mutex_unlock(&res_lock); +#endif + + return ret; +} |