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