Asterisk - The Open Source Telephony Project  18.5.0
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.

Referenced by ast_search_dns(), and ast_search_dns_ex().

Function Documentation

◆ ast_dns_get_nameservers()

struct ao2_container* ast_dns_get_nameservers ( void  )

Retrieve the configured nameservers of the system.

Definition at line 583 of file dns.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ast_inet_ntoa(), 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().

584 {
585 #ifdef HAVE_RES_NINIT
586  struct __res_state dnsstate;
587 #endif
588  struct __res_state *state;
589  struct ao2_container *nameservers;
590  int i;
591 
593  if (!nameservers) {
594  return NULL;
595  }
596 
597 #ifdef HAVE_RES_NINIT
598  memset(&dnsstate, 0, sizeof(dnsstate));
599  res_ninit(&dnsstate);
600  state = &dnsstate;
601 #else
602  ast_mutex_lock(&res_lock);
603  res_init();
604  state = &_res;
605 #endif
606 
607  for (i = 0; i < state->nscount; i++) {
608  ast_str_container_add(nameservers, ast_inet_ntoa(state->nsaddr_list[i].sin_addr));
609  }
610 
611 #ifdef HAVE_RES_NINIT
612 #ifdef HAVE_RES_NDESTROY
613  res_ndestroy(&dnsstate);
614 #else
615  res_nclose(&dnsstate);
616 #endif
617 #else
618 #ifdef HAVE_RES_CLOSE
619  res_close();
620 #endif
621  ast_mutex_unlock(&res_lock);
622 #endif
623 
624  return nameservers;
625 }
enum sip_cc_notify_state state
Definition: chan_sip.c:959
#define ast_mutex_lock(a)
Definition: lock.h:187
#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:201
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: main/utils.c:782
Generic container type.
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:206
#define ast_mutex_unlock(a)
Definition: lock.h:188

◆ 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 493 of file dns.c.

References ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, dns_parse_answer(), LOG_WARNING, and MAX_SIZE.

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

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

◆ 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 538 of file dns.c.

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

Referenced by dns_system_resolver_process_query().

541 {
542  int ret, dns_response_len;
543  unsigned char dns_response[MAX_SIZE];
544 
545  /* Assert that the callbacks are not NULL */
546  ast_assert(response_handler != NULL);
547  ast_assert(record_handler != NULL);
548 
549  /* Try the DNS search. */
550  dns_response_len = dns_search_res(dname,
551  rr_class,
552  rr_type,
553  dns_response,
554  sizeof(dns_response));
555 
556  if (dns_response_len < 0) {
557  ast_debug(1, "DNS search failed for %s\n", dname);
558  response_handler(context, (unsigned char *)"", 0, NXDOMAIN);
559  return AST_DNS_SEARCH_FAILURE;
560  }
561 
562  /* Parse records from DNS response */
564  rr_class,
565  rr_type,
566  dns_response,
567  dns_response_len,
568  response_handler,
569  record_handler);
570 
571  /* Handle the return code from parsing the DNS response */
572  if (ret == AST_DNS_SEARCH_FAILURE) {
573  /* Parsing Error */
574  ast_log(LOG_WARNING, "DNS Parse error for %s\n", dname);
575  } else if (ret == AST_DNS_SEARCH_NO_RECORDS) {
576  /* No results found */
577  ast_debug(1, "DNS search yielded no results for %s\n", dname);
578  }
579 
580  return ret;
581 }
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:409
#define LOG_WARNING
Definition: logger.h:274
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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 MAX_SIZE
The maximum size permitted for the answer from the DNS server.
Definition: dns.c:47
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ 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.

References AST_DNS_SEARCH_FAILURE, ast_mutex_lock, ast_mutex_unlock, dns_search_res(), and NULL.

Referenced by dns_parse_answer_ex().

224 {
225  if (dns_response == NULL || field_size < 0 || remaining_len < field_size) {
226  return AST_DNS_SEARCH_FAILURE;
227  }
228 
229  *dns_response += field_size;
230  remaining_len -= field_size;
231 
232  return remaining_len;
233 }
#define NULL
Definition: resample.c:96

◆ 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 330 of file dns.c.

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

Referenced by ast_search_dns().

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

◆ 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 409 of file dns.c.

References dns_HEADER::ancount, answer(), AST_DNS_SEARCH_FAILURE, AST_DNS_SEARCH_NO_RECORDS, AST_DNS_SEARCH_SUCCESS, ast_log, dn_answer::class, 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().

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

◆ 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.

References AST_DNS_SEARCH_FAILURE.

Referenced by ast_search_dns_ex(), and dns_advance_field().

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 }

◆ 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.

References AST_DNS_SEARCH_FAILURE.

Referenced by dns_parse_answer(), and dns_parse_answer_ex().

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) {
202  return AST_DNS_SEARCH_FAILURE;
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 }
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)