Wed Jan 8 2020 09:50:21

Asterisk developer's documentation


srv.c File Reference

DNS SRV Record Lookup Support for Asterisk. More...

#include "asterisk.h"
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include "asterisk/channel.h"
#include "asterisk/srv.h"
#include "asterisk/dns.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"

Go to the source code of this file.

Data Structures

struct  srv_context
 
struct  srv_context::srv_entries
 
struct  srv_entry
 

Functions

int ast_get_srv (struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
 
void ast_srv_cleanup (struct srv_context **context)
 Cleanup resources associated with ast_srv_lookup. More...
 
int ast_srv_get_nth_record (struct srv_context *context, int record_num, const char **host, unsigned short *port, unsigned short *priority, unsigned short *weight)
 Retrieve details from a specific SRV record. More...
 
unsigned int ast_srv_get_record_count (struct srv_context *context)
 Get the number of records for a given SRV context. More...
 
int ast_srv_lookup (struct srv_context **context, const char *service, const char **host, unsigned short *port)
 Retrieve set of SRV lookups, in order. More...
 
static int parse_srv (unsigned char *answer, int len, unsigned char *msg, struct srv_entry **result)
 
static void process_weights (struct srv_context *context)
 
static int srv_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 

Detailed Description

DNS SRV Record Lookup Support for Asterisk.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Note
Funding provided by nic.at

Definition in file srv.c.

Function Documentation

int ast_get_srv ( struct ast_channel chan,
char *  host,
int  hostlen,
int *  port,
const char *  service 
)

Lookup entry in SRV records Returns 1 if found, 0 if not found, -1 on hangup Only do SRV record lookup if you get a domain without a port. If you get a port #, it's a DNS host name.

Parameters
chanAst channel
hosthost name (return value)
hostlenLength of string "host"
portPort number (return value)
serviceService tag for SRV lookup (like "_sip._udp" or "_stun._udp"

Definition at line 263 of file srv.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_free, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_search_dns(), ast_verb, srv_context::entries, srv_context::have_weights, srv_entry::host, srv_entry::port, process_weights(), and srv_callback().

Referenced by ast_get_ip_or_srv(), and create_addr().

264 {
265  struct srv_context context = { .entries = AST_LIST_HEAD_NOLOCK_INIT_VALUE };
266  struct srv_entry *current;
267  int ret;
268 
269  if (chan && ast_autoservice_start(chan) < 0) {
270  return -1;
271  }
272 
273  ret = ast_search_dns(&context, service, C_IN, T_SRV, srv_callback);
274 
275  if (context.have_weights) {
276  process_weights(&context);
277  }
278 
279  if (chan) {
280  ret |= ast_autoservice_stop(chan);
281  }
282 
283  /* TODO: there could be a "." entry in the returned list of
284  answers... if so, this requires special handling */
285 
286  /* the list of entries will be sorted in the proper selection order
287  already, so we just need the first one (if any) */
288 
289  if ((ret > 0) && (current = AST_LIST_REMOVE_HEAD(&context.entries, list))) {
290  ast_copy_string(host, current->host, hostlen);
291  *port = current->port;
292  ast_free(current);
293  ast_verb(4, "ast_get_srv: SRV lookup for '%s' mapped to host %s, port %d\n",
294  service, host, *port);
295  } else {
296  host[0] = '\0';
297  *port = -1;
298  }
299 
300  while ((current = AST_LIST_REMOVE_HEAD(&context.entries, list))) {
301  ast_free(current);
302  }
303 
304  return ret;
305 }
unsigned int have_weights
Definition: srv.c:70
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
char host[1]
Definition: srv.c:66
struct srv_entry::@300 list
static void process_weights(struct srv_context *context)
Definition: srv.c:154
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))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:259
enum ast_cc_service_type service
Definition: chan_sip.c:821
#define ast_verb(level,...)
Definition: logger.h:243
unsigned short port
Definition: srv.c:63
struct srv_context::srv_entries entries
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
Definition: srv.c:60
#define ast_free(a)
Definition: astmm.h:97
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:251
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
static int srv_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Definition: srv.c:117
void ast_srv_cleanup ( struct srv_context **  context)

Cleanup resources associated with ast_srv_lookup.

Parameters
contextPointer passed into ast_srv_lookup

Definition at line 251 of file srv.c.

References ast_srv_lookup(), srv_entry::host, and srv_entry::port.

Referenced by launch_ha_netscript(), srds_destroy_cb(), and srv_datastore_setup().

252 {
253  const char *host;
254  unsigned short port;
255 
256  if (*context) {
257  /* We have a context to clean up. */
258  while (!(ast_srv_lookup(context, NULL, &host, &port))) {
259  }
260  }
261 }
char host[1]
Definition: srv.c:66
unsigned short port
Definition: srv.c:63
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:206
int ast_srv_get_nth_record ( struct srv_context context,
int  record_num,
const char **  host,
unsigned short *  port,
unsigned short *  priority,
unsigned short *  weight 
)

Retrieve details from a specific SRV record.

After calling ast_srv_lookup, the srv_context will contain the data from several records. You can retrieve the data of a specific one by asking for a specific record number. The records are sorted based on priority and secondarily based on weight. See RFC 2782 for the exact sorting rules.

Parameters
contextThe context returned by ast_srv_lookup
record_numThe 1-indexed record number to retrieve
[out]hostThe host portion of the record
[out]portThe port portion of the record
[out]priorityThe priority portion of the record
[out]weightThe weight portion of the record
Return values
-1Failed to retrieve information. Likely due to an out of range record_num
0Success

Definition at line 312 of file srv.c.

References AST_LIST_TRAVERSE, srv_context::entries, srv_entry::host, srv_context::num_records, srv_entry::port, srv_entry::priority, and srv_entry::weight.

Referenced by srv_result_read().

314 {
315  int i = 1;
316  int res = -1;
317  struct srv_entry *entry;
318 
319  if (record_num < 1 || record_num > context->num_records) {
320  return res;
321  }
322 
323  AST_LIST_TRAVERSE(&context->entries, entry, list) {
324  if (i == record_num) {
325  *host = entry->host;
326  *port = entry->port;
327  *priority = entry->priority;
328  *weight = entry->weight;
329  res = 0;
330  break;
331  }
332  ++i;
333  }
334 
335  return res;
336 }
char host[1]
Definition: srv.c:66
struct srv_entry::@300 list
unsigned short port
Definition: srv.c:63
struct srv_context::srv_entries entries
unsigned short priority
Definition: srv.c:61
unsigned int num_records
Definition: srv.c:72
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Definition: srv.c:60
unsigned short weight
Definition: srv.c:62
unsigned int ast_srv_get_record_count ( struct srv_context context)

Get the number of records for a given SRV context.

This is meant to be used after calling ast_srv_lookup, so that one may retrieve the number of records returned during a specific SRV lookup.

Parameters
contextThe context returned by ast_srv_lookup
Returns
Number of records in context

Definition at line 307 of file srv.c.

References srv_context::num_records.

Referenced by srv_result_read().

308 {
309  return context->num_records;
310 }
unsigned int num_records
Definition: srv.c:72
int ast_srv_lookup ( struct srv_context **  context,
const char *  service,
const char **  host,
unsigned short *  port 
)

Retrieve set of SRV lookups, in order.

Parameters
[in]contextA pointer in which to hold the result
[in]serviceThe service name to look up
[out]hostResult host
[out]portAssociated TCP portnum
Return values
-1Query failed
0Result exists in host and port
1No more results

Definition at line 206 of file srv.c.

References ast_calloc, ast_free, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_search_dns(), process_weights(), and srv_callback().

Referenced by ast_srv_cleanup(), launch_ha_netscript(), and srv_datastore_setup().

207 {
208  struct srv_entry *cur;
209 
210  if (*context == NULL) {
211  if (!(*context = ast_calloc(1, sizeof(struct srv_context)))) {
212  return -1;
213  }
214  AST_LIST_HEAD_INIT_NOLOCK(&(*context)->entries);
215 
216  if ((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 0) {
217  ast_free(*context);
218  *context = NULL;
219  return -1;
220  }
221 
222  if ((*context)->have_weights) {
223  process_weights(*context);
224  }
225 
226  (*context)->prev = AST_LIST_FIRST(&(*context)->entries);
227  *host = (*context)->prev->host;
228  *port = (*context)->prev->port;
229  AST_LIST_TRAVERSE(&(*context)->entries, cur, list) {
230  ++((*context)->num_records);
231  }
232  return 0;
233  }
234 
235  if (((*context)->prev = AST_LIST_NEXT((*context)->prev, list))) {
236  /* Retrieve next item in result */
237  *host = (*context)->prev->host;
238  *port = (*context)->prev->port;
239  return 0;
240  } else {
241  /* No more results */
242  while ((cur = AST_LIST_REMOVE_HEAD(&(*context)->entries, list))) {
243  ast_free(cur);
244  }
245  ast_free(*context);
246  *context = NULL;
247  return 1;
248  }
249 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
char host[1]
Definition: srv.c:66
struct srv_entry::@300 list
static void process_weights(struct srv_context *context)
Definition: srv.c:154
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))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:259
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
enum ast_cc_service_type service
Definition: chan_sip.c:821
unsigned short port
Definition: srv.c:63
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Definition: srv.c:60
#define ast_free(a)
Definition: astmm.h:97
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:666
#define ast_calloc(a, b)
Definition: astmm.h:82
static int srv_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Definition: srv.c:117
static int parse_srv ( unsigned char *  answer,
int  len,
unsigned char *  msg,
struct srv_entry **  result 
)
static

Definition at line 76 of file srv.c.

References ast_calloc, ast_log(), srv_entry::host, LOG_WARNING, srv_entry::port, srv_entry::priority, and srv_entry::weight.

Referenced by srv_callback().

77 {
78  struct srv {
79  unsigned short priority;
80  unsigned short weight;
81  unsigned short port;
82  } __attribute__((__packed__)) *srv = (struct srv *) answer;
83 
84  int res = 0;
85  char repl[256] = "";
86  struct srv_entry *entry;
87 
88  if (len < sizeof(*srv))
89  return -1;
90 
91  answer += sizeof(*srv);
92  len -= sizeof(*srv);
93 
94  if ((res = dn_expand(msg, answer + len, answer, repl, sizeof(repl) - 1)) <= 0) {
95  ast_log(LOG_WARNING, "Failed to expand hostname\n");
96  return -1;
97  }
98 
99  /* the magic value "." for the target domain means that this service
100  is *NOT* available at the domain we searched */
101  if (!strcmp(repl, "."))
102  return -1;
103 
104  if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(repl))))
105  return -1;
106 
107  entry->priority = ntohs(srv->priority);
108  entry->weight = ntohs(srv->weight);
109  entry->port = ntohs(srv->port);
110  strcpy(entry->host, repl);
111 
112  *result = entry;
113 
114  return 0;
115 }
char host[1]
Definition: srv.c:66
#define LOG_WARNING
Definition: logger.h:144
unsigned short port
Definition: srv.c:63
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
unsigned short priority
Definition: srv.c:61
Definition: srv.c:60
#define ast_calloc(a, b)
Definition: astmm.h:82
unsigned short weight
Definition: srv.c:62
static void process_weights ( struct srv_context context)
static

Definition at line 154 of file srv.c.

References AST_LIST_APPEND_LIST, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_MOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_random(), srv_context::entries, srv_entry::priority, srv_entry::weight, and srv_entry::weight_sum.

Referenced by ast_get_srv(), and ast_srv_lookup().

155 {
156  struct srv_entry *current;
157  struct srv_entries newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
158 
159  while (AST_LIST_FIRST(&context->entries)) {
160  unsigned int random_weight;
161  unsigned int weight_sum;
162  unsigned short cur_priority = AST_LIST_FIRST(&context->entries)->priority;
163  struct srv_entries temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
164  weight_sum = 0;
165 
166  AST_LIST_TRAVERSE_SAFE_BEGIN(&context->entries, current, list) {
167  if (current->priority != cur_priority)
168  break;
169 
170  AST_LIST_MOVE_CURRENT(&temp_list, list);
171  }
173 
174  while (AST_LIST_FIRST(&temp_list)) {
175  weight_sum = 0;
176  AST_LIST_TRAVERSE(&temp_list, current, list)
177  current->weight_sum = weight_sum += current->weight;
178 
179  /* if all the remaining entries have weight == 0,
180  then just append them to the result list and quit */
181  if (weight_sum == 0) {
182  AST_LIST_APPEND_LIST(&newlist, &temp_list, list);
183  break;
184  }
185 
186  random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0)));
187 
188  AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) {
189  if (current->weight < random_weight)
190  continue;
191 
192  AST_LIST_MOVE_CURRENT(&newlist, list);
193  break;
194  }
196  }
197 
198  }
199 
200  /* now that the new list has been ordered,
201  put it in place */
202 
203  AST_LIST_APPEND_LIST(&context->entries, &newlist, list);
204 }
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
struct srv_context::srv_entries entries
long int ast_random(void)
Definition: utils.c:1640
#define AST_LIST_MOVE_CURRENT(newhead, field)
Definition: linkedlists.h:567
unsigned short priority
Definition: srv.c:61
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
Definition: srv.c:60
if(yyss+yystacksize-1<=yyssp)
Definition: ast_expr2.c:1874
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:251
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
unsigned short weight
Definition: srv.c:62
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:768
static int srv_callback ( void *  context,
unsigned char *  answer,
int  len,
unsigned char *  fullanswer 
)
static

Definition at line 117 of file srv.c.

References AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, srv_context::entries, srv_context::have_weights, parse_srv(), srv_entry::priority, and srv_entry::weight.

Referenced by ast_get_srv(), and ast_srv_lookup().

118 {
119  struct srv_context *c = (struct srv_context *) context;
120  struct srv_entry *entry = NULL;
121  struct srv_entry *current;
122 
123  if (parse_srv(answer, len, fullanswer, &entry))
124  return -1;
125 
126  if (entry->weight)
127  c->have_weights = 1;
128 
129  AST_LIST_TRAVERSE_SAFE_BEGIN(&c->entries, current, list) {
130  /* insert this entry just before the first existing
131  entry with a higher priority */
132  if (current->priority <= entry->priority)
133  continue;
134 
136  entry = NULL;
137  break;
138  }
140 
141  /* if we didn't find a place to insert the entry before an existing
142  entry, then just add it to the end */
143  if (entry)
144  AST_LIST_INSERT_TAIL(&c->entries, entry, list);
145 
146  return 0;
147 }
unsigned int have_weights
Definition: srv.c:70
struct srv_entry::@300 list
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
struct srv_context::srv_entries entries
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
unsigned short priority
Definition: srv.c:61
static int parse_srv(unsigned char *answer, int len, unsigned char *msg, struct srv_entry **result)
Definition: srv.c:76
Definition: srv.c:60
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:584
unsigned short weight
Definition: srv.c:62