blob: 0ce63c910728ee8cbc74ecb01a147090e36dd8d1 [file] [log] [blame]
Baptiste Assmann325137d2015-04-13 23:40:55 +02001/*
2 * Name server resolution
3 *
4 * Copyright 2014 Baptiste Assmann <bedis9@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14#include <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20#include <sys/types.h>
21
22#include <common/time.h>
23#include <common/ticks.h>
24
Baptiste Assmannfa4a6632017-05-04 09:05:00 +020025#include <import/lru.h>
26#include <import/xxhash.h>
27
William Lallemand69e96442016-11-19 00:58:54 +010028#include <types/applet.h>
29#include <types/cli.h>
Baptiste Assmann325137d2015-04-13 23:40:55 +020030#include <types/global.h>
31#include <types/dns.h>
32#include <types/proto_udp.h>
William Lallemand69e96442016-11-19 00:58:54 +010033#include <types/stats.h>
Baptiste Assmann325137d2015-04-13 23:40:55 +020034
William Lallemand69e96442016-11-19 00:58:54 +010035#include <proto/channel.h>
36#include <proto/cli.h>
Baptiste Assmann325137d2015-04-13 23:40:55 +020037#include <proto/checks.h>
38#include <proto/dns.h>
39#include <proto/fd.h>
40#include <proto/log.h>
41#include <proto/server.h>
42#include <proto/task.h>
43#include <proto/proto_udp.h>
William Lallemand69e96442016-11-19 00:58:54 +010044#include <proto/stream_interface.h>
Baptiste Assmann325137d2015-04-13 23:40:55 +020045
46struct list dns_resolvers = LIST_HEAD_INIT(dns_resolvers);
47struct dns_resolution *resolution = NULL;
48
49static int64_t dns_query_id_seed; /* random seed */
50
Baptiste Assmannfa4a6632017-05-04 09:05:00 +020051static struct lru64_head *dns_lru_tree;
52static int dns_cache_size = 1024; /* arbitrary DNS cache size */
53
Olivier Houcharda8c6db82017-07-06 18:46:47 +020054static struct pool_head *dns_answer_item_pool;
55
Baptiste Assmann325137d2015-04-13 23:40:55 +020056/* proto_udp callback functions for a DNS resolution */
57struct dgram_data_cb resolve_dgram_cb = {
58 .recv = dns_resolve_recv,
59 .send = dns_resolve_send,
60};
61
Baptiste Assmann201c07f2017-05-22 15:17:15 +020062/* local function prototypes */
63static int dns_run_resolution(struct dns_requester *requester);
64
Baptiste Assmann325137d2015-04-13 23:40:55 +020065#if DEBUG
66/*
67 * go through the resolutions associated to a resolvers section and print the ID and hostname in
68 * domain name format
69 * should be used for debug purpose only
70 */
71void dns_print_current_resolutions(struct dns_resolvers *resolvers)
72{
Baptiste Assmann201c07f2017-05-22 15:17:15 +020073 list_for_each_entry(resolution, &resolvers->resolution.curr, list) {
Baptiste Assmann325137d2015-04-13 23:40:55 +020074 printf(" resolution %d for %s\n", resolution->query_id, resolution->hostname_dn);
75 }
76}
77#endif
78
Baptiste Assmann201c07f2017-05-22 15:17:15 +020079void dump_dns_config()
80{
81 struct dns_resolvers *curr_resolvers = NULL;
82 struct dns_nameserver *curr_nameserver = NULL;
83 struct dns_resolution *curr_resolution = NULL;
84 struct dns_requester *curr_requester = NULL;
85
86 printf("===============\n");
87 list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
88 printf("Resolvers: %s\n", curr_resolvers->id);
89
90 printf(" nameservers:\n");
91 list_for_each_entry(curr_nameserver, &curr_resolvers->nameserver_list, list) {
92 printf(" %s\n", curr_nameserver->id);
93 }
94
95/*
96 printf(" resolution.pool list:\n");
97 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.pool, list) {
98 printf(" %p\n", curr_resolution);
99 }
100*/
101
102 printf(" resolution.wait list:\n");
103 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.wait, list) {
104 printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
105 printf(" requester.wait list:\n");
106 list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
107 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
108 }
109 printf(" requester.curr list:\n");
110 list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
111 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
112 }
113 }
114 printf(" resolution.curr list:\n");
115 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.curr, list) {
116 printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
117 printf(" requester.wait list:\n");
118 list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
119 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
120 }
121 printf(" requester.curr list:\n");
122 list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
123 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
124 }
125 }
126 }
127
128 printf("===============\n");
129}
130
131/*
132 * Initiates a new name resolution:
133 * - generates a query id
134 * - configure the resolution structure
135 * - startup the resolvers task if required
136 *
137 * returns:
138 * - 0 if everything started properly
139 * - -1 in case of error or if resolution already running
140 */
141int dns_trigger_resolution(struct dns_resolution *resolution)
142{
143 struct dns_requester *requester = NULL, *tmprequester;
144 struct dns_resolvers *resolvers = NULL;
145 int inter;
146
147 /* process the element of the wait queue */
148 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
149 inter = 0;
150
151 switch (obj_type(requester->requester)) {
152 case OBJ_TYPE_SERVER:
153 inter = objt_server(requester->requester)->check.inter;
154 resolvers = objt_server(requester->requester)->resolvers;
155 break;
156 case OBJ_TYPE_NONE:
157 default:
158 return -1;
159 }
160
161 /* if data is fresh enough, let's use it */
162 if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
163 /* we only use cache if the response there is valid.
164 * If not valid, we run the resolution and move the requester to
165 * the run queue. */
166 if (resolution->status != RSLV_STATUS_VALID) {
167 LIST_DEL(&requester->list);
168 LIST_ADDQ(&resolution->requester.curr, &requester->list);
169 dns_run_resolution(requester);
170 continue;
171 }
172
173 requester->requester_cb(requester, NULL);
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200174 resolvers = NULL;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200175 }
176 else {
177 LIST_DEL(&requester->list);
178 LIST_ADDQ(&resolution->requester.curr, &requester->list);
179 dns_run_resolution(requester);
180 }
181 }
182
183 if (resolvers)
184 dns_update_resolvers_timeout(resolvers);
185
186 return 0;
187}
188
Baptiste Assmann325137d2015-04-13 23:40:55 +0200189/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200190 * Prepare and send a DNS resolution.
191 *
192 * Return code:
193 * - 0 if no error occured
194 * - -1 in case of error
195 */
196static int
197dns_run_resolution(struct dns_requester *requester)
198{
199 struct dns_resolution *resolution;
200 struct dns_resolvers *resolvers;
201 int query_id, query_type, i;
202 struct proxy *proxy;
203
204 resolution = NULL;
205 resolvers = NULL;
206 proxy = NULL;
207 query_type = -1;
208 switch (obj_type(requester->requester)) {
209 case OBJ_TYPE_SERVER:
210 resolution = objt_server(requester->requester)->resolution;
211 resolvers = objt_server(requester->requester)->resolvers;
212 proxy = objt_server(requester->requester)->proxy;
213 query_type = requester->prefered_query_type;
214 break;
215 case OBJ_TYPE_NONE:
216 default:
217 return -1;
218 }
219
220 /*
221 * check if a resolution has already been started for this server
222 * return directly to avoid resolution pill up.
223 */
224 if (resolution->step != RSLV_STEP_NONE)
225 return 0;
226
227 /* generates a query id */
228 i = 0;
229 do {
230 query_id = dns_rnd16();
231 /* we do try only 100 times to find a free query id */
232 if (i++ > 100) {
233 chunk_printf(&trash, "could not generate a query id for %s, in resolvers %s",
234 resolution->hostname_dn, resolvers->id);
235
236 if (proxy)
237 send_log(proxy, LOG_NOTICE, "%s.\n", trash.str);
238 return -1;
239 }
240 } while (eb32_lookup(&resolvers->query_ids, query_id));
241
242 /* move the resolution into the run queue */
243 LIST_DEL(&resolution->list);
244 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
245
246 /* now update resolution parameters */
247 resolution->query_id = query_id;
248 resolution->qid.key = query_id;
249 resolution->step = RSLV_STEP_RUNNING;
250 resolution->query_type = query_type;
251 resolution->try = resolvers->resolve_retries;
252 resolution->try_cname = 0;
253 resolution->nb_responses = 0;
254 eb32_insert(&resolvers->query_ids, &resolution->qid);
255
256 dns_send_query(resolution);
257 resolution->try -= 1;
258
259 /* update wakeup date if this resolution is the only one in the FIFO list */
260 if (dns_check_resolution_queue(resolvers) == 1) {
261 /* update task timeout */
262 dns_update_resolvers_timeout(resolvers);
263 task_queue(resolvers->t);
264 }
265
266 return 0;
267}
268
269/*
Baptiste Assmann325137d2015-04-13 23:40:55 +0200270 * check if there is more than 1 resolution in the resolver's resolution list
271 * return value:
272 * 0: empty list
273 * 1: exactly one entry in the list
274 * 2: more than one entry in the list
275 */
276int dns_check_resolution_queue(struct dns_resolvers *resolvers)
277{
278
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200279 if (LIST_ISEMPTY(&resolvers->resolution.curr))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200280 return 0;
281
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200282 if ((resolvers->resolution.curr.n) && (resolvers->resolution.curr.n == resolvers->resolution.curr.p))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200283 return 1;
284
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200285 if (! ((resolvers->resolution.curr.n == resolvers->resolution.curr.p)
286 && (&resolvers->resolution.curr != resolvers->resolution.curr.n)))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200287 return 2;
288
289 return 0;
290}
291
292/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200293 * reset some resolution parameters to initial values and also delete the
294 * query ID from the resolver's tree.
Baptiste Assmann325137d2015-04-13 23:40:55 +0200295 */
296void dns_reset_resolution(struct dns_resolution *resolution)
297{
298 /* update resolution status */
299 resolution->step = RSLV_STEP_NONE;
300
301 resolution->try = 0;
302 resolution->try_cname = 0;
303 resolution->last_resolution = now_ms;
304 resolution->nb_responses = 0;
305
306 /* clean up query id */
307 eb32_delete(&resolution->qid);
308 resolution->query_id = 0;
309 resolution->qid.key = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200310}
311
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200312static inline void free_dns_answer_item(struct dns_answer_item *item)
313{
314 pool_free2(dns_answer_item_pool, item);
315}
316
317
Baptiste Assmann325137d2015-04-13 23:40:55 +0200318/*
319 * function called when a network IO is generated on a name server socket for an incoming packet
320 * It performs the following actions:
321 * - check if the packet requires processing (not outdated resolution)
322 * - ensure the DNS packet received is valid and call requester's callback
323 * - call requester's error callback if invalid response
Baptiste Assmann3cf7f982016-04-17 22:43:26 +0200324 * - check the dn_name in the packet against the one sent
Baptiste Assmann325137d2015-04-13 23:40:55 +0200325 */
326void dns_resolve_recv(struct dgram_conn *dgram)
327{
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200328 struct dns_nameserver *nameserver, *tmpnameserver;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200329 struct dns_resolvers *resolvers;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200330 struct dns_resolution *resolution = NULL;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200331 struct dns_query_item *query;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200332 unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
333 unsigned char *bufend;
William Lallemandcc9b94a2017-06-08 19:30:39 +0200334 int fd, buflen, dns_resp, need_resend = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200335 unsigned short query_id;
336 struct eb32_node *eb;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200337 struct lru64 *lru = NULL;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200338 struct dns_requester *requester = NULL, *tmprequester = NULL;
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200339 struct dns_answer_item *item1, *item2 = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200340
341 fd = dgram->t.sock.fd;
342
343 /* check if ready for reading */
344 if (!fd_recv_ready(fd))
345 return;
346
347 /* no need to go further if we can't retrieve the nameserver */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200348 if ((nameserver = dgram->owner) == NULL)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200349 return;
350
351 resolvers = nameserver->resolvers;
352
353 /* process all pending input messages */
354 while (1) {
355 /* read message received */
356 memset(buf, '\0', DNS_MAX_UDP_MESSAGE + 1);
357 if ((buflen = recv(fd, (char*)buf , DNS_MAX_UDP_MESSAGE, 0)) < 0) {
358 /* FIXME : for now we consider EAGAIN only */
359 fd_cant_recv(fd);
360 break;
361 }
362
363 /* message too big */
364 if (buflen > DNS_MAX_UDP_MESSAGE) {
365 nameserver->counters.too_big += 1;
366 continue;
367 }
368
369 /* initializing variables */
370 bufend = buf + buflen; /* pointer to mark the end of the buffer */
371
372 /* read the query id from the packet (16 bits) */
373 if (buf + 2 > bufend) {
374 nameserver->counters.invalid += 1;
375 continue;
376 }
377 query_id = dns_response_get_query_id(buf);
378
379 /* search the query_id in the pending resolution tree */
Baptiste Assmann01daef32015-09-02 22:05:24 +0200380 eb = eb32_lookup(&resolvers->query_ids, query_id);
381 if (eb == NULL) {
Baptiste Assmann325137d2015-04-13 23:40:55 +0200382 /* unknown query id means an outdated response and can be safely ignored */
383 nameserver->counters.outdated += 1;
384 continue;
385 }
386
387 /* known query id means a resolution in prgress */
388 resolution = eb32_entry(eb, struct dns_resolution, qid);
389
390 if (!resolution) {
391 nameserver->counters.outdated += 1;
392 continue;
393 }
394
395 /* number of responses received */
396 resolution->nb_responses += 1;
397
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200398 dns_resp = dns_validate_dns_response(buf, bufend, resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200399
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200400 switch (dns_resp) {
401 case DNS_RESP_VALID:
402 need_resend = 0;
403 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200404
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200405 case DNS_RESP_INVALID:
406 case DNS_RESP_QUERY_COUNT_ERROR:
407 case DNS_RESP_WRONG_NAME:
408 if (resolution->status != RSLV_STATUS_INVALID) {
409 resolution->status = RSLV_STATUS_INVALID;
410 resolution->last_status_change = now_ms;
411 }
412 nameserver->counters.invalid += 1;
413 need_resend = 0;
414 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200415
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200416 case DNS_RESP_ANCOUNT_ZERO:
417 if (resolution->status != RSLV_STATUS_OTHER) {
418 resolution->status = RSLV_STATUS_OTHER;
419 resolution->last_status_change = now_ms;
420 }
421 nameserver->counters.any_err += 1;
422 need_resend = 1;
423 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200424
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200425 case DNS_RESP_NX_DOMAIN:
426 if (resolution->status != RSLV_STATUS_NX) {
427 resolution->status = RSLV_STATUS_NX;
428 resolution->last_status_change = now_ms;
429 }
430 nameserver->counters.nx += 1;
431 need_resend = 0;
432 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200433
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200434 case DNS_RESP_REFUSED:
435 if (resolution->status != RSLV_STATUS_REFUSED) {
436 resolution->status = RSLV_STATUS_REFUSED;
437 resolution->last_status_change = now_ms;
438 }
439 nameserver->counters.refused += 1;
440 need_resend = 0;
441 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200442
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200443 case DNS_RESP_CNAME_ERROR:
444 if (resolution->status != RSLV_STATUS_OTHER) {
445 resolution->status = RSLV_STATUS_OTHER;
446 resolution->last_status_change = now_ms;
447 }
448 nameserver->counters.cname_error += 1;
449 need_resend = 1;
450 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200451
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200452 case DNS_RESP_TRUNCATED:
453 if (resolution->status != RSLV_STATUS_OTHER) {
454 resolution->status = RSLV_STATUS_OTHER;
455 resolution->last_status_change = now_ms;
456 }
457 nameserver->counters.truncated += 1;
458 need_resend = 1;
459 break;
Baptiste Assmann96972bc2015-09-09 00:46:58 +0200460
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200461 case DNS_RESP_NO_EXPECTED_RECORD:
462 if (resolution->status != RSLV_STATUS_OTHER) {
463 resolution->status = RSLV_STATUS_OTHER;
464 resolution->last_status_change = now_ms;
465 }
466 nameserver->counters.other += 1;
467 need_resend = 1;
468 break;
469
470 case DNS_RESP_ERROR:
471 case DNS_RESP_INTERNAL:
472 if (resolution->status != RSLV_STATUS_OTHER) {
473 resolution->status = RSLV_STATUS_OTHER;
474 resolution->last_status_change = now_ms;
475 }
476 nameserver->counters.other += 1;
477 need_resend = 1;
478 break;
479 }
480
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200481 /* Check for any obsolete record */
482 list_for_each_entry_safe(item1, item2, &resolution->response.answer_list,
483 list) {
484 if (item1->last_seen + nameserver->resolvers->hold.obsolete / 1000 < now.tv_sec) {
485 LIST_DEL(&item1->list);
486 free_dns_answer_item(item1);
487 }
488 }
489
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200490 /* some error codes trigger a re-send of the query, but switching the
491 * query type.
492 * This is the case for the following error codes:
493 * DNS_RESP_ANCOUNT_ZERO
494 * DNS_RESP_TRUNCATED
495 * DNS_RESP_ERROR
496 * DNS_RESP_INTERNAL
497 * DNS_RESP_NO_EXPECTED_RECORD
498 * DNS_RESP_CNAME_ERROR
499 */
500 if (need_resend) {
501 int family_prio;
502 int res_preferred_afinet, res_preferred_afinet6;
503
504 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
505 switch (obj_type(requester->requester)) {
506 case OBJ_TYPE_SERVER:
507 family_prio = objt_server(requester->requester)->dns_opts.family_prio;
508 break;
509 case OBJ_TYPE_NONE:
510 default:
511 family_prio = AF_INET6;
512 }
513 res_preferred_afinet = family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
514 res_preferred_afinet6 = family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
515 if ((res_preferred_afinet || res_preferred_afinet6)
516 || (resolution->try > 0)) {
517 /* let's change the query type */
518 if (res_preferred_afinet6) {
519 /* fallback from AAAA to A */
520 resolution->query_type = DNS_RTYPE_A;
521 }
522 else if (res_preferred_afinet) {
523 /* fallback from A to AAAA */
524 resolution->query_type = DNS_RTYPE_AAAA;
525 }
526 else {
527 resolution->try -= 1;
528 if (family_prio == AF_INET) {
529 resolution->query_type = DNS_RTYPE_A;
530 } else {
531 resolution->query_type = DNS_RTYPE_AAAA;
532 }
533 }
534
535 dns_send_query(resolution);
536 /*
537 * move the resolution to the last element of the FIFO queue
538 * and update timeout wakeup based on the new first entry
539 */
540 if (dns_check_resolution_queue(resolvers) > 1) {
541 /* second resolution becomes first one */
542 LIST_DEL(&resolution->list);
543 /* ex first resolution goes to the end of the queue */
544 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
545 }
546
547 dns_update_resolvers_timeout(resolvers);
548 goto next_packet;
549 }
550
551 /* if we're there, this means that we already ran out of chances to re-send
552 * the query */
553 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
554 requester->requester_error_cb(requester, dns_resp);
555 }
556 goto next_packet;
557 }
558
559 /* now processing those error codes only:
560 * DNS_RESP_NX_DOMAIN
561 * DNS_RESP_REFUSED
562 */
563 if (dns_resp != DNS_RESP_VALID) {
564 /* now parse list of requesters currently waiting for this resolution */
565 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
566 requester->requester_error_cb(requester, dns_resp);
567
568 /* we can move the requester the wait queue */
569 LIST_DEL(&requester->list);
570 LIST_ADDQ(&resolution->requester.wait, &requester->list);
571 }
572 goto next_packet;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200573 }
574
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200575 /* Now let's check the query's dname corresponds to the one we sent.
576 * We can check only the first query of the list. We send one query at a time
577 * so we get one query in the response */
Baptiste Assmann729c9012017-05-22 15:13:10 +0200578 query = LIST_NEXT(&resolution->response.query_list, struct dns_query_item *, list);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200579 if (query && memcmp(query->name, resolution->hostname_dn, resolution->hostname_dn_len) != 0) {
580 nameserver->counters.other += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200581 /* now parse list of requesters currently waiting for this resolution */
582 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
583 requester->requester_error_cb(requester, DNS_RESP_WRONG_NAME);
584 /* we can move the requester the wait queue */
585 LIST_DEL(&requester->list);
586 LIST_ADDQ(&resolution->requester.wait, &requester->list);
587 }
588 goto next_packet;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200589 }
590
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200591 /* no errors, we can save the response in the cache */
592 if (dns_lru_tree) {
593 unsigned long long seed = 1;
594 struct chunk *buf = get_trash_chunk();
595 struct chunk *tmp = NULL;
596
597 chunk_reset(buf);
598 tmp = dns_cache_key(resolution->query_type, resolution->hostname_dn,
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200599 resolution->hostname_dn_len, buf);
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200600 if (!tmp) {
601 nameserver->counters.other += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200602 /* now parse list of requesters currently waiting for this resolution */
603 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
604 requester->requester_error_cb(requester, DNS_RESP_ERROR);
605 /* we can move the requester the wait queue */
606 LIST_DEL(&requester->list);
607 LIST_ADDQ(&resolution->requester.wait, &requester->list);
608 }
609 goto next_packet;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200610 }
611
612 lru = lru64_get(XXH64(buf->str, buf->len, seed),
613 dns_lru_tree, nameserver->resolvers, 1);
614
615 lru64_commit(lru, resolution, nameserver->resolvers, 1, NULL);
616 }
617
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200618 if (resolution->status != RSLV_STATUS_VALID) {
619 resolution->status = RSLV_STATUS_VALID;
620 resolution->last_status_change = now_ms;
621 }
622
Baptiste Assmann37bb3722015-08-07 10:18:32 +0200623 nameserver->counters.valid += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200624 /* now parse list of requesters currently waiting for this resolution */
625 tmpnameserver = nameserver;
626 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
627 requester->requester_cb(requester, tmpnameserver);
628 /* we can move the requester the wait queue */
629 LIST_DEL(&requester->list);
630 LIST_ADDQ(&resolution->requester.wait, &requester->list);
631 /* first response is managed by the server, others are from the cache */
632 tmpnameserver = NULL;
633 }
634
635 next_packet:
636 /* resolution may be NULL when we receive an ICMP unreachable packet */
637 if (resolution && LIST_ISEMPTY(&resolution->requester.curr)) {
638 /* move the resolution into the wait queue */
639 LIST_DEL(&resolution->list);
640 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
641 /* update last resolution date and time */
642 resolution->last_resolution = now_ms;
643 /* reset current status flag */
644 resolution->step = RSLV_STEP_NONE;
645 /* reset values */
646 dns_reset_resolution(resolution);
647 }
648
649 } // end of while "packets" loop
650
651 dns_update_resolvers_timeout(nameserver->resolvers);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200652}
653
654/*
655 * function called when a resolvers network socket is ready to send data
656 * It performs the following actions:
657 */
658void dns_resolve_send(struct dgram_conn *dgram)
659{
660 int fd;
661 struct dns_nameserver *nameserver;
662 struct dns_resolvers *resolvers;
663 struct dns_resolution *resolution;
664
665 fd = dgram->t.sock.fd;
666
667 /* check if ready for sending */
668 if (!fd_send_ready(fd))
669 return;
670
671 /* we don't want/need to be waked up any more for sending */
672 fd_stop_send(fd);
673
674 /* no need to go further if we can't retrieve the nameserver */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200675 if ((nameserver = dgram->owner) == NULL)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200676 return;
677
678 resolvers = nameserver->resolvers;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200679 resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200680
681 dns_send_query(resolution);
682 dns_update_resolvers_timeout(resolvers);
683}
684
685/*
686 * forge and send a DNS query to resolvers associated to a resolution
687 * It performs the following actions:
688 * returns:
689 * 0 in case of error or safe ignorance
690 * 1 if no error
691 */
692int dns_send_query(struct dns_resolution *resolution)
693{
Baptiste Assmann42746372017-05-03 12:12:02 +0200694 struct dns_resolvers *resolvers = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200695 struct dns_nameserver *nameserver;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200696 struct dns_requester *requester = NULL;
Erwan Velu5457eb42015-10-15 15:07:26 +0200697 int ret, bufsize, fd;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200698
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200699 /* nothing to do */
700 if (LIST_ISEMPTY(&resolution->requester.curr))
701 return 0;
702
703 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
704
705 switch (obj_type(requester->requester)) {
706 case OBJ_TYPE_SERVER:
707 resolvers = objt_server(requester->requester)->resolvers;
708 break;
709 case OBJ_TYPE_NONE:
710 default:
711 return 0;
712 }
Baptiste Assmann42746372017-05-03 12:12:02 +0200713
714 if (!resolvers)
715 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200716
Baptiste Assmann325137d2015-04-13 23:40:55 +0200717 bufsize = dns_build_query(resolution->query_id, resolution->query_type, resolution->hostname_dn,
718 resolution->hostname_dn_len, trash.str, trash.size);
719
720 if (bufsize == -1)
721 return 0;
722
723 list_for_each_entry(nameserver, &resolvers->nameserver_list, list) {
724 fd = nameserver->dgram->t.sock.fd;
725 errno = 0;
726
727 ret = send(fd, trash.str, bufsize, 0);
728
729 if (ret > 0)
730 nameserver->counters.sent += 1;
731
732 if (ret == 0 || errno == EAGAIN) {
733 /* nothing written, let's update the poller that we wanted to send
734 * but we were not able to */
735 fd_want_send(fd);
736 fd_cant_send(fd);
737 }
738 }
739
740 /* update resolution */
Baptiste Assmann325137d2015-04-13 23:40:55 +0200741 resolution->nb_responses = 0;
742 resolution->last_sent_packet = now_ms;
743
744 return 1;
745}
746
747/*
748 * update a resolvers' task timeout for next wake up
749 */
750void dns_update_resolvers_timeout(struct dns_resolvers *resolvers)
751{
752 struct dns_resolution *resolution;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200753 struct dns_requester *requester;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200754
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200755 if ((LIST_ISEMPTY(&resolvers->resolution.curr)) && (LIST_ISEMPTY(&resolvers->resolution.wait))) {
Baptiste Assmann325137d2015-04-13 23:40:55 +0200756 resolvers->t->expire = TICK_ETERNITY;
757 }
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200758 else if (!LIST_ISEMPTY(&resolvers->resolution.curr)) {
759 resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
760 if (!resolvers->t->expire || tick_is_le(resolvers->t->expire, tick_add(resolution->last_sent_packet, resolvers->timeout.retry))) {
761 resolvers->t->expire = tick_add(resolution->last_sent_packet, resolvers->timeout.retry);
762 }
Baptiste Assmann325137d2015-04-13 23:40:55 +0200763 }
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200764 else if (!LIST_ISEMPTY(&resolvers->resolution.wait)) {
765 int valid_period, inter, need_wakeup;
766 struct dns_resolution *res_back;
767 need_wakeup = 0;
768 list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.wait, list) {
769 valid_period = 0;
770 inter = 0;
771
772 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
773
774 switch (obj_type(requester->requester)) {
775 case OBJ_TYPE_SERVER:
776 valid_period = objt_server(requester->requester)->check.inter;
777 break;
778 case OBJ_TYPE_NONE:
779 default:
780 continue;
781 }
782
783 if (resolvers->hold.valid < valid_period)
784 inter = resolvers->hold.valid;
785 else
786 inter = valid_period;
787
788 if (tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
789 switch (obj_type(requester->requester)) {
790 case OBJ_TYPE_SERVER:
791 dns_trigger_resolution(objt_server(requester->requester)->resolution);
792 break;
793 case OBJ_TYPE_NONE:
794 default:
795 ;;
796 }
797 }
798 else {
799 need_wakeup = 1;
800 }
801 }
802 /* in such case, we wake up in 1s */
803 if (need_wakeup) {
804 int r = 1000;
805
806 resolution = LIST_NEXT(&resolvers->resolution.wait, struct dns_resolution *, list);
807 if (tick_is_le(resolvers->t->expire, tick_add(now_ms, r)))
808 resolvers->t->expire = tick_add(now_ms, r);
809 resolvers->t->expire = tick_add(now_ms, 1000);
810 }
811 }
812
813 task_queue(resolvers->t);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200814}
815
816/*
817 * Analyse, re-build and copy the name <name> from the DNS response packet <buffer>.
818 * <name> must point to the 'data_len' information or pointer 'c0' for compressed data.
819 * The result is copied into <dest>, ensuring we don't overflow using <dest_len>
820 * Returns the number of bytes the caller can move forward. If 0 it means an error occured
821 * while parsing the name.
822 * <offset> is the number of bytes the caller could move forward.
823 */
824int dns_read_name(unsigned char *buffer, unsigned char *bufend, unsigned char *name, char *destination, int dest_len, int *offset)
825{
826 int nb_bytes = 0, n = 0;
827 int label_len;
828 unsigned char *reader = name;
829 char *dest = destination;
830
831 while (1) {
832 /* name compression is in use */
833 if ((*reader & 0xc0) == 0xc0) {
834 /* a pointer must point BEFORE current position */
835 if ((buffer + reader[1]) > reader) {
836 goto out_error;
837 }
838
839 n = dns_read_name(buffer, bufend, buffer + reader[1], dest, dest_len - nb_bytes, offset);
840 if (n == 0)
841 goto out_error;
842
843 dest += n;
844 nb_bytes += n;
845 goto out;
846 }
847
848 label_len = *reader;
849 if (label_len == 0)
850 goto out;
851 /* Check if:
852 * - we won't read outside the buffer
853 * - there is enough place in the destination
854 */
855 if ((reader + label_len >= bufend) || (nb_bytes + label_len >= dest_len))
856 goto out_error;
857
858 /* +1 to take label len + label string */
859 label_len += 1;
860
861 memcpy(dest, reader, label_len);
862
863 dest += label_len;
864 nb_bytes += label_len;
865 reader += label_len;
866 }
867
868 out:
869 /* offset computation:
870 * parse from <name> until finding either NULL or a pointer "c0xx"
871 */
872 reader = name;
873 *offset = 0;
874 while (reader < bufend) {
875 if ((reader[0] & 0xc0) == 0xc0) {
876 *offset += 2;
877 break;
878 }
879 else if (*reader == 0) {
880 *offset += 1;
881 break;
882 }
883 *offset += 1;
884 ++reader;
885 }
886
887 return nb_bytes;
888
889 out_error:
890 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200891}
892
893/*
894 * Function to validate that the buffer DNS response provided in <resp> and
895 * finishing before <bufend> is valid from a DNS protocol point of view.
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200896 *
Baptiste Assmann729c9012017-05-22 15:13:10 +0200897 * The result is stored in <resolution>' response, buf_response, response_query_records
898 * and response_answer_records members.
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200899 *
900 * This function returns one of the DNS_RESP_* code to indicate the type of
901 * error found.
Baptiste Assmann325137d2015-04-13 23:40:55 +0200902 */
Baptiste Assmann729c9012017-05-22 15:13:10 +0200903int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200904{
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200905 unsigned char *reader;
906 char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200907 int len, flags, offset;
908 int dns_query_record_id;
Baptiste Assmann69fce672017-05-04 08:37:45 +0200909 int nb_saved_records;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200910 struct dns_query_item *dns_query;
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200911 struct dns_answer_item *dns_answer_record, *tmp_record;
Baptiste Assmann729c9012017-05-22 15:13:10 +0200912 struct dns_response_packet *dns_p;
Olivier Houcharda8c6db82017-07-06 18:46:47 +0200913 int found = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200914
915 reader = resp;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200916 len = 0;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200917 previous_dname = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200918
Baptiste Assmann729c9012017-05-22 15:13:10 +0200919 /* initialization of response buffer and structure */
920 dns_p = &resolution->response;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200921
922 /* query id */
923 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200924 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200925 dns_p->header.id = reader[0] * 256 + reader[1];
926 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200927
928 /*
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200929 * flags and rcode are stored over 2 bytes
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200930 * First byte contains:
931 * - response flag (1 bit)
932 * - opcode (4 bits)
933 * - authoritative (1 bit)
934 * - truncated (1 bit)
935 * - recursion desired (1 bit)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200936 */
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200937 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200938 return DNS_RESP_INVALID;
939
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200940 flags = reader[0] * 256 + reader[1];
941
942 if (flags & DNS_FLAG_TRUNCATED)
943 return DNS_RESP_TRUNCATED;
944
945 if ((flags & DNS_FLAG_REPLYCODE) != DNS_RCODE_NO_ERROR) {
946 if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_NX_DOMAIN)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200947 return DNS_RESP_NX_DOMAIN;
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200948 else if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_REFUSED)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200949 return DNS_RESP_REFUSED;
950
951 return DNS_RESP_ERROR;
952 }
953
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200954 /* move forward 2 bytes for flags */
955 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200956
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200957 /* 2 bytes for question count */
958 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200959 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200960 dns_p->header.qdcount = reader[0] * 256 + reader[1];
961 /* (for now) we send one query only, so we expect only one in the response too */
962 if (dns_p->header.qdcount != 1)
963 return DNS_RESP_QUERY_COUNT_ERROR;
964 if (dns_p->header.qdcount > DNS_MAX_QUERY_RECORDS)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200965 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200966 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200967
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200968 /* 2 bytes for answer count */
969 if (reader + 2 >= bufend)
970 return DNS_RESP_INVALID;
971 dns_p->header.ancount = reader[0] * 256 + reader[1];
972 if (dns_p->header.ancount == 0)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200973 return DNS_RESP_ANCOUNT_ZERO;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200974 /* check if too many records are announced */
975 if (dns_p->header.ancount > DNS_MAX_ANSWER_RECORDS)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200976 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200977 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200978
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200979 /* 2 bytes authority count */
980 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200981 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200982 dns_p->header.nscount = reader[0] * 256 + reader[1];
983 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200984
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200985 /* 2 bytes additional count */
986 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200987 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200988 dns_p->header.arcount = reader[0] * 256 + reader[1];
989 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200990
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200991 /* parsing dns queries */
992 LIST_INIT(&dns_p->query_list);
993 for (dns_query_record_id = 0; dns_query_record_id < dns_p->header.qdcount; dns_query_record_id++) {
994 /* use next pre-allocated dns_query_item after ensuring there is
995 * still one available.
996 * It's then added to our packet query list.
997 */
998 if (dns_query_record_id > DNS_MAX_QUERY_RECORDS)
999 return DNS_RESP_INVALID;
Baptiste Assmann729c9012017-05-22 15:13:10 +02001000 dns_query = &resolution->response_query_records[dns_query_record_id];
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001001 LIST_ADDQ(&dns_p->query_list, &dns_query->list);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001002
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001003 /* name is a NULL terminated string in our case, since we have
1004 * one query per response and the first one can't be compressed
1005 * (using the 0x0c format)
1006 */
1007 offset = 0;
1008 len = dns_read_name(resp, bufend, reader, dns_query->name, DNS_MAX_NAME_SIZE, &offset);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001009
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001010 if (len == 0)
1011 return DNS_RESP_INVALID;
1012
1013 reader += offset;
1014 previous_dname = dns_query->name;
1015
1016 /* move forward 2 bytes for question type */
1017 if (reader + 2 >= bufend)
1018 return DNS_RESP_INVALID;
1019 dns_query->type = reader[0] * 256 + reader[1];
1020 reader += 2;
1021
1022 /* move forward 2 bytes for question class */
1023 if (reader + 2 >= bufend)
1024 return DNS_RESP_INVALID;
1025 dns_query->class = reader[0] * 256 + reader[1];
1026 reader += 2;
1027 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001028
1029 /* now parsing response records */
Baptiste Assmann69fce672017-05-04 08:37:45 +02001030 nb_saved_records = 0;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001031 for (int i = 0; i < dns_p->header.ancount; i++) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001032 if (reader >= bufend)
1033 return DNS_RESP_INVALID;
1034
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001035 dns_answer_record = pool_alloc2(dns_answer_item_pool);
1036 if (dns_answer_record == NULL)
1037 return (DNS_RESP_INVALID);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001038
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001039 offset = 0;
1040 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001041
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001042 if (len == 0) {
1043 free_dns_answer_item(dns_answer_record);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001044 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001045 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001046
1047 /* check if the current record dname is valid.
1048 * previous_dname points either to queried dname or last CNAME target
1049 */
1050 if (memcmp(previous_dname, tmpname, len) != 0) {
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001051 free_dns_answer_item(dns_answer_record);
1052 if (i == 0) {
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001053 /* first record, means a mismatch issue between queried dname
1054 * and dname found in the first record */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001055 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001056 } else {
1057 /* if not the first record, this means we have a CNAME resolution
1058 * error */
1059 return DNS_RESP_CNAME_ERROR;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001060 }
1061
Baptiste Assmann325137d2015-04-13 23:40:55 +02001062 }
1063
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001064 memcpy(dns_answer_record->name, tmpname, len);
1065 dns_answer_record->name[len] = 0;
Baptiste Assmann2359ff12015-08-07 11:24:05 +02001066
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001067 reader += offset;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001068 if (reader >= bufend) {
1069 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001070 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001071 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001072
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001073 if (reader >= bufend) {
1074 free_dns_answer_item(dns_answer_record);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001075 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001076 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001077
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001078 /* 2 bytes for record type (A, AAAA, CNAME, etc...) */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001079 if (reader + 2 > bufend) {
1080 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001081 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001082 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001083 dns_answer_record->type = reader[0] * 256 + reader[1];
1084 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001085
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001086 /* 2 bytes for class (2) */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001087 if (reader + 2 > bufend) {
1088 free_dns_answer_item(dns_answer_record);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001089 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001090 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001091 dns_answer_record->class = reader[0] * 256 + reader[1];
Baptiste Assmann325137d2015-04-13 23:40:55 +02001092 reader += 2;
1093
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001094 /* 4 bytes for ttl (4) */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001095 if (reader + 4 > bufend) {
1096 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001097 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001098 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001099 dns_answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
1100 + reader[2] * 256 + reader[3];
1101 reader += 4;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001102
1103 /* now reading data len */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001104 if (reader + 2 > bufend) {
1105 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001106 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001107 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001108 dns_answer_record->data_len = reader[0] * 256 + reader[1];
Baptiste Assmann325137d2015-04-13 23:40:55 +02001109
1110 /* move forward 2 bytes for data len */
1111 reader += 2;
1112
1113 /* analyzing record content */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001114 switch (dns_answer_record->type) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001115 case DNS_RTYPE_A:
1116 /* ipv4 is stored on 4 bytes */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001117 if (dns_answer_record->data_len != 4) {
1118 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001119 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001120 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001121 dns_answer_record->address.sa_family = AF_INET;
1122 memcpy(&(((struct sockaddr_in *)&dns_answer_record->address)->sin_addr),
1123 reader, dns_answer_record->data_len);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001124 break;
1125
1126 case DNS_RTYPE_CNAME:
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001127 /* check if this is the last record and update the caller about the status:
1128 * no IP could be found and last record was a CNAME. Could be triggered
1129 * by a wrong query type
1130 *
1131 * + 1 because dns_answer_record_id starts at 0 while number of answers
1132 * is an integer and starts at 1.
1133 */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001134 if (i + 1 == dns_p->header.ancount) {
1135 free_dns_answer_item(dns_answer_record);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001136 return DNS_RESP_CNAME_ERROR;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001137 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001138
1139 offset = 0;
1140 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
1141
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001142 if (len == 0) {
1143 free_dns_answer_item(dns_answer_record);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001144 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001145 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001146
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001147 memcpy(dns_answer_record->target, tmpname, len);
1148 dns_answer_record->target[len] = 0;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001149
1150 previous_dname = dns_answer_record->target;
1151
Baptiste Assmann325137d2015-04-13 23:40:55 +02001152 break;
1153
1154 case DNS_RTYPE_AAAA:
1155 /* ipv6 is stored on 16 bytes */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001156 if (dns_answer_record->data_len != 16) {
1157 free_dns_answer_item(dns_answer_record);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001158 return DNS_RESP_INVALID;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001159 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001160 dns_answer_record->address.sa_family = AF_INET6;
1161 memcpy(&(((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr),
1162 reader, dns_answer_record->data_len);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001163 break;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001164
Baptiste Assmann325137d2015-04-13 23:40:55 +02001165 } /* switch (record type) */
1166
Baptiste Assmann69fce672017-05-04 08:37:45 +02001167 /* increment the counter for number of records saved into our local response */
1168 nb_saved_records += 1;
1169
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001170 /* move forward dns_answer_record->data_len for analyzing next record in the response */
1171 reader += dns_answer_record->data_len;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001172
1173 /* Lookup to see if we already had this entry */
1174
1175 list_for_each_entry(tmp_record, &dns_p->answer_list, list) {
1176 if (tmp_record->type != dns_answer_record->type)
1177 continue;
1178 switch (tmp_record->type) {
1179 case DNS_RTYPE_A:
1180 if (!memcmp(&((struct sockaddr_in *)&dns_answer_record->address)->sin_addr,
1181 &((struct sockaddr_in *)&tmp_record->address)->sin_addr, sizeof(in_addr_t)))
1182 found = 1;
1183 break;
1184 case DNS_RTYPE_AAAA:
1185 if (!memcmp(&((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr,
1186 &((struct sockaddr_in6 *)&tmp_record->address)->sin6_addr, sizeof(struct in6_addr)))
1187 found = 1;
1188 break;
1189 default:
1190 break;
1191 }
1192 if (found == 1)
1193 break;
1194 }
1195 if (found == 1) {
1196 tmp_record->last_seen = now.tv_sec;
1197 free_dns_answer_item(dns_answer_record);
1198 } else {
1199 dns_answer_record->last_seen = now.tv_sec;
1200 LIST_ADDQ(&dns_p->answer_list, &dns_answer_record->list);
1201 }
1202
Baptiste Assmann325137d2015-04-13 23:40:55 +02001203 } /* for i 0 to ancount */
1204
Baptiste Assmann96972bc2015-09-09 00:46:58 +02001205
Baptiste Assmann69fce672017-05-04 08:37:45 +02001206 /* save the number of records we really own */
1207 dns_p->header.ancount = nb_saved_records;
1208
Baptiste Assmann325137d2015-04-13 23:40:55 +02001209 return DNS_RESP_VALID;
1210}
1211
1212/*
1213 * search dn_name resolution in resp.
1214 * If existing IP not found, return the first IP matching family_priority,
1215 * otherwise, first ip found
1216 * The following tasks are the responsibility of the caller:
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001217 * - <dns_p> contains an error free DNS response
Baptiste Assmann325137d2015-04-13 23:40:55 +02001218 * For both cases above, dns_validate_dns_response is required
1219 * returns one of the DNS_UPD_* code
1220 */
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001221#define DNS_MAX_IP_REC 20
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001222int dns_get_ip_from_response(struct dns_response_packet *dns_p,
Baptiste Assmann42746372017-05-03 12:12:02 +02001223 struct dns_options *dns_opts, void *currentip,
Thierry Fournierada34842016-02-17 21:25:09 +01001224 short currentip_sin_family,
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001225 void **newip, short *newip_sin_family,
1226 void *owner)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001227{
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001228 struct dns_answer_item *record;
Thierry Fournierada34842016-02-17 21:25:09 +01001229 int family_priority;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001230 int currentip_found;
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001231 unsigned char *newip4, *newip6;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001232 int currentip_sel;
1233 int j;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001234 int score, max_score;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001235
Baptiste Assmann42746372017-05-03 12:12:02 +02001236 family_priority = dns_opts->family_prio;
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001237 *newip = newip4 = newip6 = NULL;
1238 currentip_found = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001239 *newip_sin_family = AF_UNSPEC;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001240 max_score = -1;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001241
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001242 /* Select an IP regarding configuration preference.
1243 * Top priority is the prefered network ip version,
1244 * second priority is the prefered network.
1245 * the last priority is the currently used IP,
1246 *
1247 * For these three priorities, a score is calculated. The
1248 * weight are:
Baptistefc725902016-12-26 23:21:08 +01001249 * 8 - prefered netwok ip version.
1250 * 4 - prefered network.
1251 * 2 - if the ip in the record is not affected to any other server in the same backend (duplication)
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001252 * 1 - current ip.
1253 * The result with the biggest score is returned.
1254 */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001255
1256 list_for_each_entry(record, &dns_p->answer_list, list) {
1257 void *ip;
1258 unsigned char ip_type;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001259
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001260 if (record->type == DNS_RTYPE_A) {
1261 ip = &(((struct sockaddr_in *)&record->address)->sin_addr);
1262 ip_type = AF_INET;
1263 } else if (record->type == DNS_RTYPE_AAAA) {
1264 ip_type = AF_INET6;
1265 ip = &(((struct sockaddr_in6 *)&record->address)->sin6_addr);
1266 } else
1267 continue;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001268 score = 0;
1269
1270 /* Check for prefered ip protocol. */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001271 if (ip_type == family_priority)
Baptistefc725902016-12-26 23:21:08 +01001272 score += 8;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001273
1274 /* Check for prefered network. */
Baptiste Assmann42746372017-05-03 12:12:02 +02001275 for (j = 0; j < dns_opts->pref_net_nb; j++) {
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001276
1277 /* Compare only the same adresses class. */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001278 if (dns_opts->pref_net[j].family != ip_type)
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001279 continue;
1280
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001281 if ((ip_type == AF_INET &&
1282 in_net_ipv4(ip,
Baptiste Assmann42746372017-05-03 12:12:02 +02001283 &dns_opts->pref_net[j].mask.in4,
1284 &dns_opts->pref_net[j].addr.in4)) ||
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001285 (ip_type == AF_INET6 &&
1286 in_net_ipv6(ip,
Baptiste Assmann42746372017-05-03 12:12:02 +02001287 &dns_opts->pref_net[j].mask.in6,
1288 &dns_opts->pref_net[j].addr.in6))) {
Baptistefc725902016-12-26 23:21:08 +01001289 score += 4;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001290 break;
1291 }
1292 }
1293
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001294 /* Check if the IP found in the record is already affected to a member of a group.
1295 * If yes, the score should be incremented by 2.
1296 */
1297 if (owner) {
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001298 if (snr_check_ip_callback(owner, ip, &ip_type))
1299 {
1300 continue;
1301 }
Baptistefc725902016-12-26 23:21:08 +01001302 }
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001303 /* Check for current ip matching. */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001304 if (ip_type == currentip_sin_family &&
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001305 ((currentip_sin_family == AF_INET &&
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001306 memcmp(ip, currentip, 4) == 0) ||
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001307 (currentip_sin_family == AF_INET6 &&
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001308 memcmp(ip, currentip, 16) == 0))) {
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001309 score += 1;
1310 currentip_sel = 1;
1311 } else
1312 currentip_sel = 0;
1313
Baptistefc725902016-12-26 23:21:08 +01001314
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001315 /* Keep the address if the score is better than the previous
Baptistefc725902016-12-26 23:21:08 +01001316 * score. The maximum score is 15, if this value is reached,
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001317 * we break the parsing. Implicitly, this score is reached
1318 * the ip selected is the current ip.
1319 */
1320 if (score > max_score) {
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001321 if (ip_type == AF_INET)
1322 newip4 = ip;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001323 else
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001324 newip6 = ip;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001325 currentip_found = currentip_sel;
Baptistefc725902016-12-26 23:21:08 +01001326 if (score == 15)
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001327 return DNS_UPD_NO;
1328 max_score = score;
1329 }
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001330
1331
1332 } /* list for each record entries */
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001333
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02001334 /* no IP found in the response */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001335 if (!newip4 && !newip6)
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02001336 return DNS_UPD_NO_IP_FOUND;
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02001337
Baptiste Assmann325137d2015-04-13 23:40:55 +02001338 /* case when the caller looks first for an IPv4 address */
1339 if (family_priority == AF_INET) {
1340 if (newip4) {
1341 *newip = newip4;
1342 *newip_sin_family = AF_INET;
1343 if (currentip_found == 1)
1344 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001345 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001346 }
1347 else if (newip6) {
1348 *newip = newip6;
1349 *newip_sin_family = AF_INET6;
1350 if (currentip_found == 1)
1351 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001352 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001353 }
1354 }
1355 /* case when the caller looks first for an IPv6 address */
1356 else if (family_priority == AF_INET6) {
1357 if (newip6) {
1358 *newip = newip6;
1359 *newip_sin_family = AF_INET6;
1360 if (currentip_found == 1)
1361 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001362 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001363 }
1364 else if (newip4) {
1365 *newip = newip4;
1366 *newip_sin_family = AF_INET;
1367 if (currentip_found == 1)
1368 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001369 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001370 }
1371 }
1372 /* case when the caller have no preference (we prefer IPv6) */
1373 else if (family_priority == AF_UNSPEC) {
1374 if (newip6) {
1375 *newip = newip6;
1376 *newip_sin_family = AF_INET6;
1377 if (currentip_found == 1)
1378 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001379 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001380 }
1381 else if (newip4) {
1382 *newip = newip4;
1383 *newip_sin_family = AF_INET;
1384 if (currentip_found == 1)
1385 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001386 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001387 }
1388 }
1389
1390 /* no reason why we should change the server's IP address */
1391 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001392
1393 return_DNS_UPD_SRVIP_NOT_FOUND:
1394 list_for_each_entry(record, &dns_p->answer_list, list) {
1395 /* move the first record to the end of the list, for internal round robin */
1396 if (record) {
1397 LIST_DEL(&record->list);
1398 LIST_ADDQ(&dns_p->answer_list, &record->list);
1399 break;
1400 }
1401 }
1402 return DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001403}
1404
1405/*
1406 * returns the query id contained in a DNS response
1407 */
Thiago Farinab1af23e2016-01-20 23:46:34 +01001408unsigned short dns_response_get_query_id(unsigned char *resp)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001409{
1410 /* read the query id from the response */
1411 return resp[0] * 256 + resp[1];
1412}
1413
1414/*
1415 * used during haproxy's init phase
1416 * parses resolvers sections and initializes:
1417 * - task (time events) for each resolvers section
1418 * - the datagram layer (network IO events) for each nameserver
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001419 * It takes one argument:
1420 * - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
Baptiste Assmann325137d2015-04-13 23:40:55 +02001421 * returns:
1422 * 0 in case of error
1423 * 1 when no error
1424 */
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001425int dns_init_resolvers(int close_socket)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001426{
1427 struct dns_resolvers *curr_resolvers;
1428 struct dns_nameserver *curnameserver;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001429 struct dns_resolution *resolution, *res_back;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001430 struct dgram_conn *dgram;
1431 struct task *t;
1432 int fd;
1433
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001434 /* initialize our DNS resolution cache */
1435 dns_lru_tree = lru64_new(dns_cache_size);
1436
Baptiste Assmann325137d2015-04-13 23:40:55 +02001437 /* give a first random value to our dns query_id seed */
1438 dns_query_id_seed = random();
1439
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001440 /* Initialize the answer items pool */
1441 dns_answer_item_pool = create_pool("dns_answer_item",
1442 sizeof(struct dns_answer_item), MEM_F_SHARED);
1443 if (dns_answer_item_pool == NULL) {
1444 Alert("Failed to create the dns answer items pool");
1445 return 0;
1446 }
1447
Baptiste Assmann325137d2015-04-13 23:40:55 +02001448 /* run through the resolvers section list */
1449 list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
1450 /* create the task associated to the resolvers section */
1451 if ((t = task_new()) == NULL) {
1452 Alert("Starting [%s] resolvers: out of memory.\n", curr_resolvers->id);
1453 return 0;
1454 }
1455
1456 /* update task's parameters */
1457 t->process = dns_process_resolve;
1458 t->context = curr_resolvers;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001459
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001460 /* no need to keep the new task if one is already affected to our resolvers
1461 * section */
1462 if (!curr_resolvers->t)
1463 curr_resolvers->t = t;
1464 else
1465 task_free(t);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001466
1467 list_for_each_entry(curnameserver, &curr_resolvers->nameserver_list, list) {
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001468 dgram = NULL;
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001469
1470 if (close_socket == 1) {
1471 if (curnameserver->dgram) {
Frédéric Lécaille64920532017-05-12 09:57:15 +02001472 fd_delete(curnameserver->dgram->t.sock.fd);
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001473 memset(curnameserver->dgram, '\0', sizeof(*dgram));
1474 dgram = curnameserver->dgram;
1475 }
1476 }
1477
1478 /* allocate memory only if it has not already been allocated
1479 * by a previous call to this function */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02001480
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001481 if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001482 Alert("Starting [%s/%s] nameserver: out of memory.\n", curr_resolvers->id,
1483 curnameserver->id);
1484 return 0;
1485 }
1486 /* update datagram's parameters */
1487 dgram->owner = (void *)curnameserver;
1488 dgram->data = &resolve_dgram_cb;
1489
1490 /* create network UDP socket for this nameserver */
Frédéric Lécaille5e5bc9f2017-04-11 08:46:37 +02001491 if ((fd = socket(curnameserver->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001492 Alert("Starting [%s/%s] nameserver: can't create socket.\n", curr_resolvers->id,
1493 curnameserver->id);
1494 free(dgram);
1495 dgram = NULL;
1496 return 0;
1497 }
1498
1499 /* "connect" the UDP socket to the name server IP */
Baptiste Assmann8c62c472015-09-21 20:55:08 +02001500 if (connect(fd, (struct sockaddr*)&curnameserver->addr, get_addr_len(&curnameserver->addr)) == -1) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001501 Alert("Starting [%s/%s] nameserver: can't connect socket.\n", curr_resolvers->id,
1502 curnameserver->id);
1503 close(fd);
1504 free(dgram);
1505 dgram = NULL;
1506 return 0;
1507 }
1508
1509 /* make the socket non blocking */
1510 fcntl(fd, F_SETFL, O_NONBLOCK);
1511
1512 /* add the fd in the fd list and update its parameters */
1513 fd_insert(fd);
1514 fdtab[fd].owner = dgram;
1515 fdtab[fd].iocb = dgram_fd_handler;
1516 fd_want_recv(fd);
1517 dgram->t.sock.fd = fd;
1518
1519 /* update nameserver's datagram property */
1520 curnameserver->dgram = dgram;
1521
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001522 continue;
1523 }
1524
1525 if (close_socket == 0)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001526 continue;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001527
1528 /* now, we can trigger DNS resolution */
1529 list_for_each_entry_safe(resolution, res_back, &curr_resolvers->resolution.wait, list) {
1530 /* if there is no requester in the wait queue, no need to trigger the resolution */
1531 if (LIST_ISEMPTY(&resolution->requester.wait))
1532 continue;
1533
1534 dns_trigger_resolution(resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001535 }
1536
1537 /* task can be queued */
1538 task_queue(t);
1539 }
1540
1541 return 1;
1542}
1543
1544/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001545 * Allocate a pool of resolution to a resolvers section.
1546 * Each resolution is associated with a UUID.
1547 *
1548 * Return code:
1549 * - 0 if everything went smoothly
1550 * - -1 if an error occured
1551 */
1552int dns_alloc_resolution_pool(struct dns_resolvers *resolvers)
1553{
1554 int i;
1555 struct dns_resolution *resolution;
1556
1557 /* return if a pool has already been set for this resolvers */
1558 if (!LIST_ISEMPTY(&resolvers->resolution.pool)) {
1559 return 0;
1560 }
1561
1562 for (i = 0; i < resolvers->resolution_pool_size; i++) {
1563 resolution = dns_alloc_resolution();
1564 if (!resolution) {
1565 Alert("Starting [%s] resolvers: can't allocate memory for DNS resolution pool.\n", resolvers->id);
1566 return -1;
1567 }
1568 resolution->uuid = i;
1569 LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
1570 }
1571
1572 return 0;
1573}
1574
1575/*
Baptiste Assmann325137d2015-04-13 23:40:55 +02001576 * Forge a DNS query. It needs the following information from the caller:
1577 * - <query_id>: the DNS query id corresponding to this query
1578 * - <query_type>: DNS_RTYPE_* request DNS record type (A, AAAA, ANY, etc...)
1579 * - <hostname_dn>: hostname in domain name format
1580 * - <hostname_dn_len>: length of <hostname_dn>
1581 * To store the query, the caller must pass a buffer <buf> and its size <bufsize>
1582 *
1583 * the DNS query is stored in <buf>
1584 * returns:
1585 * -1 if <buf> is too short
1586 */
1587int dns_build_query(int query_id, int query_type, char *hostname_dn, int hostname_dn_len, char *buf, int bufsize)
1588{
1589 struct dns_header *dns;
Vincent Bernat9b7125c2016-04-08 22:17:45 +02001590 struct dns_question qinfo;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001591 char *ptr, *bufend;
1592
1593 memset(buf, '\0', bufsize);
1594 ptr = buf;
1595 bufend = buf + bufsize;
1596
1597 /* check if there is enough room for DNS headers */
1598 if (ptr + sizeof(struct dns_header) >= bufend)
1599 return -1;
1600
1601 /* set dns query headers */
1602 dns = (struct dns_header *)ptr;
1603 dns->id = (unsigned short) htons(query_id);
Nenad Merdanovic8ab79422016-07-13 14:03:43 +02001604 dns->flags = htons(0x0100); /* qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, rcode=0 */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001605 dns->qdcount = htons(1); /* 1 question */
1606 dns->ancount = 0;
1607 dns->nscount = 0;
1608 dns->arcount = 0;
1609
1610 /* move forward ptr */
1611 ptr += sizeof(struct dns_header);
1612
1613 /* check if there is enough room for query hostname */
1614 if ((ptr + hostname_dn_len) >= bufend)
1615 return -1;
1616
1617 /* set up query hostname */
1618 memcpy(ptr, hostname_dn, hostname_dn_len);
1619 ptr[hostname_dn_len + 1] = '\0';
1620
1621 /* move forward ptr */
1622 ptr += (hostname_dn_len + 1);
1623
1624 /* check if there is enough room for query hostname*/
1625 if (ptr + sizeof(struct dns_question) >= bufend)
1626 return -1;
1627
1628 /* set up query info (type and class) */
Vincent Bernat9b7125c2016-04-08 22:17:45 +02001629 qinfo.qtype = htons(query_type);
1630 qinfo.qclass = htons(DNS_RCLASS_IN);
1631 memcpy(ptr, &qinfo, sizeof(qinfo));
Baptiste Assmann325137d2015-04-13 23:40:55 +02001632
1633 ptr += sizeof(struct dns_question);
1634
1635 return ptr - buf;
1636}
1637
1638/*
1639 * turn a string into domain name label:
1640 * www.haproxy.org into 3www7haproxy3org
1641 * if dn memory is pre-allocated, you must provide its size in dn_len
1642 * if dn memory isn't allocated, dn_len must be set to 0.
1643 * In the second case, memory will be allocated.
1644 * in case of error, -1 is returned, otherwise, number of bytes copied in dn
1645 */
Willy Tarreau2100b492015-07-22 16:42:43 +02001646char *dns_str_to_dn_label(const char *string, char *dn, int dn_len)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001647{
1648 char *c, *d;
1649 int i, offset;
1650
1651 /* offset between string size and theorical dn size */
1652 offset = 1;
1653
1654 /*
1655 * first, get the size of the string turned into its domain name version
1656 * This function also validates the string respect the RFC
1657 */
1658 if ((i = dns_str_to_dn_label_len(string)) == -1)
1659 return NULL;
1660
1661 /* yes, so let's check there is enough memory */
1662 if (dn_len < i + offset)
1663 return NULL;
1664
Willy Tarreaud69d6f32015-07-22 16:45:36 +02001665 i = strlen(string);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001666 memcpy(dn + offset, string, i);
1667 dn[i + offset] = '\0';
1668 /* avoid a '\0' at the beginning of dn string which may prevent the for loop
1669 * below from working.
1670 * Actually, this is the reason of the offset. */
1671 dn[0] = '0';
1672
1673 for (c = dn; *c ; ++c) {
1674 /* c points to the first '0' char or a dot, which we don't want to read */
1675 d = c + offset;
1676 i = 0;
1677 while (*d != '.' && *d) {
1678 i++;
1679 d++;
1680 }
1681 *c = i;
1682
1683 c = d - 1; /* because of c++ of the for loop */
1684 }
1685
1686 return dn;
1687}
1688
1689/*
1690 * compute and return the length of <string> it it were translated into domain name
1691 * label:
1692 * www.haproxy.org into 3www7haproxy3org would return 16
1693 * NOTE: add +1 for '\0' when allocating memory ;)
1694 */
1695int dns_str_to_dn_label_len(const char *string)
1696{
1697 return strlen(string) + 1;
1698}
1699
1700/*
1701 * validates host name:
1702 * - total size
1703 * - each label size individually
1704 * returns:
1705 * 0 in case of error. If <err> is not NULL, an error message is stored there.
1706 * 1 when no error. <err> is left unaffected.
1707 */
1708int dns_hostname_validation(const char *string, char **err)
1709{
1710 const char *c, *d;
1711 int i;
1712
1713 if (strlen(string) > DNS_MAX_NAME_SIZE) {
1714 if (err)
1715 *err = DNS_TOO_LONG_FQDN;
1716 return 0;
1717 }
1718
1719 c = string;
1720 while (*c) {
1721 d = c;
1722
1723 i = 0;
1724 while (*d != '.' && *d && i <= DNS_MAX_LABEL_SIZE) {
1725 i++;
1726 if (!((*d == '-') || (*d == '_') ||
1727 ((*d >= 'a') && (*d <= 'z')) ||
1728 ((*d >= 'A') && (*d <= 'Z')) ||
1729 ((*d >= '0') && (*d <= '9')))) {
1730 if (err)
1731 *err = DNS_INVALID_CHARACTER;
1732 return 0;
1733 }
1734 d++;
1735 }
1736
1737 if ((i >= DNS_MAX_LABEL_SIZE) && (d[i] != '.')) {
1738 if (err)
1739 *err = DNS_LABEL_TOO_LONG;
1740 return 0;
1741 }
1742
1743 if (*d == '\0')
1744 goto out;
1745
1746 c = ++d;
1747 }
1748 out:
1749 return 1;
1750}
1751
1752/*
1753 * 2 bytes random generator to generate DNS query ID
1754 */
1755uint16_t dns_rnd16(void)
1756{
1757 dns_query_id_seed ^= dns_query_id_seed << 13;
1758 dns_query_id_seed ^= dns_query_id_seed >> 7;
1759 dns_query_id_seed ^= dns_query_id_seed << 17;
1760 return dns_query_id_seed;
1761}
1762
1763
1764/*
1765 * function called when a timeout occurs during name resolution process
1766 * if max number of tries is reached, then stop, otherwise, retry.
1767 */
1768struct task *dns_process_resolve(struct task *t)
1769{
1770 struct dns_resolvers *resolvers = t->context;
1771 struct dns_resolution *resolution, *res_back;
Baptiste Assmann060e5732016-01-06 02:01:59 +01001772 int res_preferred_afinet, res_preferred_afinet6;
Baptiste Assmann42746372017-05-03 12:12:02 +02001773 struct dns_options *dns_opts = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001774
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001775 /* if both there is no resolution in the run queue, we can re-schedule a wake up */
1776 if (LIST_ISEMPTY(&resolvers->resolution.curr)) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001777 /* no first entry, so wake up was useless */
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001778 dns_update_resolvers_timeout(resolvers);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001779 return t;
1780 }
1781
1782 /* look for the first resolution which is not expired */
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001783 list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.curr, list) {
1784 struct dns_requester *requester = NULL;
1785
Baptiste Assmann325137d2015-04-13 23:40:55 +02001786 /* when we find the first resolution in the future, then we can stop here */
1787 if (tick_is_le(now_ms, resolution->last_sent_packet))
1788 goto out;
1789
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001790 if (LIST_ISEMPTY(&resolution->requester.curr))
1791 goto out;
1792
Baptiste Assmann325137d2015-04-13 23:40:55 +02001793 /*
1794 * if current resolution has been tried too many times and finishes in timeout
1795 * we update its status and remove it from the list
1796 */
Baptiste Assmannf778bb42015-09-09 00:54:38 +02001797 if (resolution->try <= 0) {
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001798 struct dns_requester *tmprequester;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001799 /* clean up resolution information and remove from the list */
1800 dns_reset_resolution(resolution);
1801
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001802 LIST_DEL(&resolution->list);
1803 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
1804
1805 if (resolution->status != RSLV_STATUS_TIMEOUT) {
1806 resolution->status = RSLV_STATUS_TIMEOUT;
1807 resolution->last_status_change = now_ms;
1808 }
1809
1810 /* notify the result to the requesters */
1811 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
1812 requester->requester_error_cb(requester, DNS_RESP_TIMEOUT);
1813 LIST_DEL(&requester->list);
1814 LIST_ADDQ(&resolution->requester.wait, &requester->list);
1815 }
Baptiste Assmann382824c2016-01-06 01:53:46 +01001816 goto out;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001817 }
1818
Baptiste Assmannf778bb42015-09-09 00:54:38 +02001819 resolution->try -= 1;
1820
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001821 /* running queue is empty, nothing to do but wait */
1822 if (LIST_ISEMPTY(&resolution->requester.curr))
1823 goto out;
1824
1825 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
1826
1827 switch (obj_type(requester->requester)) {
1828 case OBJ_TYPE_SERVER:
1829 dns_opts = &(objt_server(requester->requester)->dns_opts);
1830 break;
1831
1832 case OBJ_TYPE_NONE:
1833 default:
1834 /* clean up resolution information and remove from the list */
1835 dns_reset_resolution(resolution);
1836
1837 LIST_DEL(&resolution->list);
1838 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
1839
1840 /* notify the result to the requester */
1841 requester->requester_error_cb(requester, DNS_RESP_INTERNAL);
1842 goto out;
1843 }
Baptiste Assmann42746372017-05-03 12:12:02 +02001844
1845 res_preferred_afinet = dns_opts->family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
1846 res_preferred_afinet6 = dns_opts->family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
Baptiste Assmann060e5732016-01-06 02:01:59 +01001847
1848 /* let's change the query type if needed */
1849 if (res_preferred_afinet6) {
1850 /* fallback from AAAA to A */
1851 resolution->query_type = DNS_RTYPE_A;
1852 }
1853 else if (res_preferred_afinet) {
1854 /* fallback from A to AAAA */
1855 resolution->query_type = DNS_RTYPE_AAAA;
1856 }
1857
Baptiste Assmann382824c2016-01-06 01:53:46 +01001858 /* resend the DNS query */
1859 dns_send_query(resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001860
Baptiste Assmann382824c2016-01-06 01:53:46 +01001861 /* check if we have more than one resolution in the list */
1862 if (dns_check_resolution_queue(resolvers) > 1) {
1863 /* move the rsolution to the end of the list */
1864 LIST_DEL(&resolution->list);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001865 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001866 }
1867 }
1868
1869 out:
1870 dns_update_resolvers_timeout(resolvers);
1871 return t;
1872}
William Lallemand69e96442016-11-19 00:58:54 +01001873
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001874/*
1875 * build a dns cache key composed as follow:
1876 * <query type>#<hostname in domain name format>
1877 * and store it into <str>.
1878 * It's up to the caller to allocate <buf> and to reset it.
1879 * The function returns NULL in case of error (IE <buf> too small) or a pointer
1880 * to buf if successful
1881 */
1882struct chunk *
1883dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf)
1884{
1885 int len, size;
1886 char *str;
1887
1888 str = buf->str;
1889 len = buf->len;
1890 size = buf->size;
1891
1892 switch (query_type) {
1893 case DNS_RTYPE_A:
1894 if (len + 1 > size)
1895 return NULL;
1896 memcpy(&str[len], "A", 1);
1897 len += 1;
1898 break;
1899 case DNS_RTYPE_AAAA:
1900 if (len + 4 > size)
1901 return NULL;
1902 memcpy(&str[len], "AAAA", 4);
1903 len += 4;
1904 break;
1905 default:
1906 return NULL;
1907 }
1908
1909 if (len + 1 > size)
1910 return NULL;
1911 memcpy(&str[len], "#", 1);
1912 len += 1;
1913
1914 if (len + hostname_dn_len + 1 > size) // +1 for trailing zero
1915 return NULL;
1916 memcpy(&str[len], hostname_dn, hostname_dn_len);
1917 len += hostname_dn_len;
1918 str[len] = '\0';
1919
1920 return buf;
1921}
1922
1923/*
1924 * returns a pointer to a cache entry which may still be considered as up to date
1925 * by the caller.
1926 * returns NULL if no entry can be found or if the data found is outdated.
1927 */
1928struct lru64 *
1929dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain) {
1930 struct lru64 *elem = NULL;
1931 struct dns_resolution *resolution = NULL;
1932 struct dns_resolvers *resolvers = NULL;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001933 struct dns_requester *requester = NULL;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001934 int inter = 0;
1935 struct chunk *buf = get_trash_chunk();
1936 struct chunk *tmp = NULL;
1937
1938 if (!dns_lru_tree)
1939 return NULL;
1940
1941 chunk_reset(buf);
1942 tmp = dns_cache_key(query_type, hostname_dn, hostname_dn_len, buf);
1943 if (tmp == NULL)
1944 return NULL;
1945
1946 elem = lru64_lookup(XXH64(buf->str, buf->len, 1), dns_lru_tree, cache_domain, 1);
1947
1948 if (!elem || !elem->data)
1949 return NULL;
1950
1951 resolution = elem->data;
1952
1953 /* since we can change the fqdn of a server at run time, it may happen that
1954 * we got an innacurate elem.
1955 * This is because resolution->hostname_dn points to (owner)->hostname_dn (which
1956 * may be changed at run time)
1957 */
1958 if ((hostname_dn_len == resolution->hostname_dn_len) &&
1959 (memcmp(hostname_dn, resolution->hostname_dn, hostname_dn_len) != 0)) {
1960 return NULL;
1961 }
1962
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001963 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
1964
1965 switch (obj_type(requester->requester)) {
1966 case OBJ_TYPE_SERVER:
1967 resolvers = objt_server(requester->requester)->resolvers;
1968 break;
1969 case OBJ_TYPE_NONE:
1970 default:
1971 return NULL;
1972 }
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001973
1974 if (!resolvers)
1975 return NULL;
1976
1977 if (resolvers->hold.valid < valid_period)
1978 inter = resolvers->hold.valid;
1979 else
1980 inter = valid_period;
1981
1982 if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms))
1983 return elem;
1984
1985 return NULL;
1986}
1987
Willy Tarreau777b5602016-12-16 18:06:26 +01001988/* if an arg is found, it sets the resolvers section pointer into cli.p0 */
William Lallemand69e96442016-11-19 00:58:54 +01001989static int cli_parse_stat_resolvers(char **args, struct appctx *appctx, void *private)
1990{
1991 struct dns_resolvers *presolvers;
1992
1993 if (*args[3]) {
William Lallemand69e96442016-11-19 00:58:54 +01001994 list_for_each_entry(presolvers, &dns_resolvers, list) {
1995 if (strcmp(presolvers->id, args[3]) == 0) {
Willy Tarreau777b5602016-12-16 18:06:26 +01001996 appctx->ctx.cli.p0 = presolvers;
William Lallemand69e96442016-11-19 00:58:54 +01001997 break;
1998 }
1999 }
Willy Tarreau777b5602016-12-16 18:06:26 +01002000 if (appctx->ctx.cli.p0 == NULL) {
William Lallemand69e96442016-11-19 00:58:54 +01002001 appctx->ctx.cli.msg = "Can't find that resolvers section\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01002002 appctx->st0 = CLI_ST_PRINT;
William Lallemand69e96442016-11-19 00:58:54 +01002003 return 1;
2004 }
2005 }
Willy Tarreau3067bfa2016-12-05 14:50:15 +01002006 return 0;
William Lallemand69e96442016-11-19 00:58:54 +01002007}
2008
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002009/*
2010 * if <resolution> is provided, then the function skips the memory allocation part.
2011 * It does the linking only.
2012 *
2013 * if <resolution> is NULL, the function links a dns resolution to a requester:
2014 * - it allocates memory for the struct requester used to link
2015 * the resolution to the requester
2016 * - it configures the resolution if this is the first requester to be linked to it
2017 * - it updates the requester with a pointer to the resolution
2018 *
2019 * Return code:
2020 * - 0 if everything happened smoothly
2021 * - -1 if an error occured. Of course, no resolution is linked to the requester
2022 */
2023int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution)
2024{
2025 struct dns_resolution *tmpresolution = NULL;
2026 struct dns_requester *tmprequester = NULL;
2027 struct dns_resolvers *resolvers = NULL;
2028 char *hostname_dn = NULL;
2029 int new_resolution;
2030
2031 if (!resolution) {
2032 tmprequester = calloc(1, sizeof(*tmprequester));
2033 if (!tmprequester)
2034 return -1;
2035
2036 switch (requester_type) {
2037 case OBJ_TYPE_SERVER:
2038 tmprequester->requester = &((struct server *)requester)->obj_type;
2039 hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2040 resolvers = objt_server(tmprequester->requester)->resolvers;
2041 switch (objt_server(tmprequester->requester)->dns_opts.family_prio) {
2042 case AF_INET:
2043 tmprequester->prefered_query_type = DNS_RTYPE_A;
2044 break;
2045 default:
2046 tmprequester->prefered_query_type = DNS_RTYPE_AAAA;
2047 }
2048
2049 break;
2050 case OBJ_TYPE_NONE:
2051 default:
2052 free(tmprequester);
2053 return -1;
2054 }
2055
2056 /* get a resolution from the resolvers' wait queue or pool */
2057 tmpresolution = dns_resolution_list_get(resolvers, hostname_dn, tmprequester->prefered_query_type);
2058 if (!tmpresolution) {
2059 free(tmprequester);
2060 return -1;
2061 }
2062 }
2063 else {
2064 tmpresolution = resolution;
2065
2066 switch (requester_type) {
2067 case OBJ_TYPE_SERVER:
2068 tmprequester = ((struct server *)requester)->dns_requester;
2069 resolvers = ((struct server *)requester)->resolvers;
2070 break;
2071 case OBJ_TYPE_NONE:
2072 default:
2073 return -1;
2074 }
2075 }
2076
2077 /* flag this resolution as NEW if applicable (not already linked to any requester).
2078 * this is required to decide which parameters we have to update on the resolution.
2079 * If new, it means we pulled up the resolution from the resolvers' pool.
2080 */
2081 if (LIST_ISEMPTY(&tmpresolution->requester.wait)) {
2082 new_resolution = 1;
2083 }
2084 else
2085 new_resolution = 0;
2086
2087 /* those parameters are related to the requester type */
2088 switch (obj_type(tmprequester->requester)) {
2089 case OBJ_TYPE_SERVER:
2090 /* some parameters should be set only if the resolution is brand new */
2091 if (new_resolution) {
2092 tmpresolution->query_type = tmprequester->prefered_query_type;
2093 tmpresolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2094 tmpresolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
2095 }
2096
2097 /* update requester as well, only if we just allocated it */
2098 objt_server(tmprequester->requester)->resolution = tmpresolution;
2099 if (!resolution) {
2100 tmprequester->requester_cb = snr_resolution_cb;
2101 tmprequester->requester_error_cb = snr_resolution_error_cb;
2102 objt_server(tmprequester->requester)->dns_requester = tmprequester;
2103 }
2104 break;
2105 case OBJ_TYPE_NONE:
2106 default:
2107 free(tmprequester);
2108 return -1;
2109 }
2110
2111 /* update some parameters only if this is a brand new resolution */
2112 if (new_resolution) {
2113 /* move the resolution to the requesters' wait queue */
2114 LIST_DEL(&tmpresolution->list);
2115 LIST_ADDQ(&resolvers->resolution.wait, &tmpresolution->list);
2116
2117 tmpresolution->status = RSLV_STATUS_NONE;
2118 tmpresolution->step = RSLV_STEP_NONE;
2119 tmpresolution->revision = 1;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02002120 LIST_INIT(&tmpresolution->response.answer_list);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002121 }
2122
2123 /* add the requester to the resolution's wait queue */
2124 if (resolution)
2125 LIST_DEL(&tmprequester->list);
2126 LIST_ADDQ(&tmpresolution->requester.wait, &tmprequester->list);
2127
2128 return 0;
2129}
2130
2131/*
2132 * pick up an available resolution from the different resolution list associated to a resolvers section,
2133 * in this order:
2134 * 1. check in resolution.curr for the same hostname and query_type
2135 * 2. check in resolution.wait for the same hostname and query_type
2136 * 3. take an available resolution from resolution.pool
2137 *
2138 * return an available resolution, NULL if none found.
2139 */
2140struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type)
2141{
2142 struct dns_resolution *resolution, *tmpresolution;
2143 struct dns_requester *requester;
2144
2145 /* search for same hostname and query type in resolution.curr */
2146 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.curr, list) {
2147 requester = NULL;
2148
2149 if (!LIST_ISEMPTY(&resolution->requester.wait))
2150 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
2151 else if (!LIST_ISEMPTY(&resolution->requester.curr))
2152 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
2153
2154 if (!requester)
2155 continue;
2156
2157 if ((query_type == requester->prefered_query_type) &&
2158 (strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
2159 return resolution;
2160 }
2161 }
2162
2163 /* search for same hostname and query type in resolution.wait */
2164 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.wait, list) {
2165 requester = NULL;
2166
2167 if (!LIST_ISEMPTY(&resolution->requester.wait))
2168 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
2169 else if (!LIST_ISEMPTY(&resolution->requester.curr))
2170 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
2171
2172 if (!requester)
2173 continue;
2174
2175 if ((query_type == requester->prefered_query_type) &&
2176 (strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
2177 return resolution;
2178 }
2179 }
2180
2181 /* take the first one (hopefully) from the pool */
2182 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.pool, list) {
2183 if (LIST_ISEMPTY(&resolution->requester.wait)) {
2184 return resolution;
2185 }
2186 }
2187
2188 return NULL;
2189}
2190
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002191/* This function allocates memory for a DNS resolution structure.
2192 * It's up to the caller to set the parameters
2193 * Returns a pointer to the structure resolution or NULL if memory could
2194 * not be allocated.
2195 */
2196struct dns_resolution *dns_alloc_resolution(void)
2197{
2198 struct dns_resolution *resolution = NULL;
Baptiste Assmann729c9012017-05-22 15:13:10 +02002199 char *buffer = NULL;
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002200
2201 resolution = calloc(1, sizeof(*resolution));
Baptiste Assmann729c9012017-05-22 15:13:10 +02002202 buffer = calloc(1, global.tune.bufsize);
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002203
Baptiste Assmann729c9012017-05-22 15:13:10 +02002204 if (!resolution || !buffer) {
2205 free(buffer);
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002206 free(resolution);
2207 return NULL;
2208 }
2209
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002210 LIST_INIT(&resolution->requester.wait);
2211 LIST_INIT(&resolution->requester.curr);
Baptiste Assmann729c9012017-05-22 15:13:10 +02002212
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002213 return resolution;
2214}
2215
2216/* This function free the memory allocated to a DNS resolution */
2217void dns_free_resolution(struct dns_resolution *resolution)
2218{
2219 free(resolution);
2220
2221 return;
2222}
2223
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002224/* this function free a resolution from its requester(s) and move it back to the pool */
2225void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution)
2226{
2227 struct dns_requester *requester, *tmprequester;
2228
2229 /* clean up configuration */
2230 dns_reset_resolution(resolution);
2231 resolution->hostname_dn = NULL;
2232 resolution->hostname_dn_len = 0;
2233
2234 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
2235 LIST_DEL(&requester->list);
2236 }
2237 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
2238 LIST_DEL(&requester->list);
2239 }
2240
2241 LIST_DEL(&resolution->list);
2242 LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
2243
2244 return;
2245}
2246
2247/*
2248 * this function remove a requester from a resolution
2249 * and takes care of all the consequences.
2250 * It also cleans up some parameters from the requester
2251 */
2252void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution)
2253{
2254 char *hostname_dn;
2255 struct dns_requester *tmprequester;
2256
2257 /* resolution is still used by other requesters, we need to move
2258 * some pointers to an other requester if needed
2259 */
2260 switch (obj_type(requester->requester)) {
2261 case OBJ_TYPE_SERVER:
2262 hostname_dn = objt_server(requester->requester)->hostname_dn;
2263 break;
2264 case OBJ_TYPE_NONE:
2265 default:
2266 hostname_dn = NULL;
2267 break;
2268 }
2269
2270 if (resolution->hostname_dn != hostname_dn)
2271 return;
2272
2273 /* First, we need to find this other requester */
2274 tmprequester = NULL;
2275 list_for_each_entry(tmprequester, &resolution->requester.wait, list) {
2276 if (tmprequester != requester)
2277 break;
2278 }
2279 if (!tmprequester) {
2280 /* if we can't find it in wait queue, let's get one in run queue */
2281 list_for_each_entry(tmprequester, &resolution->requester.curr, list) {
2282 if (tmprequester != requester)
2283 break;
2284 }
2285 }
2286
2287 /* move hostname_dn related pointers to the next requester */
2288 switch (obj_type(tmprequester->requester)) {
2289 case OBJ_TYPE_SERVER:
2290 resolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2291 resolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
2292 break;
2293 case OBJ_TYPE_NONE:
2294 default:
2295 ;;
2296 }
2297
2298
2299 /* clean up the requester */
2300 LIST_DEL(&requester->list);
2301 switch (obj_type(requester->requester)) {
2302 case OBJ_TYPE_SERVER:
2303 objt_server(requester->requester)->resolution = NULL;
2304 break;
2305 case OBJ_TYPE_NONE:
2306 default:
2307 ;;
2308 }
2309}
2310
Willy Tarreau777b5602016-12-16 18:06:26 +01002311/* This function dumps counters from all resolvers section and associated name
2312 * servers. It returns 0 if the output buffer is full and it needs to be called
2313 * again, otherwise non-zero. It may limit itself to the resolver pointed to by
2314 * <cli.p0> if it's not null.
William Lallemand69e96442016-11-19 00:58:54 +01002315 */
2316static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx)
2317{
2318 struct stream_interface *si = appctx->owner;
2319 struct dns_resolvers *presolvers;
2320 struct dns_nameserver *pnameserver;
2321
2322 chunk_reset(&trash);
2323
2324 switch (appctx->st2) {
2325 case STAT_ST_INIT:
2326 appctx->st2 = STAT_ST_LIST; /* let's start producing data */
2327 /* fall through */
2328
2329 case STAT_ST_LIST:
2330 if (LIST_ISEMPTY(&dns_resolvers)) {
2331 chunk_appendf(&trash, "No resolvers found\n");
2332 }
2333 else {
2334 list_for_each_entry(presolvers, &dns_resolvers, list) {
Willy Tarreau777b5602016-12-16 18:06:26 +01002335 if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != presolvers)
William Lallemand69e96442016-11-19 00:58:54 +01002336 continue;
2337
2338 chunk_appendf(&trash, "Resolvers section %s\n", presolvers->id);
2339 list_for_each_entry(pnameserver, &presolvers->nameserver_list, list) {
2340 chunk_appendf(&trash, " nameserver %s:\n", pnameserver->id);
2341 chunk_appendf(&trash, " sent: %ld\n", pnameserver->counters.sent);
2342 chunk_appendf(&trash, " valid: %ld\n", pnameserver->counters.valid);
2343 chunk_appendf(&trash, " update: %ld\n", pnameserver->counters.update);
2344 chunk_appendf(&trash, " cname: %ld\n", pnameserver->counters.cname);
2345 chunk_appendf(&trash, " cname_error: %ld\n", pnameserver->counters.cname_error);
2346 chunk_appendf(&trash, " any_err: %ld\n", pnameserver->counters.any_err);
2347 chunk_appendf(&trash, " nx: %ld\n", pnameserver->counters.nx);
2348 chunk_appendf(&trash, " timeout: %ld\n", pnameserver->counters.timeout);
2349 chunk_appendf(&trash, " refused: %ld\n", pnameserver->counters.refused);
2350 chunk_appendf(&trash, " other: %ld\n", pnameserver->counters.other);
2351 chunk_appendf(&trash, " invalid: %ld\n", pnameserver->counters.invalid);
2352 chunk_appendf(&trash, " too_big: %ld\n", pnameserver->counters.too_big);
2353 chunk_appendf(&trash, " truncated: %ld\n", pnameserver->counters.truncated);
2354 chunk_appendf(&trash, " outdated: %ld\n", pnameserver->counters.outdated);
2355 }
2356 }
2357 }
2358
2359 /* display response */
2360 if (bi_putchk(si_ic(si), &trash) == -1) {
2361 /* let's try again later from this session. We add ourselves into
2362 * this session's users so that it can remove us upon termination.
2363 */
2364 si->flags |= SI_FL_WAIT_ROOM;
2365 return 0;
2366 }
2367
2368 appctx->st2 = STAT_ST_FIN;
2369 /* fall through */
2370
2371 default:
2372 appctx->st2 = STAT_ST_FIN;
2373 return 1;
2374 }
2375}
2376
2377/* register cli keywords */
2378static struct cli_kw_list cli_kws = {{ },{
2379 { { "show", "stat", "resolvers", NULL }, "show stat resolvers [id]: dumps counters from all resolvers section and\n"
2380 " associated name servers",
2381 cli_parse_stat_resolvers, cli_io_handler_dump_resolvers_to_buffer },
2382 {{},}
2383}};
2384
2385
2386__attribute__((constructor))
2387static void __dns_init(void)
2388{
2389 cli_register_kw(&cli_kws);
2390}
2391