22#include <pjlib-util/errno.h>
24#include <arpa/nameser.h>
36#ifdef HAVE_PJSIP_EXTERNAL_RESOLVER
41 pjsip_transport_type_e transport;
52 struct targets resolving;
56 pjsip_server_addresses addresses;
60 pjsip_resolver_callback *callback;
66enum 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,
76static int sip_available_transports[] = {
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,
96static void sip_resolve_destroy(
void *data)
98 struct sip_resolve *resolve = data;
114static int sip_transport_is_available(
enum pjsip_transport_type_e transport)
116 enum sip_resolver_transport resolver_transport;
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;
134 return sip_available_transports[resolver_transport];
152static int sip_resolve_add(
struct sip_resolve *resolve,
const char *
name,
int rr_type,
int rr_class, pjsip_transport_type_e transport,
int port)
154 struct sip_target target = {
155 .transport = transport,
159 if (!resolve->queries) {
161 if (!resolve->queries) {
167 target.port = pjsip_transport_get_default_port_for_type(transport);
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);
188static int sip_resolve_invoke_user_callback(
void *data)
190 struct sip_resolve *resolve = data;
194 char addr[PJ_INET6_ADDRSTRLEN + 10];
197 for (idx = 0; idx < resolve->addresses.count; ++idx) {
198 pj_sockaddr_print(&resolve->addresses.entry[idx].addr, addr,
sizeof(addr), 3);
201 pjsip_transport_get_type_desc(resolve->addresses.entry[idx].type));
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);
225static int sip_resolve_handle_naptr(
struct sip_resolve *resolve,
const struct ast_dns_record *record,
226 const char *
service, pjsip_transport_type_e transport)
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",
245 ast_debug(2,
"[%p] NAPTR service %s received with unsupported flags '%s'\n",
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;
273 ast_debug(2,
"[%p] All parallel queries completed\n", resolve);
275 resolve->queries =
NULL;
280 resolving = resolve->resolving;
291 struct sip_target *target;
295 ast_debug(2,
"[%p] No result information for target '%s' of type '%d'\n", resolve,
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",
314 if (address_count == PJSIP_MAX_RESOLVED_ADDRESSES) {
318 resolve->addresses.entry[address_count].type = target->transport;
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,
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,
339 ast_debug(2,
"[%p] SRV record being skipped on target '%s' because NAPTR record exists\n",
348 if ((target->transport & PJSIP_TRANSPORT_IPV6) &&
349 sip_transport_is_available(target->transport)) {
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,
360 if (!(target->transport & PJSIP_TRANSPORT_IPV6) &&
361 sip_transport_is_available(target->transport)) {
372 ast_debug(2,
"[%p] NAPTR record skipped because order '%hu' does not match strict order '%hu'\n",
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);
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);
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);
404 resolve->addresses.count = address_count;
410 if (resolve->queries) {
411 ast_debug(2,
"[%p] New queries added, performing parallel resolution again\n", resolve);
417 ast_debug(2,
"[%p] Resolution completed - %d viable targets\n", resolve, resolve->addresses.count);
421 if (
ast_sip_push_task(resolve->serializer, sip_resolve_invoke_user_callback, resolve)) {
438static int sip_resolve_get_ip_addr_ver(
const pj_str_t *host)
443 if (pj_inet_aton(host, &
dummy) > 0) {
447 if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) {
464static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool,
const pjsip_host_info *target,
465 void *token, pjsip_resolver_callback *cb)
468 pjsip_transport_type_e
type = target->type;
469 struct sip_resolve *resolve;
470 char host[NI_MAXHOST];
475 ast_debug(2,
"Performing SIP DNS resolution of target '%s'\n", host);
478 ip_addr_ver = sip_resolve_get_ip_addr_ver(&target->addr.host);
481 if (
type == PJSIP_TRANSPORT_UNSPECIFIED) {
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;
493 if (ip_addr_ver || target->addr.port) {
494 type = PJSIP_TRANSPORT_UDP;
497 if (ip_addr_ver == 6) {
498 type = (pjsip_transport_type_e)((
int)
type | PJSIP_TRANSPORT_IPV6);
502 ast_debug(2,
"Transport type for target '%s' is '%s'\n", host, pjsip_transport_get_type_desc(
type));
506 pjsip_server_addresses addresses = {
507 .entry[0].type =
type,
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);
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);
521 pj_sockaddr_set_port(&addresses.entry[0].addr, !target->addr.port ? pjsip_transport_get_default_port_for_type(
type) : target->addr.port);
523 ast_debug(2,
"Target '%s' is an IP address, skipping resolution\n", host);
525 cb(PJ_SUCCESS, token, &addresses);
532 cb(PJ_ENOMEM, token,
NULL);
536 resolve->callback = cb;
537 resolve->token = token;
541 cb(PJ_ENOMEM, token,
NULL);
545 ast_debug(2,
"[%p] Created resolution tracking for target '%s'\n", resolve, host);
548 if (!target->addr.port) {
549 char srv[NI_MAXHOST];
562 res |= sip_resolve_add(resolve, host, T_NAPTR, C_IN,
type, 0);
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);
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);
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);
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);
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);
604 cb(PJ_ENOMEM, token,
NULL);
607 if (!resolve->queries) {
608 ast_debug(2,
"[%p] No resolution queries for target '%s'\n", resolve, host);
610 cb(PJLIB_UTIL_EDNSNOANSWERREC, token,
NULL);
616 ast_debug(2,
"[%p] Starting initial resolution using parallel queries for target '%s'\n", resolve, host);
630static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e transport,
const char *
name)
632 pjsip_tpmgr_fla2_param prm;
633 enum sip_resolver_transport resolver_transport;
635 pjsip_tpmgr_fla2_param_default(&prm);
636 prm.tp_type = transport;
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;
651 ast_verb(2,
"'%s' is an unsupported SIP transport\n",
name);
656 pool, &prm) == PJ_SUCCESS) {
657 ast_verb(2,
"'%s' is an available SIP transport\n",
name);
658 sip_available_transports[resolver_transport] = 1;
660 ast_verb(2,
"'%s' is not an available SIP transport, disabling resolver support for it\n",
666static pjsip_ext_resolver ext_resolver = {
667 .resolve = sip_resolve,
677static int sip_replace_resolver(
void *data)
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");
713 ast_log(
LOG_NOTICE,
"The version of PJSIP in use does not support external resolvers, using PJSIP provided resolver\n");
Asterisk main include file. File version handling, generic pbx functions.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
enum ast_cc_service_type service
static void dummy(char *unused,...)
int ast_dns_query_get_rr_type(const struct ast_dns_query *query)
Get the record resource type of a DNS query.
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
const char * ast_dns_query_get_name(const struct ast_dns_query *query)
Get the name queried in a DNS query.
size_t ast_dns_record_get_data_size(const struct ast_dns_record *record)
Retrieve the size of the raw DNS record.
DNS NAPTR Record Parsing API.
const char * ast_dns_naptr_get_replacement(const struct ast_dns_record *record)
Get the replacement value from a NAPTR record.
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
Get the order from a NAPTR record.
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.
struct ast_dns_query_set * ast_dns_query_set_create(void)
Create a query set to hold queries.
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_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.
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.
DNS SRV Record Parsing API.
const char * ast_dns_srv_get_host(const struct ast_dns_record *record)
Get the hostname from an SRV record.
unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record)
Get the port from an SRV record.
static struct queries queries
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
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.
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
void ast_sip_initialize_resolver(void)
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
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.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
The result of a DNS query.
A ast_taskprocessor structure is a singleton by name.
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct ast_taskprocessor * ast_threadpool_serializer_get_current(void)
Get the threadpool serializer currently associated with this thread.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.