Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Macros | Functions
dns.c File Reference

DNS Support for Asterisk. More...

#include "asterisk.h"
#include "asterisk/network.h"
#include <arpa/nameser.h>
#include <resolv.h>
#include "asterisk/channel.h"
#include "asterisk/dns.h"
#include "asterisk/endian.h"
Include dependency graph for dns.c:

Go to the source code of this file.

Data Structures

struct  dn_answer
 
struct  dns_HEADER
 

Macros

#define MAX_SIZE   4096
 The maximum size permitted for the answer from the DNS server. More...
 

Functions

struct ao2_containerast_dns_get_nameservers (void)
 Retrieve the configured nameservers of the system. More...
 
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))
 Lookup record in DNS. More...
 
enum ast_dns_search_result ast_search_dns_ex (void *context, const char *dname, int rr_class, int rr_type, int(*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode), int(*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
 Extended version of the DNS search function. More...
 
static int dns_advance_field (unsigned char **dns_response, int remaining_len, int field_size)
 Advances the position of the DNS response pointer by the size of the current field. More...
 
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))
 Parse DNS lookup result, call callback. More...
 
static int dns_parse_answer_ex (void *context, int rr_class, int rr_type, unsigned char *answer, int answer_len, int(*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode), int(*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
 Extended version of the DNS Parsing function. More...
 
static int dns_search_res (const char *dname, int rr_class, int rr_type, unsigned char *dns_response, int dns_response_len)
 Handles the DNS search if the system has RES_NINIT. More...
 
static int skip_name (unsigned char *s, int len)
 Tries to find the position of the next field in the DNS response. More...
 

Detailed Description

DNS Support for Asterisk.

Author
Thorsten Lockert tholo.nosp@m.@tro.nosp@m.llpho.nosp@m.ne.o.nosp@m.rg
Reference

Definition in file dns.c.

Macro Definition Documentation

◆ MAX_SIZE

#define MAX_SIZE   4096

The maximum size permitted for the answer from the DNS server.

Definition at line 47 of file dns.c.

Function Documentation

◆ ast_dns_get_nameservers()

struct ao2_container * ast_dns_get_nameservers ( void  )

Retrieve the configured nameservers of the system.

Definition at line 581 of file dns.c.

582{
583#ifdef HAVE_RES_NINIT
584 struct __res_state dnsstate;
585#endif
586 struct __res_state *state;
587 struct ao2_container *nameservers;
588 int i;
589
591 if (!nameservers) {
592 return NULL;
593 }
594
595#ifdef HAVE_RES_NINIT
596 memset(&dnsstate, 0, sizeof(dnsstate));
597 res_ninit(&dnsstate);
598 state = &dnsstate;
599#else
600 ast_mutex_lock(&res_lock);
601 res_init();
602 state = &_res;
603#endif
604
605 for (i = 0; i < state->nscount; i++) {
606 char addr[INET6_ADDRSTRLEN];
607 const char *addrp = NULL;
608
609 /* glibc sets sin_family to 0 when the nameserver is an IPv6 address */
610 if (state->nsaddr_list[i].sin_family) {
611 addrp = inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, addr, sizeof(addr));
612#if defined(HAVE_RES_NINIT) && defined(HAVE_STRUCT___RES_STATE__U__EXT_NSADDRS)
613 } else if (state->_u._ext.nsaddrs[i]) {
614 addrp = inet_ntop(AF_INET6, &state->_u._ext.nsaddrs[i]->sin6_addr, addr, sizeof(addr));
615#endif
616 }
617
618 if (addrp) {
619 ast_debug(1, "Discovered nameserver: %s\n", addrp);
620 ast_str_container_add(nameservers, addrp);
621 }
622 }
623
624#ifdef HAVE_RES_NINIT
625#ifdef HAVE_RES_NDESTROY
626 res_ndestroy(&dnsstate);
627#else
628 res_nclose(&dnsstate);
629#endif
630#else
631#ifdef HAVE_RES_CLOSE
632 res_close();
633#endif
634 ast_mutex_unlock(&res_lock);
635#endif
636
637 return nameservers;
638}
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
enum cc_state state
Definition: ccss.c:393
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define NULL
Definition: resample.c:96
struct ao2_container * ast_str_container_alloc_options(enum ao2_alloc_opts opts, int buckets)
Allocates a hash container for bare strings.
Definition: strings.c:200
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:205
Generic container type.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_str_container_add(), ast_str_container_alloc_options(), NULL, and state.

Referenced by system_create_resolver_and_set_nameservers().

◆ ast_search_dns()

int ast_search_dns ( void *  context,
const char *  dname,
int  class,
int  type,
int(*)(void *context, unsigned char *answer, int len, unsigned char *fullanswer)  callback 
)

Lookup record in DNS.

Perform DNS lookup (used by DNS, enum and SRV lookups)

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.

Definition at line 491 of file dns.c.

494{
495#ifdef HAVE_RES_NINIT
496 struct __res_state dnsstate;
497#endif
498 unsigned char answer[MAX_SIZE];
499 int res, ret = -1;
500
501#ifdef HAVE_RES_NINIT
502 memset(&dnsstate, 0, sizeof(dnsstate));
503 res_ninit(&dnsstate);
504 res = res_nsearch(&dnsstate, dname, class, type, answer, sizeof(answer));
505#else
506 ast_mutex_lock(&res_lock);
507 res_init();
508 res = res_search(dname, class, type, answer, sizeof(answer));
509#endif
510 if (res > 0) {
511 if ((res = dns_parse_answer(context, class, type, answer, res, callback)) < 0) {
512 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
513 ret = -1;
514 } else if (res == 0) {
515 ast_debug(1, "No matches found in DNS for %s\n", dname);
516 ret = 0;
517 } else
518 ret = 1;
519 }
520#ifdef HAVE_RES_NINIT
521#ifdef HAVE_RES_NDESTROY
522 res_ndestroy(&dnsstate);
523#else
524 res_nclose(&dnsstate);
525#endif
526#else
527#ifdef HAVE_RES_CLOSE
528 res_close();
529#endif
530 ast_mutex_unlock(&res_lock);
531#endif
532
533 return ret;
534}
#define ast_log
Definition: astobj2.c:42
static const char type[]
Definition: chan_ooh323.c:109
static int answer(void *data)
Definition: chan_pjsip.c:687
#define MAX_SIZE
The maximum size permitted for the answer from the DNS server.
Definition: dns.c:47
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))
Parse DNS lookup result, call callback.
Definition: dns.c:329
#define LOG_WARNING

References answer(), ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, voicemailpwcheck::context, dns_parse_answer(), LOG_WARNING, MAX_SIZE, and type.

Referenced by ast_get_enum(), ast_get_srv(), ast_get_txt(), ast_srv_lookup(), blr_ebl(), and blr_txt().

◆ ast_search_dns_ex()

enum ast_dns_search_result ast_search_dns_ex ( void *  context,
const char *  dname,
int  rr_class,
int  rr_type,
int(*)(void *context, unsigned char *dns_response, int dns_response_len, int rcode)  response_handler,
int(*)(void *context, unsigned char *record, int record_len, int ttl)  record_handler 
)

Extended version of the DNS search function.

Performs a DNS lookup, (used by DNS, enum and SRV lookups), parses the results and notifies the observer with the response and discovered records via invoking the provided callbacks (used by ast_dns_system_resolver).

Parameters
contextVoid pointer containing data to use in the handler functions.
dnameDomain name to lookup (host, SRV domain, TXT record name).
rr_classRecord Class (see "man res_search").
rr_typeRecord type (see "man res_search").
response_handlerCallback function for handling the DNS response. Invoked upon completion of the DNS search.
record_handlerCallback function for handling the discovered resource records from the DNS search. Invoked n times, where n is the number of records discovered while parsing the DNS response.
Return values
AST_DNS_SEARCH_FAILUREon search failure
AST_DNS_SEARCH_NO_RECORDSon no records found
AST_DNS_SEARCH_SUCCESSon success
Note
Asterisk DNS is synchronus at this time. This means that if your DNS service does not work, Asterisk may lock while waiting for a response.

Definition at line 536 of file dns.c.

539{
540 int ret, dns_response_len;
541 unsigned char dns_response[MAX_SIZE];
542
543 /* Assert that the callbacks are not NULL */
544 ast_assert(response_handler != NULL);
545 ast_assert(record_handler != NULL);
546
547 /* Try the DNS search. */
548 dns_response_len = dns_search_res(dname,
549 rr_class,
550 rr_type,
551 dns_response,
552 sizeof(dns_response));
553
554 if (dns_response_len < 0) {
555 ast_debug(1, "DNS search failed for %s\n", dname);
556 response_handler(context, (unsigned char *)"", 0, NXDOMAIN);
558 }
559
560 /* Parse records from DNS response */
562 rr_class,
563 rr_type,
564 dns_response,
565 dns_response_len,
566 response_handler,
567 record_handler);
568
569 /* Handle the return code from parsing the DNS response */
570 if (ret == AST_DNS_SEARCH_FAILURE) {
571 /* Parsing Error */
572 ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
573 } else if (ret == AST_DNS_SEARCH_NO_RECORDS) {
574 /* No results found */
575 ast_debug(1, "DNS search yielded no results for %s\n", dname);
576 }
577
578 return ret;
579}
static int dns_search_res(const char *dname, int rr_class, int rr_type, unsigned char *dns_response, int dns_response_len)
Handles the DNS search if the system has RES_NINIT.
Definition: dns.c:287
static int dns_parse_answer_ex(void *context, int rr_class, int rr_type, unsigned char *answer, int answer_len, int(*response_handler)(void *context, unsigned char *dns_response, int dns_response_len, int rcode), int(*record_handler)(void *context, unsigned char *record, int record_len, int ttl))
Extended version of the DNS Parsing function.
Definition: dns.c:407
@ AST_DNS_SEARCH_FAILURE
Definition: dns.h:29
@ AST_DNS_SEARCH_NO_RECORDS
Definition: dns.h:30
#define ast_assert(a)
Definition: utils.h:739

References ast_assert, ast_debug, AST_DNS_SEARCH_FAILURE, AST_DNS_SEARCH_NO_RECORDS, ast_log, voicemailpwcheck::context, dns_parse_answer_ex(), dns_search_res(), LOG_WARNING, MAX_SIZE, and NULL.

Referenced by dns_system_resolver_process_query().

◆ dns_advance_field()

static int dns_advance_field ( unsigned char **  dns_response,
int  remaining_len,
int  field_size 
)
static

Advances the position of the DNS response pointer by the size of the current field.

Definition at line 223 of file dns.c.

224{
225 if (dns_response == NULL || field_size < 0 || remaining_len < field_size) {
227 }
228
229 *dns_response += field_size;
230 remaining_len -= field_size;
231
232 return remaining_len;
233}

References AST_DNS_SEARCH_FAILURE, and NULL.

Referenced by dns_parse_answer_ex().

◆ dns_parse_answer()

static int dns_parse_answer ( void *  context,
int  class,
int  type,
unsigned char *  answer,
int  len,
int(*)(void *context, unsigned char *answer, int len, unsigned char *fullanswer)  callback 
)
static

Parse DNS lookup result, call callback.

Definition at line 329 of file dns.c.

332{
333 unsigned char *fullanswer = answer;
334 struct dn_answer *ans;
335 dns_HEADER *h;
336 int ret = 0;
337 int res;
338 int x;
339
340 h = (dns_HEADER *)answer;
341 answer += sizeof(dns_HEADER);
342 len -= sizeof(dns_HEADER);
343
344 for (x = 0; x < ntohs(h->qdcount); x++) {
345 if ((res = skip_name(answer, len)) < 0) {
346 ast_log(LOG_WARNING, "Couldn't skip over name\n");
347 return -1;
348 }
349 answer += res + 4; /* Skip name and QCODE / QCLASS */
350 len -= res + 4;
351 if (len < 0) {
352 ast_log(LOG_WARNING, "Strange query size\n");
353 return -1;
354 }
355 }
356
357 for (x = 0; x < ntohs(h->ancount); x++) {
358 if ((res = skip_name(answer, len)) < 0) {
359 ast_log(LOG_WARNING, "Failed skipping name\n");
360 return -1;
361 }
362 answer += res;
363 len -= res;
364 ans = (struct dn_answer *)answer;
365 answer += sizeof(struct dn_answer);
366 len -= sizeof(struct dn_answer);
367 if (len < 0) {
368 ast_log(LOG_WARNING, "Length of DNS answer exceeds frame\n");
369 return -1;
370 }
371
372 if (ntohs(ans->class) == class && ntohs(ans->rtype) == type) {
373 if (callback) {
374 if ((res = callback(context, answer, ntohs(ans->size), fullanswer)) < 0) {
375 ast_log(LOG_WARNING, "Failed to parse result\n");
376 return -1;
377 }
378 ret = 1;
379 }
380 }
381 answer += ntohs(ans->size);
382 len -= ntohs(ans->size);
383 }
384 return ret;
385}
static int skip_name(unsigned char *s, int len)
Tries to find the position of the next field in the DNS response.
Definition: dns.c:179
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Definition: dns.c:161
unsigned short class
Definition: dns.c:163
unsigned short size
Definition: dns.c:165
unsigned short rtype
Definition: dns.c:162
unsigned ancount
Definition: dns.c:156
unsigned qdcount
Definition: dns.c:155

References dns_HEADER::ancount, answer(), ast_log, dn_answer::class, voicemailpwcheck::context, len(), LOG_WARNING, dns_HEADER::qdcount, dn_answer::rtype, dn_answer::size, skip_name(), and type.

Referenced by ast_search_dns().

◆ dns_parse_answer_ex()

static int dns_parse_answer_ex ( void *  context,
int  rr_class,
int  rr_type,
unsigned char *  answer,
int  answer_len,
int(*)(void *context, unsigned char *dns_response, int dns_response_len, int rcode)  response_handler,
int(*)(void *context, unsigned char *record, int record_len, int ttl)  record_handler 
)
static

Extended version of the DNS Parsing function.

Parses the DNS lookup result and notifies the observer of each discovered resource record with the provided callback.

Definition at line 407 of file dns.c.

410{
411 unsigned char *dns_response = answer;
412 dns_HEADER *dns_header = (dns_HEADER *)answer;
413
414 struct dn_answer *ans;
415 int res, x, pos, dns_response_len, ret;
416
417 dns_response_len = answer_len;
419
420 /* Invoke the response_handler callback to notify the observer of the raw DNS response */
421 response_handler(context, dns_response, dns_response_len, ntohs(dns_header->rcode));
422
423 /* Verify there is something to parse */
424 if (answer_len == 0) {
425 return ret;
426 }
427
428 /* Try advancing the cursor for the dns header */
429 if ((pos = dns_advance_field(&answer, answer_len, sizeof(dns_HEADER))) < 0) {
430 ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
432 }
433
434 /* Skip domain name and QCODE / QCLASS */
435 for (x = 0; x < ntohs(dns_header->qdcount); x++) {
436 if ((res = skip_name(answer, pos)) < 0) {
437 ast_log(LOG_WARNING, "Failed skipping name\n");
439 }
440
441 /* Try advancing the cursor for the name and QCODE / QCLASS fields */
442 if ((pos = dns_advance_field(&answer, pos, res + 4)) < 0) {
444 }
445 }
446
447 /* Extract the individual records */
448 for (x = 0; x < ntohs(dns_header->ancount); x++) {
449 if ((res = skip_name(answer, pos)) < 0) {
450 ast_log(LOG_WARNING, "Failed skipping name\n");
452 }
453
454 /* Try advancing the cursor to the current record */
455 if ((pos = dns_advance_field(&answer, pos, res)) < 0) {
456 ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
458 }
459
460 /* Cast the current value for the answer pointer as a dn_answer struct */
461 ans = (struct dn_answer *) answer;
462
463 /* Try advancing the cursor to the end of the current record */
464 if ((pos = dns_advance_field(&answer, pos, sizeof(struct dn_answer))) < 0) {
465 ast_log(LOG_WARNING, "Length of DNS answer exceeds available search frames\n");
467 }
468
469 /* Skip over the records that do not have the same resource record class and type we care about */
470 if (ntohs(ans->class) == rr_class && ntohs(ans->rtype) == rr_type) {
471 /* Invoke the record handler callback to deliver the discovered record */
472 record_handler(context, answer, ntohs(ans->size), ntohl(ans->ttl));
473 /*At least one record was found */
475 }
476
477 /* Try and update the field to the next record, but ignore any errors that come
478 * back because this may be the end of the line. */
479 pos = dns_advance_field(&answer, pos, ntohs(ans->size));
480 }
481
482 return ret;
483}
static int dns_advance_field(unsigned char **dns_response, int remaining_len, int field_size)
Advances the position of the DNS response pointer by the size of the current field.
Definition: dns.c:223
@ AST_DNS_SEARCH_SUCCESS
Definition: dns.h:31
unsigned int ttl
Definition: dns.c:164

References dns_HEADER::ancount, answer(), AST_DNS_SEARCH_FAILURE, AST_DNS_SEARCH_NO_RECORDS, AST_DNS_SEARCH_SUCCESS, ast_log, dn_answer::class, voicemailpwcheck::context, dns_advance_field(), LOG_WARNING, dns_HEADER::qdcount, dn_answer::rtype, dn_answer::size, skip_name(), and dn_answer::ttl.

Referenced by ast_search_dns_ex().

◆ dns_search_res()

static int dns_search_res ( const char *  dname,
int  rr_class,
int  rr_type,
unsigned char *  dns_response,
int  dns_response_len 
)
static

Handles the DNS search if the system has RES_NINIT.

Definition at line 287 of file dns.c.

289{
290
291 int ret = AST_DNS_SEARCH_FAILURE;
292 struct __res_state dns_state;
293
294 memset(&dns_state, 0, sizeof(dns_state));
295 res_ninit(&dns_state);
296 ret = res_nsearch(&dns_state,
297 dname,
298 rr_class,
299 rr_type,
300 dns_response,
301 dns_response_len);
302
303#ifdef HAVE_RES_NDESTROY
304 res_ndestroy(&dns_state);
305#else
306 res_nclose(&dns_state);
307#endif
308
309 return ret;
310}

References AST_DNS_SEARCH_FAILURE.

Referenced by ast_search_dns_ex().

◆ skip_name()

static int skip_name ( unsigned char *  s,
int  len 
)
static

Tries to find the position of the next field in the DNS response.

Definition at line 179 of file dns.c.

180{
181 int x = 0;
182
183 while (x < len) {
184 if (*s == '\0') {
185 s++;
186 x++;
187 break;
188 }
189
190 if ((*s & 0xc0) == 0xc0) {
191 s += 2;
192 x += 2;
193 break;
194 }
195
196 x += *s + 1;
197 s += *s + 1;
198 }
199
200 /* If we are out of room to search, return failure. */
201 if (x >= len) {
203 }
204
205 /* Return the value for the current position in the DNS response. This is the start
206 position of the next field. */
207 return x;
208}

References AST_DNS_SEARCH_FAILURE, and len().

Referenced by dns_parse_answer(), and dns_parse_answer_ex().