22 #include <pjlib-util/errno.h>
24 #include <arpa/nameser.h>
31 #include "asterisk/res_pjsip.h"
32 #include "include/res_pjsip_private.h"
34 #include "asterisk/threadpool.h"
36 #ifdef HAVE_PJSIP_EXTERNAL_RESOLVER
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,
76 static 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,
96 static void sip_resolve_destroy(
void *data)
114 static 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];
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)
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);
188 static int sip_resolve_invoke_user_callback(
void *data)
192 if (DEBUG_ATLEAST(2)) {
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);
199 ast_log(LOG_DEBUG,
"[%p] Address '%d' is %s with transport '%s'\n",
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);
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",
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);
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) {
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)) {
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;
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);
438 static 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) {
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)
468 pjsip_transport_type_e type = target->type;
470 char host[NI_MAXHOST];
473 ast_copy_pj_str(host, &target->addr.host,
sizeof(host));
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));
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);
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);
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);
630 static 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);
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;
660 ast_verb(2,
"'%s' is not an available SIP transport, disabling resolver support for it\n",
666 static pjsip_ext_resolver ext_resolver = {
677 static int sip_replace_resolver(
void *data)
682 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
"Transport Availability", 256, 256);
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");
695 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
698 pjsip_endpt_set_ext_resolver(ast_sip_get_pjsip_endpoint(), &ext_resolver);
702 void ast_sip_initialize_resolver(
void)
710 void ast_sip_initialize_resolver(
void)
713 ast_log(LOG_NOTICE,
"The version of PJSIP in use does not support external resolvers, using PJSIP provided resolver\n");
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
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.
const char * ast_dns_query_get_name(const struct ast_dns_query *query)
Get the name queried in a DNS query.
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.
struct ast_dns_query_set * ast_dns_query_set_create(void)
Create a query set to hold queries.
size_t ast_dns_record_get_data_size(const struct ast_dns_record *record)
Retrieve the size of the raw DNS record.
pjsip_server_addresses addresses
Current viable server addresses.
The vector used for current targets.
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
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.
unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record)
Get the port from an SRV record.
const char * ast_dns_srv_get_host(const struct ast_dns_record *record)
Get the hostname from an SRV record.
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.
void * token
User provided data.
Structure which contains transport+port information for an active query.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
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.
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.
The result of a DNS query.
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
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.
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.
A ast_taskprocessor structure is a singleton by name.
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.
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.
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.