Asterisk - The Open Source Telephony Project  18.5.0
Functions
dns_srv.c File Reference

DNS SRV Record Support. More...

#include "asterisk.h"
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include "asterisk/dns_core.h"
#include "asterisk/dns_srv.h"
#include "asterisk/linkedlists.h"
#include "asterisk/dns_internal.h"
#include "asterisk/utils.h"
Include dependency graph for dns_srv.c:

Go to the source code of this file.

Functions

const char * ast_dns_srv_get_host (const struct ast_dns_record *record)
 Get the hostname from an SRV record. More...
 
unsigned short ast_dns_srv_get_port (const struct ast_dns_record *record)
 Get the port from an SRV record. More...
 
unsigned short ast_dns_srv_get_priority (const struct ast_dns_record *record)
 Get the priority from an SRV record. More...
 
unsigned short ast_dns_srv_get_weight (const struct ast_dns_record *record)
 Get the weight from an SRV record. 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...
 

Detailed Description

DNS SRV Record Support.

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

Definition in file dns_srv.c.

Function Documentation

◆ ast_dns_srv_get_host()

const char* ast_dns_srv_get_host ( const struct ast_dns_record record)

Get the hostname from an SRV record.

Parameters
recordThe DNS record
Returns
the hostname

Definition at line 188 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::host.

Referenced by AST_TEST_DEFINE(), nominal_test(), and sip_resolve_callback().

189 {
190  struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
191 
192  ast_assert(ast_dns_record_get_rr_type(record) == T_SRV);
193  return srv->host;
194 }
#define ast_assert(a)
Definition: utils.h:695
An SRV record.
Definition: dns_internal.h:74
const char * host
The hostname in the SRV record.
Definition: dns_internal.h:78
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145

◆ ast_dns_srv_get_port()

unsigned short ast_dns_srv_get_port ( const struct ast_dns_record record)

Get the port from an SRV record.

Parameters
recordThe DNS record
Returns
the port

Definition at line 212 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::port.

Referenced by AST_TEST_DEFINE(), nominal_test(), and sip_resolve_callback().

213 {
214  struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
215 
216  ast_assert(ast_dns_record_get_rr_type(record) == T_SRV);
217  return srv->port;
218 }
#define ast_assert(a)
Definition: utils.h:695
unsigned short port
The port in the SRV record.
Definition: dns_internal.h:84
An SRV record.
Definition: dns_internal.h:74
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145

◆ ast_dns_srv_get_priority()

unsigned short ast_dns_srv_get_priority ( const struct ast_dns_record record)

Get the priority from an SRV record.

Parameters
recordThe DNS record
Returns
the priority

Definition at line 196 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::priority.

Referenced by AST_TEST_DEFINE(), and nominal_test().

197 {
198  struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
199 
200  ast_assert(ast_dns_record_get_rr_type(record) == T_SRV);
201  return srv->priority;
202 }
#define ast_assert(a)
Definition: utils.h:695
An SRV record.
Definition: dns_internal.h:74
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145
unsigned short priority
The priority of the SRV record.
Definition: dns_internal.h:80

◆ ast_dns_srv_get_weight()

unsigned short ast_dns_srv_get_weight ( const struct ast_dns_record record)

Get the weight from an SRV record.

Parameters
recordThe DNS record
Returns
the weight

Definition at line 204 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::weight.

Referenced by AST_TEST_DEFINE(), and nominal_test().

205 {
206  struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
207 
208  ast_assert(ast_dns_record_get_rr_type(record) == T_SRV);
209  return srv->weight;
210 }
#define ast_assert(a)
Definition: utils.h:695
An SRV record.
Definition: dns_internal.h:74
unsigned short weight
The weight of the SRV record.
Definition: dns_internal.h:82
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145

◆ 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