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