| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2015, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Joshua Colp <jcolp@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <pjsip.h>
 | 
					
						
							|  |  |  | #include <pjlib-util/errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <arpa/nameser.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/astobj2.h"
 | 
					
						
							|  |  |  | #include "asterisk/dns_core.h"
 | 
					
						
							|  |  |  | #include "asterisk/dns_query_set.h"
 | 
					
						
							|  |  |  | #include "asterisk/dns_srv.h"
 | 
					
						
							|  |  |  | #include "asterisk/dns_naptr.h"
 | 
					
						
							|  |  |  | #include "asterisk/res_pjsip.h"
 | 
					
						
							|  |  |  | #include "include/res_pjsip_private.h"
 | 
					
						
							| 
									
										
										
										
											2015-06-05 15:37:33 -05:00
										 |  |  | #include "asterisk/taskprocessor.h"
 | 
					
						
							|  |  |  | #include "asterisk/threadpool.h"
 | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_PJSIP_EXTERNAL_RESOLVER
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Structure which contains transport+port information for an active query */ | 
					
						
							|  |  |  | struct sip_target { | 
					
						
							|  |  |  | 	/*! \brief The transport to be used */ | 
					
						
							|  |  |  | 	pjsip_transport_type_e transport; | 
					
						
							|  |  |  | 	/*! \brief The port */ | 
					
						
							|  |  |  | 	int port; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief The vector used for current targets */ | 
					
						
							|  |  |  | AST_VECTOR(targets, struct sip_target); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Structure which keeps track of resolution */ | 
					
						
							|  |  |  | struct sip_resolve { | 
					
						
							|  |  |  | 	/*! \brief Addresses currently being resolved, indexed based on index of queries in query set */ | 
					
						
							|  |  |  | 	struct targets resolving; | 
					
						
							|  |  |  | 	/*! \brief Active queries */ | 
					
						
							|  |  |  | 	struct ast_dns_query_set *queries; | 
					
						
							|  |  |  | 	/*! \brief Current viable server addresses */ | 
					
						
							|  |  |  | 	pjsip_server_addresses addresses; | 
					
						
							| 
									
										
										
										
											2015-06-05 15:37:33 -05:00
										 |  |  | 	/*! \brief Serializer to run async callback into pjlib. */ | 
					
						
							|  |  |  | 	struct ast_taskprocessor *serializer; | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	/*! \brief Callback to invoke upon completion */ | 
					
						
							|  |  |  | 	pjsip_resolver_callback *callback; | 
					
						
							|  |  |  | 	/*! \brief User provided data */ | 
					
						
							|  |  |  | 	void *token; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Our own defined transports, reduces the size of sip_available_transports */ | 
					
						
							|  |  |  | enum sip_resolver_transport { | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_UDP, | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_TCP, | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_TLS, | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_UDP6, | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_TCP6, | 
					
						
							|  |  |  | 	SIP_RESOLVER_TRANSPORT_TLS6, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief Available transports on the system */ | 
					
						
							|  |  |  | static int sip_available_transports[] = { | 
					
						
							|  |  |  | 	/* This is a list of transports with whether they are available as a valid transport
 | 
					
						
							|  |  |  | 	 * stored. We use our own identifier as to reduce the size of sip_available_transports. | 
					
						
							|  |  |  | 	 * As this array is only manipulated at startup it does not require a lock to protect | 
					
						
							|  |  |  | 	 * it. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_UDP] = 0, | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_TCP] = 0, | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_TLS] = 0, | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_UDP6] = 0, | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_TCP6] = 0, | 
					
						
							|  |  |  | 	[SIP_RESOLVER_TRANSPORT_TLS6] = 0, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Destroy resolution data | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param data The resolution data to destroy | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void sip_resolve_destroy(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sip_resolve *resolve = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_VECTOR_FREE(&resolve->resolving); | 
					
						
							|  |  |  | 	ao2_cleanup(resolve->queries); | 
					
						
							| 
									
										
										
										
											2015-06-05 15:37:33 -05:00
										 |  |  | 	ast_taskprocessor_unreference(resolve->serializer); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Check whether a transport is available or not | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param transport The PJSIP transport type | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return 1 success (transport is available) | 
					
						
							|  |  |  |  * \return 0 failure (transport is not available) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int sip_transport_is_available(enum pjsip_transport_type_e transport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	enum sip_resolver_transport resolver_transport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (transport == PJSIP_TRANSPORT_UDP) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_UDP; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TCP) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TCP; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TLS) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TLS; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_UDP6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_UDP6; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TCP6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TCP6; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TLS6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TLS6; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sip_available_transports[resolver_transport]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Add a query to be resolved | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param resolve The ongoing resolution | 
					
						
							|  |  |  |  * \param name What to resolve | 
					
						
							|  |  |  |  * \param rr_type The type of record to look up | 
					
						
							|  |  |  |  * \param rr_class The type of class to look up | 
					
						
							|  |  |  |  * \param transport The transport to use for any resulting records | 
					
						
							|  |  |  |  * \param port The port to use for any resulting records - if not specified the | 
					
						
							|  |  |  |  *             default for the transport is used | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval -1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sip_target target = { | 
					
						
							|  |  |  | 		.transport = transport, | 
					
						
							|  |  |  | 		.port = port, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!resolve->queries) { | 
					
						
							|  |  |  | 		resolve->queries = ast_dns_query_set_create(); | 
					
						
							| 
									
										
										
										
											2015-06-05 11:43:35 -05:00
										 |  |  | 		if (!resolve->queries) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!port) { | 
					
						
							|  |  |  | 		target.port = pjsip_transport_get_default_port_for_type(transport); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (AST_VECTOR_APPEND(&resolve->resolving, target)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "[%p] Added target '%s' with record type '%d', transport '%s', and port '%d'\n", | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 		resolve, name, rr_type, pjsip_transport_get_type_desc(transport), target.port); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ast_dns_query_set_add(resolve->queries, name, rr_type, rr_class); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Task used to invoke the user specific callback | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param data The complete resolution | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int sip_resolve_invoke_user_callback(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sip_resolve *resolve = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-05 11:43:35 -05:00
										 |  |  | 	if (DEBUG_ATLEAST(2)) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		/* This includes space for the IP address, [, ], :, and the port */ | 
					
						
							|  |  |  | 		char addr[PJ_INET6_ADDRSTRLEN + 10]; | 
					
						
							| 
									
										
										
										
											2015-06-05 11:43:35 -05:00
										 |  |  | 		int idx; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (idx = 0; idx < resolve->addresses.count; ++idx) { | 
					
						
							|  |  |  | 			pj_sockaddr_print(&resolve->addresses.entry[idx].addr, addr, sizeof(addr), 3); | 
					
						
							|  |  |  | 			ast_log(LOG_DEBUG, "[%p] Address '%d' is %s with transport '%s'\n", | 
					
						
							|  |  |  | 				resolve, idx, addr, | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 				pjsip_transport_get_type_desc(resolve->addresses.entry[idx].type)); | 
					
						
							| 
									
										
										
										
											2015-06-05 11:43:35 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "[%p] Invoking user callback with '%d' addresses\n", resolve, resolve->addresses.count); | 
					
						
							|  |  |  | 	resolve->callback(resolve->addresses.count ? PJ_SUCCESS : PJLIB_UTIL_EDNSNOANSWERREC, resolve->token, &resolve->addresses); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_ref(resolve, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Handle a NAPTR record according to RFC3263 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param resolve The ongoing resolution | 
					
						
							|  |  |  |  * \param record The NAPTR record itself | 
					
						
							|  |  |  |  * \param service The service to look for | 
					
						
							|  |  |  |  * \param transport The transport to use for resulting queries | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval -1 failure (record not handled / supported) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int sip_resolve_handle_naptr(struct sip_resolve *resolve, const struct ast_dns_record *record, | 
					
						
							|  |  |  | 	const char *service, pjsip_transport_type_e transport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (strcasecmp(ast_dns_naptr_get_service(record), service)) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 	/* It is possible for us to receive an explicit transport that is already IPv6, in that case
 | 
					
						
							|  |  |  | 	 * we can't turn it into an IPv6 transport and check. If it's not IPv6 though we need to check | 
					
						
							|  |  |  | 	 * for both IPv4 and IPv6 as PJSIP does not provide enough differentiation to know that we | 
					
						
							|  |  |  | 	 * want only IPv4. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	if (!sip_transport_is_available(transport) && | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 		(!(transport & PJSIP_TRANSPORT_IPV6) && !sip_transport_is_available(transport | PJSIP_TRANSPORT_IPV6))) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		ast_debug(2, "[%p] NAPTR service %s skipped as transport is unavailable\n", | 
					
						
							|  |  |  | 			resolve, service); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (strcasecmp(ast_dns_naptr_get_flags(record), "s")) { | 
					
						
							|  |  |  | 		ast_debug(2, "[%p] NAPTR service %s received with unsupported flags '%s'\n", | 
					
						
							|  |  |  | 			resolve, service, ast_dns_naptr_get_flags(record)); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(ast_dns_naptr_get_replacement(record))) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 	return sip_resolve_add(resolve, ast_dns_naptr_get_replacement(record), T_SRV, C_IN, | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		transport, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Query set callback function, invoked when all queries have completed | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param query_set The completed query set | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void sip_resolve_callback(const struct ast_dns_query_set *query_set) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sip_resolve *resolve = ast_dns_query_set_get_data(query_set); | 
					
						
							|  |  |  | 	struct ast_dns_query_set *queries = resolve->queries; | 
					
						
							|  |  |  | 	struct targets resolving; | 
					
						
							|  |  |  | 	int idx, address_count = 0, have_naptr = 0, have_srv = 0; | 
					
						
							|  |  |  | 	unsigned short order = 0; | 
					
						
							|  |  |  | 	int strict_order = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "[%p] All parallel queries completed\n", resolve); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resolve->queries = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* This purposely steals the resolving list so we can add entries to the new one in
 | 
					
						
							|  |  |  | 	 * the same loop and also have access to the old. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	resolving = resolve->resolving; | 
					
						
							|  |  |  | 	AST_VECTOR_INIT(&resolve->resolving, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* The order of queries is what defines the preference order for the records within
 | 
					
						
							|  |  |  | 	 * this specific query set. The preference order overall is defined as a result of | 
					
						
							|  |  |  | 	 * drilling down from other records. Each completed query set replaces the results | 
					
						
							|  |  |  | 	 * of the last. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	for (idx = 0; idx < ast_dns_query_set_num_queries(queries); ++idx) { | 
					
						
							|  |  |  | 		struct ast_dns_query *query = ast_dns_query_set_get(queries, idx); | 
					
						
							|  |  |  | 		struct ast_dns_result *result = ast_dns_query_get_result(query); | 
					
						
							|  |  |  | 		struct sip_target *target; | 
					
						
							|  |  |  | 		const struct ast_dns_record *record; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!result) { | 
					
						
							|  |  |  | 			ast_debug(2, "[%p] No result information for target '%s' of type '%d'\n", resolve, | 
					
						
							|  |  |  | 				ast_dns_query_get_name(query), ast_dns_query_get_rr_type(query)); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		target = AST_VECTOR_GET_ADDR(&resolving, idx); | 
					
						
							|  |  |  | 		for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 			if (ast_dns_record_get_rr_type(record) == T_A || | 
					
						
							|  |  |  | 				ast_dns_record_get_rr_type(record) == T_AAAA) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				/* If NAPTR or SRV records exist the subsequent results from them take preference */ | 
					
						
							|  |  |  | 				if (have_naptr || have_srv) { | 
					
						
							|  |  |  | 					ast_debug(2, "[%p] %s record being skipped on target '%s' because NAPTR or SRV record exists\n", | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 						resolve, ast_dns_record_get_rr_type(record) == T_A ? "A" : "AAAA", | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 						ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* PJSIP has a fixed maximum number of addresses that can exist, so limit ourselves to that */ | 
					
						
							|  |  |  | 				if (address_count == PJSIP_MAX_RESOLVED_ADDRESSES) { | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				resolve->addresses.entry[address_count].type = target->transport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* Populate address information for the new address entry */ | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 				if (ast_dns_record_get_rr_type(record) == T_A) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 					ast_debug(2, "[%p] A record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 					resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in); | 
					
						
							|  |  |  | 					pj_sockaddr_init(pj_AF_INET(), &resolve->addresses.entry[address_count].addr, NULL, | 
					
						
							|  |  |  | 						target->port); | 
					
						
							| 
									
										
										
										
											2018-07-30 14:49:08 +02:00
										 |  |  | 					resolve->addresses.entry[address_count].addr.ipv4.sin_addr = *(pj_in_addr *) ast_dns_record_get_data(record); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					ast_debug(2, "[%p] AAAA record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 					resolve->addresses.entry[address_count].addr_len = sizeof(pj_sockaddr_in6); | 
					
						
							|  |  |  | 					pj_sockaddr_init(pj_AF_INET6(), &resolve->addresses.entry[address_count].addr, NULL, | 
					
						
							|  |  |  | 						target->port); | 
					
						
							|  |  |  | 					pj_memcpy(&resolve->addresses.entry[address_count].addr.ipv6.sin6_addr, ast_dns_record_get_data(record), | 
					
						
							|  |  |  | 						ast_dns_record_get_data_size(record)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				address_count++; | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 			} else if (ast_dns_record_get_rr_type(record) == T_SRV) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				if (have_naptr) { | 
					
						
							|  |  |  | 					ast_debug(2, "[%p] SRV record being skipped on target '%s' because NAPTR record exists\n", | 
					
						
							|  |  |  | 						resolve, ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* SRV records just create new queries for AAAA+A, nothing fancy */ | 
					
						
							|  |  |  | 				ast_debug(2, "[%p] SRV record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 				/* If an explicit IPv6 target transport has been requested look for only AAAA records */ | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 				if ((target->transport & PJSIP_TRANSPORT_IPV6) && | 
					
						
							|  |  |  | 					sip_transport_is_available(target->transport)) { | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 					sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport, | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 						ast_dns_srv_get_port(record)); | 
					
						
							|  |  |  | 					have_srv = 1; | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 				} else if (!(target->transport & PJSIP_TRANSPORT_IPV6) && | 
					
						
							|  |  |  | 					sip_transport_is_available(target->transport | PJSIP_TRANSPORT_IPV6)) { | 
					
						
							|  |  |  | 					sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_AAAA, C_IN, target->transport | PJSIP_TRANSPORT_IPV6, | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 						ast_dns_srv_get_port(record)); | 
					
						
							|  |  |  | 					have_srv = 1; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 				if (!(target->transport & PJSIP_TRANSPORT_IPV6) && | 
					
						
							|  |  |  | 					sip_transport_is_available(target->transport)) { | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 					sip_resolve_add(resolve, ast_dns_srv_get_host(record), T_A, C_IN, target->transport, | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 						ast_dns_srv_get_port(record)); | 
					
						
							|  |  |  | 					have_srv = 1; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 			} else if (ast_dns_record_get_rr_type(record) == T_NAPTR) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				int added = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				ast_debug(2, "[%p] NAPTR record received on target '%s'\n", resolve, ast_dns_query_get_name(query)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (strict_order && (ast_dns_naptr_get_order(record) != order)) { | 
					
						
							|  |  |  | 					ast_debug(2, "[%p] NAPTR record skipped because order '%hu' does not match strict order '%hu'\n", | 
					
						
							|  |  |  | 						resolve, ast_dns_naptr_get_order(record), order); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 				if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_UDP || | 
					
						
							|  |  |  | 					target->transport == PJSIP_TRANSPORT_UDP6) { | 
					
						
							|  |  |  | 					added = sip_resolve_handle_naptr(resolve, record, "sip+d2u", | 
					
						
							|  |  |  | 						target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : target->transport); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 				if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TCP || | 
					
						
							|  |  |  | 					target->transport == PJSIP_TRANSPORT_TCP6) { | 
					
						
							|  |  |  | 					added = sip_resolve_handle_naptr(resolve, record, "sip+d2t", | 
					
						
							|  |  |  | 						target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : target->transport); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 				if (target->transport == PJSIP_TRANSPORT_UNSPECIFIED || target->transport == PJSIP_TRANSPORT_TLS || | 
					
						
							|  |  |  | 					target->transport == PJSIP_TRANSPORT_TLS6) { | 
					
						
							|  |  |  | 					added = sip_resolve_handle_naptr(resolve, record, "sips+d2t", | 
					
						
							|  |  |  | 						target->transport == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : target->transport); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				/* If this record was successfully handled then we need to limit ourselves to this order */ | 
					
						
							|  |  |  | 				if (!added) { | 
					
						
							|  |  |  | 					have_naptr = 1; | 
					
						
							|  |  |  | 					strict_order = 1; | 
					
						
							|  |  |  | 					order = ast_dns_naptr_get_order(record); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Update the server addresses count, this is not limited as it can never exceed the max allowed */ | 
					
						
							|  |  |  | 	resolve->addresses.count = address_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Free the vector we stole as we are responsible for it */ | 
					
						
							|  |  |  | 	AST_VECTOR_FREE(&resolving); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If additional queries were added start the resolution process again */ | 
					
						
							|  |  |  | 	if (resolve->queries) { | 
					
						
							|  |  |  | 		ast_debug(2, "[%p] New queries added, performing parallel resolution again\n", resolve); | 
					
						
							|  |  |  | 		ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve); | 
					
						
							|  |  |  | 		ao2_ref(queries, -1); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "[%p] Resolution completed - %d viable targets\n", resolve, resolve->addresses.count); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Push a task to invoke the callback, we do this so it is guaranteed to run in a PJSIP thread */ | 
					
						
							|  |  |  | 	ao2_ref(resolve, +1); | 
					
						
							| 
									
										
										
										
											2015-06-05 15:37:33 -05:00
										 |  |  | 	if (ast_sip_push_task(resolve->serializer, sip_resolve_invoke_user_callback, resolve)) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		ao2_ref(resolve, -1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_ref(queries, -1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Determine what address family a host may be if it is already an IP address | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param host The host (which may be an IP address) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 6 The host is an IPv6 address | 
					
						
							|  |  |  |  * \retval 4 The host is an IPv4 address | 
					
						
							|  |  |  |  * \retval 0 The host is not an IP address | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int sip_resolve_get_ip_addr_ver(const pj_str_t *host) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pj_in_addr dummy; | 
					
						
							|  |  |  | 	pj_in6_addr dummy6; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pj_inet_aton(host, &dummy) > 0) { | 
					
						
							|  |  |  | 		return 4; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pj_inet_pton(pj_AF_INET6(), host, &dummy6) == PJ_SUCCESS) { | 
					
						
							|  |  |  | 		return 6; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Perform SIP resolution of a host | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param resolver Configured resolver instance | 
					
						
							|  |  |  |  * \param pool Memory pool to allocate things from | 
					
						
							|  |  |  |  * \param target The target we are resolving | 
					
						
							|  |  |  |  * \param token User data to pass to the resolver callback | 
					
						
							|  |  |  |  * \param cb User resolver callback to invoke upon resolution completion | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void sip_resolve(pjsip_resolver_t *resolver, pj_pool_t *pool, const pjsip_host_info *target, | 
					
						
							|  |  |  | 	void *token, pjsip_resolver_callback *cb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ip_addr_ver; | 
					
						
							|  |  |  | 	pjsip_transport_type_e type = target->type; | 
					
						
							|  |  |  | 	struct sip_resolve *resolve; | 
					
						
							|  |  |  | 	char host[NI_MAXHOST]; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_copy_pj_str(host, &target->addr.host, sizeof(host)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "Performing SIP DNS resolution of target '%s'\n", host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If the provided target is already an address don't bother resolving */ | 
					
						
							|  |  |  | 	ip_addr_ver = sip_resolve_get_ip_addr_ver(&target->addr.host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Determine the transport to use if none has been explicitly specified */ | 
					
						
							|  |  |  | 	if (type == PJSIP_TRANSPORT_UNSPECIFIED) { | 
					
						
							|  |  |  | 		/* If we've been told to use a secure or reliable transport restrict ourselves to that */ | 
					
						
							|  |  |  | #if PJ_HAS_TCP
 | 
					
						
							|  |  |  | 		if (target->flag & PJSIP_TRANSPORT_SECURE) { | 
					
						
							|  |  |  | 			type = PJSIP_TRANSPORT_TLS; | 
					
						
							|  |  |  | 		} else if (target->flag & PJSIP_TRANSPORT_RELIABLE) { | 
					
						
							|  |  |  | 			type = PJSIP_TRANSPORT_TCP; | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 		/* According to the RFC otherwise if an explicit IP address OR an explicit port is specified
 | 
					
						
							|  |  |  | 		 * we use UDP | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		if (ip_addr_ver || target->addr.port) { | 
					
						
							|  |  |  | 			type = PJSIP_TRANSPORT_UDP; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ip_addr_ver == 6) { | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 			type = (pjsip_transport_type_e)((int) type | PJSIP_TRANSPORT_IPV6); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 	ast_debug(2, "Transport type for target '%s' is '%s'\n", host, pjsip_transport_get_type_desc(type)); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If it's already an address call the callback immediately */ | 
					
						
							|  |  |  | 	if (ip_addr_ver) { | 
					
						
							|  |  |  | 		pjsip_server_addresses addresses = { | 
					
						
							|  |  |  | 			.entry[0].type = type, | 
					
						
							|  |  |  | 			.count = 1, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ip_addr_ver == 4) { | 
					
						
							|  |  |  | 			addresses.entry[0].addr_len = sizeof(pj_sockaddr_in); | 
					
						
							|  |  |  | 			pj_sockaddr_init(pj_AF_INET(), &addresses.entry[0].addr, NULL, 0); | 
					
						
							|  |  |  | 			pj_inet_aton(&target->addr.host, &addresses.entry[0].addr.ipv4.sin_addr); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			addresses.entry[0].addr_len = sizeof(pj_sockaddr_in6); | 
					
						
							|  |  |  | 			pj_sockaddr_init(pj_AF_INET6(), &addresses.entry[0].addr, NULL, 0); | 
					
						
							|  |  |  | 			pj_inet_pton(pj_AF_INET6(), &target->addr.host, &addresses.entry[0].addr.ipv6.sin6_addr); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pj_sockaddr_set_port(&addresses.entry[0].addr, !target->addr.port ? pjsip_transport_get_default_port_for_type(type) : target->addr.port); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ast_debug(2, "Target '%s' is an IP address, skipping resolution\n", host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cb(PJ_SUCCESS, token, &addresses); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resolve = ao2_alloc_options(sizeof(*resolve), sip_resolve_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); | 
					
						
							|  |  |  | 	if (!resolve) { | 
					
						
							|  |  |  | 		cb(PJ_ENOMEM, token, NULL); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	resolve->callback = cb; | 
					
						
							|  |  |  | 	resolve->token = token; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-05 12:16:22 -05:00
										 |  |  | 	if (AST_VECTOR_INIT(&resolve->resolving, 4)) { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		ao2_ref(resolve, -1); | 
					
						
							|  |  |  | 		cb(PJ_ENOMEM, token, NULL); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(2, "[%p] Created resolution tracking for target '%s'\n", resolve, host); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If no port has been specified we can do NAPTR + SRV */ | 
					
						
							|  |  |  | 	if (!target->addr.port) { | 
					
						
							|  |  |  | 		char srv[NI_MAXHOST]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 		/* When resolving addresses PJSIP can request an explicit transport type. It will explicitly
 | 
					
						
							|  |  |  | 		 * request an IPv6 transport if a message has been tagged to use an explicitly IPv6 transport. | 
					
						
							|  |  |  | 		 * For other cases it can be left unspecified OR an explicit non-IPv6 transport can be requested. | 
					
						
							|  |  |  | 		 * In the case where a non-IPv6 transport is requested there is no way to differentiate between | 
					
						
							|  |  |  | 		 * a transport being requested as part of a SIP URI (sip:test.com;transport=tcp) and a message | 
					
						
							|  |  |  | 		 * being tagged with a specific IPv4 transport. In this case we look for both IPv4 and IPv6 addresses. | 
					
						
							|  |  |  | 		 * If a message has been tagged with a specific IPv4 transport the IPv6 addresses will simply | 
					
						
							|  |  |  | 		 * be discarded. The code below and elsewhere handles the case where we know they requested IPv6 | 
					
						
							|  |  |  | 		 * explicitly and only looks for IPv6 records. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 		res |= sip_resolve_add(resolve, host, T_NAPTR, C_IN, type, 0); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 		if (type == PJSIP_TRANSPORT_UNSPECIFIED || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_TLS && sip_transport_is_available(PJSIP_TRANSPORT_TLS)) || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_TLS6 && sip_transport_is_available(PJSIP_TRANSPORT_TLS6))) { | 
					
						
							| 
									
										
										
										
											2018-05-06 22:17:34 -04:00
										 |  |  | 			if (snprintf(srv, sizeof(srv), "_sips._tcp.%s", host) < NI_MAXHOST) { | 
					
						
							|  |  |  | 				res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, | 
					
						
							|  |  |  | 					type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TLS : type, 0); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 		if (type == PJSIP_TRANSPORT_UNSPECIFIED || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_TCP && sip_transport_is_available(PJSIP_TRANSPORT_TCP)) || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_TCP6 && sip_transport_is_available(PJSIP_TRANSPORT_TCP6))) { | 
					
						
							| 
									
										
										
										
											2018-05-06 22:17:34 -04:00
										 |  |  | 			if (snprintf(srv, sizeof(srv), "_sip._tcp.%s", host) < NI_MAXHOST) { | 
					
						
							|  |  |  | 				res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, | 
					
						
							|  |  |  | 					type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_TCP : type, 0); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-09 21:14:09 +00:00
										 |  |  | 		if (type == PJSIP_TRANSPORT_UNSPECIFIED || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_UDP && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) || | 
					
						
							|  |  |  | 			(type == PJSIP_TRANSPORT_UDP6 && sip_transport_is_available(PJSIP_TRANSPORT_UDP6))) { | 
					
						
							| 
									
										
										
										
											2018-05-06 22:17:34 -04:00
										 |  |  | 			if (snprintf(srv, sizeof(srv), "_sip._udp.%s", host) < NI_MAXHOST) { | 
					
						
							|  |  |  | 				res |= sip_resolve_add(resolve, srv, T_SRV, C_IN, | 
					
						
							|  |  |  | 					type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type, 0); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP6)) || | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 		((type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type))) { | 
					
						
							|  |  |  | 		res |= sip_resolve_add(resolve, host, T_AAAA, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP6 : type), target->addr.port); | 
					
						
							|  |  |  | 	} else if (!(type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type | PJSIP_TRANSPORT_IPV6)) { | 
					
						
							|  |  |  | 		res |= sip_resolve_add(resolve, host, T_AAAA, C_IN, type | PJSIP_TRANSPORT_IPV6, target->addr.port); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((type == PJSIP_TRANSPORT_UNSPECIFIED && sip_transport_is_available(PJSIP_TRANSPORT_UDP)) || | 
					
						
							| 
									
										
										
										
											2020-05-10 11:01:56 +01:00
										 |  |  | 		(!(type & PJSIP_TRANSPORT_IPV6) && sip_transport_is_available(type))) { | 
					
						
							| 
									
										
										
										
											2016-11-20 09:19:18 +11:00
										 |  |  | 		res |= sip_resolve_add(resolve, host, T_A, C_IN, (type == PJSIP_TRANSPORT_UNSPECIFIED ? PJSIP_TRANSPORT_UDP : type), target->addr.port); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (res) { | 
					
						
							|  |  |  | 		ao2_ref(resolve, -1); | 
					
						
							|  |  |  | 		cb(PJ_ENOMEM, token, NULL); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-05 12:16:22 -05:00
										 |  |  | 	if (!resolve->queries) { | 
					
						
							|  |  |  | 		ast_debug(2, "[%p] No resolution queries for target '%s'\n", resolve, host); | 
					
						
							|  |  |  | 		ao2_ref(resolve, -1); | 
					
						
							|  |  |  | 		cb(PJLIB_UTIL_EDNSNOANSWERREC, token, NULL); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-05 15:37:33 -05:00
										 |  |  | 	resolve->serializer = ao2_bump(ast_threadpool_serializer_get_current()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	ast_debug(2, "[%p] Starting initial resolution using parallel queries for target '%s'\n", resolve, host); | 
					
						
							|  |  |  | 	ast_dns_query_set_resolve_async(resolve->queries, sip_resolve_callback, resolve); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ao2_ref(resolve, -1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Determine if a specific transport is configured on the system | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param pool A memory pool to allocate things from | 
					
						
							|  |  |  |  * \param transport The type of transport to check | 
					
						
							|  |  |  |  * \param name A friendly name to print in the verbose message | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \return Nothing | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void sip_check_transport(pj_pool_t *pool, pjsip_transport_type_e transport, const char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pjsip_tpmgr_fla2_param prm; | 
					
						
							|  |  |  | 	enum sip_resolver_transport resolver_transport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pjsip_tpmgr_fla2_param_default(&prm); | 
					
						
							|  |  |  | 	prm.tp_type = transport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (transport == PJSIP_TRANSPORT_UDP) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_UDP; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TCP) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TCP; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TLS) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TLS; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_UDP6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_UDP6; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TCP6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TCP6; | 
					
						
							|  |  |  | 	} else if (transport == PJSIP_TRANSPORT_TLS6) { | 
					
						
							|  |  |  | 		resolver_transport = SIP_RESOLVER_TRANSPORT_TLS6; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_verb(2, "'%s' is an unsupported SIP transport\n", name); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), | 
					
						
							|  |  |  | 		pool, &prm) == PJ_SUCCESS) { | 
					
						
							|  |  |  | 		ast_verb(2, "'%s' is an available SIP transport\n", name); | 
					
						
							|  |  |  | 		sip_available_transports[resolver_transport] = 1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ast_verb(2, "'%s' is not an available SIP transport, disabling resolver support for it\n", | 
					
						
							|  |  |  | 			name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \brief External resolver implementation for PJSIP */ | 
					
						
							| 
									
										
										
										
											2019-10-23 12:36:17 -05:00
										 |  |  | static pjsip_ext_resolver ext_resolver = { | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	.resolve = sip_resolve, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \internal | 
					
						
							|  |  |  |  * \brief Task to determine available transports and set ourselves an external resolver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \retval 0 success | 
					
						
							|  |  |  |  * \retval -1 failure | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int sip_replace_resolver(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pj_pool_t *pool; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Transport Availability", 256, 256); | 
					
						
							|  |  |  | 	if (!pool) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Determine what transports are available on the system */ | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_UDP, "UDP+IPv4"); | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_TCP, "TCP+IPv4"); | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_TLS, "TLS+IPv4"); | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_UDP6, "UDP+IPv6"); | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_TCP6, "TCP+IPv6"); | 
					
						
							|  |  |  | 	sip_check_transport(pool, PJSIP_TRANSPORT_TLS6, "TLS+IPv6"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Replace the PJSIP resolver with our own implementation */ | 
					
						
							| 
									
										
										
										
											2019-10-23 12:36:17 -05:00
										 |  |  | 	pjsip_endpt_set_ext_resolver(ast_sip_get_pjsip_endpoint(), &ext_resolver); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_initialize_resolver(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Replace the existing PJSIP resolver with our own implementation */ | 
					
						
							| 
									
										
										
										
											2018-07-19 13:27:30 -05:00
										 |  |  | 	ast_sip_push_task_wait_servant(NULL, sip_replace_resolver, NULL); | 
					
						
							| 
									
										
										
										
											2015-04-13 10:47:01 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_initialize_resolver(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* External resolver support does not exist in the version of PJSIP in use */ | 
					
						
							|  |  |  | 	ast_log(LOG_NOTICE, "The version of PJSIP in use does not support external resolvers, using PJSIP provided resolver\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |