blob: 221f87099c3271169d6897d104702cdafa39f13a [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
Baptiste Assmann325137d2015-04-13 23:40:55 +020054/* proto_udp callback functions for a DNS resolution */
55struct dgram_data_cb resolve_dgram_cb = {
56 .recv = dns_resolve_recv,
57 .send = dns_resolve_send,
58};
59
Baptiste Assmann201c07f2017-05-22 15:17:15 +020060/* local function prototypes */
61static int dns_run_resolution(struct dns_requester *requester);
62
Baptiste Assmann325137d2015-04-13 23:40:55 +020063#if DEBUG
64/*
65 * go through the resolutions associated to a resolvers section and print the ID and hostname in
66 * domain name format
67 * should be used for debug purpose only
68 */
69void dns_print_current_resolutions(struct dns_resolvers *resolvers)
70{
Baptiste Assmann201c07f2017-05-22 15:17:15 +020071 list_for_each_entry(resolution, &resolvers->resolution.curr, list) {
Baptiste Assmann325137d2015-04-13 23:40:55 +020072 printf(" resolution %d for %s\n", resolution->query_id, resolution->hostname_dn);
73 }
74}
75#endif
76
Baptiste Assmann201c07f2017-05-22 15:17:15 +020077void dump_dns_config()
78{
79 struct dns_resolvers *curr_resolvers = NULL;
80 struct dns_nameserver *curr_nameserver = NULL;
81 struct dns_resolution *curr_resolution = NULL;
82 struct dns_requester *curr_requester = NULL;
83
84 printf("===============\n");
85 list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
86 printf("Resolvers: %s\n", curr_resolvers->id);
87
88 printf(" nameservers:\n");
89 list_for_each_entry(curr_nameserver, &curr_resolvers->nameserver_list, list) {
90 printf(" %s\n", curr_nameserver->id);
91 }
92
93/*
94 printf(" resolution.pool list:\n");
95 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.pool, list) {
96 printf(" %p\n", curr_resolution);
97 }
98*/
99
100 printf(" resolution.wait list:\n");
101 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.wait, list) {
102 printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
103 printf(" requester.wait list:\n");
104 list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
105 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
106 }
107 printf(" requester.curr list:\n");
108 list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
109 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
110 }
111 }
112 printf(" resolution.curr list:\n");
113 list_for_each_entry(curr_resolution, &curr_resolvers->resolution.curr, list) {
114 printf(" %p %s\n", curr_resolution, curr_resolution->hostname_dn);
115 printf(" requester.wait list:\n");
116 list_for_each_entry(curr_requester, &curr_resolution->requester.wait, list) {
117 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
118 }
119 printf(" requester.curr list:\n");
120 list_for_each_entry(curr_requester, &curr_resolution->requester.curr, list) {
121 printf(" %p %s %d\n", curr_requester, objt_server(curr_requester->requester)->id, curr_requester->prefered_query_type);
122 }
123 }
124 }
125
126 printf("===============\n");
127}
128
129/*
130 * Initiates a new name resolution:
131 * - generates a query id
132 * - configure the resolution structure
133 * - startup the resolvers task if required
134 *
135 * returns:
136 * - 0 if everything started properly
137 * - -1 in case of error or if resolution already running
138 */
139int dns_trigger_resolution(struct dns_resolution *resolution)
140{
141 struct dns_requester *requester = NULL, *tmprequester;
142 struct dns_resolvers *resolvers = NULL;
143 int inter;
144
145 /* process the element of the wait queue */
146 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
147 inter = 0;
148
149 switch (obj_type(requester->requester)) {
150 case OBJ_TYPE_SERVER:
151 inter = objt_server(requester->requester)->check.inter;
152 resolvers = objt_server(requester->requester)->resolvers;
153 break;
154 case OBJ_TYPE_NONE:
155 default:
156 return -1;
157 }
158
159 /* if data is fresh enough, let's use it */
160 if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
161 /* we only use cache if the response there is valid.
162 * If not valid, we run the resolution and move the requester to
163 * the run queue. */
164 if (resolution->status != RSLV_STATUS_VALID) {
165 LIST_DEL(&requester->list);
166 LIST_ADDQ(&resolution->requester.curr, &requester->list);
167 dns_run_resolution(requester);
168 continue;
169 }
170
171 requester->requester_cb(requester, NULL);
172 }
173 else {
174 LIST_DEL(&requester->list);
175 LIST_ADDQ(&resolution->requester.curr, &requester->list);
176 dns_run_resolution(requester);
177 }
178 }
179
180 if (resolvers)
181 dns_update_resolvers_timeout(resolvers);
182
183 return 0;
184}
185
Baptiste Assmann325137d2015-04-13 23:40:55 +0200186/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200187 * Prepare and send a DNS resolution.
188 *
189 * Return code:
190 * - 0 if no error occured
191 * - -1 in case of error
192 */
193static int
194dns_run_resolution(struct dns_requester *requester)
195{
196 struct dns_resolution *resolution;
197 struct dns_resolvers *resolvers;
198 int query_id, query_type, i;
199 struct proxy *proxy;
200
201 resolution = NULL;
202 resolvers = NULL;
203 proxy = NULL;
204 query_type = -1;
205 switch (obj_type(requester->requester)) {
206 case OBJ_TYPE_SERVER:
207 resolution = objt_server(requester->requester)->resolution;
208 resolvers = objt_server(requester->requester)->resolvers;
209 proxy = objt_server(requester->requester)->proxy;
210 query_type = requester->prefered_query_type;
211 break;
212 case OBJ_TYPE_NONE:
213 default:
214 return -1;
215 }
216
217 /*
218 * check if a resolution has already been started for this server
219 * return directly to avoid resolution pill up.
220 */
221 if (resolution->step != RSLV_STEP_NONE)
222 return 0;
223
224 /* generates a query id */
225 i = 0;
226 do {
227 query_id = dns_rnd16();
228 /* we do try only 100 times to find a free query id */
229 if (i++ > 100) {
230 chunk_printf(&trash, "could not generate a query id for %s, in resolvers %s",
231 resolution->hostname_dn, resolvers->id);
232
233 if (proxy)
234 send_log(proxy, LOG_NOTICE, "%s.\n", trash.str);
235 return -1;
236 }
237 } while (eb32_lookup(&resolvers->query_ids, query_id));
238
239 /* move the resolution into the run queue */
240 LIST_DEL(&resolution->list);
241 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
242
243 /* now update resolution parameters */
244 resolution->query_id = query_id;
245 resolution->qid.key = query_id;
246 resolution->step = RSLV_STEP_RUNNING;
247 resolution->query_type = query_type;
248 resolution->try = resolvers->resolve_retries;
249 resolution->try_cname = 0;
250 resolution->nb_responses = 0;
251 eb32_insert(&resolvers->query_ids, &resolution->qid);
252
253 dns_send_query(resolution);
254 resolution->try -= 1;
255
256 /* update wakeup date if this resolution is the only one in the FIFO list */
257 if (dns_check_resolution_queue(resolvers) == 1) {
258 /* update task timeout */
259 dns_update_resolvers_timeout(resolvers);
260 task_queue(resolvers->t);
261 }
262
263 return 0;
264}
265
266/*
Baptiste Assmann325137d2015-04-13 23:40:55 +0200267 * check if there is more than 1 resolution in the resolver's resolution list
268 * return value:
269 * 0: empty list
270 * 1: exactly one entry in the list
271 * 2: more than one entry in the list
272 */
273int dns_check_resolution_queue(struct dns_resolvers *resolvers)
274{
275
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200276 if (LIST_ISEMPTY(&resolvers->resolution.curr))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200277 return 0;
278
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200279 if ((resolvers->resolution.curr.n) && (resolvers->resolution.curr.n == resolvers->resolution.curr.p))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200280 return 1;
281
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200282 if (! ((resolvers->resolution.curr.n == resolvers->resolution.curr.p)
283 && (&resolvers->resolution.curr != resolvers->resolution.curr.n)))
Baptiste Assmann325137d2015-04-13 23:40:55 +0200284 return 2;
285
286 return 0;
287}
288
289/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200290 * reset some resolution parameters to initial values and also delete the
291 * query ID from the resolver's tree.
Baptiste Assmann325137d2015-04-13 23:40:55 +0200292 */
293void dns_reset_resolution(struct dns_resolution *resolution)
294{
295 /* update resolution status */
296 resolution->step = RSLV_STEP_NONE;
297
298 resolution->try = 0;
299 resolution->try_cname = 0;
300 resolution->last_resolution = now_ms;
301 resolution->nb_responses = 0;
302
303 /* clean up query id */
304 eb32_delete(&resolution->qid);
305 resolution->query_id = 0;
306 resolution->qid.key = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200307}
308
309/*
310 * function called when a network IO is generated on a name server socket for an incoming packet
311 * It performs the following actions:
312 * - check if the packet requires processing (not outdated resolution)
313 * - ensure the DNS packet received is valid and call requester's callback
314 * - call requester's error callback if invalid response
Baptiste Assmann3cf7f982016-04-17 22:43:26 +0200315 * - check the dn_name in the packet against the one sent
Baptiste Assmann325137d2015-04-13 23:40:55 +0200316 */
317void dns_resolve_recv(struct dgram_conn *dgram)
318{
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200319 struct dns_nameserver *nameserver, *tmpnameserver;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200320 struct dns_resolvers *resolvers;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200321 struct dns_resolution *resolution = NULL;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200322 struct dns_query_item *query;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200323 unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
324 unsigned char *bufend;
William Lallemandcc9b94a2017-06-08 19:30:39 +0200325 int fd, buflen, dns_resp, need_resend = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200326 unsigned short query_id;
327 struct eb32_node *eb;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200328 struct lru64 *lru = NULL;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200329 struct dns_requester *requester = NULL, *tmprequester = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200330
331 fd = dgram->t.sock.fd;
332
333 /* check if ready for reading */
334 if (!fd_recv_ready(fd))
335 return;
336
337 /* no need to go further if we can't retrieve the nameserver */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200338 if ((nameserver = dgram->owner) == NULL)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200339 return;
340
341 resolvers = nameserver->resolvers;
342
343 /* process all pending input messages */
344 while (1) {
345 /* read message received */
346 memset(buf, '\0', DNS_MAX_UDP_MESSAGE + 1);
347 if ((buflen = recv(fd, (char*)buf , DNS_MAX_UDP_MESSAGE, 0)) < 0) {
348 /* FIXME : for now we consider EAGAIN only */
349 fd_cant_recv(fd);
350 break;
351 }
352
353 /* message too big */
354 if (buflen > DNS_MAX_UDP_MESSAGE) {
355 nameserver->counters.too_big += 1;
356 continue;
357 }
358
359 /* initializing variables */
360 bufend = buf + buflen; /* pointer to mark the end of the buffer */
361
362 /* read the query id from the packet (16 bits) */
363 if (buf + 2 > bufend) {
364 nameserver->counters.invalid += 1;
365 continue;
366 }
367 query_id = dns_response_get_query_id(buf);
368
369 /* search the query_id in the pending resolution tree */
Baptiste Assmann01daef32015-09-02 22:05:24 +0200370 eb = eb32_lookup(&resolvers->query_ids, query_id);
371 if (eb == NULL) {
Baptiste Assmann325137d2015-04-13 23:40:55 +0200372 /* unknown query id means an outdated response and can be safely ignored */
373 nameserver->counters.outdated += 1;
374 continue;
375 }
376
377 /* known query id means a resolution in prgress */
378 resolution = eb32_entry(eb, struct dns_resolution, qid);
379
380 if (!resolution) {
381 nameserver->counters.outdated += 1;
382 continue;
383 }
384
385 /* number of responses received */
386 resolution->nb_responses += 1;
387
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200388 dns_resp = dns_validate_dns_response(buf, bufend, resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200389
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200390 switch (dns_resp) {
391 case DNS_RESP_VALID:
392 need_resend = 0;
393 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200394
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200395 case DNS_RESP_INVALID:
396 case DNS_RESP_QUERY_COUNT_ERROR:
397 case DNS_RESP_WRONG_NAME:
398 if (resolution->status != RSLV_STATUS_INVALID) {
399 resolution->status = RSLV_STATUS_INVALID;
400 resolution->last_status_change = now_ms;
401 }
402 nameserver->counters.invalid += 1;
403 need_resend = 0;
404 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200405
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200406 case DNS_RESP_ANCOUNT_ZERO:
407 if (resolution->status != RSLV_STATUS_OTHER) {
408 resolution->status = RSLV_STATUS_OTHER;
409 resolution->last_status_change = now_ms;
410 }
411 nameserver->counters.any_err += 1;
412 need_resend = 1;
413 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200414
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200415 case DNS_RESP_NX_DOMAIN:
416 if (resolution->status != RSLV_STATUS_NX) {
417 resolution->status = RSLV_STATUS_NX;
418 resolution->last_status_change = now_ms;
419 }
420 nameserver->counters.nx += 1;
421 need_resend = 0;
422 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200423
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200424 case DNS_RESP_REFUSED:
425 if (resolution->status != RSLV_STATUS_REFUSED) {
426 resolution->status = RSLV_STATUS_REFUSED;
427 resolution->last_status_change = now_ms;
428 }
429 nameserver->counters.refused += 1;
430 need_resend = 0;
431 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200432
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200433 case DNS_RESP_CNAME_ERROR:
434 if (resolution->status != RSLV_STATUS_OTHER) {
435 resolution->status = RSLV_STATUS_OTHER;
436 resolution->last_status_change = now_ms;
437 }
438 nameserver->counters.cname_error += 1;
439 need_resend = 1;
440 break;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200441
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200442 case DNS_RESP_TRUNCATED:
443 if (resolution->status != RSLV_STATUS_OTHER) {
444 resolution->status = RSLV_STATUS_OTHER;
445 resolution->last_status_change = now_ms;
446 }
447 nameserver->counters.truncated += 1;
448 need_resend = 1;
449 break;
Baptiste Assmann96972bc2015-09-09 00:46:58 +0200450
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200451 case DNS_RESP_NO_EXPECTED_RECORD:
452 if (resolution->status != RSLV_STATUS_OTHER) {
453 resolution->status = RSLV_STATUS_OTHER;
454 resolution->last_status_change = now_ms;
455 }
456 nameserver->counters.other += 1;
457 need_resend = 1;
458 break;
459
460 case DNS_RESP_ERROR:
461 case DNS_RESP_INTERNAL:
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
471 /* some error codes trigger a re-send of the query, but switching the
472 * query type.
473 * This is the case for the following error codes:
474 * DNS_RESP_ANCOUNT_ZERO
475 * DNS_RESP_TRUNCATED
476 * DNS_RESP_ERROR
477 * DNS_RESP_INTERNAL
478 * DNS_RESP_NO_EXPECTED_RECORD
479 * DNS_RESP_CNAME_ERROR
480 */
481 if (need_resend) {
482 int family_prio;
483 int res_preferred_afinet, res_preferred_afinet6;
484
485 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
486 switch (obj_type(requester->requester)) {
487 case OBJ_TYPE_SERVER:
488 family_prio = objt_server(requester->requester)->dns_opts.family_prio;
489 break;
490 case OBJ_TYPE_NONE:
491 default:
492 family_prio = AF_INET6;
493 }
494 res_preferred_afinet = family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
495 res_preferred_afinet6 = family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
496 if ((res_preferred_afinet || res_preferred_afinet6)
497 || (resolution->try > 0)) {
498 /* let's change the query type */
499 if (res_preferred_afinet6) {
500 /* fallback from AAAA to A */
501 resolution->query_type = DNS_RTYPE_A;
502 }
503 else if (res_preferred_afinet) {
504 /* fallback from A to AAAA */
505 resolution->query_type = DNS_RTYPE_AAAA;
506 }
507 else {
508 resolution->try -= 1;
509 if (family_prio == AF_INET) {
510 resolution->query_type = DNS_RTYPE_A;
511 } else {
512 resolution->query_type = DNS_RTYPE_AAAA;
513 }
514 }
515
516 dns_send_query(resolution);
517 /*
518 * move the resolution to the last element of the FIFO queue
519 * and update timeout wakeup based on the new first entry
520 */
521 if (dns_check_resolution_queue(resolvers) > 1) {
522 /* second resolution becomes first one */
523 LIST_DEL(&resolution->list);
524 /* ex first resolution goes to the end of the queue */
525 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
526 }
527
528 dns_update_resolvers_timeout(resolvers);
529 goto next_packet;
530 }
531
532 /* if we're there, this means that we already ran out of chances to re-send
533 * the query */
534 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
535 requester->requester_error_cb(requester, dns_resp);
536 }
537 goto next_packet;
538 }
539
540 /* now processing those error codes only:
541 * DNS_RESP_NX_DOMAIN
542 * DNS_RESP_REFUSED
543 */
544 if (dns_resp != DNS_RESP_VALID) {
545 /* now parse list of requesters currently waiting for this resolution */
546 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
547 requester->requester_error_cb(requester, dns_resp);
548
549 /* we can move the requester the wait queue */
550 LIST_DEL(&requester->list);
551 LIST_ADDQ(&resolution->requester.wait, &requester->list);
552 }
553 goto next_packet;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200554 }
555
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200556 /* Now let's check the query's dname corresponds to the one we sent.
557 * We can check only the first query of the list. We send one query at a time
558 * so we get one query in the response */
Baptiste Assmann729c9012017-05-22 15:13:10 +0200559 query = LIST_NEXT(&resolution->response.query_list, struct dns_query_item *, list);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200560 if (query && memcmp(query->name, resolution->hostname_dn, resolution->hostname_dn_len) != 0) {
561 nameserver->counters.other += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200562 /* now parse list of requesters currently waiting for this resolution */
563 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
564 requester->requester_error_cb(requester, DNS_RESP_WRONG_NAME);
565 /* we can move the requester the wait queue */
566 LIST_DEL(&requester->list);
567 LIST_ADDQ(&resolution->requester.wait, &requester->list);
568 }
569 goto next_packet;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200570 }
571
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200572 /* no errors, we can save the response in the cache */
573 if (dns_lru_tree) {
574 unsigned long long seed = 1;
575 struct chunk *buf = get_trash_chunk();
576 struct chunk *tmp = NULL;
577
578 chunk_reset(buf);
579 tmp = dns_cache_key(resolution->query_type, resolution->hostname_dn,
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200580 resolution->hostname_dn_len, buf);
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200581 if (!tmp) {
582 nameserver->counters.other += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200583 /* now parse list of requesters currently waiting for this resolution */
584 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
585 requester->requester_error_cb(requester, DNS_RESP_ERROR);
586 /* we can move the requester the wait queue */
587 LIST_DEL(&requester->list);
588 LIST_ADDQ(&resolution->requester.wait, &requester->list);
589 }
590 goto next_packet;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +0200591 }
592
593 lru = lru64_get(XXH64(buf->str, buf->len, seed),
594 dns_lru_tree, nameserver->resolvers, 1);
595
596 lru64_commit(lru, resolution, nameserver->resolvers, 1, NULL);
597 }
598
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200599 if (resolution->status != RSLV_STATUS_VALID) {
600 resolution->status = RSLV_STATUS_VALID;
601 resolution->last_status_change = now_ms;
602 }
603
Baptiste Assmann37bb3722015-08-07 10:18:32 +0200604 nameserver->counters.valid += 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200605 /* now parse list of requesters currently waiting for this resolution */
606 tmpnameserver = nameserver;
607 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
608 requester->requester_cb(requester, tmpnameserver);
609 /* we can move the requester the wait queue */
610 LIST_DEL(&requester->list);
611 LIST_ADDQ(&resolution->requester.wait, &requester->list);
612 /* first response is managed by the server, others are from the cache */
613 tmpnameserver = NULL;
614 }
615
616 next_packet:
617 /* resolution may be NULL when we receive an ICMP unreachable packet */
618 if (resolution && LIST_ISEMPTY(&resolution->requester.curr)) {
619 /* move the resolution into the wait queue */
620 LIST_DEL(&resolution->list);
621 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
622 /* update last resolution date and time */
623 resolution->last_resolution = now_ms;
624 /* reset current status flag */
625 resolution->step = RSLV_STEP_NONE;
626 /* reset values */
627 dns_reset_resolution(resolution);
628 }
629
630 } // end of while "packets" loop
631
632 dns_update_resolvers_timeout(nameserver->resolvers);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200633}
634
635/*
636 * function called when a resolvers network socket is ready to send data
637 * It performs the following actions:
638 */
639void dns_resolve_send(struct dgram_conn *dgram)
640{
641 int fd;
642 struct dns_nameserver *nameserver;
643 struct dns_resolvers *resolvers;
644 struct dns_resolution *resolution;
645
646 fd = dgram->t.sock.fd;
647
648 /* check if ready for sending */
649 if (!fd_send_ready(fd))
650 return;
651
652 /* we don't want/need to be waked up any more for sending */
653 fd_stop_send(fd);
654
655 /* no need to go further if we can't retrieve the nameserver */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200656 if ((nameserver = dgram->owner) == NULL)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200657 return;
658
659 resolvers = nameserver->resolvers;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200660 resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200661
662 dns_send_query(resolution);
663 dns_update_resolvers_timeout(resolvers);
664}
665
666/*
667 * forge and send a DNS query to resolvers associated to a resolution
668 * It performs the following actions:
669 * returns:
670 * 0 in case of error or safe ignorance
671 * 1 if no error
672 */
673int dns_send_query(struct dns_resolution *resolution)
674{
Baptiste Assmann42746372017-05-03 12:12:02 +0200675 struct dns_resolvers *resolvers = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200676 struct dns_nameserver *nameserver;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200677 struct dns_requester *requester = NULL;
Erwan Velu5457eb42015-10-15 15:07:26 +0200678 int ret, bufsize, fd;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200679
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200680 /* nothing to do */
681 if (LIST_ISEMPTY(&resolution->requester.curr))
682 return 0;
683
684 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
685
686 switch (obj_type(requester->requester)) {
687 case OBJ_TYPE_SERVER:
688 resolvers = objt_server(requester->requester)->resolvers;
689 break;
690 case OBJ_TYPE_NONE:
691 default:
692 return 0;
693 }
Baptiste Assmann42746372017-05-03 12:12:02 +0200694
695 if (!resolvers)
696 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200697
Baptiste Assmann325137d2015-04-13 23:40:55 +0200698 bufsize = dns_build_query(resolution->query_id, resolution->query_type, resolution->hostname_dn,
699 resolution->hostname_dn_len, trash.str, trash.size);
700
701 if (bufsize == -1)
702 return 0;
703
704 list_for_each_entry(nameserver, &resolvers->nameserver_list, list) {
705 fd = nameserver->dgram->t.sock.fd;
706 errno = 0;
707
708 ret = send(fd, trash.str, bufsize, 0);
709
710 if (ret > 0)
711 nameserver->counters.sent += 1;
712
713 if (ret == 0 || errno == EAGAIN) {
714 /* nothing written, let's update the poller that we wanted to send
715 * but we were not able to */
716 fd_want_send(fd);
717 fd_cant_send(fd);
718 }
719 }
720
721 /* update resolution */
Baptiste Assmann325137d2015-04-13 23:40:55 +0200722 resolution->nb_responses = 0;
723 resolution->last_sent_packet = now_ms;
724
725 return 1;
726}
727
728/*
729 * update a resolvers' task timeout for next wake up
730 */
731void dns_update_resolvers_timeout(struct dns_resolvers *resolvers)
732{
733 struct dns_resolution *resolution;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200734 struct dns_requester *requester;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200735
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200736 if ((LIST_ISEMPTY(&resolvers->resolution.curr)) && (LIST_ISEMPTY(&resolvers->resolution.wait))) {
Baptiste Assmann325137d2015-04-13 23:40:55 +0200737 resolvers->t->expire = TICK_ETERNITY;
738 }
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200739 else if (!LIST_ISEMPTY(&resolvers->resolution.curr)) {
740 resolution = LIST_NEXT(&resolvers->resolution.curr, struct dns_resolution *, list);
741 if (!resolvers->t->expire || tick_is_le(resolvers->t->expire, tick_add(resolution->last_sent_packet, resolvers->timeout.retry))) {
742 resolvers->t->expire = tick_add(resolution->last_sent_packet, resolvers->timeout.retry);
743 }
Baptiste Assmann325137d2015-04-13 23:40:55 +0200744 }
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200745 else if (!LIST_ISEMPTY(&resolvers->resolution.wait)) {
746 int valid_period, inter, need_wakeup;
747 struct dns_resolution *res_back;
748 need_wakeup = 0;
749 list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.wait, list) {
750 valid_period = 0;
751 inter = 0;
752
753 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
754
755 switch (obj_type(requester->requester)) {
756 case OBJ_TYPE_SERVER:
757 valid_period = objt_server(requester->requester)->check.inter;
758 break;
759 case OBJ_TYPE_NONE:
760 default:
761 continue;
762 }
763
764 if (resolvers->hold.valid < valid_period)
765 inter = resolvers->hold.valid;
766 else
767 inter = valid_period;
768
769 if (tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms)) {
770 switch (obj_type(requester->requester)) {
771 case OBJ_TYPE_SERVER:
772 dns_trigger_resolution(objt_server(requester->requester)->resolution);
773 break;
774 case OBJ_TYPE_NONE:
775 default:
776 ;;
777 }
778 }
779 else {
780 need_wakeup = 1;
781 }
782 }
783 /* in such case, we wake up in 1s */
784 if (need_wakeup) {
785 int r = 1000;
786
787 resolution = LIST_NEXT(&resolvers->resolution.wait, struct dns_resolution *, list);
788 if (tick_is_le(resolvers->t->expire, tick_add(now_ms, r)))
789 resolvers->t->expire = tick_add(now_ms, r);
790 resolvers->t->expire = tick_add(now_ms, 1000);
791 }
792 }
793
794 task_queue(resolvers->t);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200795}
796
797/*
798 * Analyse, re-build and copy the name <name> from the DNS response packet <buffer>.
799 * <name> must point to the 'data_len' information or pointer 'c0' for compressed data.
800 * The result is copied into <dest>, ensuring we don't overflow using <dest_len>
801 * Returns the number of bytes the caller can move forward. If 0 it means an error occured
802 * while parsing the name.
803 * <offset> is the number of bytes the caller could move forward.
804 */
805int dns_read_name(unsigned char *buffer, unsigned char *bufend, unsigned char *name, char *destination, int dest_len, int *offset)
806{
807 int nb_bytes = 0, n = 0;
808 int label_len;
809 unsigned char *reader = name;
810 char *dest = destination;
811
812 while (1) {
813 /* name compression is in use */
814 if ((*reader & 0xc0) == 0xc0) {
815 /* a pointer must point BEFORE current position */
816 if ((buffer + reader[1]) > reader) {
817 goto out_error;
818 }
819
820 n = dns_read_name(buffer, bufend, buffer + reader[1], dest, dest_len - nb_bytes, offset);
821 if (n == 0)
822 goto out_error;
823
824 dest += n;
825 nb_bytes += n;
826 goto out;
827 }
828
829 label_len = *reader;
830 if (label_len == 0)
831 goto out;
832 /* Check if:
833 * - we won't read outside the buffer
834 * - there is enough place in the destination
835 */
836 if ((reader + label_len >= bufend) || (nb_bytes + label_len >= dest_len))
837 goto out_error;
838
839 /* +1 to take label len + label string */
840 label_len += 1;
841
842 memcpy(dest, reader, label_len);
843
844 dest += label_len;
845 nb_bytes += label_len;
846 reader += label_len;
847 }
848
849 out:
850 /* offset computation:
851 * parse from <name> until finding either NULL or a pointer "c0xx"
852 */
853 reader = name;
854 *offset = 0;
855 while (reader < bufend) {
856 if ((reader[0] & 0xc0) == 0xc0) {
857 *offset += 2;
858 break;
859 }
860 else if (*reader == 0) {
861 *offset += 1;
862 break;
863 }
864 *offset += 1;
865 ++reader;
866 }
867
868 return nb_bytes;
869
870 out_error:
871 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200872}
873
874/*
875 * Function to validate that the buffer DNS response provided in <resp> and
876 * finishing before <bufend> is valid from a DNS protocol point of view.
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200877 *
Baptiste Assmann729c9012017-05-22 15:13:10 +0200878 * The result is stored in <resolution>' response, buf_response, response_query_records
879 * and response_answer_records members.
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200880 *
881 * This function returns one of the DNS_RESP_* code to indicate the type of
882 * error found.
Baptiste Assmann325137d2015-04-13 23:40:55 +0200883 */
Baptiste Assmann729c9012017-05-22 15:13:10 +0200884int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200885{
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200886 unsigned char *reader;
887 char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
888 int len, flags, offset, ret;
889 int dns_query_record_id, dns_answer_record_id;
Baptiste Assmann69fce672017-05-04 08:37:45 +0200890 int nb_saved_records;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200891 struct dns_query_item *dns_query;
892 struct dns_answer_item *dns_answer_record;
Baptiste Assmann729c9012017-05-22 15:13:10 +0200893 struct dns_response_packet *dns_p;
894 struct chunk *dns_response_buffer;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200895
896 reader = resp;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200897 len = 0;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200898 previous_dname = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200899
Baptiste Assmann729c9012017-05-22 15:13:10 +0200900 /* initialization of response buffer and structure */
901 dns_p = &resolution->response;
902 dns_response_buffer = &resolution->response_buffer;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200903 memset(dns_p, '\0', sizeof(struct dns_response_packet));
Baptiste Assmann729c9012017-05-22 15:13:10 +0200904 chunk_reset(dns_response_buffer);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200905
906 /* query id */
907 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200908 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200909 dns_p->header.id = reader[0] * 256 + reader[1];
910 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200911
912 /*
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200913 * flags and rcode are stored over 2 bytes
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200914 * First byte contains:
915 * - response flag (1 bit)
916 * - opcode (4 bits)
917 * - authoritative (1 bit)
918 * - truncated (1 bit)
919 * - recursion desired (1 bit)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200920 */
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200921 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200922 return DNS_RESP_INVALID;
923
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200924 flags = reader[0] * 256 + reader[1];
925
926 if (flags & DNS_FLAG_TRUNCATED)
927 return DNS_RESP_TRUNCATED;
928
929 if ((flags & DNS_FLAG_REPLYCODE) != DNS_RCODE_NO_ERROR) {
930 if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_NX_DOMAIN)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200931 return DNS_RESP_NX_DOMAIN;
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200932 else if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_REFUSED)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200933 return DNS_RESP_REFUSED;
934
935 return DNS_RESP_ERROR;
936 }
937
Baptiste Assmann3440f0d2015-09-02 22:08:38 +0200938 /* move forward 2 bytes for flags */
939 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200940
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200941 /* 2 bytes for question count */
942 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200943 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200944 dns_p->header.qdcount = reader[0] * 256 + reader[1];
945 /* (for now) we send one query only, so we expect only one in the response too */
946 if (dns_p->header.qdcount != 1)
947 return DNS_RESP_QUERY_COUNT_ERROR;
948 if (dns_p->header.qdcount > DNS_MAX_QUERY_RECORDS)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200949 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200950 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200951
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200952 /* 2 bytes for answer count */
953 if (reader + 2 >= bufend)
954 return DNS_RESP_INVALID;
955 dns_p->header.ancount = reader[0] * 256 + reader[1];
956 if (dns_p->header.ancount == 0)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200957 return DNS_RESP_ANCOUNT_ZERO;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200958 /* check if too many records are announced */
959 if (dns_p->header.ancount > DNS_MAX_ANSWER_RECORDS)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200960 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200961 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200962
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200963 /* 2 bytes authority count */
964 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200965 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200966 dns_p->header.nscount = reader[0] * 256 + reader[1];
967 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200968
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200969 /* 2 bytes additional count */
970 if (reader + 2 >= bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200971 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200972 dns_p->header.arcount = reader[0] * 256 + reader[1];
973 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +0200974
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200975 /* parsing dns queries */
976 LIST_INIT(&dns_p->query_list);
977 for (dns_query_record_id = 0; dns_query_record_id < dns_p->header.qdcount; dns_query_record_id++) {
978 /* use next pre-allocated dns_query_item after ensuring there is
979 * still one available.
980 * It's then added to our packet query list.
981 */
982 if (dns_query_record_id > DNS_MAX_QUERY_RECORDS)
983 return DNS_RESP_INVALID;
Baptiste Assmann729c9012017-05-22 15:13:10 +0200984 dns_query = &resolution->response_query_records[dns_query_record_id];
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200985 LIST_ADDQ(&dns_p->query_list, &dns_query->list);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200986
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200987 /* name is a NULL terminated string in our case, since we have
988 * one query per response and the first one can't be compressed
989 * (using the 0x0c format)
990 */
991 offset = 0;
992 len = dns_read_name(resp, bufend, reader, dns_query->name, DNS_MAX_NAME_SIZE, &offset);
Baptiste Assmann325137d2015-04-13 23:40:55 +0200993
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200994 if (len == 0)
995 return DNS_RESP_INVALID;
996
997 reader += offset;
998 previous_dname = dns_query->name;
999
1000 /* move forward 2 bytes for question type */
1001 if (reader + 2 >= bufend)
1002 return DNS_RESP_INVALID;
1003 dns_query->type = reader[0] * 256 + reader[1];
1004 reader += 2;
1005
1006 /* move forward 2 bytes for question class */
1007 if (reader + 2 >= bufend)
1008 return DNS_RESP_INVALID;
1009 dns_query->class = reader[0] * 256 + reader[1];
1010 reader += 2;
1011 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001012
1013 /* now parsing response records */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001014 LIST_INIT(&dns_p->answer_list);
Baptiste Assmann69fce672017-05-04 08:37:45 +02001015 nb_saved_records = 0;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001016 for (dns_answer_record_id = 0; dns_answer_record_id < dns_p->header.ancount; dns_answer_record_id++) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001017 if (reader >= bufend)
1018 return DNS_RESP_INVALID;
1019
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001020 /* pull next response record from the list, if still one available, then add it
1021 * to the record list */
1022 if (dns_answer_record_id > DNS_MAX_ANSWER_RECORDS)
1023 return DNS_RESP_INVALID;
Baptiste Assmann729c9012017-05-22 15:13:10 +02001024 dns_answer_record = &resolution->response_answer_records[dns_answer_record_id];
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001025 LIST_ADDQ(&dns_p->answer_list, &dns_answer_record->list);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001026
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001027 offset = 0;
1028 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001029
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001030 if (len == 0)
1031 return DNS_RESP_INVALID;
1032
1033 /* check if the current record dname is valid.
1034 * previous_dname points either to queried dname or last CNAME target
1035 */
1036 if (memcmp(previous_dname, tmpname, len) != 0) {
1037 if (dns_answer_record_id == 0) {
1038 /* first record, means a mismatch issue between queried dname
1039 * and dname found in the first record */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001040 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001041 } else {
1042 /* if not the first record, this means we have a CNAME resolution
1043 * error */
1044 return DNS_RESP_CNAME_ERROR;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001045 }
1046
Baptiste Assmann325137d2015-04-13 23:40:55 +02001047 }
1048
Baptiste Assmann729c9012017-05-22 15:13:10 +02001049 dns_answer_record->name = chunk_newstr(dns_response_buffer);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001050 if (dns_answer_record->name == NULL)
1051 return DNS_RESP_INVALID;
Baptiste Assmann5d681ba2015-10-15 15:23:28 +02001052
Baptiste Assmann729c9012017-05-22 15:13:10 +02001053 ret = chunk_strncat(dns_response_buffer, tmpname, len);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001054 if (ret == 0)
1055 return DNS_RESP_INVALID;
Baptiste Assmann2359ff12015-08-07 11:24:05 +02001056
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001057 reader += offset;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001058 if (reader >= bufend)
1059 return DNS_RESP_INVALID;
1060
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001061 if (reader >= bufend)
1062 return DNS_RESP_INVALID;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001063
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001064 /* 2 bytes for record type (A, AAAA, CNAME, etc...) */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001065 if (reader + 2 > bufend)
1066 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001067 dns_answer_record->type = reader[0] * 256 + reader[1];
1068 reader += 2;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001069
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001070 /* 2 bytes for class (2) */
1071 if (reader + 2 > bufend)
1072 return DNS_RESP_INVALID;
1073 dns_answer_record->class = reader[0] * 256 + reader[1];
Baptiste Assmann325137d2015-04-13 23:40:55 +02001074 reader += 2;
1075
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001076 /* 4 bytes for ttl (4) */
1077 if (reader + 4 > bufend)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001078 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001079 dns_answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
1080 + reader[2] * 256 + reader[3];
1081 reader += 4;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001082
1083 /* now reading data len */
1084 if (reader + 2 > bufend)
1085 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001086 dns_answer_record->data_len = reader[0] * 256 + reader[1];
Baptiste Assmann325137d2015-04-13 23:40:55 +02001087
1088 /* move forward 2 bytes for data len */
1089 reader += 2;
1090
1091 /* analyzing record content */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001092 switch (dns_answer_record->type) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001093 case DNS_RTYPE_A:
1094 /* ipv4 is stored on 4 bytes */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001095 if (dns_answer_record->data_len != 4)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001096 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001097 dns_answer_record->address.sa_family = AF_INET;
1098 memcpy(&(((struct sockaddr_in *)&dns_answer_record->address)->sin_addr),
1099 reader, dns_answer_record->data_len);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001100 break;
1101
1102 case DNS_RTYPE_CNAME:
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001103 /* check if this is the last record and update the caller about the status:
1104 * no IP could be found and last record was a CNAME. Could be triggered
1105 * by a wrong query type
1106 *
1107 * + 1 because dns_answer_record_id starts at 0 while number of answers
1108 * is an integer and starts at 1.
1109 */
1110 if (dns_answer_record_id + 1 == dns_p->header.ancount)
1111 return DNS_RESP_CNAME_ERROR;
1112
1113 offset = 0;
1114 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset);
1115
1116 if (len == 0)
1117 return DNS_RESP_INVALID;
1118
Baptiste Assmann729c9012017-05-22 15:13:10 +02001119 dns_answer_record->target = chunk_newstr(dns_response_buffer);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001120 if (dns_answer_record->target == NULL)
1121 return DNS_RESP_INVALID;
1122
Baptiste Assmann729c9012017-05-22 15:13:10 +02001123 ret = chunk_strncat(dns_response_buffer, tmpname, len);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001124 if (ret == 0)
1125 return DNS_RESP_INVALID;
1126
1127 previous_dname = dns_answer_record->target;
1128
Baptiste Assmann325137d2015-04-13 23:40:55 +02001129 break;
1130
1131 case DNS_RTYPE_AAAA:
1132 /* ipv6 is stored on 16 bytes */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001133 if (dns_answer_record->data_len != 16)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001134 return DNS_RESP_INVALID;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001135 dns_answer_record->address.sa_family = AF_INET6;
1136 memcpy(&(((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr),
1137 reader, dns_answer_record->data_len);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001138 break;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001139
Baptiste Assmann325137d2015-04-13 23:40:55 +02001140 } /* switch (record type) */
1141
Baptiste Assmann69fce672017-05-04 08:37:45 +02001142 /* increment the counter for number of records saved into our local response */
1143 nb_saved_records += 1;
1144
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001145 /* move forward dns_answer_record->data_len for analyzing next record in the response */
1146 reader += dns_answer_record->data_len;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001147 } /* for i 0 to ancount */
1148
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001149 /* let's add a last \0 to close our last string */
Baptiste Assmann729c9012017-05-22 15:13:10 +02001150 ret = chunk_strncat(dns_response_buffer, "\0", 1);
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001151 if (ret == 0)
1152 return DNS_RESP_INVALID;
Baptiste Assmann96972bc2015-09-09 00:46:58 +02001153
Baptiste Assmann69fce672017-05-04 08:37:45 +02001154 /* save the number of records we really own */
1155 dns_p->header.ancount = nb_saved_records;
1156
Baptiste Assmann325137d2015-04-13 23:40:55 +02001157 return DNS_RESP_VALID;
1158}
1159
1160/*
1161 * search dn_name resolution in resp.
1162 * If existing IP not found, return the first IP matching family_priority,
1163 * otherwise, first ip found
1164 * The following tasks are the responsibility of the caller:
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001165 * - <dns_p> contains an error free DNS response
Baptiste Assmann325137d2015-04-13 23:40:55 +02001166 * For both cases above, dns_validate_dns_response is required
1167 * returns one of the DNS_UPD_* code
1168 */
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001169#define DNS_MAX_IP_REC 20
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001170int dns_get_ip_from_response(struct dns_response_packet *dns_p,
Baptiste Assmann42746372017-05-03 12:12:02 +02001171 struct dns_options *dns_opts, void *currentip,
Thierry Fournierada34842016-02-17 21:25:09 +01001172 short currentip_sin_family,
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001173 void **newip, short *newip_sin_family,
1174 void *owner)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001175{
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001176 struct dns_answer_item *record;
Thierry Fournierada34842016-02-17 21:25:09 +01001177 int family_priority;
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001178 int i, currentip_found;
1179 unsigned char *newip4, *newip6;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001180 struct {
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001181 void *ip;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001182 unsigned char type;
1183 } rec[DNS_MAX_IP_REC];
1184 int currentip_sel;
1185 int j;
1186 int rec_nb = 0;
1187 int score, max_score;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001188
Baptiste Assmann42746372017-05-03 12:12:02 +02001189 family_priority = dns_opts->family_prio;
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001190 *newip = newip4 = newip6 = NULL;
1191 currentip_found = 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001192 *newip_sin_family = AF_UNSPEC;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001193
1194 /* now parsing response records */
Baptiste Assmann729c9012017-05-22 15:13:10 +02001195 list_for_each_entry(record, &dns_p->answer_list, list) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001196 /* analyzing record content */
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001197 switch (record->type) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001198 case DNS_RTYPE_A:
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001199 /* Store IPv4, only if some room is avalaible. */
1200 if (rec_nb < DNS_MAX_IP_REC) {
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001201 rec[rec_nb].ip = &(((struct sockaddr_in *)&record->address)->sin_addr);
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001202 rec[rec_nb].type = AF_INET;
1203 rec_nb++;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001204 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001205 break;
1206
Baptiste Assmann3cf7f982016-04-17 22:43:26 +02001207 /* we're looking for IPs only. CNAME validation is done when
1208 * parsing the response buffer for the first time */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001209 case DNS_RTYPE_CNAME:
Baptiste Assmann325137d2015-04-13 23:40:55 +02001210 break;
1211
1212 case DNS_RTYPE_AAAA:
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001213 /* Store IPv6, only if some room is avalaible. */
1214 if (rec_nb < DNS_MAX_IP_REC) {
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001215 rec[rec_nb].ip = &(((struct sockaddr_in6 *)&record->address)->sin6_addr);
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001216 rec[rec_nb].type = AF_INET6;
1217 rec_nb++;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001218 }
Baptiste Assmann325137d2015-04-13 23:40:55 +02001219 break;
1220
Baptiste Assmann325137d2015-04-13 23:40:55 +02001221 } /* switch (record type) */
Baptiste Assmannbcbd4912016-04-18 19:42:57 +02001222 } /* list for each record entries */
Baptiste Assmann325137d2015-04-13 23:40:55 +02001223
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001224 /* Select an IP regarding configuration preference.
1225 * Top priority is the prefered network ip version,
1226 * second priority is the prefered network.
1227 * the last priority is the currently used IP,
1228 *
1229 * For these three priorities, a score is calculated. The
1230 * weight are:
Baptistefc725902016-12-26 23:21:08 +01001231 * 8 - prefered netwok ip version.
1232 * 4 - prefered network.
1233 * 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 +01001234 * 1 - current ip.
1235 * The result with the biggest score is returned.
1236 */
1237 max_score = -1;
1238 for (i = 0; i < rec_nb; i++) {
Baptistefc725902016-12-26 23:21:08 +01001239 int record_ip_already_affected = 0;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001240
1241 score = 0;
1242
1243 /* Check for prefered ip protocol. */
1244 if (rec[i].type == family_priority)
Baptistefc725902016-12-26 23:21:08 +01001245 score += 8;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001246
1247 /* Check for prefered network. */
Baptiste Assmann42746372017-05-03 12:12:02 +02001248 for (j = 0; j < dns_opts->pref_net_nb; j++) {
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001249
1250 /* Compare only the same adresses class. */
Baptiste Assmann42746372017-05-03 12:12:02 +02001251 if (dns_opts->pref_net[j].family != rec[i].type)
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001252 continue;
1253
1254 if ((rec[i].type == AF_INET &&
Willy Tarreaueec1d382016-07-13 11:59:39 +02001255 in_net_ipv4(rec[i].ip,
Baptiste Assmann42746372017-05-03 12:12:02 +02001256 &dns_opts->pref_net[j].mask.in4,
1257 &dns_opts->pref_net[j].addr.in4)) ||
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001258 (rec[i].type == AF_INET6 &&
Willy Tarreaueec1d382016-07-13 11:59:39 +02001259 in_net_ipv6(rec[i].ip,
Baptiste Assmann42746372017-05-03 12:12:02 +02001260 &dns_opts->pref_net[j].mask.in6,
1261 &dns_opts->pref_net[j].addr.in6))) {
Baptistefc725902016-12-26 23:21:08 +01001262 score += 4;
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001263 break;
1264 }
1265 }
1266
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001267 /* Check if the IP found in the record is already affected to a member of a group.
1268 * If yes, the score should be incremented by 2.
1269 */
1270 if (owner) {
1271 if (snr_check_ip_callback(owner, rec[i].ip, &rec[i].type))
Baptistefc725902016-12-26 23:21:08 +01001272 record_ip_already_affected = 1;
Baptistefc725902016-12-26 23:21:08 +01001273 }
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02001274 if (record_ip_already_affected == 0)
Baptistefc725902016-12-26 23:21:08 +01001275 score += 2;
1276
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001277 /* Check for current ip matching. */
1278 if (rec[i].type == currentip_sin_family &&
1279 ((currentip_sin_family == AF_INET &&
Willy Tarreaueec1d382016-07-13 11:59:39 +02001280 memcmp(rec[i].ip, currentip, 4) == 0) ||
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001281 (currentip_sin_family == AF_INET6 &&
1282 memcmp(rec[i].ip, currentip, 16) == 0))) {
1283 score += 1;
1284 currentip_sel = 1;
1285 } else
1286 currentip_sel = 0;
1287
Baptistefc725902016-12-26 23:21:08 +01001288
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001289 /* Keep the address if the score is better than the previous
Baptistefc725902016-12-26 23:21:08 +01001290 * score. The maximum score is 15, if this value is reached,
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001291 * we break the parsing. Implicitly, this score is reached
1292 * the ip selected is the current ip.
1293 */
1294 if (score > max_score) {
1295 if (rec[i].type == AF_INET)
1296 newip4 = rec[i].ip;
1297 else
1298 newip6 = rec[i].ip;
1299 currentip_found = currentip_sel;
Baptistefc725902016-12-26 23:21:08 +01001300 if (score == 15)
Thierry Fournierac88cfe2016-02-17 22:05:30 +01001301 return DNS_UPD_NO;
1302 max_score = score;
1303 }
1304 }
1305
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02001306 /* no IP found in the response */
1307 if (!newip4 && !newip6) {
1308 return DNS_UPD_NO_IP_FOUND;
1309 }
1310
Baptiste Assmann325137d2015-04-13 23:40:55 +02001311 /* case when the caller looks first for an IPv4 address */
1312 if (family_priority == AF_INET) {
1313 if (newip4) {
1314 *newip = newip4;
1315 *newip_sin_family = AF_INET;
1316 if (currentip_found == 1)
1317 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001318 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001319 }
1320 else if (newip6) {
1321 *newip = newip6;
1322 *newip_sin_family = AF_INET6;
1323 if (currentip_found == 1)
1324 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001325 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001326 }
1327 }
1328 /* case when the caller looks first for an IPv6 address */
1329 else if (family_priority == AF_INET6) {
1330 if (newip6) {
1331 *newip = newip6;
1332 *newip_sin_family = AF_INET6;
1333 if (currentip_found == 1)
1334 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001335 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001336 }
1337 else if (newip4) {
1338 *newip = newip4;
1339 *newip_sin_family = AF_INET;
1340 if (currentip_found == 1)
1341 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001342 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001343 }
1344 }
1345 /* case when the caller have no preference (we prefer IPv6) */
1346 else if (family_priority == AF_UNSPEC) {
1347 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 else if (newip4) {
1355 *newip = newip4;
1356 *newip_sin_family = AF_INET;
1357 if (currentip_found == 1)
1358 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001359 goto return_DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001360 }
1361 }
1362
1363 /* no reason why we should change the server's IP address */
1364 return DNS_UPD_NO;
Baptiste Assmann8ea0bcc2017-05-04 08:24:11 +02001365
1366 return_DNS_UPD_SRVIP_NOT_FOUND:
1367 list_for_each_entry(record, &dns_p->answer_list, list) {
1368 /* move the first record to the end of the list, for internal round robin */
1369 if (record) {
1370 LIST_DEL(&record->list);
1371 LIST_ADDQ(&dns_p->answer_list, &record->list);
1372 break;
1373 }
1374 }
1375 return DNS_UPD_SRVIP_NOT_FOUND;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001376}
1377
1378/*
1379 * returns the query id contained in a DNS response
1380 */
Thiago Farinab1af23e2016-01-20 23:46:34 +01001381unsigned short dns_response_get_query_id(unsigned char *resp)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001382{
1383 /* read the query id from the response */
1384 return resp[0] * 256 + resp[1];
1385}
1386
1387/*
1388 * used during haproxy's init phase
1389 * parses resolvers sections and initializes:
1390 * - task (time events) for each resolvers section
1391 * - the datagram layer (network IO events) for each nameserver
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001392 * It takes one argument:
1393 * - close_first takes 2 values: 0 or 1. If 1, the connection is closed first.
Baptiste Assmann325137d2015-04-13 23:40:55 +02001394 * returns:
1395 * 0 in case of error
1396 * 1 when no error
1397 */
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001398int dns_init_resolvers(int close_socket)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001399{
1400 struct dns_resolvers *curr_resolvers;
1401 struct dns_nameserver *curnameserver;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001402 struct dns_resolution *resolution, *res_back;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001403 struct dgram_conn *dgram;
1404 struct task *t;
1405 int fd;
1406
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001407 /* initialize our DNS resolution cache */
1408 dns_lru_tree = lru64_new(dns_cache_size);
1409
Baptiste Assmann325137d2015-04-13 23:40:55 +02001410 /* give a first random value to our dns query_id seed */
1411 dns_query_id_seed = random();
1412
1413 /* run through the resolvers section list */
1414 list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
1415 /* create the task associated to the resolvers section */
1416 if ((t = task_new()) == NULL) {
1417 Alert("Starting [%s] resolvers: out of memory.\n", curr_resolvers->id);
1418 return 0;
1419 }
1420
1421 /* update task's parameters */
1422 t->process = dns_process_resolve;
1423 t->context = curr_resolvers;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001424
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001425 /* no need to keep the new task if one is already affected to our resolvers
1426 * section */
1427 if (!curr_resolvers->t)
1428 curr_resolvers->t = t;
1429 else
1430 task_free(t);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001431
1432 list_for_each_entry(curnameserver, &curr_resolvers->nameserver_list, list) {
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001433 dgram = NULL;
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001434
1435 if (close_socket == 1) {
1436 if (curnameserver->dgram) {
Frédéric Lécaille64920532017-05-12 09:57:15 +02001437 fd_delete(curnameserver->dgram->t.sock.fd);
Baptiste Assmann5cd1b922017-02-02 22:44:15 +01001438 memset(curnameserver->dgram, '\0', sizeof(*dgram));
1439 dgram = curnameserver->dgram;
1440 }
1441 }
1442
1443 /* allocate memory only if it has not already been allocated
1444 * by a previous call to this function */
1445 if (!dgram && (dgram = calloc(1, sizeof(*dgram))) == NULL) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001446 Alert("Starting [%s/%s] nameserver: out of memory.\n", curr_resolvers->id,
1447 curnameserver->id);
1448 return 0;
1449 }
1450 /* update datagram's parameters */
1451 dgram->owner = (void *)curnameserver;
1452 dgram->data = &resolve_dgram_cb;
1453
1454 /* create network UDP socket for this nameserver */
Frédéric Lécaille5e5bc9f2017-04-11 08:46:37 +02001455 if ((fd = socket(curnameserver->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001456 Alert("Starting [%s/%s] nameserver: can't create socket.\n", curr_resolvers->id,
1457 curnameserver->id);
1458 free(dgram);
1459 dgram = NULL;
1460 return 0;
1461 }
1462
1463 /* "connect" the UDP socket to the name server IP */
Baptiste Assmann8c62c472015-09-21 20:55:08 +02001464 if (connect(fd, (struct sockaddr*)&curnameserver->addr, get_addr_len(&curnameserver->addr)) == -1) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001465 Alert("Starting [%s/%s] nameserver: can't connect socket.\n", curr_resolvers->id,
1466 curnameserver->id);
1467 close(fd);
1468 free(dgram);
1469 dgram = NULL;
1470 return 0;
1471 }
1472
1473 /* make the socket non blocking */
1474 fcntl(fd, F_SETFL, O_NONBLOCK);
1475
1476 /* add the fd in the fd list and update its parameters */
1477 fd_insert(fd);
1478 fdtab[fd].owner = dgram;
1479 fdtab[fd].iocb = dgram_fd_handler;
1480 fd_want_recv(fd);
1481 dgram->t.sock.fd = fd;
1482
1483 /* update nameserver's datagram property */
1484 curnameserver->dgram = dgram;
1485
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001486 continue;
1487 }
1488
1489 if (close_socket == 0)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001490 continue;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001491
1492 /* now, we can trigger DNS resolution */
1493 list_for_each_entry_safe(resolution, res_back, &curr_resolvers->resolution.wait, list) {
1494 /* if there is no requester in the wait queue, no need to trigger the resolution */
1495 if (LIST_ISEMPTY(&resolution->requester.wait))
1496 continue;
1497
1498 dns_trigger_resolution(resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001499 }
1500
1501 /* task can be queued */
1502 task_queue(t);
1503 }
1504
1505 return 1;
1506}
1507
1508/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001509 * Allocate a pool of resolution to a resolvers section.
1510 * Each resolution is associated with a UUID.
1511 *
1512 * Return code:
1513 * - 0 if everything went smoothly
1514 * - -1 if an error occured
1515 */
1516int dns_alloc_resolution_pool(struct dns_resolvers *resolvers)
1517{
1518 int i;
1519 struct dns_resolution *resolution;
1520
1521 /* return if a pool has already been set for this resolvers */
1522 if (!LIST_ISEMPTY(&resolvers->resolution.pool)) {
1523 return 0;
1524 }
1525
1526 for (i = 0; i < resolvers->resolution_pool_size; i++) {
1527 resolution = dns_alloc_resolution();
1528 if (!resolution) {
1529 Alert("Starting [%s] resolvers: can't allocate memory for DNS resolution pool.\n", resolvers->id);
1530 return -1;
1531 }
1532 resolution->uuid = i;
1533 LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
1534 }
1535
1536 return 0;
1537}
1538
1539/*
Baptiste Assmann325137d2015-04-13 23:40:55 +02001540 * Forge a DNS query. It needs the following information from the caller:
1541 * - <query_id>: the DNS query id corresponding to this query
1542 * - <query_type>: DNS_RTYPE_* request DNS record type (A, AAAA, ANY, etc...)
1543 * - <hostname_dn>: hostname in domain name format
1544 * - <hostname_dn_len>: length of <hostname_dn>
1545 * To store the query, the caller must pass a buffer <buf> and its size <bufsize>
1546 *
1547 * the DNS query is stored in <buf>
1548 * returns:
1549 * -1 if <buf> is too short
1550 */
1551int dns_build_query(int query_id, int query_type, char *hostname_dn, int hostname_dn_len, char *buf, int bufsize)
1552{
1553 struct dns_header *dns;
Vincent Bernat9b7125c2016-04-08 22:17:45 +02001554 struct dns_question qinfo;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001555 char *ptr, *bufend;
1556
1557 memset(buf, '\0', bufsize);
1558 ptr = buf;
1559 bufend = buf + bufsize;
1560
1561 /* check if there is enough room for DNS headers */
1562 if (ptr + sizeof(struct dns_header) >= bufend)
1563 return -1;
1564
1565 /* set dns query headers */
1566 dns = (struct dns_header *)ptr;
1567 dns->id = (unsigned short) htons(query_id);
Nenad Merdanovic8ab79422016-07-13 14:03:43 +02001568 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 +02001569 dns->qdcount = htons(1); /* 1 question */
1570 dns->ancount = 0;
1571 dns->nscount = 0;
1572 dns->arcount = 0;
1573
1574 /* move forward ptr */
1575 ptr += sizeof(struct dns_header);
1576
1577 /* check if there is enough room for query hostname */
1578 if ((ptr + hostname_dn_len) >= bufend)
1579 return -1;
1580
1581 /* set up query hostname */
1582 memcpy(ptr, hostname_dn, hostname_dn_len);
1583 ptr[hostname_dn_len + 1] = '\0';
1584
1585 /* move forward ptr */
1586 ptr += (hostname_dn_len + 1);
1587
1588 /* check if there is enough room for query hostname*/
1589 if (ptr + sizeof(struct dns_question) >= bufend)
1590 return -1;
1591
1592 /* set up query info (type and class) */
Vincent Bernat9b7125c2016-04-08 22:17:45 +02001593 qinfo.qtype = htons(query_type);
1594 qinfo.qclass = htons(DNS_RCLASS_IN);
1595 memcpy(ptr, &qinfo, sizeof(qinfo));
Baptiste Assmann325137d2015-04-13 23:40:55 +02001596
1597 ptr += sizeof(struct dns_question);
1598
1599 return ptr - buf;
1600}
1601
1602/*
1603 * turn a string into domain name label:
1604 * www.haproxy.org into 3www7haproxy3org
1605 * if dn memory is pre-allocated, you must provide its size in dn_len
1606 * if dn memory isn't allocated, dn_len must be set to 0.
1607 * In the second case, memory will be allocated.
1608 * in case of error, -1 is returned, otherwise, number of bytes copied in dn
1609 */
Willy Tarreau2100b492015-07-22 16:42:43 +02001610char *dns_str_to_dn_label(const char *string, char *dn, int dn_len)
Baptiste Assmann325137d2015-04-13 23:40:55 +02001611{
1612 char *c, *d;
1613 int i, offset;
1614
1615 /* offset between string size and theorical dn size */
1616 offset = 1;
1617
1618 /*
1619 * first, get the size of the string turned into its domain name version
1620 * This function also validates the string respect the RFC
1621 */
1622 if ((i = dns_str_to_dn_label_len(string)) == -1)
1623 return NULL;
1624
1625 /* yes, so let's check there is enough memory */
1626 if (dn_len < i + offset)
1627 return NULL;
1628
Willy Tarreaud69d6f32015-07-22 16:45:36 +02001629 i = strlen(string);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001630 memcpy(dn + offset, string, i);
1631 dn[i + offset] = '\0';
1632 /* avoid a '\0' at the beginning of dn string which may prevent the for loop
1633 * below from working.
1634 * Actually, this is the reason of the offset. */
1635 dn[0] = '0';
1636
1637 for (c = dn; *c ; ++c) {
1638 /* c points to the first '0' char or a dot, which we don't want to read */
1639 d = c + offset;
1640 i = 0;
1641 while (*d != '.' && *d) {
1642 i++;
1643 d++;
1644 }
1645 *c = i;
1646
1647 c = d - 1; /* because of c++ of the for loop */
1648 }
1649
1650 return dn;
1651}
1652
1653/*
1654 * compute and return the length of <string> it it were translated into domain name
1655 * label:
1656 * www.haproxy.org into 3www7haproxy3org would return 16
1657 * NOTE: add +1 for '\0' when allocating memory ;)
1658 */
1659int dns_str_to_dn_label_len(const char *string)
1660{
1661 return strlen(string) + 1;
1662}
1663
1664/*
1665 * validates host name:
1666 * - total size
1667 * - each label size individually
1668 * returns:
1669 * 0 in case of error. If <err> is not NULL, an error message is stored there.
1670 * 1 when no error. <err> is left unaffected.
1671 */
1672int dns_hostname_validation(const char *string, char **err)
1673{
1674 const char *c, *d;
1675 int i;
1676
1677 if (strlen(string) > DNS_MAX_NAME_SIZE) {
1678 if (err)
1679 *err = DNS_TOO_LONG_FQDN;
1680 return 0;
1681 }
1682
1683 c = string;
1684 while (*c) {
1685 d = c;
1686
1687 i = 0;
1688 while (*d != '.' && *d && i <= DNS_MAX_LABEL_SIZE) {
1689 i++;
1690 if (!((*d == '-') || (*d == '_') ||
1691 ((*d >= 'a') && (*d <= 'z')) ||
1692 ((*d >= 'A') && (*d <= 'Z')) ||
1693 ((*d >= '0') && (*d <= '9')))) {
1694 if (err)
1695 *err = DNS_INVALID_CHARACTER;
1696 return 0;
1697 }
1698 d++;
1699 }
1700
1701 if ((i >= DNS_MAX_LABEL_SIZE) && (d[i] != '.')) {
1702 if (err)
1703 *err = DNS_LABEL_TOO_LONG;
1704 return 0;
1705 }
1706
1707 if (*d == '\0')
1708 goto out;
1709
1710 c = ++d;
1711 }
1712 out:
1713 return 1;
1714}
1715
1716/*
1717 * 2 bytes random generator to generate DNS query ID
1718 */
1719uint16_t dns_rnd16(void)
1720{
1721 dns_query_id_seed ^= dns_query_id_seed << 13;
1722 dns_query_id_seed ^= dns_query_id_seed >> 7;
1723 dns_query_id_seed ^= dns_query_id_seed << 17;
1724 return dns_query_id_seed;
1725}
1726
1727
1728/*
1729 * function called when a timeout occurs during name resolution process
1730 * if max number of tries is reached, then stop, otherwise, retry.
1731 */
1732struct task *dns_process_resolve(struct task *t)
1733{
1734 struct dns_resolvers *resolvers = t->context;
1735 struct dns_resolution *resolution, *res_back;
Baptiste Assmann060e5732016-01-06 02:01:59 +01001736 int res_preferred_afinet, res_preferred_afinet6;
Baptiste Assmann42746372017-05-03 12:12:02 +02001737 struct dns_options *dns_opts = NULL;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001738
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001739 /* if both there is no resolution in the run queue, we can re-schedule a wake up */
1740 if (LIST_ISEMPTY(&resolvers->resolution.curr)) {
Baptiste Assmann325137d2015-04-13 23:40:55 +02001741 /* no first entry, so wake up was useless */
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001742 dns_update_resolvers_timeout(resolvers);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001743 return t;
1744 }
1745
1746 /* look for the first resolution which is not expired */
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001747 list_for_each_entry_safe(resolution, res_back, &resolvers->resolution.curr, list) {
1748 struct dns_requester *requester = NULL;
1749
Baptiste Assmann325137d2015-04-13 23:40:55 +02001750 /* when we find the first resolution in the future, then we can stop here */
1751 if (tick_is_le(now_ms, resolution->last_sent_packet))
1752 goto out;
1753
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001754 if (LIST_ISEMPTY(&resolution->requester.curr))
1755 goto out;
1756
Baptiste Assmann325137d2015-04-13 23:40:55 +02001757 /*
1758 * if current resolution has been tried too many times and finishes in timeout
1759 * we update its status and remove it from the list
1760 */
Baptiste Assmannf778bb42015-09-09 00:54:38 +02001761 if (resolution->try <= 0) {
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001762 struct dns_requester *tmprequester;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001763 /* clean up resolution information and remove from the list */
1764 dns_reset_resolution(resolution);
1765
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001766 LIST_DEL(&resolution->list);
1767 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
1768
1769 if (resolution->status != RSLV_STATUS_TIMEOUT) {
1770 resolution->status = RSLV_STATUS_TIMEOUT;
1771 resolution->last_status_change = now_ms;
1772 }
1773
1774 /* notify the result to the requesters */
1775 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
1776 requester->requester_error_cb(requester, DNS_RESP_TIMEOUT);
1777 LIST_DEL(&requester->list);
1778 LIST_ADDQ(&resolution->requester.wait, &requester->list);
1779 }
Baptiste Assmann382824c2016-01-06 01:53:46 +01001780 goto out;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001781 }
1782
Baptiste Assmannf778bb42015-09-09 00:54:38 +02001783 resolution->try -= 1;
1784
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001785 /* running queue is empty, nothing to do but wait */
1786 if (LIST_ISEMPTY(&resolution->requester.curr))
1787 goto out;
1788
1789 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
1790
1791 switch (obj_type(requester->requester)) {
1792 case OBJ_TYPE_SERVER:
1793 dns_opts = &(objt_server(requester->requester)->dns_opts);
1794 break;
1795
1796 case OBJ_TYPE_NONE:
1797 default:
1798 /* clean up resolution information and remove from the list */
1799 dns_reset_resolution(resolution);
1800
1801 LIST_DEL(&resolution->list);
1802 LIST_ADDQ(&resolvers->resolution.wait, &resolution->list);
1803
1804 /* notify the result to the requester */
1805 requester->requester_error_cb(requester, DNS_RESP_INTERNAL);
1806 goto out;
1807 }
Baptiste Assmann42746372017-05-03 12:12:02 +02001808
1809 res_preferred_afinet = dns_opts->family_prio == AF_INET && resolution->query_type == DNS_RTYPE_A;
1810 res_preferred_afinet6 = dns_opts->family_prio == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
Baptiste Assmann060e5732016-01-06 02:01:59 +01001811
1812 /* let's change the query type if needed */
1813 if (res_preferred_afinet6) {
1814 /* fallback from AAAA to A */
1815 resolution->query_type = DNS_RTYPE_A;
1816 }
1817 else if (res_preferred_afinet) {
1818 /* fallback from A to AAAA */
1819 resolution->query_type = DNS_RTYPE_AAAA;
1820 }
1821
Baptiste Assmann382824c2016-01-06 01:53:46 +01001822 /* resend the DNS query */
1823 dns_send_query(resolution);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001824
Baptiste Assmann382824c2016-01-06 01:53:46 +01001825 /* check if we have more than one resolution in the list */
1826 if (dns_check_resolution_queue(resolvers) > 1) {
1827 /* move the rsolution to the end of the list */
1828 LIST_DEL(&resolution->list);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001829 LIST_ADDQ(&resolvers->resolution.curr, &resolution->list);
Baptiste Assmann325137d2015-04-13 23:40:55 +02001830 }
1831 }
1832
1833 out:
1834 dns_update_resolvers_timeout(resolvers);
1835 return t;
1836}
William Lallemand69e96442016-11-19 00:58:54 +01001837
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001838/*
1839 * build a dns cache key composed as follow:
1840 * <query type>#<hostname in domain name format>
1841 * and store it into <str>.
1842 * It's up to the caller to allocate <buf> and to reset it.
1843 * The function returns NULL in case of error (IE <buf> too small) or a pointer
1844 * to buf if successful
1845 */
1846struct chunk *
1847dns_cache_key(int query_type, char *hostname_dn, int hostname_dn_len, struct chunk *buf)
1848{
1849 int len, size;
1850 char *str;
1851
1852 str = buf->str;
1853 len = buf->len;
1854 size = buf->size;
1855
1856 switch (query_type) {
1857 case DNS_RTYPE_A:
1858 if (len + 1 > size)
1859 return NULL;
1860 memcpy(&str[len], "A", 1);
1861 len += 1;
1862 break;
1863 case DNS_RTYPE_AAAA:
1864 if (len + 4 > size)
1865 return NULL;
1866 memcpy(&str[len], "AAAA", 4);
1867 len += 4;
1868 break;
1869 default:
1870 return NULL;
1871 }
1872
1873 if (len + 1 > size)
1874 return NULL;
1875 memcpy(&str[len], "#", 1);
1876 len += 1;
1877
1878 if (len + hostname_dn_len + 1 > size) // +1 for trailing zero
1879 return NULL;
1880 memcpy(&str[len], hostname_dn, hostname_dn_len);
1881 len += hostname_dn_len;
1882 str[len] = '\0';
1883
1884 return buf;
1885}
1886
1887/*
1888 * returns a pointer to a cache entry which may still be considered as up to date
1889 * by the caller.
1890 * returns NULL if no entry can be found or if the data found is outdated.
1891 */
1892struct lru64 *
1893dns_cache_lookup(int query_type, char *hostname_dn, int hostname_dn_len, int valid_period, void *cache_domain) {
1894 struct lru64 *elem = NULL;
1895 struct dns_resolution *resolution = NULL;
1896 struct dns_resolvers *resolvers = NULL;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001897 struct dns_requester *requester = NULL;
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001898 int inter = 0;
1899 struct chunk *buf = get_trash_chunk();
1900 struct chunk *tmp = NULL;
1901
1902 if (!dns_lru_tree)
1903 return NULL;
1904
1905 chunk_reset(buf);
1906 tmp = dns_cache_key(query_type, hostname_dn, hostname_dn_len, buf);
1907 if (tmp == NULL)
1908 return NULL;
1909
1910 elem = lru64_lookup(XXH64(buf->str, buf->len, 1), dns_lru_tree, cache_domain, 1);
1911
1912 if (!elem || !elem->data)
1913 return NULL;
1914
1915 resolution = elem->data;
1916
1917 /* since we can change the fqdn of a server at run time, it may happen that
1918 * we got an innacurate elem.
1919 * This is because resolution->hostname_dn points to (owner)->hostname_dn (which
1920 * may be changed at run time)
1921 */
1922 if ((hostname_dn_len == resolution->hostname_dn_len) &&
1923 (memcmp(hostname_dn, resolution->hostname_dn, hostname_dn_len) != 0)) {
1924 return NULL;
1925 }
1926
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001927 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
1928
1929 switch (obj_type(requester->requester)) {
1930 case OBJ_TYPE_SERVER:
1931 resolvers = objt_server(requester->requester)->resolvers;
1932 break;
1933 case OBJ_TYPE_NONE:
1934 default:
1935 return NULL;
1936 }
Baptiste Assmannfa4a6632017-05-04 09:05:00 +02001937
1938 if (!resolvers)
1939 return NULL;
1940
1941 if (resolvers->hold.valid < valid_period)
1942 inter = resolvers->hold.valid;
1943 else
1944 inter = valid_period;
1945
1946 if (!tick_is_expired(tick_add(resolution->last_resolution, inter), now_ms))
1947 return elem;
1948
1949 return NULL;
1950}
1951
Willy Tarreau777b5602016-12-16 18:06:26 +01001952/* if an arg is found, it sets the resolvers section pointer into cli.p0 */
William Lallemand69e96442016-11-19 00:58:54 +01001953static int cli_parse_stat_resolvers(char **args, struct appctx *appctx, void *private)
1954{
1955 struct dns_resolvers *presolvers;
1956
1957 if (*args[3]) {
William Lallemand69e96442016-11-19 00:58:54 +01001958 list_for_each_entry(presolvers, &dns_resolvers, list) {
1959 if (strcmp(presolvers->id, args[3]) == 0) {
Willy Tarreau777b5602016-12-16 18:06:26 +01001960 appctx->ctx.cli.p0 = presolvers;
William Lallemand69e96442016-11-19 00:58:54 +01001961 break;
1962 }
1963 }
Willy Tarreau777b5602016-12-16 18:06:26 +01001964 if (appctx->ctx.cli.p0 == NULL) {
William Lallemand69e96442016-11-19 00:58:54 +01001965 appctx->ctx.cli.msg = "Can't find that resolvers section\n";
Willy Tarreau3b6e5472016-11-24 15:53:53 +01001966 appctx->st0 = CLI_ST_PRINT;
William Lallemand69e96442016-11-19 00:58:54 +01001967 return 1;
1968 }
1969 }
Willy Tarreau3067bfa2016-12-05 14:50:15 +01001970 return 0;
William Lallemand69e96442016-11-19 00:58:54 +01001971}
1972
Baptiste Assmann201c07f2017-05-22 15:17:15 +02001973/*
1974 * if <resolution> is provided, then the function skips the memory allocation part.
1975 * It does the linking only.
1976 *
1977 * if <resolution> is NULL, the function links a dns resolution to a requester:
1978 * - it allocates memory for the struct requester used to link
1979 * the resolution to the requester
1980 * - it configures the resolution if this is the first requester to be linked to it
1981 * - it updates the requester with a pointer to the resolution
1982 *
1983 * Return code:
1984 * - 0 if everything happened smoothly
1985 * - -1 if an error occured. Of course, no resolution is linked to the requester
1986 */
1987int dns_link_resolution(void *requester, int requester_type, struct dns_resolution *resolution)
1988{
1989 struct dns_resolution *tmpresolution = NULL;
1990 struct dns_requester *tmprequester = NULL;
1991 struct dns_resolvers *resolvers = NULL;
1992 char *hostname_dn = NULL;
1993 int new_resolution;
1994
1995 if (!resolution) {
1996 tmprequester = calloc(1, sizeof(*tmprequester));
1997 if (!tmprequester)
1998 return -1;
1999
2000 switch (requester_type) {
2001 case OBJ_TYPE_SERVER:
2002 tmprequester->requester = &((struct server *)requester)->obj_type;
2003 hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2004 resolvers = objt_server(tmprequester->requester)->resolvers;
2005 switch (objt_server(tmprequester->requester)->dns_opts.family_prio) {
2006 case AF_INET:
2007 tmprequester->prefered_query_type = DNS_RTYPE_A;
2008 break;
2009 default:
2010 tmprequester->prefered_query_type = DNS_RTYPE_AAAA;
2011 }
2012
2013 break;
2014 case OBJ_TYPE_NONE:
2015 default:
2016 free(tmprequester);
2017 return -1;
2018 }
2019
2020 /* get a resolution from the resolvers' wait queue or pool */
2021 tmpresolution = dns_resolution_list_get(resolvers, hostname_dn, tmprequester->prefered_query_type);
2022 if (!tmpresolution) {
2023 free(tmprequester);
2024 return -1;
2025 }
2026 }
2027 else {
2028 tmpresolution = resolution;
2029
2030 switch (requester_type) {
2031 case OBJ_TYPE_SERVER:
2032 tmprequester = ((struct server *)requester)->dns_requester;
2033 resolvers = ((struct server *)requester)->resolvers;
2034 break;
2035 case OBJ_TYPE_NONE:
2036 default:
2037 return -1;
2038 }
2039 }
2040
2041 /* flag this resolution as NEW if applicable (not already linked to any requester).
2042 * this is required to decide which parameters we have to update on the resolution.
2043 * If new, it means we pulled up the resolution from the resolvers' pool.
2044 */
2045 if (LIST_ISEMPTY(&tmpresolution->requester.wait)) {
2046 new_resolution = 1;
2047 }
2048 else
2049 new_resolution = 0;
2050
2051 /* those parameters are related to the requester type */
2052 switch (obj_type(tmprequester->requester)) {
2053 case OBJ_TYPE_SERVER:
2054 /* some parameters should be set only if the resolution is brand new */
2055 if (new_resolution) {
2056 tmpresolution->query_type = tmprequester->prefered_query_type;
2057 tmpresolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2058 tmpresolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
2059 }
2060
2061 /* update requester as well, only if we just allocated it */
2062 objt_server(tmprequester->requester)->resolution = tmpresolution;
2063 if (!resolution) {
2064 tmprequester->requester_cb = snr_resolution_cb;
2065 tmprequester->requester_error_cb = snr_resolution_error_cb;
2066 objt_server(tmprequester->requester)->dns_requester = tmprequester;
2067 }
2068 break;
2069 case OBJ_TYPE_NONE:
2070 default:
2071 free(tmprequester);
2072 return -1;
2073 }
2074
2075 /* update some parameters only if this is a brand new resolution */
2076 if (new_resolution) {
2077 /* move the resolution to the requesters' wait queue */
2078 LIST_DEL(&tmpresolution->list);
2079 LIST_ADDQ(&resolvers->resolution.wait, &tmpresolution->list);
2080
2081 tmpresolution->status = RSLV_STATUS_NONE;
2082 tmpresolution->step = RSLV_STEP_NONE;
2083 tmpresolution->revision = 1;
2084 }
2085
2086 /* add the requester to the resolution's wait queue */
2087 if (resolution)
2088 LIST_DEL(&tmprequester->list);
2089 LIST_ADDQ(&tmpresolution->requester.wait, &tmprequester->list);
2090
2091 return 0;
2092}
2093
2094/*
2095 * pick up an available resolution from the different resolution list associated to a resolvers section,
2096 * in this order:
2097 * 1. check in resolution.curr for the same hostname and query_type
2098 * 2. check in resolution.wait for the same hostname and query_type
2099 * 3. take an available resolution from resolution.pool
2100 *
2101 * return an available resolution, NULL if none found.
2102 */
2103struct dns_resolution *dns_resolution_list_get(struct dns_resolvers *resolvers, char *hostname_dn, int query_type)
2104{
2105 struct dns_resolution *resolution, *tmpresolution;
2106 struct dns_requester *requester;
2107
2108 /* search for same hostname and query type in resolution.curr */
2109 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.curr, list) {
2110 requester = NULL;
2111
2112 if (!LIST_ISEMPTY(&resolution->requester.wait))
2113 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
2114 else if (!LIST_ISEMPTY(&resolution->requester.curr))
2115 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
2116
2117 if (!requester)
2118 continue;
2119
2120 if ((query_type == requester->prefered_query_type) &&
2121 (strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
2122 return resolution;
2123 }
2124 }
2125
2126 /* search for same hostname and query type in resolution.wait */
2127 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.wait, list) {
2128 requester = NULL;
2129
2130 if (!LIST_ISEMPTY(&resolution->requester.wait))
2131 requester = LIST_NEXT(&resolution->requester.wait, struct dns_requester *, list);
2132 else if (!LIST_ISEMPTY(&resolution->requester.curr))
2133 requester = LIST_NEXT(&resolution->requester.curr, struct dns_requester *, list);
2134
2135 if (!requester)
2136 continue;
2137
2138 if ((query_type == requester->prefered_query_type) &&
2139 (strcmp(hostname_dn, resolution->hostname_dn) == 0)) {
2140 return resolution;
2141 }
2142 }
2143
2144 /* take the first one (hopefully) from the pool */
2145 list_for_each_entry_safe(resolution, tmpresolution, &resolvers->resolution.pool, list) {
2146 if (LIST_ISEMPTY(&resolution->requester.wait)) {
2147 return resolution;
2148 }
2149 }
2150
2151 return NULL;
2152}
2153
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002154/* This function allocates memory for a DNS resolution structure.
2155 * It's up to the caller to set the parameters
2156 * Returns a pointer to the structure resolution or NULL if memory could
2157 * not be allocated.
2158 */
2159struct dns_resolution *dns_alloc_resolution(void)
2160{
2161 struct dns_resolution *resolution = NULL;
Baptiste Assmann729c9012017-05-22 15:13:10 +02002162 char *buffer = NULL;
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002163
2164 resolution = calloc(1, sizeof(*resolution));
Baptiste Assmann729c9012017-05-22 15:13:10 +02002165 buffer = calloc(1, global.tune.bufsize);
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002166
Baptiste Assmann729c9012017-05-22 15:13:10 +02002167 if (!resolution || !buffer) {
2168 free(buffer);
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002169 free(resolution);
2170 return NULL;
2171 }
2172
Baptiste Assmann729c9012017-05-22 15:13:10 +02002173 chunk_init(&resolution->response_buffer, buffer, global.tune.bufsize);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002174 LIST_INIT(&resolution->requester.wait);
2175 LIST_INIT(&resolution->requester.curr);
Baptiste Assmann729c9012017-05-22 15:13:10 +02002176
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002177 return resolution;
2178}
2179
2180/* This function free the memory allocated to a DNS resolution */
2181void dns_free_resolution(struct dns_resolution *resolution)
2182{
Baptiste Assmann729c9012017-05-22 15:13:10 +02002183 chunk_destroy(&resolution->response_buffer);
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002184 free(resolution);
2185
2186 return;
2187}
2188
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002189/* this function free a resolution from its requester(s) and move it back to the pool */
2190void dns_resolution_free(struct dns_resolvers *resolvers, struct dns_resolution *resolution)
2191{
2192 struct dns_requester *requester, *tmprequester;
2193
2194 /* clean up configuration */
2195 dns_reset_resolution(resolution);
2196 resolution->hostname_dn = NULL;
2197 resolution->hostname_dn_len = 0;
2198
2199 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.wait, list) {
2200 LIST_DEL(&requester->list);
2201 }
2202 list_for_each_entry_safe(requester, tmprequester, &resolution->requester.curr, list) {
2203 LIST_DEL(&requester->list);
2204 }
2205
2206 LIST_DEL(&resolution->list);
2207 LIST_ADDQ(&resolvers->resolution.pool, &resolution->list);
2208
2209 return;
2210}
2211
2212/*
2213 * this function remove a requester from a resolution
2214 * and takes care of all the consequences.
2215 * It also cleans up some parameters from the requester
2216 */
2217void dns_rm_requester_from_resolution(struct dns_requester *requester, struct dns_resolution *resolution)
2218{
2219 char *hostname_dn;
2220 struct dns_requester *tmprequester;
2221
2222 /* resolution is still used by other requesters, we need to move
2223 * some pointers to an other requester if needed
2224 */
2225 switch (obj_type(requester->requester)) {
2226 case OBJ_TYPE_SERVER:
2227 hostname_dn = objt_server(requester->requester)->hostname_dn;
2228 break;
2229 case OBJ_TYPE_NONE:
2230 default:
2231 hostname_dn = NULL;
2232 break;
2233 }
2234
2235 if (resolution->hostname_dn != hostname_dn)
2236 return;
2237
2238 /* First, we need to find this other requester */
2239 tmprequester = NULL;
2240 list_for_each_entry(tmprequester, &resolution->requester.wait, list) {
2241 if (tmprequester != requester)
2242 break;
2243 }
2244 if (!tmprequester) {
2245 /* if we can't find it in wait queue, let's get one in run queue */
2246 list_for_each_entry(tmprequester, &resolution->requester.curr, list) {
2247 if (tmprequester != requester)
2248 break;
2249 }
2250 }
2251
2252 /* move hostname_dn related pointers to the next requester */
2253 switch (obj_type(tmprequester->requester)) {
2254 case OBJ_TYPE_SERVER:
2255 resolution->hostname_dn = objt_server(tmprequester->requester)->hostname_dn;
2256 resolution->hostname_dn_len = objt_server(tmprequester->requester)->hostname_dn_len;
2257 break;
2258 case OBJ_TYPE_NONE:
2259 default:
2260 ;;
2261 }
2262
2263
2264 /* clean up the requester */
2265 LIST_DEL(&requester->list);
2266 switch (obj_type(requester->requester)) {
2267 case OBJ_TYPE_SERVER:
2268 objt_server(requester->requester)->resolution = NULL;
2269 break;
2270 case OBJ_TYPE_NONE:
2271 default:
2272 ;;
2273 }
2274}
2275
Willy Tarreau777b5602016-12-16 18:06:26 +01002276/* This function dumps counters from all resolvers section and associated name
2277 * servers. It returns 0 if the output buffer is full and it needs to be called
2278 * again, otherwise non-zero. It may limit itself to the resolver pointed to by
2279 * <cli.p0> if it's not null.
William Lallemand69e96442016-11-19 00:58:54 +01002280 */
2281static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx)
2282{
2283 struct stream_interface *si = appctx->owner;
2284 struct dns_resolvers *presolvers;
2285 struct dns_nameserver *pnameserver;
2286
2287 chunk_reset(&trash);
2288
2289 switch (appctx->st2) {
2290 case STAT_ST_INIT:
2291 appctx->st2 = STAT_ST_LIST; /* let's start producing data */
2292 /* fall through */
2293
2294 case STAT_ST_LIST:
2295 if (LIST_ISEMPTY(&dns_resolvers)) {
2296 chunk_appendf(&trash, "No resolvers found\n");
2297 }
2298 else {
2299 list_for_each_entry(presolvers, &dns_resolvers, list) {
Willy Tarreau777b5602016-12-16 18:06:26 +01002300 if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != presolvers)
William Lallemand69e96442016-11-19 00:58:54 +01002301 continue;
2302
2303 chunk_appendf(&trash, "Resolvers section %s\n", presolvers->id);
2304 list_for_each_entry(pnameserver, &presolvers->nameserver_list, list) {
2305 chunk_appendf(&trash, " nameserver %s:\n", pnameserver->id);
2306 chunk_appendf(&trash, " sent: %ld\n", pnameserver->counters.sent);
2307 chunk_appendf(&trash, " valid: %ld\n", pnameserver->counters.valid);
2308 chunk_appendf(&trash, " update: %ld\n", pnameserver->counters.update);
2309 chunk_appendf(&trash, " cname: %ld\n", pnameserver->counters.cname);
2310 chunk_appendf(&trash, " cname_error: %ld\n", pnameserver->counters.cname_error);
2311 chunk_appendf(&trash, " any_err: %ld\n", pnameserver->counters.any_err);
2312 chunk_appendf(&trash, " nx: %ld\n", pnameserver->counters.nx);
2313 chunk_appendf(&trash, " timeout: %ld\n", pnameserver->counters.timeout);
2314 chunk_appendf(&trash, " refused: %ld\n", pnameserver->counters.refused);
2315 chunk_appendf(&trash, " other: %ld\n", pnameserver->counters.other);
2316 chunk_appendf(&trash, " invalid: %ld\n", pnameserver->counters.invalid);
2317 chunk_appendf(&trash, " too_big: %ld\n", pnameserver->counters.too_big);
2318 chunk_appendf(&trash, " truncated: %ld\n", pnameserver->counters.truncated);
2319 chunk_appendf(&trash, " outdated: %ld\n", pnameserver->counters.outdated);
2320 }
2321 }
2322 }
2323
2324 /* display response */
2325 if (bi_putchk(si_ic(si), &trash) == -1) {
2326 /* let's try again later from this session. We add ourselves into
2327 * this session's users so that it can remove us upon termination.
2328 */
2329 si->flags |= SI_FL_WAIT_ROOM;
2330 return 0;
2331 }
2332
2333 appctx->st2 = STAT_ST_FIN;
2334 /* fall through */
2335
2336 default:
2337 appctx->st2 = STAT_ST_FIN;
2338 return 1;
2339 }
2340}
2341
2342/* register cli keywords */
2343static struct cli_kw_list cli_kws = {{ },{
2344 { { "show", "stat", "resolvers", NULL }, "show stat resolvers [id]: dumps counters from all resolvers section and\n"
2345 " associated name servers",
2346 cli_parse_stat_resolvers, cli_io_handler_dump_resolvers_to_buffer },
2347 {{},}
2348}};
2349
2350
2351__attribute__((constructor))
2352static void __dns_init(void)
2353{
2354 cli_register_kw(&cli_kws);
2355}
2356