Asterisk - The Open Source Telephony Project  21.4.1
pjsip_resolver.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 #include "asterisk.h"
20 
21 #include <pjsip.h>
22 #include <pjlib-util/errno.h>
23 
24 #include <arpa/nameser.h>
25 
26 #include "asterisk/astobj2.h"
27 #include "asterisk/dns_core.h"
28 #include "asterisk/dns_query_set.h"
29 #include "asterisk/dns_srv.h"
30 #include "asterisk/dns_naptr.h"
31 #include "asterisk/res_pjsip.h"
32 #include "include/res_pjsip_private.h"
33 #include "asterisk/taskprocessor.h"
34 #include "asterisk/threadpool.h"
35 
36 #ifdef HAVE_PJSIP_EXTERNAL_RESOLVER
37 
38 /*! \brief Structure which contains transport+port information for an active query */
39 struct sip_target {
40  /*! \brief The transport to be used */
41  pjsip_transport_type_e transport;
42  /*! \brief The port */
43  int port;
44 };
45 
46 /*! \brief The vector used for current targets */
48 
49 /*! \brief Structure which keeps track of resolution */
50 struct sip_resolve {
51  /*! \brief Addresses currently being resolved, indexed based on index of queries in query set */
53  /*! \brief Active queries */
55  /*! \brief Current viable server addresses */
56  pjsip_server_addresses addresses;
57  /*! \brief Serializer to run async callback into pjlib. */
59  /*! \brief Callback to invoke upon completion */
60  pjsip_resolver_callback *callback;
61  /*! \brief User provided data */
62  void *token;
63 };
64 
65 /*! \brief Our own defined transports, reduces the size of sip_available_transports */
66 enum sip_resolver_transport {
67  SIP_RESOLVER_TRANSPORT_UDP,
68  SIP_RESOLVER_TRANSPORT_TCP,
69  SIP_RESOLVER_TRANSPORT_TLS,
70  SIP_RESOLVER_TRANSPORT_UDP6,
71  SIP_RESOLVER_TRANSPORT_TCP6,
72  SIP_RESOLVER_TRANSPORT_TLS6,
73 };
74 
75 /*! \brief Available transports on the system */
76 static int sip_available_transports[] = {
77  /* This is a list of transports with whether they are available as a valid transport
78  * stored. We use our own identifier as to reduce the size of sip_available_transports.
79  * As this array is only manipulated at startup it does not require a lock to protect
80  * it.
81  */
82  [SIP_RESOLVER_TRANSPORT_UDP] = 0,
83  [SIP_RESOLVER_TRANSPORT_TCP] = 0,
84  [SIP_RESOLVER_TRANSPORT_TLS] = 0,
85  [SIP_RESOLVER_TRANSPORT_UDP6] = 0,
86  [SIP_RESOLVER_TRANSPORT_TCP6] = 0,
87  [SIP_RESOLVER_TRANSPORT_TLS6] = 0,
88 };
89 
90 /*!
91  * \internal
92  * \brief Destroy resolution data
93  *
94  * \param data The resolution data to destroy
95  */
96 static void sip_resolve_destroy(void *data)
97 {
98  struct sip_resolve *resolve = data;
99 
100  AST_VECTOR_FREE(&resolve->resolving);
101  ao2_cleanup(resolve->queries);
103 }
104 
105 /*!
106  * \internal
107  * \brief Check whether a transport is available or not
108  *
109  * \param transport The PJSIP transport type
110  *
111  * \return 1 success (transport is available)
112  * \return 0 failure (transport is not available)
113  */
114 static int sip_transport_is_available(enum pjsip_transport_type_e transport)
115 {
116  enum sip_resolver_transport resolver_transport;
117 
118  if (transport == PJSIP_TRANSPORT_UDP) {
119  resolver_transport = SIP_RESOLVER_TRANSPORT_UDP;
120  } else if (transport == PJSIP_TRANSPORT_TCP) {
121  resolver_transport = SIP_RESOLVER_TRANSPORT_TCP;
122  } else if (transport == PJSIP_TRANSPORT_TLS) {
123  resolver_transport = SIP_RESOLVER_TRANSPORT_TLS;
124  } else if (transport == PJSIP_TRANSPORT_UDP6) {
125  resolver_transport = SIP_RESOLVER_TRANSPORT_UDP6;
126  } else if (transport == PJSIP_TRANSPORT_TCP6) {
127  resolver_transport = SIP_RESOLVER_TRANSPORT_TCP6;
128  } else if (transport == PJSIP_TRANSPORT_TLS6) {
129  resolver_transport = SIP_RESOLVER_TRANSPORT_TLS6;
130  } else {
131  return 0;
132  }
133 
134  return sip_available_transports[resolver_transport];
135 }
136 
137 /*!
138  * \internal
139  * \brief Add a query to be resolved
140  *
141  * \param resolve The ongoing resolution
142  * \param name What to resolve
143  * \param rr_type The type of record to look up
144  * \param rr_class The type of class to look up
145  * \param transport The transport to use for any resulting records
146  * \param port The port to use for any resulting records - if not specified the
147  * default for the transport is used
148  *
149  * \retval 0 success
150  * \retval -1 failure
151  */
152 static int sip_resolve_add(struct sip_resolve *resolve, const char *name, int rr_type, int rr_class, pjsip_transport_type_e transport, int port)
153 {
154  struct sip_target target = {
155  .transport = transport,
156  .port = port,
157  };
158 
159  if (!resolve->queries) {
160  resolve->queries = ast_dns_query_set_create();
161  if (!resolve->queries) {
162  return -1;
163  }
164  }
165 
166  if (!port) {
167  target.port = pjsip_transport_get_default_port_for_type(transport);
168  }
169 
170  if (AST_VECTOR_APPEND(&resolve->resolving, target)) {
171  return -1;
172  }
173 
174  ast_debug(2, "[%p] Added target '%s' with record type '%d', transport '%s', and port '%d'\n",
175  resolve, name, rr_type, pjsip_transport_get_type_desc(transport), target.port);
176 
177  return ast_dns_query_set_add(resolve->queries, name, rr_type, rr_class);
178 }
179 
180 /*!
181  * \internal
182  * \brief Task used to invoke the user specific callback
183  *
184  * \param data The complete resolution
185  *
186  * \retval 0 Always
187  */
188 static int sip_resolve_invoke_user_callback(void *data)
189 {
190  struct sip_resolve *resolve = data;
191 
192  if (DEBUG_ATLEAST(2)) {
193  /* This includes space for the IP address, [, ], :, and the port */
194  char addr[PJ_INET6_ADDRSTRLEN + 10];
195  int idx;
196 
197  for (idx = 0; idx < resolve->addresses.count; ++idx) {
198  pj_sockaddr_print(&resolve->addresses.entry[idx].addr, addr, sizeof(addr), 3);
199  ast_log(LOG_DEBUG, "[%p] Address '%d' is %s with transport '%s'\n",
200  resolve, idx, addr,
201  pjsip_transport_get_type_desc(resolve->addresses.entry[idx].type));
202  }
203  }
204 
205  ast_debug(2, "[%p] Invoking user callback with '%d' addresses\n", resolve, resolve->addresses.count);
206  resolve->callback(resolve->addresses.count ? PJ_SUCCESS : PJLIB_UTIL_EDNSNOANSWERREC, resolve->token, &resolve->addresses);
207 
208  ao2_ref(resolve, -1);
209 
210  return 0;
211 }
212 
213 /*!
214  * \internal
215  * \brief Handle a NAPTR record according to RFC3263
216  *
217  * \param resolve The ongoing resolution
218  * \param record The NAPTR record itself
219  * \param service The service to look for
220  * \param transport The transport to use for resulting queries
221  *
222  * \retval 0 success
223  * \retval -1 failure (record not handled / supported)
224  */
225 static int sip_resolve_handle_naptr(struct sip_resolve *resolve, const struct ast_dns_record *record,
226  const char *service, pjsip_transport_type_e transport)
227 {
228  if (strcasecmp(ast_dns_naptr_get_service(record), service)) {
229  return -1;
230  }
231 
232  /* It is possible for us to receive an explicit transport that is already IPv6, in that case
233  * we can't turn it into an IPv6 transport and check. If it's not IPv6 though we need to check
234  * for both IPv4 and IPv6 as PJSIP does not provide enough differentiation to know that we
235  * want only IPv4.
236  */
237  if (!sip_transport_is_available(transport) &&
238  (!(transport & PJSIP_TRANSPORT_IPV6) && !sip_transport_is_available(transport | PJSIP_TRANSPORT_IPV6))) {
239  ast_debug(2, "[%p] NAPTR service %s skipped as transport is unavailable\n",
240  resolve, service);
241  return -1;
242  }
243 
244  if (strcasecmp(ast_dns_naptr_get_flags(record), "s")) {
245  ast_debug(2, "[%p] NAPTR service %s received with unsupported flags '%s'\n",
246  resolve, service, ast_dns_naptr_get_flags(record));
247  return -1;
248  }
249 
250  if (ast_strlen_zero(ast_dns_naptr_get_replacement(record))) {
251  return -1;
252  }
253 
254  return sip_resolve_add(resolve, ast_dns_naptr_get_replacement(record), T_SRV, C_IN,
255  transport, 0);
256 }
257 
258 /*!
259  * \internal
260  * \brief Query set callback function, invoked when all queries have completed
261  *
262  * \param query_set The completed query set
263  */
264 static void sip_resolve_callback(const struct ast_dns_query_set *query_set)
265 {
266  struct sip_resolve *resolve = ast_dns_query_set_get_data(query_set);
267  struct ast_dns_query_set *queries = resolve->queries;
268  struct targets resolving;
269  int idx, address_count = 0, have_naptr = 0, have_srv = 0;
270  unsigned short order = 0;
271  int strict_order = 0;
272 
273  ast_debug(2, "[%p] All parallel queries completed\n", resolve);
274 
275  resolve->queries = NULL;
276 
277  /* This purposely steals the resolving list so we can add entries to the new one in
278  * the same loop and also have access to the old.
279  */
280  resolving = resolve->resolving;
281  AST_VECTOR_INIT(&resolve->resolving, 0);
282 
283  /* The order of queries is what defines the preference order for the records within
284  * this specific query set. The preference order overall is defined as a result of
285  * drilling down from other records. Each completed query set replaces the results
286  * of the last.
287  */
288  for (idx = 0; idx < ast_dns_query_set_num_queries(queries); ++idx) {
289  struct ast_dns_query *query = ast_dns_query_set_get(queries, idx);
290  struct ast_dns_result *result = ast_dns_query_get_result(query);
291  struct sip_target *target;
292  const struct ast_dns_record *record;
293 
294  if (!result) {
295  ast_debug(2, "[%p] No result information for target '%s' of type '%d'\n", resolve,
297  continue;
298  }
299 
300  target = AST_VECTOR_GET_ADDR(&resolving, idx);
301  for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
302 
303  if (ast_dns_record_get_rr_type(record) == T_A ||
304  ast_dns_record_get_rr_type(record) == T_AAAA) {
305  /* If NAPTR or SRV records exist the subsequent results from them take preference */
306  if (have_naptr || have_srv) {
307  ast_debug(2, "[%p] %s record being skipped on target '%s' because NAPTR or SRV record exists\n",
308  resolve, ast_dns_record_get_rr_type(record) == T_A ? "A" : "AAAA",
309  ast_dns_query_get_name(query));
310  continue;
311  }
312 
313  /* PJSIP has a fixed maximum number of addresses that can exist, so limit ourselves to that */
314  if (address_count == PJSIP_MAX_RESOLVED_ADDRESSES) {
315  break;
316  }
317 
318  resolve->addresses.entry[address_count].type = target->transport;
319 
320  /* Populate address information for the new address entry */
321  if (ast_dns_record_get_rr_type(record) == T_A) {
322  ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
323  resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in);
324  pj_sockaddr_init(pj_AF_INET(), &resolve->addresses.entry[address_count].addr, NULL,
325  target->port);
326  resolve->addresses.entry[address_count].addr.ipv4.sin_addr = *(pj_in_addr *) ast_dns_record_get_data(record);
327  } else {
328  ast_debug(2, "[%p] AAAA record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
329  resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in6);
330  pj_sockaddr_init(pj_AF_INET6(), &resolve->addresses.entry[address_count].addr, NULL,
331  target->port);
332  pj_memcpy(&resolve->addresses.entry[address_count].addr.ipv6.sin6_addr, ast_dns_record_get_data(record),
334  }
335 
336  address_count++;
337  } else if (ast_dns_record_get_rr_type(record) == T_SRV) {
338  if (have_naptr) {
339  ast_debug(2, "[%p] SRV record being skipped on target '%s' because NAPTR record exists\n",
340  resolve, ast_dns_query_get_name(query));
341  continue;
342  }
343 
344  /* SRV records just create new queries for AAAA+A, nothing fancy */
345  ast_debug(2, "[%p] SRV record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
346 
347  /* If an explicit IPv6 target transport has been requested look for only AAAA records */
348  if ((target->transport & PJSIP_TRANSPORT_IPV6) &&
349  sip_transport_is_available(target->transport)) {
350  sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport,
351  ast_dns_srv_get_port(record));
352  have_srv = 1;
353  } else if (!(target->transport & PJSIP_TRANSPORT_IPV6) &&
354  sip_transport_is_available(target->transport | PJSIP_TRANSPORT_IPV6)) {
355  sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport | PJSIP_TRANSPORT_IPV6,
356  ast_dns_srv_get_port(record));
357  have_srv = 1;
358  }
359 
360  if (!(target->transport & PJSIP_TRANSPORT_IPV6) &&
361  sip_transport_is_available(target->transport)) {
362  sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_A, C_IN, target->transport,
363  ast_dns_srv_get_port(record));
364  have_srv = 1;
365  }
366  } else if (ast_dns_record_get_rr_type(record) == T_NAPTR) {
367  int added = -1;
368 
369  ast_debug(2, "[%p] NAPTR record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
370 
371  if (strict_order && (ast_dns_naptr_get_order(record) != order)) {
372  ast_debug(2, "[%p] NAPTR record skipped because order '%hu' does not match strict order '%hu'\n",
373  resolve, ast_dns_naptr_get_order(record), order);
374  continue;
375  }
376 
377  if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_UDP ||
378  target->transport == PJSIP_TRANSPORT_UDP6) {
379  added = sip_resolve_handle_naptr(resolve, record, "sip+d2u",
380  target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : target->transport);
381  }
382  if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TCP ||
383  target->transport == PJSIP_TRANSPORT_TCP6) {
384  added = sip_resolve_handle_naptr(resolve, record, "sip+d2t",
385  target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : target->transport);
386  }
387  if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TLS ||
388  target->transport == PJSIP_TRANSPORT_TLS6) {
389  added = sip_resolve_handle_naptr(resolve, record, "sips+d2t",
390  target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : target->transport);
391  }
392 
393  /* If this record was successfully handled then we need to limit ourselves to this order */
394  if (!added) {
395  have_naptr = 1;
396  strict_order = 1;
397  order = ast_dns_naptr_get_order(record);
398  }
399  }
400  }
401  }
402 
403  /* Update the server addresses count, this is not limited as it can never exceed the max allowed */
404  resolve->addresses.count = address_count;
405 
406  /* Free the vector we stole as we are responsible for it */
407  AST_VECTOR_FREE(&resolving);
408 
409  /* If additional queries were added start the resolution process again */
410  if (resolve->queries) {
411  ast_debug(2, "[%p] New queries added, performing parallel resolution again\n", resolve);
412  ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve);
413  ao2_ref(queries, -1);
414  return;
415  }
416 
417  ast_debug(2, "[%p] Resolution completed - %d viable targets\n", resolve, resolve->addresses.count);
418 
419  /* Push a task to invoke the callback, we do this so it is guaranteed to run in a PJSIP thread */
420  ao2_ref(resolve, +1);
421  if (ast_sip_push_task(resolve->serializer, sip_resolve_invoke_user_callback, resolve)) {
422  ao2_ref(resolve, -1);
423  }
424 
425  ao2_ref(queries, -1);
426 }
427 
428 /*!
429  * \internal
430  * \brief Determine what address family a host may be if it is already an IP address
431  *
432  * \param host The host (which may be an IP address)
433  *
434  * \retval 6 The host is an IPv6 address
435  * \retval 4 The host is an IPv4 address
436  * \retval 0 The host is not an IP address
437  */
438 static int sip_resolve_get_ip_addr_ver(const pj_str_t *host)
439 {
440  pj_in_addr dummy;
441  pj_in6_addr dummy6;
442 
443  if (pj_inet_aton(host, &dummy) > 0) {
444  return 4;
445  }
446 
447  if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) {
448  return 6;
449  }
450 
451  return 0;
452 }
453 
454 /*!
455  * \internal
456  * \brief Perform SIP resolution of a host
457  *
458  * \param resolver Configured resolver instance
459  * \param pool Memory pool to allocate things from
460  * \param target The target we are resolving
461  * \param token User data to pass to the resolver callback
462  * \param cb User resolver callback to invoke upon resolution completion
463  */
464 static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target,
465  void *token, pjsip_resolver_callback *cb)
466 {
467  int ip_addr_ver;
468  pjsip_transport_type_e type = target->type;
469  struct sip_resolve *resolve;
470  char host[NI_MAXHOST];
471  int res = 0;
472 
473  ast_copy_pj_str(host, &target->addr.host, sizeof(host));
474 
475  ast_debug(2, "Performing SIP DNS resolution of target '%s'\n", host);
476 
477  /* If the provided target is already an address don't bother resolving */
478  ip_addr_ver = sip_resolve_get_ip_addr_ver(&target->addr.host);
479 
480  /* Determine the transport to use if none has been explicitly specified */
481  if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
482  /* If we've been told to use a secure or reliable transport restrict ourselves to that */
483 #if PJ_HAS_TCP
484  if (target->flag & PJSIP_TRANSPORT_SECURE) {
485  type = PJSIP_TRANSPORT_TLS;
486  } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) {
487  type = PJSIP_TRANSPORT_TCP;
488  } else
489 #endif
490  /* According to the RFC otherwise if an explicit IP address OR an explicit port is specified
491  * we use UDP
492  */
493  if (ip_addr_ver || target->addr.port) {
494  type = PJSIP_TRANSPORT_UDP;
495  }
496 
497  if (ip_addr_ver == 6) {
498  type = (pjsip_transport_type_e)((int) type | PJSIP_TRANSPORT_IPV6);
499  }
500  }
501 
502  ast_debug(2, "Transport type for target '%s' is '%s'\n", host, pjsip_transport_get_type_desc(type));
503 
504  /* If it's already an address call the callback immediately */
505  if (ip_addr_ver) {
506  pjsip_server_addresses addresses = {
507  .entry[0].type = type,
508  .count = 1,
509  };
510 
511  if (ip_addr_ver == 4) {
512  addresses.entry[0].addr_len = sizeof(pj_sockaddr_in);
513  pj_sockaddr_init(pj_AF_INET(), &addresses.entry[0].addr, NULL, 0);
514  pj_inet_aton(&target->addr.host, &addresses.entry[0].addr.ipv4.sin_addr);
515  } else {
516  addresses.entry[0].addr_len = sizeof(pj_sockaddr_in6);
517  pj_sockaddr_init(pj_AF_INET6(), &addresses.entry[0].addr, NULL, 0);
518  pj_inet_pton(pj_AF_INET6(), &target->addr.host, &addresses.entry[0].addr.ipv6.sin6_addr);
519  }
520 
521  pj_sockaddr_set_port(&addresses.entry[0].addr, !target->addr.port ? pjsip_transport_get_default_port_for_type(type) : target->addr.port);
522 
523  ast_debug(2, "Target '%s' is an IP address, skipping resolution\n", host);
524 
525  cb(PJ_SUCCESS, token, &addresses);
526 
527  return;
528  }
529 
530  resolve = ao2_alloc_options(sizeof(*resolve), sip_resolve_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
531  if (!resolve) {
532  cb(PJ_ENOMEM, token, NULL);
533  return;
534  }
535 
536  resolve->callback = cb;
537  resolve->token = token;
538 
539  if (AST_VECTOR_INIT(&resolve->resolving, 4)) {
540  ao2_ref(resolve, -1);
541  cb(PJ_ENOMEM, token, NULL);
542  return;
543  }
544 
545  ast_debug(2, "[%p] Created resolution tracking for target '%s'\n", resolve, host);
546 
547  /* If no port has been specified we can do NAPTR + SRV */
548  if (!target->addr.port) {
549  char srv[NI_MAXHOST];
550 
551  /* When resolving addresses PJSIP can request an explicit transport type. It will explicitly
552  * request an IPv6 transport if a message has been tagged to use an explicitly IPv6 transport.
553  * For other cases it can be left unspecified OR an explicit non-IPv6 transport can be requested.
554  * In the case where a non-IPv6 transport is requested there is no way to differentiate between
555  * a transport being requested as part of a SIP URI (sip:test.com;transport=tcp) and a message
556  * being tagged with a specific IPv4 transport. In this case we look for both IPv4 and IPv6 addresses.
557  * If a message has been tagged with a specific IPv4 transport the IPv6 addresses will simply
558  * be discarded. The code below and elsewhere handles the case where we know they requested IPv6
559  * explicitly and only looks for IPv6 records.
560  */
561 
562  res |= sip_resolve_add(resolve, host, T_NAPTR, C_IN, type, 0);
563 
564  if (type == PJSIP_TRANSPORT_UNSPECIFIED ||
565  (type == PJSIP_TRANSPORT_TLS && sip_transport_is_available(PJSIP_TRANSPORT_TLS)) ||
566  (type == PJSIP_TRANSPORT_TLS6 && sip_transport_is_available(PJSIP_TRANSPORT_TLS6))) {
567  if (snprintf(srv, sizeof(srv), "_sips._tcp.%s", host) < NI_MAXHOST) {
568  res |= sip_resolve_add(resolve, srv, T_SRV, C_IN,
569  type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : type, 0);
570  }
571  }
572  if (type == PJSIP_TRANSPORT_UNSPECIFIED ||
573  (type == PJSIP_TRANSPORT_TCP && sip_transport_is_available(PJSIP_TRANSPORT_TCP)) ||
574  (type == PJSIP_TRANSPORT_TCP6 && sip_transport_is_available(PJSIP_TRANSPORT_TCP6))) {
575  if (snprintf(srv, sizeof(srv), "_sip._tcp.%s", host) < NI_MAXHOST) {
576  res |= sip_resolve_add(resolve, srv, T_SRV, C_IN,
577  type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : type, 0);
578  }
579  }
580  if (type == PJSIP_TRANSPORT_UNSPECIFIED ||
581  (type == PJSIP_TRANSPORT_UDP && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) ||
582  (type == PJSIP_TRANSPORT_UDP6 && sip_transport_is_available(PJSIP_TRANSPORT_UDP6))) {
583  if (snprintf(srv, sizeof(srv), "_sip._udp.%s", host) < NI_MAXHOST) {
584  res |= sip_resolve_add(resolve, srv, T_SRV, C_IN,
585  type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type, 0);
586  }
587  }
588  }
589 
590  if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP6)) ||
591  ((type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type))) {
592  res |= sip_resolve_add(resolve, host, T_AAAA, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP6 : type), target->addr.port);
593  } else if (!(type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type | PJSIP_TRANSPORT_IPV6)) {
594  res |= sip_resolve_add(resolve, host, T_AAAA, C_IN, type | PJSIP_TRANSPORT_IPV6, target->addr.port);
595  }
596 
597  if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) ||
598  (!(type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type))) {
599  res |= sip_resolve_add(resolve, host, T_A, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port);
600  }
601 
602  if (res) {
603  ao2_ref(resolve, -1);
604  cb(PJ_ENOMEM, token, NULL);
605  return;
606  }
607  if (!resolve->queries) {
608  ast_debug(2, "[%p] No resolution queries for target '%s'\n", resolve, host);
609  ao2_ref(resolve, -1);
610  cb(PJLIB_UTIL_EDNSNOANSWERREC, token, NULL);
611  return;
612  }
613 
614  resolve->serializer = ao2_bump(ast_threadpool_serializer_get_current());
615 
616  ast_debug(2, "[%p] Starting initial resolution using parallel queries for target '%s'\n", resolve, host);
617  ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve);
618 
619  ao2_ref(resolve, -1);
620 }
621 
622 /*!
623  * \internal
624  * \brief Determine if a specific transport is configured on the system
625  *
626  * \param pool A memory pool to allocate things from
627  * \param transport The type of transport to check
628  * \param name A friendly name to print in the verbose message
629  */
630 static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e transport, const char *name)
631 {
632  pjsip_tpmgr_fla2_param prm;
633  enum sip_resolver_transport resolver_transport;
634 
635  pjsip_tpmgr_fla2_param_default(&prm);
636  prm.tp_type = transport;
637 
638  if (transport == PJSIP_TRANSPORT_UDP) {
639  resolver_transport = SIP_RESOLVER_TRANSPORT_UDP;
640  } else if (transport == PJSIP_TRANSPORT_TCP) {
641  resolver_transport = SIP_RESOLVER_TRANSPORT_TCP;
642  } else if (transport == PJSIP_TRANSPORT_TLS) {
643  resolver_transport = SIP_RESOLVER_TRANSPORT_TLS;
644  } else if (transport == PJSIP_TRANSPORT_UDP6) {
645  resolver_transport = SIP_RESOLVER_TRANSPORT_UDP6;
646  } else if (transport == PJSIP_TRANSPORT_TCP6) {
647  resolver_transport = SIP_RESOLVER_TRANSPORT_TCP6;
648  } else if (transport == PJSIP_TRANSPORT_TLS6) {
649  resolver_transport = SIP_RESOLVER_TRANSPORT_TLS6;
650  } else {
651  ast_verb(2, "'%s' is an unsupported SIP transport\n", name);
652  return;
653  }
654 
655  if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
656  pool, &prm) == PJ_SUCCESS) {
657  ast_verb(2, "'%s' is an available SIP transport\n", name);
658  sip_available_transports[resolver_transport] = 1;
659  } else {
660  ast_verb(2, "'%s' is not an available SIP transport, disabling resolver support for it\n",
661  name);
662  }
663 }
664 
665 /*! \brief External resolver implementation for PJSIP */
666 static pjsip_ext_resolver ext_resolver = {
667  .resolve = sip_resolve,
668 };
669 
670 /*!
671  * \internal
672  * \brief Task to determine available transports and set ourselves an external resolver
673  *
674  * \retval 0 success
675  * \retval -1 failure
676  */
677 static int sip_replace_resolver(void *data)
678 {
679  pj_pool_t *pool;
680 
681 
682  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Transport Availability", 256, 256);
683  if (!pool) {
684  return -1;
685  }
686 
687  /* Determine what transports are available on the system */
688  sip_check_transport(pool, PJSIP_TRANSPORT_UDP, "UDP+IPv4");
689  sip_check_transport(pool, PJSIP_TRANSPORT_TCP, "TCP+IPv4");
690  sip_check_transport(pool, PJSIP_TRANSPORT_TLS, "TLS+IPv4");
691  sip_check_transport(pool, PJSIP_TRANSPORT_UDP6, "UDP+IPv6");
692  sip_check_transport(pool, PJSIP_TRANSPORT_TCP6, "TCP+IPv6");
693  sip_check_transport(pool, PJSIP_TRANSPORT_TLS6, "TLS+IPv6");
694 
695  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
696 
697  /* Replace the PJSIP resolver with our own implementation */
698  pjsip_endpt_set_ext_resolver(ast_sip_get_pjsip_endpoint(), &ext_resolver);
699  return 0;
700 }
701 
702 void ast_sip_initialize_resolver(void)
703 {
704  /* Replace the existing PJSIP resolver with our own implementation */
705  ast_sip_push_task_wait_servant(NULL, sip_replace_resolver, NULL);
706 }
707 
708 #else
709 
710 void ast_sip_initialize_resolver(void)
711 {
712  /* External resolver support does not exist in the version of PJSIP in use */
713  ast_log(LOG_NOTICE, "The version of PJSIP in use does not support external resolvers, using PJSIP provided resolver\n");
714 }
715 
716 #endif
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
Definition: dns_core.c:170
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
Definition: dns_core.c:160
const char * ast_dns_query_get_name(const struct ast_dns_query *query)
Get the name queried in a DNS query.
Definition: dns_core.c:57
For AST_LIST.
Definition: dns_internal.h:39
static pj_pool_t * pool
Global memory pool for configuration and timers.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
struct ast_dns_query_set * ast_dns_query_set_create(void)
Create a query set to hold queries.
Definition: dns_query_set.c:60
size_t ast_dns_record_get_data_size(const struct ast_dns_record *record)
Retrieve the size of the raw DNS record.
Definition: dns_core.c:165
pjsip_server_addresses addresses
Current viable server addresses.
The vector used for current targets.
int port
The port.
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
Definition: dns_naptr.c:608
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record)
Get the port from an SRV record.
Definition: dns_srv.c:212
const char * ast_dns_srv_get_host(const struct ast_dns_record *record)
Get the hostname from an SRV record.
Definition: dns_srv.c:188
pjsip_transport_type_e transport
The transport to be used.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void * token
User provided data.
Structure which contains transport+port information for an active query.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668
pjsip_resolver_callback * callback
Callback to invoke upon completion.
struct ast_dns_query * ast_dns_query_set_get(const struct ast_dns_query_set *query_set, unsigned int index)
Retrieve a query from a query set.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
struct ast_dns_query_set * queries
Active queries.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
The result of a DNS query.
Definition: dns_internal.h:117
DNS Query Set API.
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
Definition: dns_naptr.c:600
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:2099
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
Definition: dns_core.c:77
A DNS query.
Definition: dns_internal.h:137
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
Definition: dns_core.c:102
An API for managing task processing threads that can be shared across modules.
struct targets resolving
Addresses currently being resolved, indexed based on index of queries in query set.
int ast_dns_query_get_rr_type(const struct ast_dns_query *query)
Get the record resource type of a DNS query.
Definition: dns_core.c:62
DNS NAPTR Record Parsing API.
unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
Get the order from a NAPTR record.
Definition: dns_naptr.c:632
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int ast_dns_query_set_add(struct ast_dns_query_set *query_set, const char *name, int rr_type, int rr_class)
Add a query to a query set.
struct ast_taskprocessor * serializer
Serializer to run async callback into pjlib.
const char * ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
Get the replacement value from a NAPTR record.
Definition: dns_naptr.c:624
DNS SRV Record Parsing API.
size_t ast_dns_query_set_num_queries(const struct ast_dns_query_set *query_set)
Retrieve the number of queries in a query set.
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
A set of DNS queries.
Definition: dns_internal.h:185
void ast_dns_query_set_resolve_async(struct ast_dns_query_set *query_set, ast_dns_query_set_callback callback, void *data)
Asynchronously resolve queries in a query set.
Core DNS API.
void * ast_dns_query_set_get_data(const struct ast_dns_query_set *query_set)
Retrieve user specific data from a query set.
Structure which keeps track of resolution.