Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions
dns_internal.h File Reference

Internal DNS structure definitions. More...

#include "asterisk/linkedlists.h"
#include "asterisk/vector.h"
#include "asterisk/dns_query_set.h"
Include dependency graph for dns_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_dns_naptr_record
 A NAPTR record. More...
 
struct  ast_dns_query
 A DNS query. More...
 
struct  ast_dns_query_active
 An active DNS query. More...
 
struct  ast_dns_query_recurring
 A recurring DNS query. More...
 
struct  ast_dns_query_set
 A set of DNS queries. More...
 
struct  ast_dns_record
 For AST_LIST. More...
 
struct  ast_dns_result
 The result of a DNS query. More...
 
struct  ast_dns_srv_record
 An SRV record. More...
 
struct  ast_dns_txt_record
 A TXT record. More...
 
struct  dns_query_set_query
 A DNS query set query, which includes its state. More...
 
struct  ast_dns_result::dns_records
 Records returned. More...
 

Functions

struct ast_sched_contextast_dns_get_sched (void)
 Retrieve the DNS scheduler context. More...
 
char * dns_find_record (const char *record, size_t record_size, const char *response, size_t response_size)
 Find the location of a DNS record within the entire DNS answer. More...
 
struct ast_dns_recorddns_naptr_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS NAPTR record. More...
 
void dns_naptr_sort (struct ast_dns_result *result)
 Sort the NAPTR records on a result. More...
 
int dns_parse_short (unsigned char *cur, uint16_t *val)
 Parse a 16-bit unsigned value from a DNS record. More...
 
int dns_parse_string (char *cur, uint8_t *size, char **val)
 Parse a DNS string from a DNS record. More...
 
struct ast_dns_querydns_query_alloc (const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
 Allocate a DNS query (but do not start resolution) More...
 
struct ast_dns_recorddns_srv_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS SRV record. More...
 
void dns_srv_sort (struct ast_dns_result *result)
 Sort the SRV records on a result. More...
 
struct ast_dns_recorddns_txt_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS TXT record. More...
 

Detailed Description

Internal DNS structure definitions.

Author
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om

Definition in file dns_internal.h.

Function Documentation

◆ ast_dns_get_sched()

struct ast_sched_context* ast_dns_get_sched ( void  )

Retrieve the DNS scheduler context.

Returns
scheduler context

Definition at line 52 of file dns_core.c.

References sched.

Referenced by ast_dns_resolve_recurring(), ast_dns_resolve_recurring_cancel(), and dns_query_recurring_resolution_callback().

53 {
54  return sched;
55 }
static struct ast_sched_context * sched
Definition: dns_core.c:50

◆ dns_find_record()

char* dns_find_record ( const char *  record,
size_t  record_size,
const char *  response,
size_t  response_size 
)

Find the location of a DNS record within the entire DNS answer.

The DNS record that has been returned by the resolver may be a copy of the record that was found in the complete DNS response. If so, then some DNS record types (specifically those that parse domains) will need to locate the DNS record within the complete DNS response. This is so that if the domain contains pointers to other sections of the DNS response, then the referenced domains may be located.

Parameters
recordThe DNS record returned by a resolver implementation
record_sizeThe size of the DNS record in bytes
responseThe complete DNS answer
response_sizeThe size of the complete DNS response

Definition at line 701 of file dns_core.c.

References ast_assert, and NULL.

Referenced by dns_naptr_alloc(), and dns_srv_alloc().

702 {
703  size_t remaining_size = response_size;
704  const char *search_base = response;
705  char *record_offset;
706 
707  while (1) {
708  record_offset = memchr(search_base, record[0], remaining_size);
709 
710  ast_assert(record_offset != NULL);
711  ast_assert(search_base + remaining_size - record_offset >= record_size);
712 
713  if (!memcmp(record_offset, record, record_size)) {
714  return record_offset;
715  }
716 
717  remaining_size -= record_offset - search_base;
718  search_base = record_offset + 1;
719  }
720 }
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96

◆ dns_naptr_alloc()

struct ast_dns_record* dns_naptr_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
)

Allocate and parse a DNS NAPTR record.

Parameters
queryThe DNS query
dataThis specific NAPTR record
sizeThe size of the NAPTR record
Return values
non-NULLsuccess
NULLfailure

Definition at line 380 of file dns_naptr.c.

References ast_dns_result::answer, ast_dns_result::answer_size, ast_assert, ast_calloc, ast_log, ast_dns_naptr_record::data, ast_dns_record::data_ptr, dns_find_record(), dns_parse_short(), dns_parse_string(), errno, ast_dns_naptr_record::flags, FLAGS_INVALID, ast_dns_naptr_record::generic, interpret_flags(), LOG_ERROR, NULL, order, ast_dns_naptr_record::order, PAST_END_OF_RECORD, ast_dns_naptr_record::preference, ast_dns_naptr_record::regexp, regexp_invalid(), ast_dns_naptr_record::replacement, ast_dns_query::result, ast_dns_naptr_record::service, and services_invalid().

381 {
382  struct ast_dns_naptr_record *naptr;
383  char *ptr = NULL;
384  uint16_t order;
385  uint16_t preference;
386  uint8_t flags_size;
387  char *flags;
388  uint8_t services_size;
389  char *services;
390  uint8_t regexp_size;
391  char *regexp;
392  char replacement[256] = "";
393  int replacement_size;
394  const char *end_of_record;
395  enum flags_result flags_res;
396  size_t naptr_len;
397 
398  ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
399  ast_assert(ptr != NULL);
400 
401  end_of_record = ptr + size;
402 
403  /* ORDER */
404  /* This assignment takes a big-endian 16-bit value and stores it in the
405  * machine's native byte order. Using this method allows us to avoid potential
406  * alignment issues in case the order is not on a short-addressable boundary.
407  * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
408  * more information
409  */
410  ptr += dns_parse_short((unsigned char *) ptr, &order);
411  if (PAST_END_OF_RECORD) {
412  return NULL;
413  }
414 
415  /* PREFERENCE */
416  ptr += dns_parse_short((unsigned char *) ptr, &preference);
417  if (PAST_END_OF_RECORD) {
418  return NULL;
419  }
420 
421  /* FLAGS */
422  ptr += dns_parse_string(ptr, &flags_size, &flags);
423  if (PAST_END_OF_RECORD) {
424  return NULL;
425  }
426 
427  /* SERVICES */
428  ptr += dns_parse_string(ptr, &services_size, &services);
429  if (PAST_END_OF_RECORD) {
430  return NULL;
431  }
432 
433  /* REGEXP */
434  ptr += dns_parse_string(ptr, &regexp_size, &regexp);
435  if (PAST_END_OF_RECORD) {
436  return NULL;
437  }
438 
439  /*
440  * The return value from dn_expand represents the size of the replacement
441  * in the buffer which MAY be compressed. Since the expanded replacement
442  * is NULL terminated, you can use strlen() to get the expanded size.
443  */
444  replacement_size = dn_expand((unsigned char *)query->result->answer,
445  (unsigned char *) end_of_record, (unsigned char *) ptr,
446  replacement, sizeof(replacement) - 1);
447  if (replacement_size < 0) {
448  ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
449  return NULL;
450  }
451 
452  ptr += replacement_size;
453 
454  if (ptr != end_of_record) {
455  ast_log(LOG_ERROR, "NAPTR record gave undersized string indications.\n");
456  return NULL;
457  }
458 
459  /* We've validated the size of the NAPTR record. Now we can validate
460  * the individual parts
461  */
462  flags_res = interpret_flags(flags, flags_size);
463  if (flags_res == FLAGS_INVALID) {
464  ast_log(LOG_ERROR, "NAPTR Record contained invalid flags %.*s\n", flags_size, flags);
465  return NULL;
466  }
467 
468  if (services_invalid(services, services_size)) {
469  ast_log(LOG_ERROR, "NAPTR record contained invalid services %.*s\n", services_size, services);
470  return NULL;
471  }
472 
473  if (regexp_invalid(regexp, regexp_size)) {
474  ast_log(LOG_ERROR, "NAPTR record contained invalid regexp %.*s\n", regexp_size, regexp);
475  return NULL;
476  }
477 
478  /* replacement_size takes into account the NULL label, so a NAPTR record with no replacement
479  * will have a replacement_size of 1.
480  */
481  if (regexp_size && replacement_size > 1) {
482  ast_log(LOG_ERROR, "NAPTR record contained both a regexp and replacement\n");
483  return NULL;
484  }
485 
486  naptr_len = sizeof(*naptr) + size + flags_size + 1 + services_size + 1
487  + regexp_size + 1 + strlen(replacement) + 1;
488  naptr = ast_calloc(1, naptr_len);
489  if (!naptr) {
490  return NULL;
491  }
492 
493  naptr->order = order;
494  naptr->preference = preference;
495 
496  ptr = naptr->data;
497  ptr += size;
498 
499  strncpy(ptr, flags, flags_size);
500  ptr[flags_size] = '\0';
501  naptr->flags = ptr;
502  ptr += flags_size + 1;
503 
504  strncpy(ptr, services, services_size);
505  ptr[services_size] = '\0';
506  naptr->service = ptr;
507  ptr += services_size + 1;
508 
509  strncpy(ptr, regexp, regexp_size);
510  ptr[regexp_size] = '\0';
511  naptr->regexp = ptr;
512  ptr += regexp_size + 1;
513 
514  strcpy(ptr, replacement);
515  naptr->replacement = ptr;
516 
517  naptr->generic.data_ptr = naptr->data;
518 
519  return (struct ast_dns_record *)naptr;
520 }
int dns_parse_string(char *cur, uint8_t *size, char **val)
Parse a DNS string from a DNS record.
Definition: dns_core.c:734
const char * replacement
The replacement from the NAPTR record.
Definition: dns_internal.h:102
char * data_ptr
pointer to record-specific data.
Definition: dns_internal.h:58
For AST_LIST.
Definition: dns_internal.h:39
const char * flags
The flags from the NAPTR record.
Definition: dns_internal.h:96
int dns_parse_short(unsigned char *cur, uint16_t *val)
Parse a 16-bit unsigned value from a DNS record.
Definition: dns_core.c:722
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
const char * regexp
The regular expression from the NAPTR record.
Definition: dns_internal.h:100
static int services_invalid(const char *services, uint8_t services_size)
Analyze NAPTR services for validity as defined by RFC 3404.
Definition: dns_naptr.c:130
#define ast_log
Definition: astobj2.c:42
integer order
Definition: analys.c:66
const char * service
The service from the NAPTR record.
Definition: dns_internal.h:98
#define PAST_END_OF_RECORD
Definition: dns_naptr.c:378
static enum flags_result interpret_flags(const char *flags, uint8_t flags_size)
Analyze and interpret NAPTR flags as per RFC 3404.
Definition: dns_naptr.c:66
#define LOG_ERROR
Definition: logger.h:285
char data[0]
Buffer for NAPTR-specific data.
Definition: dns_internal.h:113
struct ast_dns_result * result
Result of the DNS query.
Definition: dns_internal.h:147
int errno
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
unsigned short preference
The preference of the NAPTR record.
Definition: dns_internal.h:106
Definition: enum.h:28
flags_result
Result of analyzing NAPTR flags on a record.
Definition: dns_naptr.c:46
static int regexp_invalid(const char *regexp, uint8_t regexp_size)
Determine if the regexp in a NAPTR record is invalid.
Definition: dns_naptr.c:309
struct ast_dns_record generic
Generic DNS record information.
Definition: dns_internal.h:94
A NAPTR record.
Definition: dns_internal.h:92
char * dns_find_record(const char *record, size_t record_size, const char *response, size_t response_size)
Find the location of a DNS record within the entire DNS answer.
Definition: dns_core.c:701
size_t answer_size
The size of the raw DNS answer.
Definition: dns_internal.h:131
const char * answer
The raw DNS answer.
Definition: dns_internal.h:129
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104

◆ dns_naptr_sort()

void dns_naptr_sort ( struct ast_dns_result result)

Sort the NAPTR records on a result.

Parameters
resultThe DNS result

Definition at line 551 of file dns_naptr.c.

References ast_alloca, AST_LIST_INSERT_TAIL, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, compare_order(), compare_preference(), order, ast_dns_naptr_record::order, records, and ast_dns_result::records.

552 {
553  struct ast_dns_record *current;
554  size_t num_records = 0;
555  struct ast_dns_naptr_record **records;
556  int i = 0;
557  int j = 0;
558  int cur_order;
559 
560  /* Determine the number of records */
561  AST_LIST_TRAVERSE(&result->records, current, list) {
562  ++num_records;
563  }
564 
565  /* No point in continuing if there are no records */
566  if (num_records == 0) {
567  return;
568  }
569 
570  /* Allocate an array with that number of records */
571  records = ast_alloca(num_records * sizeof(*records));
572 
573  /* Move records from the list to the array */
574  AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
575  records[i++] = (struct ast_dns_naptr_record *) current;
577  }
579 
580  /* Sort the array by order */
581  qsort(records, num_records, sizeof(*records), compare_order);
582 
583  /* Sort subarrays by preference */
584  for (i = 0; i < num_records; i = j) {
585  cur_order = records[i]->order;
586  for (j = i + 1; j < num_records; ++j) {
587  if (records[j]->order != cur_order) {
588  break;
589  }
590  }
591  qsort(&records[i], j - i, sizeof(*records), compare_preference);
592  }
593 
594  /* Place sorted records back into the original list */
595  for (i = 0; i < num_records; ++i) {
596  AST_LIST_INSERT_TAIL(&result->records, (struct ast_dns_record *)(records[i]), list);
597  }
598 }
static int records
Definition: cdr_mysql.c:84
static int compare_order(const void *record1, const void *record2)
Definition: dns_naptr.c:523
For AST_LIST.
Definition: dns_internal.h:39
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
static int compare_preference(const void *record1, const void *record2)
Definition: dns_naptr.c:537
integer order
Definition: analys.c:66
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
A NAPTR record.
Definition: dns_internal.h:92
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
struct ast_dns_result::dns_records records
unsigned short order
The order for the NAPTR record.
Definition: dns_internal.h:104

◆ dns_parse_short()

int dns_parse_short ( unsigned char *  cur,
uint16_t *  val 
)

Parse a 16-bit unsigned value from a DNS record.

Parameters
curPointer to the location of the 16-bit value in the DNS record
[out]valThe parsed 16-bit unsigned integer
Returns
The number of bytes consumed while parsing

Definition at line 722 of file dns_core.c.

Referenced by dns_naptr_alloc(), and dns_srv_alloc().

723 {
724  /* This assignment takes a big-endian 16-bit value and stores it in the
725  * machine's native byte order. Using this method allows us to avoid potential
726  * alignment issues in case the order is not on a short-addressable boundary.
727  * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
728  * more information
729  */
730  *val = (cur[1] << 0) | (cur[0] << 8);
731  return sizeof(*val);
732 }
Definition: ast_expr2.c:325

◆ dns_parse_string()

int dns_parse_string ( char *  cur,
uint8_t *  size,
char **  val 
)

Parse a DNS string from a DNS record.

A DNS string consists of an 8-bit size, followed by the string value (not NULL-terminated).

Parameters
curPointer to the location of the DNS string
[out]sizeThe parsed size of the DNS string
[out]valThe contained string (not NULL-terminated)
Returns
The number of bytes consumed while parsing

Definition at line 734 of file dns_core.c.

Referenced by dns_naptr_alloc().

735 {
736  *size = *cur++;
737  *val = cur;
738  return *size + 1;
739 }
Definition: ast_expr2.c:325

◆ dns_query_alloc()

struct ast_dns_query* dns_query_alloc ( const char *  name,
int  rr_type,
int  rr_class,
ast_dns_resolve_callback  callback,
void *  data 
)

Allocate a DNS query (but do not start resolution)

Parameters
nameThe name of what to resolve
rr_typeResource record type
rr_classResource record class
callbackThe callback to invoke upon completion
dataUser data to make available on the query
Return values
non-NULLsuccess
NULLfailure
Note
The result passed to the callback does not need to be freed
The user data MUST be an ao2 object
This function increments the reference count of the user data, it does NOT steal
The query must be released upon completion or cancellation using ao2_ref

Definition at line 193 of file dns_core.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, ast_log, AST_RWLIST_FIRST, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK, ast_strlen_zero, ast_dns_query::callback, dns_query_destroy(), LOG_ERROR, LOG_WARNING, ast_dns_query::name, NULL, ast_dns_query::resolver, ast_dns_query::rr_class, ast_dns_query::rr_type, and ast_dns_query::user_data.

Referenced by ast_dns_query_set_add(), ast_dns_resolve_async(), and dns_query_recurring_resolution_callback().

194 {
195  struct ast_dns_query *query;
196 
197  if (ast_strlen_zero(name)) {
198  ast_log(LOG_WARNING, "Could not perform asynchronous resolution, no name provided\n");
199  return NULL;
200  } else if (rr_type > 65536) {
201  ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record type '%d' exceeds maximum\n",
202  name, rr_type);
203  return NULL;
204  } else if (rr_type < 0) {
205  ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', invalid resource record type '%d'\n",
206  name, rr_type);
207  return NULL;
208  } else if (rr_class > 65536) {
209  ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record class '%d' exceeds maximum\n",
210  name, rr_class);
211  return NULL;
212  } else if (rr_class < 0) {
213  ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', invalid resource class '%d'\n",
214  name, rr_class);
215  return NULL;
216  } else if (!callback) {
217  ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', no callback provided\n",
218  name);
219  return NULL;
220  }
221 
222  query = ao2_alloc_options(sizeof(*query) + strlen(name) + 1, dns_query_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
223  if (!query) {
224  return NULL;
225  }
226 
227  query->callback = callback;
228  query->user_data = ao2_bump(data);
229  query->rr_type = rr_type;
230  query->rr_class = rr_class;
231  strcpy(query->name, name); /* SAFE */
232 
236 
237  if (!query->resolver) {
238  ast_log(LOG_ERROR, "Attempted to do a DNS query for '%s' of class '%d' and type '%d' but no resolver is available\n",
239  name, rr_class, rr_type);
240  ao2_ref(query, -1);
241  return NULL;
242  }
243 
244  return query;
245 }
int rr_type
Resource record type.
Definition: dns_internal.h:149
#define LOG_WARNING
Definition: logger.h:274
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
int rr_class
Resource record class.
Definition: dns_internal.h:151
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
char name[0]
The name of what is being resolved.
Definition: dns_internal.h:153
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void * user_data
User-specific data.
Definition: dns_internal.h:141
static void dns_query_destroy(void *data)
Destructor for a DNS query.
Definition: dns_core.c:184
#define LOG_ERROR
Definition: logger.h:285
ast_dns_resolve_callback callback
Callback to invoke upon completion.
Definition: dns_internal.h:139
static const char name[]
Definition: cdr_mysql.c:74
A DNS query.
Definition: dns_internal.h:137
struct ast_dns_resolver * resolver
The resolver in use for this query.
Definition: dns_internal.h:143
#define AST_RWLIST_FIRST
Definition: linkedlists.h:422

◆ dns_srv_alloc()

struct ast_dns_record* dns_srv_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
)

Allocate and parse a DNS SRV record.

Parameters
queryThe DNS query
dataThis specific SRV record
sizeThe size of the SRV record
Return values
non-NULLsuccess
NULLfailure

Definition at line 42 of file dns_srv.c.

References ast_dns_result::answer, ast_dns_result::answer_size, ast_assert, ast_calloc, ast_copy_string(), ast_log, ast_dns_srv_record::data, ast_dns_record::data_ptr, dns_find_record(), dns_parse_short(), errno, ast_dns_srv_record::generic, host, ast_dns_srv_record::host, LOG_ERROR, NULL, ast_dns_srv_record::port, priority, ast_dns_srv_record::priority, ast_dns_query::result, ast_dns_srv_record::weight, and weight.

43 {
44  uint16_t priority;
45  uint16_t weight;
46  uint16_t port;
47  const char *ptr;
48  const char *end_of_record;
49  struct ast_dns_srv_record *srv;
50  int host_size;
51  char host[NI_MAXHOST] = "";
52  size_t host_len;
53 
54  ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
55  ast_assert(ptr != NULL);
56 
57  end_of_record = ptr + size;
58 
59  /* PRIORITY */
60  ptr += dns_parse_short((unsigned char *) ptr, &priority);
61  if (ptr >= end_of_record) {
62  return NULL;
63  }
64 
65  /* WEIGHT */
66  ptr += dns_parse_short((unsigned char *) ptr, &weight);
67  if (ptr >= end_of_record) {
68  return NULL;
69  }
70 
71  /* PORT */
72  ptr += dns_parse_short((unsigned char *) ptr, &port);
73  if (ptr >= end_of_record) {
74  return NULL;
75  }
76 
77  /*
78  * The return value from dn_expand represents the size of the replacement
79  * in the buffer which MAY be compressed. Since the expanded replacement
80  * is NULL terminated, you can use strlen() to get the expanded size.
81  */
82  host_size = dn_expand((unsigned char *)query->result->answer,
83  (unsigned char *) end_of_record, (unsigned char *) ptr, host, sizeof(host) - 1);
84  if (host_size < 0) {
85  ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
86  return NULL;
87  }
88 
89  if (!strcmp(host, ".")) {
90  return NULL;
91  }
92 
93  host_len = strlen(host) + 1;
94  srv = ast_calloc(1, sizeof(*srv) + size + host_len);
95  if (!srv) {
96  return NULL;
97  }
98 
99  srv->priority = priority;
100  srv->weight = weight;
101  srv->port = port;
102 
103  srv->host = srv->data + size;
104  ast_copy_string((char *)srv->host, host, host_len); /* SAFE */
105  srv->generic.data_ptr = srv->data;
106 
107  return (struct ast_dns_record *)srv;
108 }
char data[0]
Additional data.
Definition: dns_internal.h:88
char * data_ptr
pointer to record-specific data.
Definition: dns_internal.h:58
For AST_LIST.
Definition: dns_internal.h:39
int dns_parse_short(unsigned char *cur, uint16_t *val)
Parse a 16-bit unsigned value from a DNS record.
Definition: dns_core.c:722
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
unsigned short port
The port in the SRV record.
Definition: dns_internal.h:84
static int priority
#define ast_log
Definition: astobj2.c:42
static char host[256]
Definition: muted.c:77
An SRV record.
Definition: dns_internal.h:74
struct ast_dns_record generic
Generic DNS record information.
Definition: dns_internal.h:76
#define LOG_ERROR
Definition: logger.h:285
char weight
struct ast_dns_result * result
Result of the DNS query.
Definition: dns_internal.h:147
int errno
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
unsigned short weight
The weight of the SRV record.
Definition: dns_internal.h:82
const char * host
The hostname in the SRV record.
Definition: dns_internal.h:78
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char * dns_find_record(const char *record, size_t record_size, const char *response, size_t response_size)
Find the location of a DNS record within the entire DNS answer.
Definition: dns_core.c:701
size_t answer_size
The size of the raw DNS answer.
Definition: dns_internal.h:131
const char * answer
The raw DNS answer.
Definition: dns_internal.h:129
unsigned short priority
The priority of the SRV record.
Definition: dns_internal.h:80

◆ dns_srv_sort()

void dns_srv_sort ( struct ast_dns_result result)

Sort the SRV records on a result.

Parameters
resultThe DNS result

Definition at line 113 of file dns_srv.c.

References AST_LIST_APPEND_LIST, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_MOVE_CURRENT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_random(), priority, ast_dns_result::records, weight, and ast_dns_srv_record::weight_sum.

114 {
115  struct ast_dns_record *current;
116  struct dns_records newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
117 
118  while (AST_LIST_FIRST(&result->records)) {
119  unsigned short cur_priority = ((struct ast_dns_srv_record *)(AST_LIST_FIRST(&result->records)))->priority;
120  struct dns_records temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
121 
122  /* Find the lowest current priority to work on, but if the priority is already zero there is no lower priority */
123  if (cur_priority) {
124  AST_LIST_TRAVERSE(&result->records, current, list) {
125  if (((struct ast_dns_srv_record *)current)->priority < cur_priority) {
126  cur_priority = ((struct ast_dns_srv_record *)current)->priority;
127  }
128  }
129  }
130 
131  /* Find all records which match this priority */
132  AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
133  if (((struct ast_dns_srv_record *)current)->priority != cur_priority) {
134  continue;
135  }
136 
138 
139  /* Records with a weight of zero must always be at the head */
140  if (((struct ast_dns_srv_record *)current)->weight == 0) {
141  AST_LIST_INSERT_HEAD(&temp_list, current, list);
142  } else {
143  AST_LIST_INSERT_TAIL(&temp_list, current, list);
144  }
145  }
147 
148  /* Apply weighting - as each record is passed the sum of all previous weights (plus its own) is stored away, and then a random weight
149  * is calculated. The first record with a weight sum greater than the random weight is put in the new list and the whole thing starts
150  * once again.
151  */
152  while (AST_LIST_FIRST(&temp_list)) {
153  unsigned int weight_sum = 0;
154  unsigned int random_weight;
155 
156  AST_LIST_TRAVERSE(&temp_list, current, list) {
157  ((struct ast_dns_srv_record *)current)->weight_sum = weight_sum += ((struct ast_dns_srv_record *)current)->weight;
158  }
159 
160  /* if all the remaining entries have weight == 0,
161  then just append them to the result list and quit */
162  if (weight_sum == 0) {
163  AST_LIST_APPEND_LIST(&newlist, &temp_list, list);
164  break;
165  }
166 
167  random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0)));
168 
169  AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) {
170  if (((struct ast_dns_srv_record *)current)->weight_sum < random_weight) {
171  continue;
172  }
173 
174  AST_LIST_MOVE_CURRENT(&newlist, list);
175  break;
176  }
178  }
179 
180  }
181 
182  /* now that the new list has been ordered,
183  put it in place */
184 
185  AST_LIST_APPEND_LIST(&result->records, &newlist, list);
186 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
For AST_LIST.
Definition: dns_internal.h:39
static int priority
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
An SRV record.
Definition: dns_internal.h:74
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
long int ast_random(void)
Definition: main/utils.c:2064
#define AST_LIST_MOVE_CURRENT(newhead, field)
Move the current list entry to another list.
Definition: linkedlists.h:581
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
char weight
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:251
unsigned int weight_sum
The running weight sum.
Definition: dns_internal.h:86
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
struct ast_dns_result::dns_records records
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:782

◆ dns_txt_alloc()

struct ast_dns_record* dns_txt_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
)

Allocate and parse a DNS TXT record.

Since
16.10.0, 17.4.0
Parameters
queryThe DNS query
dataThis specific TXT record
sizeThe size of the TXT record
Return values
non-NULLsuccess
NULLfailure

Definition at line 38 of file dns_txt.c.

References ast_calloc, ast_dns_txt_record::count, ast_dns_txt_record::data, ast_dns_record::data_ptr, ast_dns_txt_record::generic, and NULL.

39 {
40  struct ast_dns_txt_record *txt;
41  const char *end_of_record = data + size;
42  size_t count = 0;
43 
44  /* Because we can't allocate additional memory, the best we can do here is just
45  * validate that this conforms to a TXT record. */
46  while (data < end_of_record) {
47  uint8_t byte_count = (uint8_t) *data;
48  count++;
49  data += byte_count + 1;
50  }
51 
52  if (data != end_of_record) {
53  /* This is not a valid TXT record, so we can bail out */
54  return NULL;
55  }
56 
57  txt = ast_calloc(1, sizeof(*txt) + size);
58  if (!txt) {
59  return NULL;
60  }
61 
62  txt->count = count;
63  txt->generic.data_ptr = txt->data;
64 
65  return (struct ast_dns_record *) txt;
66 }
struct ast_dns_record generic
Generic DNS record information.
Definition: dns_internal.h:66
A TXT record.
Definition: dns_internal.h:64
char * data_ptr
pointer to record-specific data.
Definition: dns_internal.h:58
For AST_LIST.
Definition: dns_internal.h:39
#define NULL
Definition: resample.c:96
char data[0]
The raw DNS record.
Definition: dns_internal.h:70
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
size_t count
The number of character strings in the TXT record.
Definition: dns_internal.h:68