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