Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Enumerations | Functions | Variables
pjsip_resolver.c File Reference
#include "asterisk.h"
#include <pjsip.h>
#include <pjlib-util/errno.h>
#include <arpa/nameser.h>
#include "asterisk/astobj2.h"
#include "asterisk/dns_core.h"
#include "asterisk/dns_query_set.h"
#include "asterisk/dns_srv.h"
#include "asterisk/dns_naptr.h"
#include "asterisk/res_pjsip.h"
#include "include/res_pjsip_private.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/threadpool.h"
Include dependency graph for pjsip_resolver.c:

Go to the source code of this file.

Data Structures

struct  sip_resolve
 Structure which keeps track of resolution. More...
 
struct  sip_target
 Structure which contains transport+port information for an active query. More...
 

Enumerations

enum  sip_resolver_transport {
  SIP_RESOLVER_TRANSPORT_UDP, SIP_RESOLVER_TRANSPORT_TCP, SIP_RESOLVER_TRANSPORT_TLS, SIP_RESOLVER_TRANSPORT_UDP6,
  SIP_RESOLVER_TRANSPORT_TCP6, SIP_RESOLVER_TRANSPORT_TLS6
}
 Our own defined transports, reduces the size of sip_available_transports. More...
 

Functions

void ast_sip_initialize_resolver (void)
 
 AST_VECTOR (targets, struct sip_target)
 The vector used for current targets. More...
 
static void sip_check_transport (pj_pool_t *pool, pjsip_transport_type_e transport, const char *name)
 
static int sip_replace_resolver (void *data)
 
static void sip_resolve (pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target, void *token, pjsip_resolver_callback *cb)
 
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)
 
static void sip_resolve_callback (const struct ast_dns_query_set *query_set)
 
static void sip_resolve_destroy (void *data)
 
static int sip_resolve_get_ip_addr_ver (const pj_str_t *host)
 
static int sip_resolve_handle_naptr (struct sip_resolve *resolve, const struct ast_dns_record *record, const char *service, pjsip_transport_type_e transport)
 
static int sip_resolve_invoke_user_callback (void *data)
 
static int sip_transport_is_available (enum pjsip_transport_type_e transport)
 

Variables

static pjsip_ext_resolver ext_resolver
 External resolver implementation for PJSIP. More...
 
static int sip_available_transports []
 Available transports on the system. More...
 

Enumeration Type Documentation

◆ sip_resolver_transport

Our own defined transports, reduces the size of sip_available_transports.

Enumerator
SIP_RESOLVER_TRANSPORT_UDP 
SIP_RESOLVER_TRANSPORT_TCP 
SIP_RESOLVER_TRANSPORT_TLS 
SIP_RESOLVER_TRANSPORT_UDP6 
SIP_RESOLVER_TRANSPORT_TCP6 
SIP_RESOLVER_TRANSPORT_TLS6 

Definition at line 66 of file pjsip_resolver.c.

Function Documentation

◆ ast_sip_initialize_resolver()

void ast_sip_initialize_resolver ( void  )

Definition at line 708 of file pjsip_resolver.c.

References ast_log, ast_sip_push_task_wait_servant(), LOG_NOTICE, NULL, and sip_replace_resolver().

Referenced by load_module().

709 {
710  /* Replace the existing PJSIP resolver with our own implementation */
712 }
#define NULL
Definition: resample.c:96
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
static int sip_replace_resolver(void *data)

◆ AST_VECTOR()

AST_VECTOR ( targets  ,
struct sip_target   
)

The vector used for current targets.

◆ sip_check_transport()

static void sip_check_transport ( pj_pool_t *  pool,
pjsip_transport_type_e  transport,
const char *  name 
)
static

Definition at line 636 of file pjsip_resolver.c.

References ast_sip_get_pjsip_endpoint(), ast_verb, sip_available_transports, SIP_RESOLVER_TRANSPORT_TCP, SIP_RESOLVER_TRANSPORT_TCP6, SIP_RESOLVER_TRANSPORT_TLS, SIP_RESOLVER_TRANSPORT_TLS6, SIP_RESOLVER_TRANSPORT_UDP, SIP_RESOLVER_TRANSPORT_UDP6, and sip_target::transport.

Referenced by sip_replace_resolver().

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 }
static int sip_available_transports[]
Available transports on the system.
static pj_pool_t * pool
Global memory pool for configuration and timers.
#define ast_verb(level,...)
Definition: logger.h:463
static const char name[]
Definition: cdr_mysql.c:74
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
sip_resolver_transport
Our own defined transports, reduces the size of sip_available_transports.

◆ sip_replace_resolver()

static int sip_replace_resolver ( void *  data)
static

Definition at line 683 of file pjsip_resolver.c.

References ast_sip_get_pjsip_endpoint(), ext_resolver, pool, and sip_check_transport().

Referenced by ast_sip_initialize_resolver().

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 }
static pj_pool_t * pool
Global memory pool for configuration and timers.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e transport, const char *name)
static pjsip_ext_resolver ext_resolver
External resolver implementation for PJSIP.

◆ sip_resolve()

static void sip_resolve ( pjsip_resolver_t *  resolver,
pj_pool_t *  pool,
const pjsip_host_info *  target,
void *  token,
pjsip_resolver_callback *  cb 
)
static

Definition at line 468 of file pjsip_resolver.c.

References sip_resolve::addresses, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_ref, ast_copy_pj_str(), ast_debug, ast_dns_query_set_resolve_async(), ast_threadpool_serializer_get_current(), AST_VECTOR_INIT, sip_resolve::callback, host, NULL, sip_resolve::queries, sip_resolve::resolving, sip_resolve::serializer, sip_resolve_add(), sip_resolve_callback(), sip_resolve_destroy(), sip_resolve_get_ip_addr_ver(), sip_transport_is_available(), sip_resolve::token, and type.

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 }
static const char type[]
Definition: chan_ooh323.c:109
static void sip_resolve_destroy(void *data)
pjsip_server_addresses addresses
Current viable server addresses.
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
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
struct ast_taskprocessor * ast_threadpool_serializer_get_current(void)
Get the threadpool serializer currently associated with this thread.
Definition: threadpool.c:1397
static void sip_resolve_callback(const struct ast_dns_query_set *query_set)
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
void * token
User provided data.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static char host[256]
Definition: muted.c:77
pjsip_resolver_callback * callback
Callback to invoke upon completion.
#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)
static int sip_transport_is_available(enum pjsip_transport_type_e transport)
struct targets resolving
Addresses currently being resolved, indexed based on index of queries in query set.
struct ast_taskprocessor * serializer
Serializer to run async callback into pjlib.
static int sip_resolve_get_ip_addr_ver(const pj_str_t *host)
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.
Structure which keeps track of resolution.

◆ sip_resolve_add()

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 
)
static

Definition at line 154 of file pjsip_resolver.c.

References ast_debug, ast_dns_query_set_add(), ast_dns_query_set_create(), AST_VECTOR_APPEND, sip_target::port, sip_resolve::queries, sip_resolve::resolving, and sip_target::transport.

Referenced by sip_resolve(), sip_resolve_callback(), and sip_resolve_handle_naptr().

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 }
#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
int port
The port.
pjsip_transport_type_e transport
The transport to be used.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure which contains transport+port information for an active query.
struct ast_dns_query_set * queries
Active queries.
static const char name[]
Definition: cdr_mysql.c:74
struct targets resolving
Addresses currently being resolved, indexed based on index of queries in query set.
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.

◆ sip_resolve_callback()

static void sip_resolve_callback ( const struct ast_dns_query_set query_set)
static

Definition at line 268 of file pjsip_resolver.c.

References sip_resolve::addresses, ao2_ref, ast_debug, ast_dns_naptr_get_order(), ast_dns_query_get_name(), ast_dns_query_get_result(), ast_dns_query_get_rr_type(), ast_dns_query_set_get(), ast_dns_query_set_get_data(), ast_dns_query_set_num_queries(), ast_dns_query_set_resolve_async(), ast_dns_record_get_data(), ast_dns_record_get_data_size(), ast_dns_record_get_next(), ast_dns_record_get_rr_type(), ast_dns_result_get_records(), ast_dns_srv_get_host(), ast_dns_srv_get_port(), ast_sip_push_task(), AST_VECTOR_FREE, AST_VECTOR_GET_ADDR, AST_VECTOR_INIT, NULL, order, sip_target::port, sip_resolve::queries, sip_resolve::resolving, result, sip_resolve::serializer, sip_resolve_add(), sip_resolve_handle_naptr(), sip_resolve_invoke_user_callback(), sip_transport_is_available(), and sip_target::transport.

Referenced by sip_resolve().

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 }
#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
static int sip_resolve_invoke_user_callback(void *data)
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
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.
int port
The port.
#define NULL
Definition: resample.c:96
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
pjsip_transport_type_e transport
The transport to be used.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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:670
integer order
Definition: analys.c:66
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
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
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
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)
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
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
struct ast_taskprocessor * serializer
Serializer to run async callback into pjlib.
static PGresult * result
Definition: cel_pgsql.c:88
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.
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_resolve_destroy()

static void sip_resolve_destroy ( void *  data)
static

Definition at line 98 of file pjsip_resolver.c.

References ao2_cleanup, ast_taskprocessor_unreference(), AST_VECTOR_FREE, sip_resolve::queries, sip_resolve::resolving, and sip_resolve::serializer.

Referenced by sip_resolve().

99 {
100  struct sip_resolve *resolve = data;
101 
102  AST_VECTOR_FREE(&resolve->resolving);
103  ao2_cleanup(resolve->queries);
105 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_dns_query_set * queries
Active queries.
struct targets resolving
Addresses currently being resolved, indexed based on index of queries in query set.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct ast_taskprocessor * serializer
Serializer to run async callback into pjlib.
Structure which keeps track of resolution.

◆ sip_resolve_get_ip_addr_ver()

static int sip_resolve_get_ip_addr_ver ( const pj_str_t *  host)
static

Definition at line 442 of file pjsip_resolver.c.

References dummy().

Referenced by sip_resolve().

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 }
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
static char host[256]
Definition: muted.c:77

◆ sip_resolve_handle_naptr()

static int sip_resolve_handle_naptr ( struct sip_resolve resolve,
const struct ast_dns_record record,
const char *  service,
pjsip_transport_type_e  transport 
)
static

Definition at line 227 of file pjsip_resolver.c.

References ast_debug, ast_dns_naptr_get_flags(), ast_dns_naptr_get_replacement(), ast_dns_naptr_get_service(), ast_strlen_zero, sip_resolve_add(), and sip_transport_is_available().

Referenced by sip_resolve_callback().

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 }
enum ast_cc_service_type service
Definition: chan_sip.c:949
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
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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)
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
static int sip_transport_is_available(enum pjsip_transport_type_e transport)
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

◆ sip_resolve_invoke_user_callback()

static int sip_resolve_invoke_user_callback ( void *  data)
static

Definition at line 190 of file pjsip_resolver.c.

References sip_resolve::addresses, ao2_ref, ast_debug, ast_log, sip_resolve::callback, DEBUG_ATLEAST, LOG_DEBUG, and sip_resolve::token.

Referenced by sip_resolve_callback().

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 }
pjsip_server_addresses addresses
Current viable server addresses.
#define LOG_DEBUG
Definition: logger.h:241
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
void * token
User provided data.
pjsip_resolver_callback * callback
Callback to invoke upon completion.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define DEBUG_ATLEAST(level)
Definition: logger.h:441
Structure which keeps track of resolution.

◆ sip_transport_is_available()

static int sip_transport_is_available ( enum pjsip_transport_type_e  transport)
static

Definition at line 116 of file pjsip_resolver.c.

References sip_available_transports, SIP_RESOLVER_TRANSPORT_TCP, SIP_RESOLVER_TRANSPORT_TCP6, SIP_RESOLVER_TRANSPORT_TLS, SIP_RESOLVER_TRANSPORT_TLS6, SIP_RESOLVER_TRANSPORT_UDP, and SIP_RESOLVER_TRANSPORT_UDP6.

Referenced by sip_resolve(), sip_resolve_callback(), and sip_resolve_handle_naptr().

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 }
static int sip_available_transports[]
Available transports on the system.
sip_resolver_transport
Our own defined transports, reduces the size of sip_available_transports.

Variable Documentation

◆ ext_resolver

pjsip_ext_resolver ext_resolver
static
Initial value:
= {
.resolve = sip_resolve,
}
static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target, void *token, pjsip_resolver_callback *cb)

External resolver implementation for PJSIP.

Definition at line 672 of file pjsip_resolver.c.

Referenced by sip_replace_resolver().

◆ sip_available_transports

int sip_available_transports[]
static

Available transports on the system.

Definition at line 76 of file pjsip_resolver.c.

Referenced by sip_check_transport(), and sip_transport_is_available().