Asterisk - The Open Source Telephony Project GIT-master-7e7a603
pjsip_resolver.c
Go to the documentation of this file.
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"
29#include "asterisk/dns_srv.h"
30#include "asterisk/dns_naptr.h"
31#include "asterisk/res_pjsip.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 */
39struct 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 */
47AST_VECTOR(targets, struct sip_target);
48
49/*! \brief Structure which keeps track of resolution */
50struct 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 */
55 /*! \brief Current viable server addresses */
56 pjsip_server_addresses addresses;
57 /*! \brief Serializer to run async callback into pjlib. */
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 */
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,
73};
74
75/*! \brief Available transports on the system */
76static 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 */
96static void sip_resolve_destroy(void *data)
97{
98 struct sip_resolve *resolve = data;
99
100 AST_VECTOR_FREE(&resolve->resolving);
101 ao2_cleanup(resolve->queries);
102 ast_taskprocessor_unreference(resolve->serializer);
103}
104
105/*!
106 * \internal
107 * \brief Check whether a transport is available or not
108 *
109 * \param transport The PJSIP transport type
110 *
111 * \return 1 success (transport is available)
112 * \return 0 failure (transport is not available)
113 */
114static int sip_transport_is_available(enum pjsip_transport_type_e transport)
115{
116 enum sip_resolver_transport resolver_transport;
117
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;
130 } else {
131 return 0;
132 }
133
134 return sip_available_transports[resolver_transport];
135}
136
137/*!
138 * \internal
139 * \brief Add a query to be resolved
140 *
141 * \param resolve The ongoing resolution
142 * \param name What to resolve
143 * \param rr_type The type of record to look up
144 * \param rr_class The type of class to look up
145 * \param transport The transport to use for any resulting records
146 * \param port The port to use for any resulting records - if not specified the
147 * default for the transport is used
148 *
149 * \retval 0 success
150 * \retval -1 failure
151 */
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)
153{
154 struct sip_target target = {
155 .transport = transport,
156 .port = port,
157 };
158
159 if (!resolve->queries) {
160 resolve->queries = ast_dns_query_set_create();
161 if (!resolve->queries) {
162 return -1;
163 }
164 }
165
166 if (!port) {
167 target.port = pjsip_transport_get_default_port_for_type(transport);
168 }
169
170 if (AST_VECTOR_APPEND(&resolve->resolving, target)) {
171 return -1;
172 }
173
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);
176
177 return ast_dns_query_set_add(resolve->queries, name, rr_type, rr_class);
178}
179
180/*!
181 * \internal
182 * \brief Task used to invoke the user specific callback
183 *
184 * \param data The complete resolution
185 *
186 * \retval 0 Always
187 */
188static int sip_resolve_invoke_user_callback(void *data)
189{
190 struct sip_resolve *resolve = data;
191
192 if (DEBUG_ATLEAST(2)) {
193 /* This includes space for the IP address, [, ], :, and the port */
194 char addr[PJ_INET6_ADDRSTRLEN + 10];
195 int idx;
196
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",
200 resolve, idx, addr,
201 pjsip_transport_get_type_desc(resolve->addresses.entry[idx].type));
202 }
203 }
204
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);
207
208 ao2_ref(resolve, -1);
209
210 return 0;
211}
212
213/*!
214 * \internal
215 * \brief Handle a NAPTR record according to RFC3263
216 *
217 * \param resolve The ongoing resolution
218 * \param record The NAPTR record itself
219 * \param service The service to look for
220 * \param transport The transport to use for resulting queries
221 *
222 * \retval 0 success
223 * \retval -1 failure (record not handled / supported)
224 */
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)
227{
228 if (strcasecmp(ast_dns_naptr_get_service(record), service)) {
229 return -1;
230 }
231
232 /* It is possible for us to receive an explicit transport that is already IPv6, in that case
233 * we can't turn it into an IPv6 transport and check. If it's not IPv6 though we need to check
234 * for both IPv4 and IPv6 as PJSIP does not provide enough differentiation to know that we
235 * want only IPv4.
236 */
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",
240 resolve, service);
241 return -1;
242 }
243
244 if (strcasecmp(ast_dns_naptr_get_flags(record), "s")) {
245 ast_debug(2, "[%p] NAPTR service %s received with unsupported flags '%s'\n",
246 resolve, service, ast_dns_naptr_get_flags(record));
247 return -1;
248 }
249
251 return -1;
252 }
253
254 return sip_resolve_add(resolve, ast_dns_naptr_get_replacement(record), T_SRV, C_IN,
255 transport, 0);
256}
257
258/*!
259 * \internal
260 * \brief Query set callback function, invoked when all queries have completed
261 *
262 * \param query_set The completed query set
263 */
264static void sip_resolve_callback(const struct ast_dns_query_set *query_set)
265{
266 struct sip_resolve *resolve = ast_dns_query_set_get_data(query_set);
267 struct ast_dns_query_set *queries = resolve->queries;
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;
272
273 ast_debug(2, "[%p] All parallel queries completed\n", resolve);
274
275 resolve->queries = NULL;
276
277 /* This purposely steals the resolving list so we can add entries to the new one in
278 * the same loop and also have access to the old.
279 */
280 resolving = resolve->resolving;
281 AST_VECTOR_INIT(&resolve->resolving, 0);
282
283 /* The order of queries is what defines the preference order for the records within
284 * this specific query set. The preference order overall is defined as a result of
285 * drilling down from other records. Each completed query set replaces the results
286 * of the last.
287 */
288 for (idx = 0; idx < ast_dns_query_set_num_queries(queries); ++idx) {
289 struct ast_dns_query *query = ast_dns_query_set_get(queries, idx);
291 struct sip_target *target;
292 const struct ast_dns_record *record;
293
294 if (!result) {
295 ast_debug(2, "[%p] No result information for target '%s' of type '%d'\n", resolve,
297 continue;
298 }
299
300 target = AST_VECTOR_GET_ADDR(&resolving, idx);
301 for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
302
303 if (ast_dns_record_get_rr_type(record) == T_A ||
304 ast_dns_record_get_rr_type(record) == T_AAAA) {
305 /* If NAPTR or SRV records exist the subsequent results from them take preference */
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",
308 resolve, ast_dns_record_get_rr_type(record) == T_A ? "A" : "AAAA",
310 continue;
311 }
312
313 /* PJSIP has a fixed maximum number of addresses that can exist, so limit ourselves to that */
314 if (address_count == PJSIP_MAX_RESOLVED_ADDRESSES) {
315 break;
316 }
317
318 resolve->addresses.entry[address_count].type = target->transport;
319
320 /* Populate address information for the new address entry */
321 if (ast_dns_record_get_rr_type(record) == T_A) {
322 ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
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,
325 target->port);
326 resolve->addresses.entry[address_count].addr.ipv4.sin_addr = *(pj_in_addr *) ast_dns_record_get_data(record);
327 } else {
328 ast_debug(2, "[%p] AAAA record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
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,
331 target->port);
332 pj_memcpy(&resolve->addresses.entry[address_count].addr.ipv6.sin6_addr, ast_dns_record_get_data(record),
334 }
335
336 address_count++;
337 } else if (ast_dns_record_get_rr_type(record) == T_SRV) {
338 if (have_naptr) {
339 ast_debug(2, "[%p] SRV record being skipped on target '%s' because NAPTR record exists\n",
340 resolve, ast_dns_query_get_name(query));
341 continue;
342 }
343
344 /* SRV records just create new queries for AAAA+A, nothing fancy */
345 ast_debug(2, "[%p] SRV record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
346
347 /* If an explicit IPv6 target transport has been requested look for only AAAA records */
348 if ((target->transport & PJSIP_TRANSPORT_IPV6) &&
349 sip_transport_is_available(target->transport)) {
350 sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport,
351 ast_dns_srv_get_port(record));
352 have_srv = 1;
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,
356 ast_dns_srv_get_port(record));
357 have_srv = 1;
358 }
359
360 if (!(target->transport & PJSIP_TRANSPORT_IPV6) &&
361 sip_transport_is_available(target->transport)) {
362 sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_A, C_IN, target->transport,
363 ast_dns_srv_get_port(record));
364 have_srv = 1;
365 }
366 } else if (ast_dns_record_get_rr_type(record) == T_NAPTR) {
367 int added = -1;
368
369 ast_debug(2, "[%p] NAPTR record received on target '%s'\n", resolve, ast_dns_query_get_name(query));
370
371 if (strict_order && (ast_dns_naptr_get_order(record) != order)) {
372 ast_debug(2, "[%p] NAPTR record skipped because order '%hu' does not match strict order '%hu'\n",
373 resolve, ast_dns_naptr_get_order(record), order);
374 continue;
375 }
376
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);
381 }
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);
386 }
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);
391 }
392
393 /* If this record was successfully handled then we need to limit ourselves to this order */
394 if (!added) {
395 have_naptr = 1;
396 strict_order = 1;
398 }
399 }
400 }
401 }
402
403 /* Update the server addresses count, this is not limited as it can never exceed the max allowed */
404 resolve->addresses.count = address_count;
405
406 /* Free the vector we stole as we are responsible for it */
407 AST_VECTOR_FREE(&resolving);
408
409 /* If additional queries were added start the resolution process again */
410 if (resolve->queries) {
411 ast_debug(2, "[%p] New queries added, performing parallel resolution again\n", resolve);
412 ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve);
413 ao2_ref(queries, -1);
414 return;
415 }
416
417 ast_debug(2, "[%p] Resolution completed - %d viable targets\n", resolve, resolve->addresses.count);
418
419 /* Push a task to invoke the callback, we do this so it is guaranteed to run in a PJSIP thread */
420 ao2_ref(resolve, +1);
421 if (ast_sip_push_task(resolve->serializer, sip_resolve_invoke_user_callback, resolve)) {
422 ao2_ref(resolve, -1);
423 }
424
425 ao2_ref(queries, -1);
426}
427
428/*!
429 * \internal
430 * \brief Determine what address family a host may be if it is already an IP address
431 *
432 * \param host The host (which may be an IP address)
433 *
434 * \retval 6 The host is an IPv6 address
435 * \retval 4 The host is an IPv4 address
436 * \retval 0 The host is not an IP address
437 */
438static int sip_resolve_get_ip_addr_ver(const pj_str_t *host)
439{
440 pj_in_addr dummy;
441 pj_in6_addr dummy6;
442
443 if (pj_inet_aton(host, &dummy) > 0) {
444 return 4;
445 }
446
447 if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) {
448 return 6;
449 }
450
451 return 0;
452}
453
454/*!
455 * \internal
456 * \brief Perform SIP resolution of a host
457 *
458 * \param resolver Configured resolver instance
459 * \param pool Memory pool to allocate things from
460 * \param target The target we are resolving
461 * \param token User data to pass to the resolver callback
462 * \param cb User resolver callback to invoke upon resolution completion
463 */
464static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target,
465 void *token, pjsip_resolver_callback *cb)
466{
467 int ip_addr_ver;
468 pjsip_transport_type_e type = target->type;
469 struct sip_resolve *resolve;
470 char host[NI_MAXHOST];
471 int res = 0;
472
473 ast_copy_pj_str(host, &target->addr.host, sizeof(host));
474
475 ast_debug(2, "Performing SIP DNS resolution of target '%s'\n", host);
476
477 /* If the provided target is already an address don't bother resolving */
478 ip_addr_ver = sip_resolve_get_ip_addr_ver(&target->addr.host);
479
480 /* Determine the transport to use if none has been explicitly specified */
481 if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
482 /* If we've been told to use a secure or reliable transport restrict ourselves to that */
483#if PJ_HAS_TCP
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;
488 } else
489#endif
490 /* According to the RFC otherwise if an explicit IP address OR an explicit port is specified
491 * we use UDP
492 */
493 if (ip_addr_ver || target->addr.port) {
494 type = PJSIP_TRANSPORT_UDP;
495 }
496
497 if (ip_addr_ver == 6) {
498 type = (pjsip_transport_type_e)((int) type | PJSIP_TRANSPORT_IPV6);
499 }
500 }
501
502 ast_debug(2, "Transport type for target '%s' is '%s'\n", host, pjsip_transport_get_type_desc(type));
503
504 /* If it's already an address call the callback immediately */
505 if (ip_addr_ver) {
506 pjsip_server_addresses addresses = {
507 .entry[0].type = type,
508 .count = 1,
509 };
510
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);
515 } else {
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);
519 }
520
521 pj_sockaddr_set_port(&addresses.entry[0].addr, !target->addr.port ? pjsip_transport_get_default_port_for_type(type) : target->addr.port);
522
523 ast_debug(2, "Target '%s' is an IP address, skipping resolution\n", host);
524
525 cb(PJ_SUCCESS, token, &addresses);
526
527 return;
528 }
529
530 resolve = ao2_alloc_options(sizeof(*resolve), sip_resolve_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
531 if (!resolve) {
532 cb(PJ_ENOMEM, token, NULL);
533 return;
534 }
535
536 resolve->callback = cb;
537 resolve->token = token;
538
539 if (AST_VECTOR_INIT(&resolve->resolving, 4)) {
540 ao2_ref(resolve, -1);
541 cb(PJ_ENOMEM, token, NULL);
542 return;
543 }
544
545 ast_debug(2, "[%p] Created resolution tracking for target '%s'\n", resolve, host);
546
547 /* If no port has been specified we can do NAPTR + SRV */
548 if (!target->addr.port) {
549 char srv[NI_MAXHOST];
550
551 /* When resolving addresses PJSIP can request an explicit transport type. It will explicitly
552 * request an IPv6 transport if a message has been tagged to use an explicitly IPv6 transport.
553 * For other cases it can be left unspecified OR an explicit non-IPv6 transport can be requested.
554 * In the case where a non-IPv6 transport is requested there is no way to differentiate between
555 * a transport being requested as part of a SIP URI (sip:test.com;transport=tcp) and a message
556 * being tagged with a specific IPv4 transport. In this case we look for both IPv4 and IPv6 addresses.
557 * If a message has been tagged with a specific IPv4 transport the IPv6 addresses will simply
558 * be discarded. The code below and elsewhere handles the case where we know they requested IPv6
559 * explicitly and only looks for IPv6 records.
560 */
561
562 res |= sip_resolve_add(resolve, host, T_NAPTR, C_IN, type, 0);
563
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);
570 }
571 }
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);
578 }
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 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);
586 }
587 }
588 }
589
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);
595 }
596
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);
600 }
601
602 if (res) {
603 ao2_ref(resolve, -1);
604 cb(PJ_ENOMEM, token, NULL);
605 return;
606 }
607 if (!resolve->queries) {
608 ast_debug(2, "[%p] No resolution queries for target '%s'\n", resolve, host);
609 ao2_ref(resolve, -1);
610 cb(PJLIB_UTIL_EDNSNOANSWERREC, token, NULL);
611 return;
612 }
613
614 resolve->serializer = ao2_bump(ast_threadpool_serializer_get_current());
615
616 ast_debug(2, "[%p] Starting initial resolution using parallel queries for target '%s'\n", resolve, host);
617 ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve);
618
619 ao2_ref(resolve, -1);
620}
621
622/*!
623 * \internal
624 * \brief Determine if a specific transport is configured on the system
625 *
626 * \param pool A memory pool to allocate things from
627 * \param transport The type of transport to check
628 * \param name A friendly name to print in the verbose message
629 */
630static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e transport, const char *name)
631{
632 pjsip_tpmgr_fla2_param prm;
633 enum sip_resolver_transport resolver_transport;
634
635 pjsip_tpmgr_fla2_param_default(&prm);
636 prm.tp_type = transport;
637
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;
650 } else {
651 ast_verb(2, "'%s' is an unsupported SIP transport\n", name);
652 return;
653 }
654
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;
659 } else {
660 ast_verb(2, "'%s' is not an available SIP transport, disabling resolver support for it\n",
661 name);
662 }
663}
664
665/*! \brief External resolver implementation for PJSIP */
666static pjsip_ext_resolver ext_resolver = {
667 .resolve = sip_resolve,
668};
669
670/*!
671 * \internal
672 * \brief Task to determine available transports and set ourselves an external resolver
673 *
674 * \retval 0 success
675 * \retval -1 failure
676 */
677static int sip_replace_resolver(void *data)
678{
679 pj_pool_t *pool;
680
681
682 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Transport Availability", 256, 256);
683 if (!pool) {
684 return -1;
685 }
686
687 /* Determine what transports are available on the system */
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");
694
695 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
696
697 /* Replace the PJSIP resolver with our own implementation */
698 pjsip_endpt_set_ext_resolver(ast_sip_get_pjsip_endpoint(), &ext_resolver);
699 return 0;
700}
701
703{
704 /* Replace the existing PJSIP resolver with our own implementation */
705 ast_sip_push_task_wait_servant(NULL, sip_replace_resolver, NULL);
706}
707
708#else
709
711{
712 /* External resolver support does not exist in the version of PJSIP in use */
713 ast_log(LOG_NOTICE, "The version of PJSIP in use does not support external resolvers, using PJSIP provided resolver\n");
714}
715
716#endif
integer order
Definition: analys.c:66
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
enum ast_cc_service_type service
Definition: ccss.c:383
static PGresult * result
Definition: cel_pgsql.c:84
static const char type[]
Definition: chan_ooh323.c:109
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
Core DNS API.
int ast_dns_query_get_rr_type(const struct ast_dns_query *query)
Get the record resource type of a DNS query.
Definition: dns_core.c:62
const struct ast_dns_record * ast_dns_record_get_next(const struct ast_dns_record *record)
Get the next DNS record.
Definition: dns_core.c:170
const char * ast_dns_record_get_data(const struct ast_dns_record *record)
Retrieve the raw DNS record.
Definition: dns_core.c:160
const struct ast_dns_record * ast_dns_result_get_records(const struct ast_dns_result *result)
Get the first record of a DNS Result.
Definition: dns_core.c:102
struct ast_dns_result * ast_dns_query_get_result(const struct ast_dns_query *query)
Get the result information for a DNS query.
Definition: dns_core.c:77
int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
Get the resource record type of a DNS record.
Definition: dns_core.c:145
const char * ast_dns_query_get_name(const struct ast_dns_query *query)
Get the name queried in a DNS query.
Definition: dns_core.c:57
size_t ast_dns_record_get_data_size(const struct ast_dns_record *record)
Retrieve the size of the raw DNS record.
Definition: dns_core.c:165
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.
Definition: dns_naptr.c:624
const char * ast_dns_naptr_get_flags(const struct ast_dns_record *record)
Get the flags from a NAPTR record.
Definition: dns_naptr.c:600
const char * ast_dns_naptr_get_service(const struct ast_dns_record *record)
Get the service from a NAPTR record.
Definition: dns_naptr.c:608
unsigned short ast_dns_naptr_get_order(const struct ast_dns_record *record)
Get the order from a NAPTR record.
Definition: dns_naptr.c:632
DNS Query Set API.
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.
Definition: dns_query_set.c:60
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.
Definition: dns_srv.c:188
unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record)
Get the port from an SRV record.
Definition: dns_srv.c:212
static const char name[]
Definition: format_mp3.c:68
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.
Definition: res_pjsip.c:2099
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
Definition: res_pjsip.c:2165
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_DEBUG
#define ast_verb(level,...)
#define LOG_NOTICE
void ast_sip_initialize_resolver(void)
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
A set of DNS queries.
Definition: dns_internal.h:185
A DNS query.
Definition: dns_internal.h:137
For AST_LIST.
Definition: dns_internal.h:39
The result of a DNS query.
Definition: dns_internal.h:117
A ast_taskprocessor structure is a singleton by name.
Definition: taskprocessor.c:69
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.
Definition: threadpool.c:1393
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET_ADDR(vec, idx)
Get an address of element in a vector.
Definition: vector.h:668