Asterisk - The Open Source Telephony Project  21.4.1
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"

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.
 

Functions

struct ao2_containerast_dns_get_nameservers (void)
 Retrieve the configured nameservers of the system.
 
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.
 
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.
 
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.
 
static int skip_name (unsigned char *s, int len)
 Tries to find the position of the next field in the DNS response.
 

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.

Function Documentation

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.

References ast_debug, dns_parse_answer(), and MAX_SIZE.

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

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_debug(level,...)
Log a DEBUG message.
#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
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.

References ast_debug, AST_DNS_SEARCH_FAILURE, AST_DNS_SEARCH_NO_RECORDS, dns_parse_answer_ex(), dns_search_res(), and MAX_SIZE.

Referenced by dns_system_resolver_process_query().

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);
557  return AST_DNS_SEARCH_FAILURE;
558  }
559 
560  /* Parse records from DNS response */
561  ret = dns_parse_answer_ex(context,
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_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
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
#define ast_debug(level,...)
Log a DEBUG message.
#define MAX_SIZE
The maximum size permitted for the answer from the DNS server.
Definition: dns.c:47
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.

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

Referenced by ast_search_dns_ex().

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");
431  return AST_DNS_SEARCH_FAILURE;
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");
438  return AST_DNS_SEARCH_FAILURE;
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) {
443  return AST_DNS_SEARCH_FAILURE;
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");
451  return AST_DNS_SEARCH_FAILURE;
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");
457  return AST_DNS_SEARCH_FAILURE;
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");
466  return AST_DNS_SEARCH_FAILURE;
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 }
unsigned ancount
Definition: dns.c:156
unsigned short size
Definition: dns.c:165
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
unsigned short class
Definition: dns.c:163
unsigned int ttl
Definition: dns.c:164
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
unsigned short rtype
Definition: dns.c:162
unsigned qdcount
Definition: dns.c:155
Definition: dns.c:161