53ea1d09eabce75536adf557cace357e753c9a06
[asterisk/asterisk.git] / main / dns_core.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2015, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Core DNS Functionality
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/linkedlists.h"
35 #include "asterisk/vector.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/strings.h"
38 #include "asterisk/sched.h"
39 #include "asterisk/dns_core.h"
40 #include "asterisk/dns_srv.h"
41 #include "asterisk/dns_tlsa.h"
42 #include "asterisk/dns_recurring.h"
43 #include "asterisk/dns_resolver.h"
44 #include "asterisk/dns_internal.h"
45
46 #include <netinet/in.h>
47 #include <arpa/nameser.h>
48
49 AST_RWLIST_HEAD_STATIC(resolvers, ast_dns_resolver);
50
51 static struct ast_sched_context *sched;
52
53 struct ast_sched_context *ast_dns_get_sched(void)
54 {
55         return sched;
56 }
57
58 const char *ast_dns_query_get_name(const struct ast_dns_query *query)
59 {
60         return query->name;
61 }
62
63 int ast_dns_query_get_rr_type(const struct ast_dns_query *query)
64 {
65         return query->rr_type;
66 }
67
68 int ast_dns_query_get_rr_class(const struct ast_dns_query *query)
69 {
70         return query->rr_class;
71 }
72
73 void *ast_dns_query_get_data(const struct ast_dns_query *query)
74 {
75         return query->user_data;
76 }
77
78 struct ast_dns_result *ast_dns_query_get_result(const struct ast_dns_query *query)
79 {
80         return query->result;
81 }
82
83 unsigned int ast_dns_result_get_secure(const struct ast_dns_result *result)
84 {
85         return result->secure;
86 }
87
88 unsigned int ast_dns_result_get_bogus(const struct ast_dns_result *result)
89 {
90         return result->bogus;
91 }
92
93 unsigned int ast_dns_result_get_rcode(const struct ast_dns_result *result)
94 {
95         return result->rcode;
96 }
97
98 const char *ast_dns_result_get_canonical(const struct ast_dns_result *result)
99 {
100         return result->canonical;
101 }
102
103 const struct ast_dns_record *ast_dns_result_get_records(const struct ast_dns_result *result)
104 {
105         return AST_LIST_FIRST(&result->records);
106 }
107
108 const char *ast_dns_result_get_answer(const struct ast_dns_result *result)
109 {
110         return result->answer;
111 }
112
113 int ast_dns_result_get_lowest_ttl(const struct ast_dns_result *result)
114 {
115         int ttl = 0;
116         const struct ast_dns_record *record;
117
118         if (ast_dns_result_get_rcode(result) == ns_r_nxdomain) {
119                 return 0;
120         }
121
122         for (record = ast_dns_result_get_records(result); record; record = ast_dns_record_get_next(record)) {
123                 if (!ttl || (ast_dns_record_get_ttl(record) && (ast_dns_record_get_ttl(record) < ttl))) {
124                         ttl = ast_dns_record_get_ttl(record);
125                 }
126         }
127
128         return ttl;
129 }
130
131 void ast_dns_result_free(struct ast_dns_result *result)
132 {
133         struct ast_dns_record *record;
134
135         if (!result) {
136                 return;
137         }
138
139         while ((record = AST_LIST_REMOVE_HEAD(&result->records, list))) {
140                 ast_free(record);
141         }
142
143         ast_free(result);
144 }
145
146 int ast_dns_record_get_rr_type(const struct ast_dns_record *record)
147 {
148         return record->rr_type;
149 }
150
151 int ast_dns_record_get_rr_class(const struct ast_dns_record *record)
152 {
153         return record->rr_class;
154 }
155
156 int ast_dns_record_get_ttl(const struct ast_dns_record *record)
157 {
158         return record->ttl;
159 }
160
161 const char *ast_dns_record_get_data(const struct ast_dns_record *record)
162 {
163         return record->data_ptr;
164 }
165
166 const struct ast_dns_record *ast_dns_record_get_next(const struct ast_dns_record *record)
167 {
168         return AST_LIST_NEXT(record, list);
169 }
170
171 /*! \brief Destructor for an active DNS query */
172 static void dns_query_active_destroy(void *data)
173 {
174         struct ast_dns_query_active *active = data;
175
176         ao2_cleanup(active->query);
177 }
178
179 /*! \brief \brief Destructor for a DNS query */
180 static void dns_query_destroy(void *data)
181 {
182         struct ast_dns_query *query = data;
183
184         ao2_cleanup(query->user_data);
185         ao2_cleanup(query->resolver_data);
186         ast_dns_result_free(query->result);
187 }
188
189 struct ast_dns_query_active *ast_dns_resolve_async(const char *name, int rr_type, int rr_class, ast_dns_resolve_callback callback, void *data)
190 {
191         struct ast_dns_query_active *active;
192
193         if (ast_strlen_zero(name)) {
194                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution, no name provided\n");
195                 return NULL;
196         } else if (rr_type > ns_t_max) {
197                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record type '%d' exceeds maximum\n",
198                         name, rr_type);
199                 return NULL;
200         } else if (rr_type < 0) {
201                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', invalid resource record type '%d'\n",
202                         name, rr_type);
203                 return NULL;
204         } else if (rr_class > ns_c_max) {
205                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', resource record class '%d' exceeds maximum\n",
206                         name, rr_class);
207                 return NULL;
208         } else if (rr_class < 0) {
209                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', invalid resource class '%d'\n",
210                         name, rr_class);
211                 return NULL;
212         } else if (!callback) {
213                 ast_log(LOG_WARNING, "Could not perform asynchronous resolution of '%s', no callback provided\n",
214                         name);
215                 return NULL;
216         }
217
218         active = ao2_alloc_options(sizeof(*active), dns_query_active_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
219         if (!active) {
220                 return NULL;
221         }
222
223         active->query = ao2_alloc_options(sizeof(*active->query) + strlen(name) + 1, dns_query_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
224         if (!active->query) {
225                 ao2_ref(active, -1);
226                 return NULL;
227         }
228
229         active->query->callback = callback;
230         active->query->user_data = ao2_bump(data);
231         active->query->rr_type = rr_type;
232         active->query->rr_class = rr_class;
233         strcpy(active->query->name, name); /* SAFE */
234
235         AST_RWLIST_RDLOCK(&resolvers);
236         active->query->resolver = AST_RWLIST_FIRST(&resolvers);
237         AST_RWLIST_UNLOCK(&resolvers);
238
239         if (!active->query->resolver) {
240                 ast_log(LOG_ERROR, "Attempted to do a DNS query for '%s' of class '%d' and type '%d' but no resolver is available\n",
241                         name, rr_class, rr_type);
242                 ao2_ref(active, -1);
243                 return NULL;
244         }
245
246         if (active->query->resolver->resolve(active->query)) {
247                 ast_log(LOG_ERROR, "Resolver '%s' returned an error when resolving '%s' of class '%d' and type '%d'\n",
248                         active->query->resolver->name, name, rr_class, rr_type);
249                 ao2_ref(active, -1);
250                 return NULL;
251         }
252
253         return active;
254 }
255
256 int ast_dns_resolve_cancel(struct ast_dns_query_active *active)
257 {
258         return active->query->resolver->cancel(active->query);
259 }
260
261 /*! \brief Structure used for signaling back for synchronous resolution completion */
262 struct dns_synchronous_resolve {
263         /*! \brief Lock used for signaling */
264         ast_mutex_t lock;
265         /*! \brief Condition used for signaling */
266         ast_cond_t cond;
267         /*! \brief Whether the query has completed */
268         unsigned int completed;
269         /*! \brief The result from the query */
270         struct ast_dns_result *result;
271 };
272
273 /*! \brief Destructor for synchronous resolution structure */
274 static void dns_synchronous_resolve_destroy(void *data)
275 {
276         struct dns_synchronous_resolve *synchronous = data;
277
278         ast_mutex_destroy(&synchronous->lock);
279         ast_cond_destroy(&synchronous->cond);
280
281         /* This purposely does not unref result as it has been passed to the caller */
282 }
283
284 /*! \brief Callback used to implement synchronous resolution */
285 static void dns_synchronous_resolve_callback(const struct ast_dns_query *query)
286 {
287         struct dns_synchronous_resolve *synchronous = ast_dns_query_get_data(query);
288
289         synchronous->result = query->result;
290         ((struct ast_dns_query *)query)->result = NULL;
291
292         ast_mutex_lock(&synchronous->lock);
293         synchronous->completed = 1;
294         ast_cond_signal(&synchronous->cond);
295         ast_mutex_unlock(&synchronous->lock);
296 }
297
298 int ast_dns_resolve(const char *name, int rr_type, int rr_class, struct ast_dns_result **result)
299 {
300         struct dns_synchronous_resolve *synchronous;
301         struct ast_dns_query_active *active;
302
303         if (ast_strlen_zero(name)) {
304                 ast_log(LOG_WARNING, "Could not perform synchronous resolution, no name provided\n");
305                 return -1;
306         } else if (rr_type > ns_t_max) {
307                 ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', resource record type '%d' exceeds maximum\n",
308                         name, rr_type);
309                 return -1;
310         } else if (rr_type < 0) {
311                 ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', invalid resource record type '%d'\n",
312                         name, rr_type);
313                 return -1;
314         } else if (rr_class > ns_c_max) {
315                 ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', resource record class '%d' exceeds maximum\n",
316                         name, rr_class);
317                 return -1;
318         } else if (rr_class < 0) {
319                 ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', invalid resource class '%d'\n",
320                         name, rr_class);
321                 return -1;
322         } else if (!result) {
323                 ast_log(LOG_WARNING, "Could not perform synchronous resolution of '%s', no result pointer provided for storing results\n",
324                         name);
325                 return -1;
326         }
327
328         synchronous = ao2_alloc_options(sizeof(*synchronous), dns_synchronous_resolve_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
329         if (!synchronous) {
330                 return -1;
331         }
332
333         ast_mutex_init(&synchronous->lock);
334         ast_cond_init(&synchronous->cond, NULL);
335
336         active = ast_dns_resolve_async(name, rr_type, rr_class, dns_synchronous_resolve_callback, synchronous);
337         if (active) {
338                 /* Wait for resolution to complete */
339                 ast_mutex_lock(&synchronous->lock);
340                 while (!synchronous->completed) {
341                         ast_cond_wait(&synchronous->cond, &synchronous->lock);
342                 }
343                 ast_mutex_unlock(&synchronous->lock);
344                 ao2_ref(active, -1);
345         }
346
347         *result = synchronous->result;
348         ao2_ref(synchronous, -1);
349
350         return *result ? 0 : -1;
351 }
352
353 int ast_dns_resolver_set_data(struct ast_dns_query *query, void *data)
354 {
355         if (query->resolver_data) {
356                 return -1;
357         }
358
359         query->resolver_data = ao2_bump(data);
360
361         return 0;
362 }
363
364 void *ast_dns_resolver_get_data(const struct ast_dns_query *query)
365 {
366         return query->resolver_data;
367 }
368
369 int ast_dns_resolver_set_result(struct ast_dns_query *query, unsigned int secure, unsigned int bogus,
370         unsigned int rcode, const char *canonical, const char *answer, size_t answer_size)
371 {
372         char *buf_ptr;
373
374         if (secure && bogus) {
375                 ast_debug(2, "Query '%p': Could not set result information, it can not be both secure and bogus\n",
376                         query);
377                 return -1;
378         }
379
380         if (ast_strlen_zero(canonical)) {
381                 ast_debug(2, "Query '%p': Could not set result information since no canonical name was provided\n",
382                         query);
383                 return -1;
384         }
385
386         if (!answer || answer_size == 0) {
387                 ast_debug(2, "Query '%p': Could not set result information since no DNS answer was provided\n",
388                         query);
389                 return -1;
390         }
391
392         ast_dns_result_free(query->result);
393
394         query->result = ast_calloc(1, sizeof(*query->result) + strlen(canonical) + 1 + answer_size);
395         if (!query->result) {
396                 return -1;
397         }
398
399         query->result->secure = secure;
400         query->result->bogus = bogus;
401         query->result->rcode = rcode;
402
403         buf_ptr = query->result->buf;
404         strcpy(buf_ptr, canonical); /* SAFE */
405         query->result->canonical = buf_ptr;
406
407         buf_ptr += strlen(canonical) + 1;
408         memcpy(buf_ptr, answer, answer_size); /* SAFE */
409         query->result->answer = buf_ptr;
410         query->result->answer_size = answer_size;
411
412         return 0;
413 }
414
415 static struct ast_dns_record *generic_record_alloc(struct ast_dns_query *query, const char *data, const size_t size)
416 {
417         struct ast_dns_record *record;
418
419         record = ast_calloc(1, sizeof(*record) + size);
420         if (!record) {
421                 return NULL;
422         }
423
424         record->data_ptr = record->data;
425
426         return record;
427 }
428
429 typedef struct ast_dns_record *(*dns_alloc_fn)(struct ast_dns_query *query, const char *data, const size_t size);
430
431 static dns_alloc_fn dns_alloc_table [] = {
432         [ns_t_naptr] = dns_naptr_alloc,
433         [ns_t_srv] = dns_srv_alloc,
434 };
435
436 static struct ast_dns_record *allocate_dns_record(int rr_type, struct ast_dns_query *query, const char *data, const size_t size)
437 {
438         dns_alloc_fn allocator = dns_alloc_table[rr_type] ?: generic_record_alloc;
439
440         return allocator(query, data, size);
441 }
442
443 int ast_dns_resolver_add_record(struct ast_dns_query *query, int rr_type, int rr_class, int ttl, const char *data, const size_t size)
444 {
445         struct ast_dns_record *record;
446
447         if (rr_type < 0) {
448                 ast_debug(2, "Query '%p': Could not add record, invalid resource record type '%d'\n",
449                         query, rr_type);
450                 return -1;
451         } else if (rr_type > ns_t_max) {
452                 ast_debug(2, "Query '%p': Could not add record, resource record type '%d' exceeds maximum\n",
453                         query, rr_type);
454                 return -1;
455         } else if (rr_class < 0) {
456                 ast_debug(2, "Query '%p': Could not add record, invalid resource record class '%d'\n",
457                         query, rr_class);
458                 return -1;
459         } else if (rr_class > ns_c_max) {
460                 ast_debug(2, "Query '%p': Could not add record, resource record class '%d' exceeds maximum\n",
461                         query, rr_class);
462                 return -1;
463         } else if (ttl < 0) {
464                 ast_debug(2, "Query '%p': Could not add record, invalid TTL '%d'\n",
465                         query, ttl);
466                 return -1;
467         } else if (!data || !size) {
468                 ast_debug(2, "Query '%p': Could not add record, no data specified\n",
469                         query);
470                 return -1;
471         } else if (!query->result) {
472                 ast_debug(2, "Query '%p': No result was set on the query, thus records can not be added\n",
473                         query);
474                 return -1;
475         }
476
477         record = allocate_dns_record(rr_type, query, data, size);
478         if (!record) {
479                 return -1;
480         }
481
482         record->rr_type = rr_type;
483         record->rr_class = rr_class;
484         record->ttl = ttl;
485         record->data_len = size;
486         memcpy(record->data_ptr, data, size);
487
488         AST_LIST_INSERT_TAIL(&query->result->records, record, list);
489
490         return 0;
491 }
492
493 typedef void (*dns_sort_fn)(struct ast_dns_result *result);
494
495 static dns_sort_fn dns_sort_table [] = {
496         [ns_t_naptr] = dns_naptr_sort,
497         [ns_t_srv] = dns_srv_sort,
498 };
499
500 static void sort_result(int rr_type, struct ast_dns_result *result)
501 {
502         if (dns_sort_table[rr_type]) {
503                 dns_sort_table[rr_type](result);
504         }
505 }
506
507 void ast_dns_resolver_completed(struct ast_dns_query *query)
508 {
509         sort_result(ast_dns_query_get_rr_type(query), query->result);
510
511         query->callback(query);
512 }
513
514 static void dns_shutdown(void)
515 {
516         if (sched) {
517                 ast_sched_context_destroy(sched);
518                 sched = NULL;
519         }
520 }
521
522 int ast_dns_resolver_register(struct ast_dns_resolver *resolver)
523 {
524         struct ast_dns_resolver *iter;
525         int inserted = 0;
526
527         if (!resolver) {
528                 return -1;
529         } else if (ast_strlen_zero(resolver->name)) {
530                 ast_log(LOG_ERROR, "Registration of DNS resolver failed as it does not have a name\n");
531                 return -1;
532         } else if (!resolver->resolve) {
533                 ast_log(LOG_ERROR, "DNS resolver '%s' does not implement the resolve callback which is required\n",
534                         resolver->name);
535                 return -1;
536         } else if (!resolver->cancel) {
537                 ast_log(LOG_ERROR, "DNS resolver '%s' does not implement the cancel callback which is required\n",
538                         resolver->name);
539                 return -1;
540         }
541
542         AST_RWLIST_WRLOCK(&resolvers);
543
544         /* On the first registration of a resolver start a scheduler for recurring queries */
545         if (AST_LIST_EMPTY(&resolvers) && !sched) {
546                 sched = ast_sched_context_create();
547                 if (!sched) {
548                         ast_log(LOG_ERROR, "DNS resolver '%s' could not be registered: Failed to create scheduler for recurring DNS queries\n",
549                                 resolver->name);
550                         AST_RWLIST_UNLOCK(&resolvers);
551                         return -1;
552                 }
553
554                 if (ast_sched_start_thread(sched)) {
555                         ast_log(LOG_ERROR, "DNS resolver '%s' could not be registered: Failed to start thread for recurring DNS queries\n",
556                                 resolver->name);
557                         dns_shutdown();
558                         AST_RWLIST_UNLOCK(&resolvers);
559                         return -1;
560                 }
561
562                 ast_register_cleanup(dns_shutdown);
563         }
564
565         AST_LIST_TRAVERSE(&resolvers, iter, next) {
566                 if (!strcmp(iter->name, resolver->name)) {
567                         ast_log(LOG_ERROR, "A DNS resolver with the name '%s' is already registered\n", resolver->name);
568                         AST_RWLIST_UNLOCK(&resolvers);
569                         return -1;
570                 }
571         }
572
573         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&resolvers, iter, next) {
574                 if (iter->priority > resolver->priority) {
575                         AST_RWLIST_INSERT_BEFORE_CURRENT(resolver, next);
576                         inserted = 1;
577                         break;
578                 }
579         }
580         AST_RWLIST_TRAVERSE_SAFE_END;
581
582         if (!inserted) {
583                 AST_RWLIST_INSERT_TAIL(&resolvers, resolver, next);
584         }
585
586         AST_RWLIST_UNLOCK(&resolvers);
587
588         ast_verb(2, "Registered DNS resolver '%s' with priority '%d'\n", resolver->name, resolver->priority);
589
590         return 0;
591 }
592
593 void ast_dns_resolver_unregister(struct ast_dns_resolver *resolver)
594 {
595         struct ast_dns_resolver *iter;
596
597         if (!resolver) {
598                 return;
599         }
600
601         AST_RWLIST_WRLOCK(&resolvers);
602         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&resolvers, iter, next) {
603                 if (resolver == iter) {
604                         AST_RWLIST_REMOVE_CURRENT(next);
605                         break;
606                 }
607         }
608         AST_RWLIST_TRAVERSE_SAFE_END;
609         AST_RWLIST_UNLOCK(&resolvers);
610
611         ast_verb(2, "Unregistered DNS resolver '%s'\n", resolver->name);
612 }
613
614 char *dns_find_record(const char *record, size_t record_size, const char *response, size_t response_size)
615 {
616         size_t remaining_size = response_size;
617         const char *search_base = response;
618         char *record_offset;
619
620         while (1) {
621                 record_offset = memchr(search_base, record[0], remaining_size);
622
623                 ast_assert(record_offset != NULL);
624                 ast_assert(search_base + remaining_size - record_offset >= record_size);
625
626                 if (!memcmp(record_offset, record, record_size)) {
627                         return record_offset;
628                 }
629
630                 remaining_size -= record_offset - search_base;
631                 search_base = record_offset + 1;
632         }
633 }
634
635 int dns_parse_short(unsigned char *cur, uint16_t *val)
636 {
637         /* This assignment takes a big-endian 16-bit value and stores it in the
638          * machine's native byte order. Using this method allows us to avoid potential
639          * alignment issues in case the order is not on a short-addressable boundary.
640          * See http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html for
641          * more information
642          */
643         *val = (cur[1] << 0) | (cur[0] << 8);
644         return sizeof(*val);
645 }
646
647 int dns_parse_string(char *cur, uint8_t *size, char **val)
648 {
649         *size = *cur++;
650         *val = cur;
651         return *size + 1;
652 }