1 /*
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/cfgparse.h>
23 #include <common/errors.h>
24 #include <common/initcall.h>
25 #include <common/time.h>
26 #include <common/ticks.h>
27 #include <common/net_helper.h>
28
29 #include <types/applet.h>
30 #include <types/cli.h>
31 #include <types/global.h>
32 #include <types/dns.h>
33 #include <types/stats.h>
34
35 #include <proto/channel.h>
36 #include <proto/cli.h>
37 #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>
44 #include <proto/proxy.h>
45 #include <proto/stream_interface.h>
46
47 struct list dns_resolvers = LIST_HEAD_INIT(dns_resolvers);
48 struct list dns_srvrq_list = LIST_HEAD_INIT(dns_srvrq_list);
49
50 static THREAD_LOCAL uint64_t dns_query_id_seed = 0; /* random seed */
51
52 DECLARE_STATIC_POOL(dns_answer_item_pool, "dns_answer_item", sizeof(struct dns_answer_item));
53 DECLARE_STATIC_POOL(dns_resolution_pool, "dns_resolution", sizeof(struct dns_resolution));
54
55 static unsigned int resolution_uuid = 1;
56
57 /* Returns a pointer to the resolvers matching the id <id>. NULL is returned if
58 * no match is found.
59 */
find_resolvers_by_id(const char * id)60 struct dns_resolvers *find_resolvers_by_id(const char *id)
61 {
62 struct dns_resolvers *res;
63
64 list_for_each_entry(res, &dns_resolvers, list) {
65 if (!strcmp(res->id, id))
66 return res;
67 }
68 return NULL;
69 }
70
71 /* Returns a pointer on the SRV request matching the name <name> for the proxy
72 * <px>. NULL is returned if no match is found.
73 */
find_srvrq_by_name(const char * name,struct proxy * px)74 struct dns_srvrq *find_srvrq_by_name(const char *name, struct proxy *px)
75 {
76 struct dns_srvrq *srvrq;
77
78 list_for_each_entry(srvrq, &dns_srvrq_list, list) {
79 if (srvrq->proxy == px && !strcmp(srvrq->name, name))
80 return srvrq;
81 }
82 return NULL;
83 }
84
85 /* Allocates a new SRVRQ for the given server with the name <fqdn>. It returns
86 * NULL if an error occurred. */
new_dns_srvrq(struct server * srv,char * fqdn)87 struct dns_srvrq *new_dns_srvrq(struct server *srv, char *fqdn)
88 {
89 struct proxy *px = srv->proxy;
90 struct dns_srvrq *srvrq = NULL;
91 int fqdn_len, hostname_dn_len;
92
93 fqdn_len = strlen(fqdn);
94 hostname_dn_len = dns_str_to_dn_label(fqdn, fqdn_len + 1, trash.area,
95 trash.size);
96 if (hostname_dn_len == -1) {
97 ha_alert("config : %s '%s', server '%s': failed to parse FQDN '%s'\n",
98 proxy_type_str(px), px->id, srv->id, fqdn);
99 goto err;
100 }
101
102 if ((srvrq = calloc(1, sizeof(*srvrq))) == NULL) {
103 ha_alert("config : %s '%s', server '%s': out of memory\n",
104 proxy_type_str(px), px->id, srv->id);
105 goto err;
106 }
107 srvrq->obj_type = OBJ_TYPE_SRVRQ;
108 srvrq->proxy = px;
109 srvrq->name = strdup(fqdn);
110 srvrq->hostname_dn = strdup(trash.area);
111 srvrq->hostname_dn_len = hostname_dn_len;
112 if (!srvrq->name || !srvrq->hostname_dn) {
113 ha_alert("config : %s '%s', server '%s': out of memory\n",
114 proxy_type_str(px), px->id, srv->id);
115 goto err;
116 }
117 LIST_ADDQ(&dns_srvrq_list, &srvrq->list);
118 return srvrq;
119
120 err:
121 if (srvrq) {
122 free(srvrq->name);
123 free(srvrq->hostname_dn);
124 free(srvrq);
125 }
126 return NULL;
127 }
128
129
130 /* 2 bytes random generator to generate DNS query ID */
dns_rnd16(void)131 static inline uint16_t dns_rnd16(void)
132 {
133 if (!dns_query_id_seed)
134 dns_query_id_seed = now_ms;
135 dns_query_id_seed ^= dns_query_id_seed << 13;
136 dns_query_id_seed ^= dns_query_id_seed >> 7;
137 dns_query_id_seed ^= dns_query_id_seed << 17;
138 return dns_query_id_seed;
139 }
140
141
dns_resolution_timeout(struct dns_resolution * res)142 static inline int dns_resolution_timeout(struct dns_resolution *res)
143 {
144 return res->resolvers->timeout.resolve;
145 }
146
147 /* Updates a resolvers' task timeout for next wake up and queue it */
dns_update_resolvers_timeout(struct dns_resolvers * resolvers)148 static void dns_update_resolvers_timeout(struct dns_resolvers *resolvers)
149 {
150 struct dns_resolution *res;
151 int next;
152
153 next = tick_add(now_ms, resolvers->timeout.resolve);
154 if (!LIST_ISEMPTY(&resolvers->resolutions.curr)) {
155 res = LIST_NEXT(&resolvers->resolutions.curr, struct dns_resolution *, list);
156 next = MIN(next, tick_add(res->last_query, resolvers->timeout.retry));
157 }
158
159 list_for_each_entry(res, &resolvers->resolutions.wait, list)
160 next = MIN(next, tick_add(res->last_resolution, dns_resolution_timeout(res)));
161
162 resolvers->t->expire = next;
163 task_queue(resolvers->t);
164 }
165
166 /* Opens an UDP socket on the namesaver's IP/Port, if required. Returns 0 on
167 * success, -1 otherwise.
168 */
dns_connect_namesaver(struct dns_nameserver * ns)169 static int dns_connect_namesaver(struct dns_nameserver *ns)
170 {
171 struct dgram_conn *dgram = ns->dgram;
172 int fd;
173
174 /* Already connected */
175 if (dgram->t.sock.fd != -1)
176 return 0;
177
178 /* Create an UDP socket and connect it on the nameserver's IP/Port */
179 if ((fd = socket(ns->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
180 send_log(NULL, LOG_WARNING,
181 "DNS : resolvers '%s': can't create socket for nameserver '%s'.\n",
182 ns->resolvers->id, ns->id);
183 return -1;
184 }
185 if (connect(fd, (struct sockaddr*)&ns->addr, get_addr_len(&ns->addr)) == -1) {
186 send_log(NULL, LOG_WARNING,
187 "DNS : resolvers '%s': can't connect socket for nameserver '%s'.\n",
188 ns->resolvers->id, ns->id);
189 close(fd);
190 return -1;
191 }
192
193 /* Make the socket non blocking */
194 fcntl(fd, F_SETFL, O_NONBLOCK);
195
196 /* Add the fd in the fd list and update its parameters */
197 dgram->t.sock.fd = fd;
198 fd_insert(fd, dgram, dgram_fd_handler, MAX_THREADS_MASK);
199 fd_want_recv(fd);
200 return 0;
201 }
202
203 /* Forges a DNS query. It needs the following information from the caller:
204 * - <query_id> : the DNS query id corresponding to this query
205 * - <query_type> : DNS_RTYPE_* request DNS record type (A, AAAA, ANY...)
206 * - <hostname_dn> : hostname in domain name format
207 * - <hostname_dn_len> : length of <hostname_dn>
208 *
209 * To store the query, the caller must pass a buffer <buf> and its size
210 * <bufsize>. It returns the number of written bytes in success, -1 if <buf> is
211 * too short.
212 */
dns_build_query(int query_id,int query_type,unsigned int accepted_payload_size,char * hostname_dn,int hostname_dn_len,char * buf,int bufsize)213 static int dns_build_query(int query_id, int query_type, unsigned int accepted_payload_size,
214 char *hostname_dn, int hostname_dn_len, char *buf, int bufsize)
215 {
216 struct dns_header dns_hdr;
217 struct dns_question qinfo;
218 struct dns_additional_record edns;
219 char *p = buf;
220
221 if (sizeof(dns_hdr) + sizeof(qinfo) + sizeof(edns) + hostname_dn_len >= bufsize)
222 return -1;
223
224 memset(buf, 0, bufsize);
225
226 /* Set dns query headers */
227 dns_hdr.id = (unsigned short) htons(query_id);
228 dns_hdr.flags = htons(0x0100); /* qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, rcode=0 */
229 dns_hdr.qdcount = htons(1); /* 1 question */
230 dns_hdr.ancount = 0;
231 dns_hdr.nscount = 0;
232 dns_hdr.arcount = htons(1);
233 memcpy(p, &dns_hdr, sizeof(dns_hdr));
234 p += sizeof(dns_hdr);
235
236 /* Set up query hostname */
237 memcpy(p, hostname_dn, hostname_dn_len);
238 p += hostname_dn_len;
239 *p++ = 0;
240
241 /* Set up query info (type and class) */
242 qinfo.qtype = htons(query_type);
243 qinfo.qclass = htons(DNS_RCLASS_IN);
244 memcpy(p, &qinfo, sizeof(qinfo));
245 p += sizeof(qinfo);
246
247 /* Set the DNS extension */
248 edns.name = 0;
249 edns.type = htons(DNS_RTYPE_OPT);
250 edns.udp_payload_size = htons(accepted_payload_size);
251 edns.extension = 0;
252 edns.data_length = 0;
253 memcpy(p, &edns, sizeof(edns));
254 p += sizeof(edns);
255
256 return (p - buf);
257 }
258
259 /* Sends a DNS query to resolvers associated to a resolution. It returns 0 on
260 * success, -1 otherwise.
261 */
dns_send_query(struct dns_resolution * resolution)262 static int dns_send_query(struct dns_resolution *resolution)
263 {
264 struct dns_resolvers *resolvers = resolution->resolvers;
265 struct dns_nameserver *ns;
266
267 list_for_each_entry(ns, &resolvers->nameservers, list) {
268 int fd = ns->dgram->t.sock.fd;
269 if (fd == -1) {
270 if (dns_connect_namesaver(ns) == -1)
271 continue;
272 fd = ns->dgram->t.sock.fd;
273 resolvers->nb_nameservers++;
274 }
275 fd_want_send(fd);
276 }
277
278 /* Update resolution */
279 resolution->nb_queries = 0;
280 resolution->nb_responses = 0;
281 resolution->last_query = now_ms;
282
283 /* Push the resolution at the end of the active list */
284 LIST_DEL(&resolution->list);
285 LIST_ADDQ(&resolvers->resolutions.curr, &resolution->list);
286 return 0;
287 }
288
289 /* Prepares and sends a DNS resolution. It returns 1 if the query was sent, 0 if
290 * skipped and -1 if an error occurred.
291 */
292 static int
dns_run_resolution(struct dns_resolution * resolution)293 dns_run_resolution(struct dns_resolution *resolution)
294 {
295 struct dns_resolvers *resolvers = resolution->resolvers;
296 int query_id, i;
297
298 /* Avoid sending requests for resolutions that don't yet have an
299 * hostname, ie resolutions linked to servers that do not yet have an
300 * fqdn */
301 if (!resolution->hostname_dn)
302 return 0;
303
304 /* Check if a resolution has already been started for this server return
305 * directly to avoid resolution pill up. */
306 if (resolution->step != RSLV_STEP_NONE)
307 return 0;
308
309 /* Generates a new query id. We try at most 100 times to find a free
310 * query id */
311 for (i = 0; i < 100; ++i) {
312 query_id = dns_rnd16();
313 if (!eb32_lookup(&resolvers->query_ids, query_id))
314 break;
315 query_id = -1;
316 }
317 if (query_id == -1) {
318 send_log(NULL, LOG_NOTICE,
319 "could not generate a query id for %s, in resolvers %s.\n",
320 resolution->hostname_dn, resolvers->id);
321 return -1;
322 }
323
324 /* Update resolution parameters */
325 resolution->query_id = query_id;
326 resolution->qid.key = query_id;
327 resolution->step = RSLV_STEP_RUNNING;
328 resolution->query_type = resolution->prefered_query_type;
329 resolution->try = resolvers->resolve_retries;
330 eb32_insert(&resolvers->query_ids, &resolution->qid);
331
332 /* Send the DNS query */
333 resolution->try -= 1;
334 dns_send_query(resolution);
335 return 1;
336 }
337
338 /* Performs a name resolution for the requester <req> */
dns_trigger_resolution(struct dns_requester * req)339 void dns_trigger_resolution(struct dns_requester *req)
340 {
341 struct dns_resolvers *resolvers;
342 struct dns_resolution *res;
343 int exp;
344
345 if (!req || !req->resolution)
346 return;
347 res = req->resolution;
348 resolvers = res->resolvers;
349
350 /* The resolution must not be triggered yet. Use the cached response, if
351 * valid */
352 exp = tick_add(res->last_resolution, resolvers->hold.valid);
353 if (resolvers->t && (res->status != RSLV_STATUS_VALID ||
354 !tick_isset(res->last_resolution) || tick_is_expired(exp, now_ms)))
355 task_wakeup(resolvers->t, TASK_WOKEN_OTHER);
356 }
357
358
359 /* Resets some resolution parameters to initial values and also delete the query
360 * ID from the resolver's tree.
361 */
dns_reset_resolution(struct dns_resolution * resolution)362 static void dns_reset_resolution(struct dns_resolution *resolution)
363 {
364 /* update resolution status */
365 resolution->step = RSLV_STEP_NONE;
366 resolution->try = 0;
367 resolution->last_resolution = now_ms;
368 resolution->nb_queries = 0;
369 resolution->nb_responses = 0;
370 resolution->query_type = resolution->prefered_query_type;
371
372 /* clean up query id */
373 eb32_delete(&resolution->qid);
374 resolution->query_id = 0;
375 resolution->qid.key = 0;
376 }
377
378 /* Returns the query id contained in a DNS response */
dns_response_get_query_id(unsigned char * resp)379 static inline unsigned short dns_response_get_query_id(unsigned char *resp)
380 {
381 return resp[0] * 256 + resp[1];
382 }
383
384
385 /* Analyses, re-builds and copies the name <name> from the DNS response packet
386 * <buffer>. <name> must point to the 'data_len' information or pointer 'c0'
387 * for compressed data. The result is copied into <dest>, ensuring we don't
388 * overflow using <dest_len> Returns the number of bytes the caller can move
389 * forward. If 0 it means an error occurred while parsing the name. <offset> is
390 * the number of bytes the caller could move forward.
391 */
dns_read_name(unsigned char * buffer,unsigned char * bufend,unsigned char * name,char * destination,int dest_len,int * offset,unsigned int depth)392 int dns_read_name(unsigned char *buffer, unsigned char *bufend,
393 unsigned char *name, char *destination, int dest_len,
394 int *offset, unsigned int depth)
395 {
396 int nb_bytes = 0, n = 0;
397 int label_len;
398 unsigned char *reader = name;
399 char *dest = destination;
400
401 while (1) {
402 if (reader >= bufend)
403 goto err;
404
405 /* Name compression is in use */
406 if ((*reader & 0xc0) == 0xc0) {
407 if (reader + 1 >= bufend)
408 goto err;
409
410 /* Must point BEFORE current position */
411 if ((buffer + reader[1]) > reader)
412 goto err;
413
414 if (depth++ > 100)
415 goto err;
416
417 n = dns_read_name(buffer, bufend, buffer + (*reader & 0x3f)*256 + reader[1],
418 dest, dest_len - nb_bytes, offset, depth);
419 if (n == 0)
420 goto err;
421
422 dest += n;
423 nb_bytes += n;
424 goto out;
425 }
426
427 label_len = *reader;
428 if (label_len == 0)
429 goto out;
430
431 /* Check if:
432 * - we won't read outside the buffer
433 * - there is enough place in the destination
434 */
435 if ((reader + label_len >= bufend) || (nb_bytes + label_len >= dest_len))
436 goto err;
437
438 /* +1 to take label len + label string */
439 label_len++;
440
441 memcpy(dest, reader, label_len);
442
443 dest += label_len;
444 nb_bytes += label_len;
445 reader += label_len;
446 }
447
448 out:
449 /* offset computation:
450 * parse from <name> until finding either NULL or a pointer "c0xx"
451 */
452 reader = name;
453 *offset = 0;
454 while (reader < bufend) {
455 if ((reader[0] & 0xc0) == 0xc0) {
456 *offset += 2;
457 break;
458 }
459 else if (*reader == 0) {
460 *offset += 1;
461 break;
462 }
463 *offset += 1;
464 ++reader;
465 }
466 return nb_bytes;
467
468 err:
469 return 0;
470 }
471
472 /* Checks for any obsolete record, also identify any SRV request, and try to
473 * find a corresponding server.
474 */
dns_check_dns_response(struct dns_resolution * res)475 static void dns_check_dns_response(struct dns_resolution *res)
476 {
477 struct dns_resolvers *resolvers = res->resolvers;
478 struct dns_requester *req, *reqback;
479 struct dns_answer_item *item, *itemback;
480 struct server *srv;
481 struct dns_srvrq *srvrq;
482
483 list_for_each_entry_safe(item, itemback, &res->response.answer_list, list) {
484
485 /* Remove obsolete items */
486 if ((item->last_seen + resolvers->hold.obsolete / 1000) < now.tv_sec) {
487 if (item->type != DNS_RTYPE_SRV)
488 goto rm_obselete_item;
489
490 list_for_each_entry_safe(req, reqback, &res->requesters, list) {
491 if ((srvrq = objt_dns_srvrq(req->owner)) == NULL)
492 continue;
493
494 /* Remove any associated server */
495 for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
496 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
497 if (srv->srvrq == srvrq && srv->svc_port == item->port &&
498 item->data_len == srv->hostname_dn_len &&
499 !memcmp(srv->hostname_dn, item->target, item->data_len)) {
500 snr_update_srv_status(srv, 1);
501 free(srv->hostname);
502 free(srv->hostname_dn);
503 srv->hostname = NULL;
504 srv->hostname_dn = NULL;
505 srv->hostname_dn_len = 0;
506 dns_unlink_resolution(srv->dns_requester);
507 }
508 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
509 }
510 }
511
512 rm_obselete_item:
513 LIST_DEL(&item->list);
514 pool_free(dns_answer_item_pool, item);
515 continue;
516 }
517
518 if (item->type != DNS_RTYPE_SRV)
519 continue;
520
521 /* Now process SRV records */
522 list_for_each_entry_safe(req, reqback, &res->requesters, list) {
523 if ((srvrq = objt_dns_srvrq(req->owner)) == NULL)
524 continue;
525
526 /* Check if a server already uses that hostname */
527 for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
528 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
529 if (srv->srvrq == srvrq && srv->svc_port == item->port &&
530 item->data_len == srv->hostname_dn_len &&
531 !memcmp(srv->hostname_dn, item->target, item->data_len)) {
532 int ha_weight;
533
534 /* DNS weight range if from 0 to 65535
535 * HAProxy weight is from 0 to 256
536 * The rule below ensures that weight 0 is well respected
537 * while allowing a "mapping" from DNS weight into HAProxy's one.
538 */
539 ha_weight = (item->weight + 255) / 256;
540 if (srv->uweight != ha_weight) {
541 char weight[9];
542
543 snprintf(weight, sizeof(weight), "%d", ha_weight);
544 server_parse_weight_change_request(srv, weight);
545 }
546 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
547 break;
548 }
549 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
550 }
551 if (srv)
552 continue;
553
554 /* If not, try to find a server with undefined hostname */
555 for (srv = srvrq->proxy->srv; srv != NULL; srv = srv->next) {
556 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
557 if (srv->srvrq == srvrq && !srv->hostname_dn)
558 break;
559 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
560 }
561 /* And update this server, if found */
562 if (srv) {
563 const char *msg = NULL;
564 char weight[9];
565 int ha_weight;
566 char hostname[DNS_MAX_NAME_SIZE];
567
568 if (dns_dn_label_to_str(item->target, item->data_len+1,
569 hostname, DNS_MAX_NAME_SIZE) == -1) {
570 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
571 continue;
572 }
573 msg = update_server_fqdn(srv, hostname, "SRV record", 1);
574 if (msg)
575 send_log(srv->proxy, LOG_NOTICE, "%s", msg);
576
577 srv->svc_port = item->port;
578 srv->flags &= ~SRV_F_MAPPORTS;
579 if ((srv->check.state & CHK_ST_CONFIGURED) &&
580 !(srv->flags & SRV_F_CHECKPORT))
581 srv->check.port = item->port;
582
583 /* DNS weight range if from 0 to 65535
584 * HAProxy weight is from 0 to 256
585 * The rule below ensures that weight 0 is well respected
586 * while allowing a "mapping" from DNS weight into HAProxy's one.
587 */
588 ha_weight = (item->weight + 255) / 256;
589
590 snprintf(weight, sizeof(weight), "%d", ha_weight);
591 server_parse_weight_change_request(srv, weight);
592 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
593 }
594 }
595 }
596 }
597
598 /* Validates that the buffer DNS response provided in <resp> and finishing
599 * before <bufend> is valid from a DNS protocol point of view.
600 *
601 * The result is stored in <resolution>' response, buf_response,
602 * response_query_records and response_answer_records members.
603 *
604 * This function returns one of the DNS_RESP_* code to indicate the type of
605 * error found.
606 */
dns_validate_dns_response(unsigned char * resp,unsigned char * bufend,struct dns_resolution * resolution,int max_answer_records)607 static int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend,
608 struct dns_resolution *resolution, int max_answer_records)
609 {
610 unsigned char *reader;
611 char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
612 int len, flags, offset;
613 int dns_query_record_id;
614 int nb_saved_records;
615 struct dns_query_item *dns_query;
616 struct dns_answer_item *dns_answer_record, *tmp_record;
617 struct dns_response_packet *dns_p;
618 int i, found = 0;
619
620 reader = resp;
621 len = 0;
622 previous_dname = NULL;
623 dns_query = NULL;
624
625 /* Initialization of response buffer and structure */
626 dns_p = &resolution->response;
627
628 /* query id */
629 if (reader + 2 >= bufend)
630 return DNS_RESP_INVALID;
631 dns_p->header.id = reader[0] * 256 + reader[1];
632 reader += 2;
633
634 /* Flags and rcode are stored over 2 bytes
635 * First byte contains:
636 * - response flag (1 bit)
637 * - opcode (4 bits)
638 * - authoritative (1 bit)
639 * - truncated (1 bit)
640 * - recursion desired (1 bit)
641 */
642 if (reader + 2 >= bufend)
643 return DNS_RESP_INVALID;
644
645 flags = reader[0] * 256 + reader[1];
646
647 if ((flags & DNS_FLAG_REPLYCODE) != DNS_RCODE_NO_ERROR) {
648 if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_NX_DOMAIN)
649 return DNS_RESP_NX_DOMAIN;
650 else if ((flags & DNS_FLAG_REPLYCODE) == DNS_RCODE_REFUSED)
651 return DNS_RESP_REFUSED;
652 return DNS_RESP_ERROR;
653 }
654
655 /* Move forward 2 bytes for flags */
656 reader += 2;
657
658 /* 2 bytes for question count */
659 if (reader + 2 >= bufend)
660 return DNS_RESP_INVALID;
661 dns_p->header.qdcount = reader[0] * 256 + reader[1];
662 /* (for now) we send one query only, so we expect only one in the
663 * response too */
664 if (dns_p->header.qdcount != 1)
665 return DNS_RESP_QUERY_COUNT_ERROR;
666 if (dns_p->header.qdcount > DNS_MAX_QUERY_RECORDS)
667 return DNS_RESP_INVALID;
668 reader += 2;
669
670 /* 2 bytes for answer count */
671 if (reader + 2 >= bufend)
672 return DNS_RESP_INVALID;
673 dns_p->header.ancount = reader[0] * 256 + reader[1];
674 if (dns_p->header.ancount == 0)
675 return DNS_RESP_ANCOUNT_ZERO;
676 /* Check if too many records are announced */
677 if (dns_p->header.ancount > max_answer_records)
678 return DNS_RESP_INVALID;
679 reader += 2;
680
681 /* 2 bytes authority count */
682 if (reader + 2 >= bufend)
683 return DNS_RESP_INVALID;
684 dns_p->header.nscount = reader[0] * 256 + reader[1];
685 reader += 2;
686
687 /* 2 bytes additional count */
688 if (reader + 2 >= bufend)
689 return DNS_RESP_INVALID;
690 dns_p->header.arcount = reader[0] * 256 + reader[1];
691 reader += 2;
692
693 /* Parsing dns queries */
694 LIST_INIT(&dns_p->query_list);
695 for (dns_query_record_id = 0; dns_query_record_id < dns_p->header.qdcount; dns_query_record_id++) {
696 /* Use next pre-allocated dns_query_item after ensuring there is
697 * still one available.
698 * It's then added to our packet query list. */
699 if (dns_query_record_id > DNS_MAX_QUERY_RECORDS)
700 return DNS_RESP_INVALID;
701 dns_query = &resolution->response_query_records[dns_query_record_id];
702 LIST_ADDQ(&dns_p->query_list, &dns_query->list);
703
704 /* Name is a NULL terminated string in our case, since we have
705 * one query per response and the first one can't be compressed
706 * (using the 0x0c format) */
707 offset = 0;
708 len = dns_read_name(resp, bufend, reader, dns_query->name, DNS_MAX_NAME_SIZE, &offset, 0);
709
710 if (len == 0)
711 return DNS_RESP_INVALID;
712
713 reader += offset;
714 previous_dname = dns_query->name;
715
716 /* move forward 2 bytes for question type */
717 if (reader + 2 >= bufend)
718 return DNS_RESP_INVALID;
719 dns_query->type = reader[0] * 256 + reader[1];
720 reader += 2;
721
722 /* move forward 2 bytes for question class */
723 if (reader + 2 >= bufend)
724 return DNS_RESP_INVALID;
725 dns_query->class = reader[0] * 256 + reader[1];
726 reader += 2;
727 }
728
729 /* TRUNCATED flag must be checked after we could read the query type
730 * because a TRUNCATED SRV query type response can still be exploited */
731 if (dns_query->type != DNS_RTYPE_SRV && flags & DNS_FLAG_TRUNCATED)
732 return DNS_RESP_TRUNCATED;
733
734 /* now parsing response records */
735 nb_saved_records = 0;
736 for (i = 0; i < dns_p->header.ancount; i++) {
737 if (reader >= bufend)
738 return DNS_RESP_INVALID;
739
740 dns_answer_record = pool_alloc(dns_answer_item_pool);
741 if (dns_answer_record == NULL)
742 return (DNS_RESP_INVALID);
743
744 offset = 0;
745 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset, 0);
746
747 if (len == 0) {
748 pool_free(dns_answer_item_pool, dns_answer_record);
749 return DNS_RESP_INVALID;
750 }
751
752 /* Check if the current record dname is valid. previous_dname
753 * points either to queried dname or last CNAME target */
754 if (dns_query->type != DNS_RTYPE_SRV && memcmp(previous_dname, tmpname, len) != 0) {
755 pool_free(dns_answer_item_pool, dns_answer_record);
756 if (i == 0) {
757 /* First record, means a mismatch issue between
758 * queried dname and dname found in the first
759 * record */
760 return DNS_RESP_INVALID;
761 }
762 else {
763 /* If not the first record, this means we have a
764 * CNAME resolution error */
765 return DNS_RESP_CNAME_ERROR;
766 }
767
768 }
769
770 memcpy(dns_answer_record->name, tmpname, len);
771 dns_answer_record->name[len] = 0;
772
773 reader += offset;
774 if (reader >= bufend) {
775 pool_free(dns_answer_item_pool, dns_answer_record);
776 return DNS_RESP_INVALID;
777 }
778
779 /* 2 bytes for record type (A, AAAA, CNAME, etc...) */
780 if (reader + 2 > bufend) {
781 pool_free(dns_answer_item_pool, dns_answer_record);
782 return DNS_RESP_INVALID;
783 }
784 dns_answer_record->type = reader[0] * 256 + reader[1];
785 reader += 2;
786
787 /* 2 bytes for class (2) */
788 if (reader + 2 > bufend) {
789 pool_free(dns_answer_item_pool, dns_answer_record);
790 return DNS_RESP_INVALID;
791 }
792 dns_answer_record->class = reader[0] * 256 + reader[1];
793 reader += 2;
794
795 /* 4 bytes for ttl (4) */
796 if (reader + 4 > bufend) {
797 pool_free(dns_answer_item_pool, dns_answer_record);
798 return DNS_RESP_INVALID;
799 }
800 dns_answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
801 + reader[2] * 256 + reader[3];
802 reader += 4;
803
804 /* Now reading data len */
805 if (reader + 2 > bufend) {
806 pool_free(dns_answer_item_pool, dns_answer_record);
807 return DNS_RESP_INVALID;
808 }
809 dns_answer_record->data_len = reader[0] * 256 + reader[1];
810
811 /* Move forward 2 bytes for data len */
812 reader += 2;
813
814 if (reader + dns_answer_record->data_len > bufend) {
815 pool_free(dns_answer_item_pool, dns_answer_record);
816 return DNS_RESP_INVALID;
817 }
818
819 /* Analyzing record content */
820 switch (dns_answer_record->type) {
821 case DNS_RTYPE_A:
822 /* ipv4 is stored on 4 bytes */
823 if (dns_answer_record->data_len != 4) {
824 pool_free(dns_answer_item_pool, dns_answer_record);
825 return DNS_RESP_INVALID;
826 }
827 dns_answer_record->address.sa_family = AF_INET;
828 memcpy(&(((struct sockaddr_in *)&dns_answer_record->address)->sin_addr),
829 reader, dns_answer_record->data_len);
830 break;
831
832 case DNS_RTYPE_CNAME:
833 /* Check if this is the last record and update the caller about the status:
834 * no IP could be found and last record was a CNAME. Could be triggered
835 * by a wrong query type
836 *
837 * + 1 because dns_answer_record_id starts at 0
838 * while number of answers is an integer and
839 * starts at 1.
840 */
841 if (i + 1 == dns_p->header.ancount) {
842 pool_free(dns_answer_item_pool, dns_answer_record);
843 return DNS_RESP_CNAME_ERROR;
844 }
845
846 offset = 0;
847 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset, 0);
848 if (len == 0) {
849 pool_free(dns_answer_item_pool, dns_answer_record);
850 return DNS_RESP_INVALID;
851 }
852
853 memcpy(dns_answer_record->target, tmpname, len);
854 dns_answer_record->target[len] = 0;
855 previous_dname = dns_answer_record->target;
856 break;
857
858
859 case DNS_RTYPE_SRV:
860 /* Answer must contain :
861 * - 2 bytes for the priority
862 * - 2 bytes for the weight
863 * - 2 bytes for the port
864 * - the target hostname
865 */
866 if (dns_answer_record->data_len <= 6) {
867 pool_free(dns_answer_item_pool, dns_answer_record);
868 return DNS_RESP_INVALID;
869 }
870 dns_answer_record->priority = read_n16(reader);
871 reader += sizeof(uint16_t);
872 dns_answer_record->weight = read_n16(reader);
873 reader += sizeof(uint16_t);
874 dns_answer_record->port = read_n16(reader);
875 reader += sizeof(uint16_t);
876 offset = 0;
877 len = dns_read_name(resp, bufend, reader, tmpname, DNS_MAX_NAME_SIZE, &offset, 0);
878 if (len == 0) {
879 pool_free(dns_answer_item_pool, dns_answer_record);
880 return DNS_RESP_INVALID;
881 }
882 dns_answer_record->data_len = len;
883 memcpy(dns_answer_record->target, tmpname, len);
884 dns_answer_record->target[len] = 0;
885 break;
886
887 case DNS_RTYPE_AAAA:
888 /* ipv6 is stored on 16 bytes */
889 if (dns_answer_record->data_len != 16) {
890 pool_free(dns_answer_item_pool, dns_answer_record);
891 return DNS_RESP_INVALID;
892 }
893 dns_answer_record->address.sa_family = AF_INET6;
894 memcpy(&(((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr),
895 reader, dns_answer_record->data_len);
896 break;
897
898 } /* switch (record type) */
899
900 /* Increment the counter for number of records saved into our
901 * local response */
902 nb_saved_records++;
903
904 /* Move forward dns_answer_record->data_len for analyzing next
905 * record in the response */
906 reader += ((dns_answer_record->type == DNS_RTYPE_SRV)
907 ? offset
908 : dns_answer_record->data_len);
909
910 /* Lookup to see if we already had this entry */
911 found = 0;
912 list_for_each_entry(tmp_record, &dns_p->answer_list, list) {
913 if (tmp_record->type != dns_answer_record->type)
914 continue;
915
916 switch(tmp_record->type) {
917 case DNS_RTYPE_A:
918 if (!memcmp(&((struct sockaddr_in *)&dns_answer_record->address)->sin_addr,
919 &((struct sockaddr_in *)&tmp_record->address)->sin_addr,
920 sizeof(in_addr_t)))
921 found = 1;
922 break;
923
924 case DNS_RTYPE_AAAA:
925 if (!memcmp(&((struct sockaddr_in6 *)&dns_answer_record->address)->sin6_addr,
926 &((struct sockaddr_in6 *)&tmp_record->address)->sin6_addr,
927 sizeof(struct in6_addr)))
928 found = 1;
929 break;
930
931 case DNS_RTYPE_SRV:
932 if (dns_answer_record->data_len == tmp_record->data_len &&
933 !memcmp(dns_answer_record->target, tmp_record->target, dns_answer_record->data_len) &&
934 dns_answer_record->port == tmp_record->port) {
935 tmp_record->weight = dns_answer_record->weight;
936 found = 1;
937 }
938 break;
939
940 default:
941 break;
942 }
943
944 if (found == 1)
945 break;
946 }
947
948 if (found == 1) {
949 tmp_record->last_seen = now.tv_sec;
950 pool_free(dns_answer_item_pool, dns_answer_record);
951 }
952 else {
953 dns_answer_record->last_seen = now.tv_sec;
954 LIST_ADDQ(&dns_p->answer_list, &dns_answer_record->list);
955 }
956 } /* for i 0 to ancount */
957
958 /* Save the number of records we really own */
959 dns_p->header.ancount = nb_saved_records;
960 dns_check_dns_response(resolution);
961 return DNS_RESP_VALID;
962 }
963
964 /* Searches dn_name resolution in resp.
965 * If existing IP not found, return the first IP matching family_priority,
966 * otherwise, first ip found
967 * The following tasks are the responsibility of the caller:
968 * - <dns_p> contains an error free DNS response
969 * For both cases above, dns_validate_dns_response is required
970 * returns one of the DNS_UPD_* code
971 */
dns_get_ip_from_response(struct dns_response_packet * dns_p,struct dns_options * dns_opts,void * currentip,short currentip_sin_family,void ** newip,short * newip_sin_family,void * owner)972 int dns_get_ip_from_response(struct dns_response_packet *dns_p,
973 struct dns_options *dns_opts, void *currentip,
974 short currentip_sin_family,
975 void **newip, short *newip_sin_family,
976 void *owner)
977 {
978 struct dns_answer_item *record;
979 int family_priority;
980 int currentip_found;
981 unsigned char *newip4, *newip6;
982 int currentip_sel;
983 int j;
984 int score, max_score;
985 int allowed_duplicated_ip;
986
987 family_priority = dns_opts->family_prio;
988 allowed_duplicated_ip = dns_opts->accept_duplicate_ip;
989 *newip = newip4 = newip6 = NULL;
990 currentip_found = 0;
991 *newip_sin_family = AF_UNSPEC;
992 max_score = -1;
993
994 /* Select an IP regarding configuration preference.
995 * Top priority is the preferred network ip version,
996 * second priority is the preferred network.
997 * the last priority is the currently used IP,
998 *
999 * For these three priorities, a score is calculated. The
1000 * weight are:
1001 * 8 - preferred ip version.
1002 * 4 - preferred network.
1003 * 2 - if the ip in the record is not affected to any other server in the same backend (duplication)
1004 * 1 - current ip.
1005 * The result with the biggest score is returned.
1006 */
1007
1008 list_for_each_entry(record, &dns_p->answer_list, list) {
1009 void *ip;
1010 unsigned char ip_type;
1011
1012 if (record->type == DNS_RTYPE_A) {
1013 ip = &(((struct sockaddr_in *)&record->address)->sin_addr);
1014 ip_type = AF_INET;
1015 }
1016 else if (record->type == DNS_RTYPE_AAAA) {
1017 ip_type = AF_INET6;
1018 ip = &(((struct sockaddr_in6 *)&record->address)->sin6_addr);
1019 }
1020 else
1021 continue;
1022 score = 0;
1023
1024 /* Check for preferred ip protocol. */
1025 if (ip_type == family_priority)
1026 score += 8;
1027
1028 /* Check for preferred network. */
1029 for (j = 0; j < dns_opts->pref_net_nb; j++) {
1030
1031 /* Compare only the same adresses class. */
1032 if (dns_opts->pref_net[j].family != ip_type)
1033 continue;
1034
1035 if ((ip_type == AF_INET &&
1036 in_net_ipv4(ip,
1037 &dns_opts->pref_net[j].mask.in4,
1038 &dns_opts->pref_net[j].addr.in4)) ||
1039 (ip_type == AF_INET6 &&
1040 in_net_ipv6(ip,
1041 &dns_opts->pref_net[j].mask.in6,
1042 &dns_opts->pref_net[j].addr.in6))) {
1043 score += 4;
1044 break;
1045 }
1046 }
1047
1048 /* Check if the IP found in the record is already affected to a
1049 * member of a group. If not, the score should be incremented
1050 * by 2. */
1051 if (owner && snr_check_ip_callback(owner, ip, &ip_type)) {
1052 if (!allowed_duplicated_ip) {
1053 continue;
1054 }
1055 } else {
1056 score += 2;
1057 }
1058
1059 /* Check for current ip matching. */
1060 if (ip_type == currentip_sin_family &&
1061 ((currentip_sin_family == AF_INET &&
1062 !memcmp(ip, currentip, 4)) ||
1063 (currentip_sin_family == AF_INET6 &&
1064 !memcmp(ip, currentip, 16)))) {
1065 score++;
1066 currentip_sel = 1;
1067 }
1068 else
1069 currentip_sel = 0;
1070
1071 /* Keep the address if the score is better than the previous
1072 * score. The maximum score is 15, if this value is reached, we
1073 * break the parsing. Implicitly, this score is reached the ip
1074 * selected is the current ip. */
1075 if (score > max_score) {
1076 if (ip_type == AF_INET)
1077 newip4 = ip;
1078 else
1079 newip6 = ip;
1080 currentip_found = currentip_sel;
1081 if (score == 15)
1082 return DNS_UPD_NO;
1083 max_score = score;
1084 }
1085 } /* list for each record entries */
1086
1087 /* No IP found in the response */
1088 if (!newip4 && !newip6)
1089 return DNS_UPD_NO_IP_FOUND;
1090
1091 /* Case when the caller looks first for an IPv4 address */
1092 if (family_priority == AF_INET) {
1093 if (newip4) {
1094 *newip = newip4;
1095 *newip_sin_family = AF_INET;
1096 }
1097 else if (newip6) {
1098 *newip = newip6;
1099 *newip_sin_family = AF_INET6;
1100 }
1101 if (!currentip_found)
1102 goto not_found;
1103 }
1104 /* Case when the caller looks first for an IPv6 address */
1105 else if (family_priority == AF_INET6) {
1106 if (newip6) {
1107 *newip = newip6;
1108 *newip_sin_family = AF_INET6;
1109 }
1110 else if (newip4) {
1111 *newip = newip4;
1112 *newip_sin_family = AF_INET;
1113 }
1114 if (!currentip_found)
1115 goto not_found;
1116 }
1117 /* Case when the caller have no preference (we prefer IPv6) */
1118 else if (family_priority == AF_UNSPEC) {
1119 if (newip6) {
1120 *newip = newip6;
1121 *newip_sin_family = AF_INET6;
1122 }
1123 else if (newip4) {
1124 *newip = newip4;
1125 *newip_sin_family = AF_INET;
1126 }
1127 if (!currentip_found)
1128 goto not_found;
1129 }
1130
1131 /* No reason why we should change the server's IP address */
1132 return DNS_UPD_NO;
1133
1134 not_found:
1135 list_for_each_entry(record, &dns_p->answer_list, list) {
1136 /* Move the first record to the end of the list, for internal
1137 * round robin */
1138 LIST_DEL(&record->list);
1139 LIST_ADDQ(&dns_p->answer_list, &record->list);
1140 break;
1141 }
1142 return DNS_UPD_SRVIP_NOT_FOUND;
1143 }
1144
1145 /* Turns a domain name label into a string.
1146 *
1147 * <dn> must be a null-terminated string. <dn_len> must include the terminating
1148 * null byte. <str> must be allocated and its size must be passed in <str_len>.
1149 *
1150 * In case of error, -1 is returned, otherwise, the number of bytes copied in
1151 * <str> (including the terminating null byte).
1152 */
dns_dn_label_to_str(const char * dn,int dn_len,char * str,int str_len)1153 int dns_dn_label_to_str(const char *dn, int dn_len, char *str, int str_len)
1154 {
1155 char *ptr;
1156 int i, sz;
1157
1158 if (str_len < dn_len - 1)
1159 return -1;
1160
1161 ptr = str;
1162 for (i = 0; i < dn_len-1; ++i) {
1163 sz = dn[i];
1164 if (i)
1165 *ptr++ = '.';
1166 memcpy(ptr, dn+i+1, sz);
1167 ptr += sz;
1168 i += sz;
1169 }
1170 *ptr++ = '\0';
1171 return (ptr - str);
1172 }
1173
1174 /* Turns a string into domain name label: www.haproxy.org into 3www7haproxy3org
1175 *
1176 * <str> must be a null-terminated string. <str_len> must include the
1177 * terminating null byte. <dn> buffer must be allocated and its size must be
1178 * passed in <dn_len>.
1179 *
1180 * In case of error, -1 is returned, otherwise, the number of bytes copied in
1181 * <dn> (excluding the terminating null byte).
1182 */
dns_str_to_dn_label(const char * str,int str_len,char * dn,int dn_len)1183 int dns_str_to_dn_label(const char *str, int str_len, char *dn, int dn_len)
1184 {
1185 int i, offset;
1186
1187 if (dn_len < str_len + 1)
1188 return -1;
1189
1190 /* First byte of dn will be used to store the length of the first
1191 * label */
1192 offset = 0;
1193 for (i = 0; i < str_len; ++i) {
1194 if (str[i] == '.') {
1195 /* 2 or more consecutive dots is invalid */
1196 if (i == offset)
1197 return -1;
1198
1199 /* ignore trailing dot */
1200 if (i + 2 == str_len) {
1201 i++;
1202 break;
1203 }
1204
1205 dn[offset] = (i - offset);
1206 offset = i+1;
1207 continue;
1208 }
1209 dn[i+1] = str[i];
1210 }
1211 dn[offset] = (i - offset - 1);
1212 dn[i] = '\0';
1213 return i;
1214 }
1215
1216 /* Validates host name:
1217 * - total size
1218 * - each label size individually
1219 * returns:
1220 * 0 in case of error. If <err> is not NULL, an error message is stored there.
1221 * 1 when no error. <err> is left unaffected.
1222 */
dns_hostname_validation(const char * string,char ** err)1223 int dns_hostname_validation(const char *string, char **err)
1224 {
1225 int i;
1226
1227 if (strlen(string) > DNS_MAX_NAME_SIZE) {
1228 if (err)
1229 *err = DNS_TOO_LONG_FQDN;
1230 return 0;
1231 }
1232
1233 while (*string) {
1234 i = 0;
1235 while (*string && *string != '.' && i < DNS_MAX_LABEL_SIZE) {
1236 if (!(*string == '-' || *string == '_' ||
1237 (*string >= 'a' && *string <= 'z') ||
1238 (*string >= 'A' && *string <= 'Z') ||
1239 (*string >= '0' && *string <= '9'))) {
1240 if (err)
1241 *err = DNS_INVALID_CHARACTER;
1242 return 0;
1243 }
1244 i++;
1245 string++;
1246 }
1247
1248 if (!(*string))
1249 break;
1250
1251 if (*string != '.' && i >= DNS_MAX_LABEL_SIZE) {
1252 if (err)
1253 *err = DNS_LABEL_TOO_LONG;
1254 return 0;
1255 }
1256
1257 string++;
1258 }
1259 return 1;
1260 }
1261
1262 /* Picks up an available resolution from the different resolution list
1263 * associated to a resolvers section, in this order:
1264 * 1. check in resolutions.curr for the same hostname and query_type
1265 * 2. check in resolutions.wait for the same hostname and query_type
1266 * 3. Get a new resolution from resolution pool
1267 *
1268 * Returns an available resolution, NULL if none found.
1269 */
dns_pick_resolution(struct dns_resolvers * resolvers,char ** hostname_dn,int hostname_dn_len,int query_type)1270 static struct dns_resolution *dns_pick_resolution(struct dns_resolvers *resolvers,
1271 char **hostname_dn, int hostname_dn_len,
1272 int query_type)
1273 {
1274 struct dns_resolution *res;
1275
1276 if (!*hostname_dn)
1277 goto from_pool;
1278
1279 /* Search for same hostname and query type in resolutions.curr */
1280 list_for_each_entry(res, &resolvers->resolutions.curr, list) {
1281 if (!res->hostname_dn)
1282 continue;
1283 if ((query_type == res->prefered_query_type) &&
1284 hostname_dn_len == res->hostname_dn_len &&
1285 !memcmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
1286 return res;
1287 }
1288
1289 /* Search for same hostname and query type in resolutions.wait */
1290 list_for_each_entry(res, &resolvers->resolutions.wait, list) {
1291 if (!res->hostname_dn)
1292 continue;
1293 if ((query_type == res->prefered_query_type) &&
1294 hostname_dn_len == res->hostname_dn_len &&
1295 !memcmp(*hostname_dn, res->hostname_dn, hostname_dn_len))
1296 return res;
1297 }
1298
1299 from_pool:
1300 /* No resolution could be found, so let's allocate a new one */
1301 res = pool_alloc(dns_resolution_pool);
1302 if (res) {
1303 memset(res, 0, sizeof(*res));
1304 res->resolvers = resolvers;
1305 res->uuid = resolution_uuid;
1306 res->status = RSLV_STATUS_NONE;
1307 res->step = RSLV_STEP_NONE;
1308 res->last_valid = now_ms;
1309
1310 LIST_INIT(&res->requesters);
1311 LIST_INIT(&res->response.answer_list);
1312
1313 res->prefered_query_type = query_type;
1314 res->query_type = query_type;
1315 res->hostname_dn = *hostname_dn;
1316 res->hostname_dn_len = hostname_dn_len;
1317
1318 ++resolution_uuid;
1319
1320 /* Move the resolution to the resolvers wait queue */
1321 LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
1322 }
1323 return res;
1324 }
1325
1326 /* Releases a resolution from its requester(s) and move it back to the pool */
dns_free_resolution(struct dns_resolution * resolution)1327 static void dns_free_resolution(struct dns_resolution *resolution)
1328 {
1329 struct dns_requester *req, *reqback;
1330 struct dns_answer_item *item, *itemback;
1331
1332 /* clean up configuration */
1333 dns_reset_resolution(resolution);
1334 resolution->hostname_dn = NULL;
1335 resolution->hostname_dn_len = 0;
1336
1337 list_for_each_entry_safe(req, reqback, &resolution->requesters, list) {
1338 LIST_DEL(&req->list);
1339 req->resolution = NULL;
1340 }
1341
1342 list_for_each_entry_safe(item, itemback, &resolution->response.answer_list, list) {
1343 LIST_DEL(&item->list);
1344 pool_free(dns_answer_item_pool, item);
1345 }
1346
1347 LIST_DEL(&resolution->list);
1348 pool_free(dns_resolution_pool, resolution);
1349 }
1350
1351 /* Links a requester (a server or a dns_srvrq) with a resolution. It returns 0
1352 * on success, -1 otherwise.
1353 */
dns_link_resolution(void * requester,int requester_type,int requester_locked)1354 int dns_link_resolution(void *requester, int requester_type, int requester_locked)
1355 {
1356 struct dns_resolution *res = NULL;
1357 struct dns_requester *req;
1358 struct dns_resolvers *resolvers;
1359 struct server *srv = NULL;
1360 struct dns_srvrq *srvrq = NULL;
1361 char **hostname_dn;
1362 int hostname_dn_len, query_type;
1363
1364 switch (requester_type) {
1365 case OBJ_TYPE_SERVER:
1366 srv = (struct server *)requester;
1367 hostname_dn = &srv->hostname_dn;
1368 hostname_dn_len = srv->hostname_dn_len;
1369 resolvers = srv->resolvers;
1370 query_type = ((srv->dns_opts.family_prio == AF_INET)
1371 ? DNS_RTYPE_A
1372 : DNS_RTYPE_AAAA);
1373 break;
1374
1375 case OBJ_TYPE_SRVRQ:
1376 srvrq = (struct dns_srvrq *)requester;
1377 hostname_dn = &srvrq->hostname_dn;
1378 hostname_dn_len = srvrq->hostname_dn_len;
1379 resolvers = srvrq->resolvers;
1380 query_type = DNS_RTYPE_SRV;
1381 break;
1382
1383 default:
1384 goto err;
1385 }
1386
1387 /* Get a resolution from the resolvers' wait queue or pool */
1388 if ((res = dns_pick_resolution(resolvers, hostname_dn, hostname_dn_len, query_type)) == NULL)
1389 goto err;
1390
1391 if (srv) {
1392 if (!requester_locked)
1393 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
1394 if (srv->dns_requester == NULL) {
1395 if ((req = calloc(1, sizeof(*req))) == NULL) {
1396 if (!requester_locked)
1397 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
1398 goto err;
1399 }
1400 req->owner = &srv->obj_type;
1401 srv->dns_requester = req;
1402 }
1403 else
1404 req = srv->dns_requester;
1405 if (!requester_locked)
1406 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
1407 }
1408 else if (srvrq) {
1409 if (srvrq->dns_requester == NULL) {
1410 if ((req = calloc(1, sizeof(*req))) == NULL)
1411 goto err;
1412 req->owner = &srvrq->obj_type;
1413 srvrq->dns_requester = req;
1414 }
1415 else
1416 req = srvrq->dns_requester;
1417 }
1418 else
1419 goto err;
1420
1421 req->resolution = res;
1422 req->requester_cb = snr_resolution_cb;
1423 req->requester_error_cb = snr_resolution_error_cb;
1424
1425 LIST_ADDQ(&res->requesters, &req->list);
1426 return 0;
1427
1428 err:
1429 if (res && LIST_ISEMPTY(&res->requesters))
1430 dns_free_resolution(res);
1431 return -1;
1432 }
1433
1434 /* Removes a requester from a DNS resoltion. It takes takes care of all the
1435 * consequences. It also cleans up some parameters from the requester.
1436 */
dns_unlink_resolution(struct dns_requester * requester)1437 void dns_unlink_resolution(struct dns_requester *requester)
1438 {
1439 struct dns_resolution *res;
1440 struct dns_requester *req;
1441
1442 /* Nothing to do */
1443 if (!requester || !requester->resolution)
1444 return;
1445 res = requester->resolution;
1446
1447 /* Clean up the requester */
1448 LIST_DEL(&requester->list);
1449 requester->resolution = NULL;
1450
1451 /* We need to find another requester linked on this resolution */
1452 if (!LIST_ISEMPTY(&res->requesters))
1453 req = LIST_NEXT(&res->requesters, struct dns_requester *, list);
1454 else {
1455 dns_free_resolution(res);
1456 return;
1457 }
1458
1459 /* Move hostname_dn related pointers to the next requester */
1460 switch (obj_type(req->owner)) {
1461 case OBJ_TYPE_SERVER:
1462 res->hostname_dn = __objt_server(req->owner)->hostname_dn;
1463 res->hostname_dn_len = __objt_server(req->owner)->hostname_dn_len;
1464 break;
1465 case OBJ_TYPE_SRVRQ:
1466 res->hostname_dn = __objt_dns_srvrq(req->owner)->hostname_dn;
1467 res->hostname_dn_len = __objt_dns_srvrq(req->owner)->hostname_dn_len;
1468 break;
1469 default:
1470 res->hostname_dn = NULL;
1471 res->hostname_dn_len = 0;
1472 break;
1473 }
1474 }
1475
1476 /* Called when a network IO is generated on a name server socket for an incoming
1477 * packet. It performs the following actions:
1478 * - check if the packet requires processing (not outdated resolution)
1479 * - ensure the DNS packet received is valid and call requester's callback
1480 * - call requester's error callback if invalid response
1481 * - check the dn_name in the packet against the one sent
1482 */
dns_resolve_recv(struct dgram_conn * dgram)1483 static void dns_resolve_recv(struct dgram_conn *dgram)
1484 {
1485 struct dns_nameserver *ns, *tmpns;
1486 struct dns_resolvers *resolvers;
1487 struct dns_resolution *res;
1488 struct dns_query_item *query;
1489 unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
1490 unsigned char *bufend;
1491 int fd, buflen, dns_resp;
1492 int max_answer_records;
1493 unsigned short query_id;
1494 struct eb32_node *eb;
1495 struct dns_requester *req;
1496
1497 fd = dgram->t.sock.fd;
1498
1499 /* check if ready for reading */
1500 if (!fd_recv_ready(fd))
1501 return;
1502
1503 /* no need to go further if we can't retrieve the nameserver */
1504 if ((ns = dgram->owner) == NULL) {
1505 HA_ATOMIC_AND(&fdtab[fd].ev, ~(FD_POLL_HUP|FD_POLL_ERR));
1506 fd_stop_recv(fd);
1507 return;
1508 }
1509
1510 resolvers = ns->resolvers;
1511 HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
1512
1513 /* process all pending input messages */
1514 while (fd_recv_ready(fd)) {
1515 /* read message received */
1516 memset(buf, '\0', resolvers->accepted_payload_size + 1);
1517 if ((buflen = recv(fd, (char*)buf , resolvers->accepted_payload_size + 1, 0)) < 0) {
1518 /* FIXME : for now we consider EAGAIN only, but at
1519 * least we purge sticky errors that would cause us to
1520 * be called in loops.
1521 */
1522 HA_ATOMIC_AND(&fdtab[fd].ev, ~(FD_POLL_HUP|FD_POLL_ERR));
1523 fd_cant_recv(fd);
1524 break;
1525 }
1526
1527 /* message too big */
1528 if (buflen > resolvers->accepted_payload_size) {
1529 ns->counters.too_big++;
1530 continue;
1531 }
1532
1533 /* initializing variables */
1534 bufend = buf + buflen; /* pointer to mark the end of the buffer */
1535
1536 /* read the query id from the packet (16 bits) */
1537 if (buf + 2 > bufend) {
1538 ns->counters.invalid++;
1539 continue;
1540 }
1541 query_id = dns_response_get_query_id(buf);
1542
1543 /* search the query_id in the pending resolution tree */
1544 eb = eb32_lookup(&resolvers->query_ids, query_id);
1545 if (eb == NULL) {
1546 /* unknown query id means an outdated response and can be safely ignored */
1547 ns->counters.outdated++;
1548 continue;
1549 }
1550
1551 /* known query id means a resolution in prgress */
1552 res = eb32_entry(eb, struct dns_resolution, qid);
1553 if (!res) {
1554 ns->counters.outdated++;
1555 continue;
1556 }
1557
1558 /* number of responses received */
1559 res->nb_responses++;
1560
1561 max_answer_records = (resolvers->accepted_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE;
1562 dns_resp = dns_validate_dns_response(buf, bufend, res, max_answer_records);
1563
1564 switch (dns_resp) {
1565 case DNS_RESP_VALID:
1566 break;
1567
1568 case DNS_RESP_INVALID:
1569 case DNS_RESP_QUERY_COUNT_ERROR:
1570 case DNS_RESP_WRONG_NAME:
1571 res->status = RSLV_STATUS_INVALID;
1572 ns->counters.invalid++;
1573 break;
1574
1575 case DNS_RESP_NX_DOMAIN:
1576 res->status = RSLV_STATUS_NX;
1577 ns->counters.nx++;
1578 break;
1579
1580 case DNS_RESP_REFUSED:
1581 res->status = RSLV_STATUS_REFUSED;
1582 ns->counters.refused++;
1583 break;
1584
1585 case DNS_RESP_ANCOUNT_ZERO:
1586 res->status = RSLV_STATUS_OTHER;
1587 ns->counters.any_err++;
1588 break;
1589
1590 case DNS_RESP_CNAME_ERROR:
1591 res->status = RSLV_STATUS_OTHER;
1592 ns->counters.cname_error++;
1593 break;
1594
1595 case DNS_RESP_TRUNCATED:
1596 res->status = RSLV_STATUS_OTHER;
1597 ns->counters.truncated++;
1598 break;
1599
1600 case DNS_RESP_NO_EXPECTED_RECORD:
1601 case DNS_RESP_ERROR:
1602 case DNS_RESP_INTERNAL:
1603 res->status = RSLV_STATUS_OTHER;
1604 ns->counters.other++;
1605 break;
1606 }
1607
1608 /* Wait all nameservers response to handle errors */
1609 if (dns_resp != DNS_RESP_VALID && res->nb_responses < resolvers->nb_nameservers)
1610 continue;
1611
1612 /* Process error codes */
1613 if (dns_resp != DNS_RESP_VALID) {
1614 if (res->prefered_query_type != res->query_type) {
1615 /* The fallback on the query type was already performed,
1616 * so check the try counter. If it falls to 0, we can
1617 * report an error. Else, wait the next attempt. */
1618 if (!res->try)
1619 goto report_res_error;
1620 }
1621 else {
1622 /* Fallback from A to AAAA or the opposite and re-send
1623 * the resolution immediately. try counter is not
1624 * decremented. */
1625 if (res->prefered_query_type == DNS_RTYPE_A) {
1626 res->query_type = DNS_RTYPE_AAAA;
1627 dns_send_query(res);
1628 }
1629 else if (res->prefered_query_type == DNS_RTYPE_AAAA) {
1630 res->query_type = DNS_RTYPE_A;
1631 dns_send_query(res);
1632 }
1633 }
1634 continue;
1635 }
1636
1637 /* Now let's check the query's dname corresponds to the one we
1638 * sent. We can check only the first query of the list. We send
1639 * one query at a time so we get one query in the response */
1640 query = LIST_NEXT(&res->response.query_list, struct dns_query_item *, list);
1641 if (query && memcmp(query->name, res->hostname_dn, res->hostname_dn_len) != 0) {
1642 dns_resp = DNS_RESP_WRONG_NAME;
1643 ns->counters.other++;
1644 goto report_res_error;
1645 }
1646
1647 /* So the resolution succeeded */
1648 res->status = RSLV_STATUS_VALID;
1649 res->last_valid = now_ms;
1650 ns->counters.valid++;
1651 goto report_res_success;
1652
1653 report_res_error:
1654 list_for_each_entry(req, &res->requesters, list)
1655 req->requester_error_cb(req, dns_resp);
1656 dns_reset_resolution(res);
1657 LIST_DEL(&res->list);
1658 LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
1659 continue;
1660
1661 report_res_success:
1662 /* Only the 1rst requester s managed by the server, others are
1663 * from the cache */
1664 tmpns = ns;
1665 list_for_each_entry(req, &res->requesters, list) {
1666 struct server *s = objt_server(req->owner);
1667
1668 if (s)
1669 HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
1670 req->requester_cb(req, tmpns);
1671 if (s)
1672 HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
1673 tmpns = NULL;
1674 }
1675
1676 dns_reset_resolution(res);
1677 LIST_DEL(&res->list);
1678 LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
1679 continue;
1680 }
1681 dns_update_resolvers_timeout(resolvers);
1682 HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
1683 }
1684
1685 /* Called when a resolvers network socket is ready to send data */
dns_resolve_send(struct dgram_conn * dgram)1686 static void dns_resolve_send(struct dgram_conn *dgram)
1687 {
1688 struct dns_resolvers *resolvers;
1689 struct dns_nameserver *ns;
1690 struct dns_resolution *res;
1691 int fd;
1692
1693 fd = dgram->t.sock.fd;
1694
1695 /* check if ready for sending */
1696 if (!fd_send_ready(fd))
1697 return;
1698
1699 /* we don't want/need to be waked up any more for sending */
1700 fd_stop_send(fd);
1701
1702 /* no need to go further if we can't retrieve the nameserver */
1703 if ((ns = dgram->owner) == NULL)
1704 return;
1705
1706 resolvers = ns->resolvers;
1707 HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
1708
1709 list_for_each_entry(res, &resolvers->resolutions.curr, list) {
1710 int ret, len;
1711
1712 if (res->nb_queries == resolvers->nb_nameservers)
1713 continue;
1714
1715 len = dns_build_query(res->query_id, res->query_type,
1716 resolvers->accepted_payload_size,
1717 res->hostname_dn, res->hostname_dn_len,
1718 trash.area, trash.size);
1719 if (len == -1)
1720 goto snd_error;
1721
1722 ret = send(fd, trash.area, len, 0);
1723 if (ret != len)
1724 goto snd_error;
1725
1726 ns->counters.sent++;
1727 res->nb_queries++;
1728 continue;
1729
1730 snd_error:
1731 ns->counters.snd_error++;
1732 res->nb_queries++;
1733 }
1734 HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
1735 }
1736
1737 /* Processes DNS resolution. First, it checks the active list to detect expired
1738 * resolutions and retry them if possible. Else a timeout is reported. Then, it
1739 * checks the wait list to trigger new resolutions.
1740 */
dns_process_resolvers(struct task * t,void * context,unsigned short state)1741 static struct task *dns_process_resolvers(struct task *t, void *context, unsigned short state)
1742 {
1743 struct dns_resolvers *resolvers = context;
1744 struct dns_resolution *res, *resback;
1745 int exp;
1746
1747 HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
1748
1749 /* Handle all expired resolutions from the active list */
1750 list_for_each_entry_safe(res, resback, &resolvers->resolutions.curr, list) {
1751 /* When we find the first resolution in the future, then we can
1752 * stop here */
1753 exp = tick_add(res->last_query, resolvers->timeout.retry);
1754 if (!tick_is_expired(exp, now_ms))
1755 break;
1756
1757 /* If current resolution has been tried too many times and
1758 * finishes in timeout we update its status and remove it from
1759 * the list */
1760 if (!res->try) {
1761 struct dns_requester *req;
1762
1763 /* Notify the result to the requesters */
1764 if (!res->nb_responses)
1765 res->status = RSLV_STATUS_TIMEOUT;
1766 list_for_each_entry(req, &res->requesters, list)
1767 req->requester_error_cb(req, res->status);
1768
1769 /* Clean up resolution info and remove it from the
1770 * current list */
1771 dns_reset_resolution(res);
1772 LIST_DEL(&res->list);
1773 LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
1774 }
1775 else {
1776 /* Otherwise resend the DNS query and requeue the resolution */
1777 if (!res->nb_responses || res->prefered_query_type != res->query_type) {
1778 /* No response received (a real timeout) or fallback already done */
1779 res->query_type = res->prefered_query_type;
1780 res->try--;
1781 }
1782 else {
1783 /* Fallback from A to AAAA or the opposite and re-send
1784 * the resolution immediately. try counter is not
1785 * decremented. */
1786 if (res->prefered_query_type == DNS_RTYPE_A)
1787 res->query_type = DNS_RTYPE_AAAA;
1788 else if (res->prefered_query_type == DNS_RTYPE_AAAA)
1789 res->query_type = DNS_RTYPE_A;
1790 else
1791 res->try--;
1792 }
1793 dns_send_query(res);
1794 }
1795 }
1796
1797 /* Handle all resolutions in the wait list */
1798 list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, list) {
1799 exp = tick_add(res->last_resolution, dns_resolution_timeout(res));
1800 if (tick_isset(res->last_resolution) && !tick_is_expired(exp, now_ms))
1801 continue;
1802
1803 if (dns_run_resolution(res) != 1) {
1804 res->last_resolution = now_ms;
1805 LIST_DEL(&res->list);
1806 LIST_ADDQ(&resolvers->resolutions.wait, &res->list);
1807 }
1808 }
1809
1810 dns_update_resolvers_timeout(resolvers);
1811 HA_SPIN_UNLOCK(DNS_LOCK, &resolvers->lock);
1812 return t;
1813 }
1814
1815 /* proto_udp callback functions for a DNS resolution */
1816 struct dgram_data_cb resolve_dgram_cb = {
1817 .recv = dns_resolve_recv,
1818 .send = dns_resolve_send,
1819 };
1820
1821 /* Release memory allocated by DNS */
dns_deinit(void)1822 static void dns_deinit(void)
1823 {
1824 struct dns_resolvers *resolvers, *resolversback;
1825 struct dns_nameserver *ns, *nsback;
1826 struct dns_resolution *res, *resback;
1827 struct dns_requester *req, *reqback;
1828 struct dns_srvrq *srvrq, *srvrqback;
1829
1830 list_for_each_entry_safe(resolvers, resolversback, &dns_resolvers, list) {
1831 list_for_each_entry_safe(ns, nsback, &resolvers->nameservers, list) {
1832 free(ns->id);
1833 free((char *)ns->conf.file);
1834 if (ns->dgram && ns->dgram->t.sock.fd != -1)
1835 fd_delete(ns->dgram->t.sock.fd);
1836 free(ns->dgram);
1837 LIST_DEL(&ns->list);
1838 free(ns);
1839 }
1840
1841 list_for_each_entry_safe(res, resback, &resolvers->resolutions.curr, list) {
1842 list_for_each_entry_safe(req, reqback, &res->requesters, list) {
1843 LIST_DEL(&req->list);
1844 free(req);
1845 }
1846 dns_free_resolution(res);
1847 }
1848
1849 list_for_each_entry_safe(res, resback, &resolvers->resolutions.wait, list) {
1850 list_for_each_entry_safe(req, reqback, &res->requesters, list) {
1851 LIST_DEL(&req->list);
1852 free(req);
1853 }
1854 dns_free_resolution(res);
1855 }
1856
1857 free(resolvers->id);
1858 free((char *)resolvers->conf.file);
1859 task_delete(resolvers->t);
1860 task_free(resolvers->t);
1861 LIST_DEL(&resolvers->list);
1862 free(resolvers);
1863 }
1864
1865 list_for_each_entry_safe(srvrq, srvrqback, &dns_srvrq_list, list) {
1866 free(srvrq->name);
1867 free(srvrq->hostname_dn);
1868 LIST_DEL(&srvrq->list);
1869 free(srvrq);
1870 }
1871 }
1872
1873 /* Finalizes the DNS configuration by allocating required resources and checking
1874 * live parameters.
1875 * Returns 0 on success, ERR_* flags otherwise.
1876 */
dns_finalize_config(void)1877 static int dns_finalize_config(void)
1878 {
1879 struct dns_resolvers *resolvers;
1880 struct proxy *px;
1881 int err_code = 0;
1882
1883 /* allocate pool of resolution per resolvers */
1884 list_for_each_entry(resolvers, &dns_resolvers, list) {
1885 struct dns_nameserver *ns;
1886 struct task *t;
1887
1888 /* Check if we can create the socket with nameservers info */
1889 list_for_each_entry(ns, &resolvers->nameservers, list) {
1890 struct dgram_conn *dgram = NULL;
1891 int fd;
1892
1893 /* Check nameserver info */
1894 if ((fd = socket(ns->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
1895 ha_alert("config : resolvers '%s': can't create socket for nameserver '%s'.\n",
1896 resolvers->id, ns->id);
1897 err_code |= (ERR_ALERT|ERR_ABORT);
1898 continue;
1899 }
1900 if (connect(fd, (struct sockaddr*)&ns->addr, get_addr_len(&ns->addr)) == -1) {
1901 ha_alert("config : resolvers '%s': can't connect socket for nameserver '%s'.\n",
1902 resolvers->id, ns->id);
1903 close(fd);
1904 err_code |= (ERR_ALERT|ERR_ABORT);
1905 continue;
1906 }
1907 close(fd);
1908
1909 /* Create dgram structure that will hold the UPD socket
1910 * and attach it on the current nameserver */
1911 if ((dgram = calloc(1, sizeof(*dgram))) == NULL) {
1912 ha_alert("config: resolvers '%s' : out of memory.\n",
1913 resolvers->id);
1914 err_code |= (ERR_ALERT|ERR_ABORT);
1915 goto err;
1916 }
1917
1918 /* Leave dgram partially initialized, no FD attached for
1919 * now. */
1920 dgram->owner = ns;
1921 dgram->data = &resolve_dgram_cb;
1922 dgram->t.sock.fd = -1;
1923 ns->dgram = dgram;
1924 }
1925
1926 /* Create the task associated to the resolvers section */
1927 if ((t = task_new(MAX_THREADS_MASK)) == NULL) {
1928 ha_alert("config : resolvers '%s' : out of memory.\n", resolvers->id);
1929 err_code |= (ERR_ALERT|ERR_ABORT);
1930 goto err;
1931 }
1932
1933 /* Update task's parameters */
1934 t->process = dns_process_resolvers;
1935 t->context = resolvers;
1936 resolvers->t = t;
1937 task_wakeup(t, TASK_WOKEN_INIT);
1938 }
1939
1940 for (px = proxies_list; px; px = px->next) {
1941 struct server *srv;
1942
1943 for (srv = px->srv; srv; srv = srv->next) {
1944 struct dns_resolvers *resolvers;
1945
1946 if (!srv->resolvers_id)
1947 continue;
1948
1949 if ((resolvers = find_resolvers_by_id(srv->resolvers_id)) == NULL) {
1950 ha_alert("config : %s '%s', server '%s': unable to find required resolvers '%s'\n",
1951 proxy_type_str(px), px->id, srv->id, srv->resolvers_id);
1952 err_code |= (ERR_ALERT|ERR_ABORT);
1953 continue;
1954 }
1955 srv->resolvers = resolvers;
1956
1957 if (srv->srvrq && !srv->srvrq->resolvers) {
1958 srv->srvrq->resolvers = srv->resolvers;
1959 if (dns_link_resolution(srv->srvrq, OBJ_TYPE_SRVRQ, 0) == -1) {
1960 ha_alert("config : %s '%s' : unable to set DNS resolution for server '%s'.\n",
1961 proxy_type_str(px), px->id, srv->id);
1962 err_code |= (ERR_ALERT|ERR_ABORT);
1963 continue;
1964 }
1965 }
1966 if (dns_link_resolution(srv, OBJ_TYPE_SERVER, 0) == -1) {
1967 ha_alert("config : %s '%s', unable to set DNS resolution for server '%s'.\n",
1968 proxy_type_str(px), px->id, srv->id);
1969 err_code |= (ERR_ALERT|ERR_ABORT);
1970 continue;
1971 }
1972 }
1973 }
1974
1975 if (err_code & (ERR_ALERT|ERR_ABORT))
1976 goto err;
1977
1978 return err_code;
1979 err:
1980 dns_deinit();
1981 return err_code;
1982
1983 }
1984
1985 /* if an arg is found, it sets the resolvers section pointer into cli.p0 */
cli_parse_stat_resolvers(char ** args,char * payload,struct appctx * appctx,void * private)1986 static int cli_parse_stat_resolvers(char **args, char *payload, struct appctx *appctx, void *private)
1987 {
1988 struct dns_resolvers *presolvers;
1989
1990 if (*args[2]) {
1991 list_for_each_entry(presolvers, &dns_resolvers, list) {
1992 if (strcmp(presolvers->id, args[2]) == 0) {
1993 appctx->ctx.cli.p0 = presolvers;
1994 break;
1995 }
1996 }
1997 if (appctx->ctx.cli.p0 == NULL) {
1998 appctx->ctx.cli.severity = LOG_ERR;
1999 appctx->ctx.cli.msg = "Can't find that resolvers section\n";
2000 appctx->st0 = CLI_ST_PRINT;
2001 return 1;
2002 }
2003 }
2004 return 0;
2005 }
2006
2007 /* Dumps counters from all resolvers section and associated name servers. It
2008 * returns 0 if the output buffer is full and it needs to be called again,
2009 * otherwise non-zero. It may limit itself to the resolver pointed to by
2010 * <cli.p0> if it's not null.
2011 */
cli_io_handler_dump_resolvers_to_buffer(struct appctx * appctx)2012 static int cli_io_handler_dump_resolvers_to_buffer(struct appctx *appctx)
2013 {
2014 struct stream_interface *si = appctx->owner;
2015 struct dns_resolvers *resolvers;
2016 struct dns_nameserver *ns;
2017
2018 chunk_reset(&trash);
2019
2020 switch (appctx->st2) {
2021 case STAT_ST_INIT:
2022 appctx->st2 = STAT_ST_LIST; /* let's start producing data */
2023 /* fall through */
2024
2025 case STAT_ST_LIST:
2026 if (LIST_ISEMPTY(&dns_resolvers)) {
2027 chunk_appendf(&trash, "No resolvers found\n");
2028 }
2029 else {
2030 list_for_each_entry(resolvers, &dns_resolvers, list) {
2031 if (appctx->ctx.cli.p0 != NULL && appctx->ctx.cli.p0 != resolvers)
2032 continue;
2033
2034 chunk_appendf(&trash, "Resolvers section %s\n", resolvers->id);
2035 list_for_each_entry(ns, &resolvers->nameservers, list) {
2036 chunk_appendf(&trash, " nameserver %s:\n", ns->id);
2037 chunk_appendf(&trash, " sent: %lld\n", ns->counters.sent);
2038 chunk_appendf(&trash, " snd_error: %lld\n", ns->counters.snd_error);
2039 chunk_appendf(&trash, " valid: %lld\n", ns->counters.valid);
2040 chunk_appendf(&trash, " update: %lld\n", ns->counters.update);
2041 chunk_appendf(&trash, " cname: %lld\n", ns->counters.cname);
2042 chunk_appendf(&trash, " cname_error: %lld\n", ns->counters.cname_error);
2043 chunk_appendf(&trash, " any_err: %lld\n", ns->counters.any_err);
2044 chunk_appendf(&trash, " nx: %lld\n", ns->counters.nx);
2045 chunk_appendf(&trash, " timeout: %lld\n", ns->counters.timeout);
2046 chunk_appendf(&trash, " refused: %lld\n", ns->counters.refused);
2047 chunk_appendf(&trash, " other: %lld\n", ns->counters.other);
2048 chunk_appendf(&trash, " invalid: %lld\n", ns->counters.invalid);
2049 chunk_appendf(&trash, " too_big: %lld\n", ns->counters.too_big);
2050 chunk_appendf(&trash, " truncated: %lld\n", ns->counters.truncated);
2051 chunk_appendf(&trash, " outdated: %lld\n", ns->counters.outdated);
2052 }
2053 chunk_appendf(&trash, "\n");
2054 }
2055 }
2056
2057 /* display response */
2058 if (ci_putchk(si_ic(si), &trash) == -1) {
2059 /* let's try again later from this session. We add ourselves into
2060 * this session's users so that it can remove us upon termination.
2061 */
2062 si_rx_room_blk(si);
2063 return 0;
2064 }
2065 /* fall through */
2066
2067 default:
2068 appctx->st2 = STAT_ST_FIN;
2069 return 1;
2070 }
2071 }
2072
2073 /* register cli keywords */
2074 static struct cli_kw_list cli_kws = {{ }, {
2075 { { "show", "resolvers", NULL }, "show resolvers [id]: dumps counters from all resolvers section and\n"
2076 " associated name servers",
2077 cli_parse_stat_resolvers, cli_io_handler_dump_resolvers_to_buffer },
2078 {{},}
2079 }
2080 };
2081
2082 INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
2083
2084 REGISTER_POST_DEINIT(dns_deinit);
2085 REGISTER_CONFIG_POSTPARSER("dns runtime resolver", dns_finalize_config);
2086