00001
00002
00003
00004
00005
00006
00007
00008
00009
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;
00027
#if BYTE_ORDER == BIG_ENDIAN
00028
00029
unsigned qr: 1;
00030
unsigned opcode: 4;
00031
unsigned aa: 1;
00032
unsigned tc: 1;
00033
unsigned rd: 1;
00034
00035
unsigned ra: 1;
00036
unsigned unused :1;
00037
unsigned ad: 1;
00038
unsigned cd: 1;
00039
unsigned rcode :4;
00040
#endif
00041
#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00042
00043 unsigned rd :1;
00044 unsigned tc :1;
00045 unsigned aa :1;
00046 unsigned opcode :4;
00047 unsigned qr :1;
00048
00049 unsigned rcode :4;
00050 unsigned cd: 1;
00051 unsigned ad: 1;
00052 unsigned unused :1;
00053 unsigned ra :1;
00054
#endif
00055
00056 unsigned qdcount :16;
00057 unsigned ancount :16;
00058 unsigned nscount :16;
00059 unsigned arcount :16;
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;
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
return -1;
00143 }
00144
if (res > 0)
00145
return 1;
00146 }
00147 }
00148 answer += ntohs(ans->size);
00149 len -= ntohs(ans->size);
00150 }
00151
return 0;
00152 }
00153
00154
#if defined(res_ninit)
00155
#define HAS_RES_NINIT
00156
#else
00157
AST_MUTEX_DEFINE_STATIC(res_lock);
00158
#if 0
00159
#warning "Warning, res_ninit is missing... Could have reentrancy issues"
00160
#endif
00161
#endif
00162
00163 int ast_search_dns(
void *context,
00164
const char *dname,
int class,
int type,
00165
int (*callback)(
void *context, u_char *answer,
int len, u_char *fullanswer))
00166 {
00167
#ifdef HAS_RES_NINIT
00168
struct __res_state dnsstate;
00169
#endif
00170
char answer[
MAX_SIZE];
00171
int res, ret = -1;
00172
00173
#ifdef HAS_RES_NINIT
00174
res_ninit(&dnsstate);
00175 res = res_nsearch(&dnsstate, dname,
class,
type, answer,
sizeof(answer));
00176
#else
00177
ast_mutex_lock(&res_lock);
00178 res_init();
00179 res = res_search(dname,
class,
type, answer,
sizeof(answer));
00180
#endif
00181
if (res > 0) {
00182
if ((res = dns_parse_answer(context,
class,
type, answer, res, callback)) < 0) {
00183
ast_log(
LOG_WARNING,
"Parse error\n");
00184 ret = -1;
00185 }
00186
else if (ret == 0) {
00187
ast_log(
LOG_DEBUG,
"No matches found\n");
00188 ret = 0;
00189 }
00190
else
00191 ret = 1;
00192 }
00193
#ifdef HAS_RES_NINIT
00194
res_nclose(&dnsstate);
00195
#else
00196
#ifndef __APPLE__
00197
res_close();
00198
#endif
00199
ast_mutex_unlock(&res_lock);
00200
#endif
00201
return ret;
00202 }