Merge "CLI: Remove special handling of 'core set verbose' from rasterisk."
[asterisk/asterisk.git] / main / dns_system_resolver.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Ashley Sanders <asanders@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 /*! \file
20  *
21  * \brief The default DNS resolver for Asterisk.
22  *
23  * \arg See also \ref res_resolver_unbound
24  *
25  * \author Ashley Sanders <asanders@digium.com>
26  */
27
28 #include "asterisk.h"
29
30 #include "asterisk/_private.h"
31 #include "asterisk/astobj2.h"
32 #include "asterisk/dns.h"
33 #include "asterisk/dns_core.h"
34 #include "asterisk/dns_resolver.h"
35 #include "asterisk/linkedlists.h"
36 #include "asterisk/taskprocessor.h"
37 #include "asterisk/utils.h"
38
39 /*! \brief The consideration priority for this resolver implementation. */
40 #define DNS_SYSTEM_RESOLVER_PRIORITY INT_MAX
41
42 /*! \brief Resolver return code upon success. */
43 #define DNS_SYSTEM_RESOLVER_SUCCESS 0
44
45 /*! \brief Resolver return code upon failure. */
46 #define DNS_SYSTEM_RESOLVER_FAILURE -1
47
48
49 static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl);
50 static int dns_system_resolver_cancel(struct ast_dns_query *query);
51 static void dns_system_resolver_destroy(void);
52 static int dns_system_resolver_process_query(void *data);
53 static int dns_system_resolver_resolve(struct ast_dns_query *query);
54 static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode);
55
56
57 /*! \brief The task processor to use for making DNS searches asynchronous. */
58 static struct ast_taskprocessor *dns_system_resolver_tp;
59
60 /*! \brief The base definition for the dns_system_resolver */
61 struct ast_dns_resolver dns_system_resolver_base = {
62         .name = "system",
63         .priority = DNS_SYSTEM_RESOLVER_PRIORITY,
64         .resolve = dns_system_resolver_resolve,
65         .cancel = dns_system_resolver_cancel,
66 };
67
68 /*!
69  * \brief Callback to handle processing resource records.
70  *
71  * \details Adds an individual resource record discovered with ast_search_dns_ex to the
72  *          ast_dns_query currently being resolved.
73  *
74  * \internal
75  *
76  * \param context     A void pointer to the ast_dns_query being processed.
77  * \param record      An individual resource record discovered during the DNS search.
78  * \param record_len  The length of the resource record.
79  * \param ttl         The resource record's expiration time limit (time to live).
80  *
81  * \retval  0 on success
82  * \retval -1 on failure
83  */
84 static int dns_system_resolver_add_record(void *context, unsigned char *record, int record_len, int ttl)
85 {
86         struct ast_dns_query *query = context;
87
88         /* Add the record to the query.*/
89         return ast_dns_resolver_add_record(query,
90                                            ast_dns_query_get_rr_type(query),
91                                            ast_dns_query_get_rr_class(query),
92                                            ttl,
93                                            (const char*) record,
94                                            record_len);
95 }
96
97 /*!
98  * \brief Cancels processing resolution for a given query.
99  *
100  * \note The system API calls block so there is no way to cancel them. Therefore, this function always
101  * returns failure when invoked.
102  *
103  * \internal
104  *
105  * \param query  The ast_dns_query to cancel.
106  *
107  * \retval  0 on success
108  * \retval -1 on failure
109  */
110 static int dns_system_resolver_cancel(struct ast_dns_query *query)
111 {
112         return DNS_SYSTEM_RESOLVER_FAILURE;
113 }
114
115 /*!
116  * \brief Destructor.
117  *
118  * \internal
119  */
120 static void dns_system_resolver_destroy(void)
121 {
122         /* Unreference the task processor */
123         dns_system_resolver_tp = ast_taskprocessor_unreference(dns_system_resolver_tp);
124
125         /* Unregister the base resolver */
126         ast_dns_resolver_unregister(&dns_system_resolver_base);
127 }
128
129 /*!
130  * \brief Callback to handle processing the query from the ast_taskprocessor instance.
131  *
132  * \internal
133  *
134  * \param data  A void pointer to the ast_dns_query being processed.
135  *
136  * \retval -1 on search failure
137  * \retval  0 on no records found
138  * \retval  1 on success
139  */
140 static int dns_system_resolver_process_query(void *data)
141 {
142         struct ast_dns_query *query = data;
143
144         /* Perform the DNS search */
145         enum ast_dns_search_result res = ast_search_dns_ex(query,
146                                                            ast_dns_query_get_name(query),
147                                                            ast_dns_query_get_rr_class(query),
148                                                            ast_dns_query_get_rr_type(query),
149                                                            dns_system_resolver_set_response,
150                                                            dns_system_resolver_add_record);
151
152         /* Handle the possible return values from the DNS search */
153         if (res == AST_DNS_SEARCH_FAILURE) {
154                 ast_debug(1, "DNS search failed for query: '%s'\n",
155                         ast_dns_query_get_name(query));
156         } else if (res == AST_DNS_SEARCH_NO_RECORDS) {
157                 ast_debug(1, "DNS search failed to yield any results for query: '%s'\n",
158                         ast_dns_query_get_name(query));
159         }
160
161         /* Mark the query as complete */
162         ast_dns_resolver_completed(query);
163
164         /* Reduce the reference count on the query object */
165         ao2_ref(query, -1);
166
167         return res;
168 }
169
170 /*!
171  * \brief Resolves a DNS query.
172  *
173  * \internal
174  *
175  * \param query  The ast_dns_query to resolve.
176  *
177  * \retval  0 on successful load of query handler to the ast_taskprocessor instance
178  * \retval -1 on failure to load the query handler to the ast_taskprocessor instance
179  */
180 static int dns_system_resolver_resolve(struct ast_dns_query *query)
181 {
182         /* Add query processing handler to the task processor */
183         int res = ast_taskprocessor_push(dns_system_resolver_tp,
184                                          dns_system_resolver_process_query,
185                                          ao2_bump(query));
186
187         /* The query processing handler was not added to the task processor */
188         if (res < 0) {
189                 ast_log(LOG_ERROR, "Failed to perform async DNS resolution of '%s'\n",
190                         ast_dns_query_get_name(query));
191                 ao2_ref(query, -1);
192         }
193
194         /* Return the result of adding the query processing handler to the task processor */
195         return res;
196 }
197
198 /*!
199  * \brief Callback to handle initializing the results field.
200  *
201  * \internal
202  *
203  * \param dns_response  The full DNS response.
204  * \param dns_response  The length of the full DNS response.
205  * \param rcode         The DNS response code.
206  *
207  * \retval  0 on success
208  * \retval -1 on failure
209  */
210 static int dns_system_resolver_set_response(void *context, unsigned char *dns_response, int dns_response_len, int rcode)
211 {
212         struct ast_dns_query *query = context;
213         int res;
214
215         /* Instantiate the query's result field (if necessary). */
216         if (!ast_dns_query_get_result(query)) {
217                 res = ast_dns_resolver_set_result(query,
218                                                   0,
219                                                   0,
220                                                   rcode,
221                                                   ast_dns_query_get_name(query),
222                                                   (const char*) dns_response,
223                                                   dns_response_len);
224
225                 if (res) {
226                         /* There was a problem instantiating the results field. */
227                         ast_log(LOG_ERROR, "Could not instantiate the results field for query: '%s'\n",
228                                 ast_dns_query_get_name(query));
229                 }
230         } else {
231                 res = DNS_SYSTEM_RESOLVER_SUCCESS;
232         }
233
234         return res;
235 }
236
237 /*!
238  * \brief Initializes the resolver.
239  *
240  * \retval  0 on success
241  * \retval -1 on failure
242  */
243 int ast_dns_system_resolver_init(void)
244 {
245         /* Register the base resolver */
246         int res = ast_dns_resolver_register(&dns_system_resolver_base);
247
248         if (res) {
249                 return DNS_SYSTEM_RESOLVER_FAILURE;
250         }
251
252         /* Instantiate the task processor */
253         dns_system_resolver_tp = ast_taskprocessor_get("dns_system_resolver_tp",
254                                                         TPS_REF_DEFAULT);
255
256         /* Return error if the task processor failed to instantiate */
257         if (!dns_system_resolver_tp) {
258                 dns_system_resolver_destroy();
259                 return DNS_SYSTEM_RESOLVER_FAILURE;
260         }
261
262         /* Register the cleanup function */
263         ast_register_cleanup(dns_system_resolver_destroy);
264
265         return DNS_SYSTEM_RESOLVER_SUCCESS;
266 }