blob: dcdc163100ec22ed7ea1e05314f4050584b88d8f [file] [log] [blame]
Baptiste Assmann325137d2015-04-13 23:40:55 +02001/*
2 * Name server resolution
3 *
Emeric Brunc9437992021-02-12 19:42:55 +01004 * Copyright 2020 Haproxy Technologies
Baptiste Assmann325137d2015-04-13 23:40:55 +02005 *
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
Willy Tarreau122eba92020-06-04 10:15:32 +020022#include <haproxy/action.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020023#include <haproxy/api.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020025#include <haproxy/channel.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020026#include <haproxy/check.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020027#include <haproxy/cli.h>
Willy Tarreau7c18b542020-06-11 09:23:02 +020028#include <haproxy/dgram.h>
Willy Tarreaueb92deb2020-06-04 10:53:16 +020029#include <haproxy/dns.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020030#include <haproxy/errors.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020031#include <haproxy/fd.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020032#include <haproxy/log.h>
Emeric Brund26a6232021-01-04 13:32:20 +010033#include <haproxy/ring.h>
Emeric Brunfd647d52021-02-12 20:03:38 +010034#include <haproxy/stream.h>
35#include <haproxy/stream_interface.h>
Baptiste Assmann325137d2015-04-13 23:40:55 +020036
Emeric Brund26a6232021-01-04 13:32:20 +010037static THREAD_LOCAL char *dns_msg_trash;
Baptiste Assmann325137d2015-04-13 23:40:55 +020038
Emeric Brunfd647d52021-02-12 20:03:38 +010039DECLARE_STATIC_POOL(dns_session_pool, "dns_session", sizeof(struct dns_session));
40DECLARE_STATIC_POOL(dns_query_pool, "dns_query", sizeof(struct dns_query));
41DECLARE_STATIC_POOL(dns_msg_buf, "dns_msg_buf", DNS_TCP_MSG_RING_MAX_SIZE);
42
Christopher Faulet67957bd2017-09-27 11:00:59 +020043/* Opens an UDP socket on the namesaver's IP/Port, if required. Returns 0 on
44 * success, -1 otherwise.
Baptiste Assmann325137d2015-04-13 23:40:55 +020045 */
Emeric Brund26a6232021-01-04 13:32:20 +010046static int dns_connect_nameserver(struct dns_nameserver *ns)
Baptiste Assmann325137d2015-04-13 23:40:55 +020047{
Emeric Brund26a6232021-01-04 13:32:20 +010048 if (ns->dgram) {
49 struct dgram_conn *dgram = &ns->dgram->conn;
50 int fd;
Baptiste Assmann325137d2015-04-13 23:40:55 +020051
Emeric Brund26a6232021-01-04 13:32:20 +010052 /* Already connected */
53 if (dgram->t.sock.fd != -1)
54 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +020055
Emeric Brund26a6232021-01-04 13:32:20 +010056 /* Create an UDP socket and connect it on the nameserver's IP/Port */
57 if ((fd = socket(dgram->addr.to.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
58 send_log(NULL, LOG_WARNING,
Emeric Brunc9437992021-02-12 19:42:55 +010059 "DNS : section '%s': can't create socket for nameserver '%s'.\n",
Emeric Brund26a6232021-01-04 13:32:20 +010060 ns->counters->pid, ns->id);
61 return -1;
62 }
63 if (connect(fd, (struct sockaddr*)&dgram->addr.to, get_addr_len(&dgram->addr.to)) == -1) {
64 send_log(NULL, LOG_WARNING,
Emeric Brunc9437992021-02-12 19:42:55 +010065 "DNS : section '%s': can't connect socket for nameserver '%s'.\n",
Emeric Brund26a6232021-01-04 13:32:20 +010066 ns->counters->id, ns->id);
Emeric Brunc9437992021-02-12 19:42:55 +010067 close(fd);
Emeric Brund26a6232021-01-04 13:32:20 +010068 return -1;
69 }
Baptiste Assmann325137d2015-04-13 23:40:55 +020070
Emeric Brund26a6232021-01-04 13:32:20 +010071 /* Make the socket non blocking */
72 fcntl(fd, F_SETFL, O_NONBLOCK);
Olivier Houcharda8c6db82017-07-06 18:46:47 +020073
Emeric Brund26a6232021-01-04 13:32:20 +010074 /* Add the fd in the fd list and update its parameters */
75 dgram->t.sock.fd = fd;
76 fd_insert(fd, dgram, dgram_fd_handler, MAX_THREADS_MASK);
77 fd_want_recv(fd);
Emeric Brun526b7922021-02-15 14:28:27 +010078 return 0;
Emeric Brunc9437992021-02-12 19:42:55 +010079 }
Emeric Brun526b7922021-02-15 14:28:27 +010080
81 return -1;
Baptiste Assmann325137d2015-04-13 23:40:55 +020082}
83
Emeric Brund26a6232021-01-04 13:32:20 +010084/* Sends a message to a name server
85 * It returns message length on success
86 * or -1 in error case
87 * 0 is returned in case of output ring buffer is full
88 */
89int dns_send_nameserver(struct dns_nameserver *ns, void *buf, size_t len)
90{
91 int ret = -1;
92
93 if (ns->dgram) {
94 struct dgram_conn *dgram = &ns->dgram->conn;
95 int fd = dgram->t.sock.fd;
96
97 if (dgram->t.sock.fd == -1) {
98 if (dns_connect_nameserver(ns) == -1)
99 return -1;
100 fd = dgram->t.sock.fd;
101 }
102
103 ret = send(fd, buf, len, 0);
104 if (ret < 0) {
105 if (errno == EAGAIN) {
106 struct ist myist;
107
Tim Duesterhus92c696e2021-02-28 16:11:36 +0100108 myist = ist2(buf, len);
Emeric Brund26a6232021-01-04 13:32:20 +0100109 ret = ring_write(ns->dgram->ring_req, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
110 if (!ret) {
111 ns->counters->snd_error++;
112 return -1;
113 }
114 fd_cant_send(fd);
115 return ret;
116 }
117 ns->counters->snd_error++;
118 fd_delete(fd);
Emeric Brund26a6232021-01-04 13:32:20 +0100119 dgram->t.sock.fd = -1;
120 return -1;
121 }
122 ns->counters->sent++;
123 }
Emeric Brunfd647d52021-02-12 20:03:38 +0100124 else if (ns->stream) {
125 struct ist myist;
126
Tim Duesterhus92c696e2021-02-28 16:11:36 +0100127 myist = ist2(buf, len);
Emeric Brunfd647d52021-02-12 20:03:38 +0100128 ret = ring_write(ns->stream->ring_req, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
129 if (!ret) {
130 ns->counters->snd_error++;
131 return -1;
132 }
133 task_wakeup(ns->stream->task_req, TASK_WOKEN_MSG);
134 return ret;
135 }
Emeric Brund26a6232021-01-04 13:32:20 +0100136
137 return ret;
138}
139
Emeric Brunfd647d52021-02-12 20:03:38 +0100140void dns_session_free(struct dns_session *);
141
Emeric Brund26a6232021-01-04 13:32:20 +0100142/* Receives a dns message
143 * Returns message length
144 * 0 is returned if no more message available
145 * -1 in error case
146 */
147ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t size)
148{
149 ssize_t ret = -1;
150
151 if (ns->dgram) {
152 struct dgram_conn *dgram = &ns->dgram->conn;
153 int fd = dgram->t.sock.fd;
154
155 if (fd == -1)
156 return -1;
157
158 if ((ret = recv(fd, data, size, 0)) < 0) {
159 if (errno == EAGAIN) {
160 fd_cant_recv(fd);
161 return 0;
162 }
163 fd_delete(fd);
Emeric Brund26a6232021-01-04 13:32:20 +0100164 dgram->t.sock.fd = -1;
165 return -1;
166 }
167 }
Emeric Brunfd647d52021-02-12 20:03:38 +0100168 else if (ns->stream) {
169 struct dns_stream_server *dss = ns->stream;
170 struct dns_session *ds;
171
172 HA_SPIN_LOCK(DNS_LOCK, &dss->lock);
173
174 if (!LIST_ISEMPTY(&dss->wait_sess)) {
175 ds = LIST_NEXT(&dss->wait_sess, struct dns_session *, waiter);
176 fprintf(stderr, "ds: %p\n", ds);
177 ret = ds->rx_msg.len < size ? ds->rx_msg.len : size;
178 memcpy(data, ds->rx_msg.area, ret);
179
180 ds->rx_msg.len = 0;
181
182 /* This barrier is here to ensure that all data is
183 * stored if the appctx detect the elem is out of the list */
184 __ha_barrier_store();
185
186 LIST_DEL_INIT(&ds->waiter);
187
188 if (ds->appctx) {
189 /* This second barrier is here to ensure that
190 * the waked up appctx won't miss that the
191 * elem is removed from the list */
192 __ha_barrier_store();
193
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +0500194 /* awake appctx because it may have other
Emeric Brunfd647d52021-02-12 20:03:38 +0100195 * message to receive
196 */
197 appctx_wakeup(ds->appctx);
198
199 /* dns_session could already be into free_sess list
200 * so we firstly remove it */
201 LIST_DEL_INIT(&ds->list);
202
203 /* decrease nb_queries to free a slot for a new query on that sess */
204 ds->nb_queries--;
205 if (ds->nb_queries) {
206 /* it remains pipelined unanswered request
207 * into this session but we just decrease
208 * the counter so the session
209 * can not be full of pipelined requests
210 * so we can add if to free_sess list
211 * to receive a new request
212 */
213 LIST_ADD(&ds->dss->free_sess, &ds->list);
214 }
215 else {
216 /* there is no more pipelined requests
217 * into this session, so we move it
218 * to idle_sess list */
219 LIST_ADD(&ds->dss->idle_sess, &ds->list);
220
221 /* update the counter of idle sessions */
222 ds->dss->idle_conns++;
223
224 /* Note: this is useless there to update
225 * the max_active_conns since we increase
226 * the idle count */
227 }
228 }
229 else {
230 /* there is no more appctx for this session
231 * it means it is ready to die
232 */
233 dns_session_free(ds);
234 }
235
236
237 }
238
239 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
240 }
Emeric Brund26a6232021-01-04 13:32:20 +0100241
242 return ret;
243}
244
245static void dns_resolve_recv(struct dgram_conn *dgram)
246{
247 struct dns_nameserver *ns;
248 int fd;
249
250 fd = dgram->t.sock.fd;
251
252 /* check if ready for reading */
253 if (!fd_recv_ready(fd))
254 return;
255
256 /* no need to go further if we can't retrieve the nameserver */
257 if ((ns = dgram->owner) == NULL) {
258 _HA_ATOMIC_AND(&fdtab[fd].ev, ~(FD_POLL_HUP|FD_POLL_ERR));
259 fd_stop_recv(fd);
260 return;
261 }
262
263 ns->process_responses(ns);
264}
265
266/* Called when a dns network socket is ready to send data */
267static void dns_resolve_send(struct dgram_conn *dgram)
268{
269 int fd;
270 struct dns_nameserver *ns;
271 struct ring *ring;
272 struct buffer *buf;
273 uint64_t msg_len;
274 size_t len, cnt, ofs;
275
276 fd = dgram->t.sock.fd;
277
278 /* check if ready for sending */
279 if (!fd_send_ready(fd))
280 return;
281
282 /* no need to go further if we can't retrieve the nameserver */
283 if ((ns = dgram->owner) == NULL) {
284 _HA_ATOMIC_AND(&fdtab[fd].ev, ~(FD_POLL_HUP|FD_POLL_ERR));
285 fd_stop_send(fd);
286 return;
287 }
288
289 ring = ns->dgram->ring_req;
290 buf = &ring->buf;
291
292 HA_RWLOCK_RDLOCK(DNS_LOCK, &ring->lock);
293 ofs = ns->dgram->ofs_req;
294
295 /* explanation for the initialization below: it would be better to do
296 * this in the parsing function but this would occasionally result in
297 * dropped events because we'd take a reference on the oldest message
298 * and keep it while being scheduled. Thus instead let's take it the
299 * first time we enter here so that we have a chance to pass many
300 * existing messages before grabbing a reference to a location. This
301 * value cannot be produced after initialization.
302 */
303 if (unlikely(ofs == ~0)) {
304 ofs = 0;
305 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
306 ofs += ring->ofs;
307 }
308
309 /* we were already there, adjust the offset to be relative to
310 * the buffer's head and remove us from the counter.
311 */
312 ofs -= ring->ofs;
313 BUG_ON(ofs >= buf->size);
314 HA_ATOMIC_SUB(b_peek(buf, ofs), 1);
315
316 while (ofs + 1 < b_data(buf)) {
317 int ret;
318
319 cnt = 1;
320 len = b_peek_varint(buf, ofs + cnt, &msg_len);
321 if (!len)
322 break;
323 cnt += len;
324 BUG_ON(msg_len + ofs + cnt + 1 > b_data(buf));
325 if (unlikely(msg_len > DNS_TCP_MSG_MAX_SIZE)) {
326 /* too large a message to ever fit, let's skip it */
327 ofs += cnt + msg_len;
328 continue;
329 }
330
331 len = b_getblk(buf, dns_msg_trash, msg_len, ofs + cnt);
332
333 ret = send(fd, dns_msg_trash, len, 0);
334 if (ret < 0) {
335 if (errno == EAGAIN) {
336 fd_cant_send(fd);
337 goto out;
338 }
339 ns->counters->snd_error++;
340 fd_delete(fd);
Emeric Brund26a6232021-01-04 13:32:20 +0100341 fd = dgram->t.sock.fd = -1;
342 goto out;
343 }
344 ns->counters->sent++;
345
346 ofs += cnt + len;
347 }
348
349 /* we don't want/need to be waked up any more for sending
350 * because all ring content is sent */
351 fd_stop_send(fd);
352
353out:
354
355 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
356 ofs += ring->ofs;
357 ns->dgram->ofs_req = ofs;
358 HA_RWLOCK_RDUNLOCK(DNS_LOCK, &ring->lock);
359
360}
361
Emeric Brunc9437992021-02-12 19:42:55 +0100362/* proto_udp callback functions for a DNS resolution */
363struct dgram_data_cb dns_dgram_cb = {
364 .recv = dns_resolve_recv,
365 .send = dns_resolve_send,
366};
Baptiste Assmann325137d2015-04-13 23:40:55 +0200367
Emeric Brunc9437992021-02-12 19:42:55 +0100368int dns_dgram_init(struct dns_nameserver *ns, struct sockaddr_storage *sk)
Baptiste Assmann325137d2015-04-13 23:40:55 +0200369{
Emeric Brunc9437992021-02-12 19:42:55 +0100370 struct dns_dgram_server *dgram;
Baptiste Assmann201c07f2017-05-22 15:17:15 +0200371
Emeric Brunc9437992021-02-12 19:42:55 +0100372 if ((dgram = calloc(1, sizeof(*dgram))) == NULL)
Christopher Faulet67957bd2017-09-27 11:00:59 +0200373 return -1;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200374
Emeric Brunc9437992021-02-12 19:42:55 +0100375 /* Leave dgram partially initialized, no FD attached for
376 * now. */
377 dgram->conn.owner = ns;
378 dgram->conn.data = &dns_dgram_cb;
379 dgram->conn.t.sock.fd = -1;
380 dgram->conn.addr.to = *sk;
381 ns->dgram = dgram;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200382
Emeric Brunc9437992021-02-12 19:42:55 +0100383 dgram->ofs_req = ~0; /* init ring offset */
384 dgram->ring_req = ring_new(2*DNS_TCP_MSG_RING_MAX_SIZE);
385 if (!dgram->ring_req) {
386 ha_alert("memory allocation error initializing the ring for nameserver.\n");
387 goto out;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200388 }
389
Emeric Brunc9437992021-02-12 19:42:55 +0100390 /* attach the task as reader */
391 if (!ring_attach(dgram->ring_req)) {
392 /* mark server attached to the ring */
393 ha_alert("nameserver sets too many watchers > 255 on ring. This is a bug and should not happen.\n");
394 goto out;
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200395 }
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +0200396 return 0;
Emeric Brunc9437992021-02-12 19:42:55 +0100397out:
398 if (dgram->ring_req)
399 ring_free(dgram->ring_req);
Christopher Fauletd6c6b5f2020-09-08 10:27:24 +0200400
Emeric Brunc9437992021-02-12 19:42:55 +0100401 free(dgram);
Olivier Houchard2ec2db92018-01-08 16:28:57 +0100402
Emeric Brunfd647d52021-02-12 20:03:38 +0100403 return -1;
404}
405
406/*
407 * IO Handler to handle message push to dns tcp server
408 */
409static void dns_session_io_handler(struct appctx *appctx)
410{
411 struct stream_interface *si = appctx->owner;
412 struct dns_session *ds = appctx->ctx.sft.ptr;
413 struct ring *ring = &ds->ring;
414 struct buffer *buf = &ring->buf;
415 uint64_t msg_len;
416 int available_room;
417 size_t len, cnt, ofs;
418 int ret = 0;
419
420 /* if stopping was requested, close immediately */
421 if (unlikely(stopping))
422 goto close;
423
424 /* we want to be sure to not miss that we have been awaked for a shutdown */
425 __ha_barrier_load();
426
427 /* that means the connection was requested to shutdown
428 * for instance idle expire */
429 if (ds->shutdown)
430 goto close;
431
432 /* an error was detected */
433 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
434 goto close;
435
436 /* con closed by server side, we will skip data write and drain data from channel */
437 if ((si_oc(si)->flags & CF_SHUTW)) {
438 goto read;
439 }
440
441 /* if the connection is not established, inform the stream that we want
442 * to be notified whenever the connection completes.
443 */
444 if (si_opposite(si)->state < SI_ST_EST) {
445 si_cant_get(si);
446 si_rx_conn_blk(si);
447 si_rx_endp_more(si);
448 return;
449 }
450
451
452 ofs = ds->ofs;
453
454 HA_RWLOCK_WRLOCK(DNS_LOCK, &ring->lock);
455 LIST_DEL_INIT(&appctx->wait_entry);
456 HA_RWLOCK_WRUNLOCK(DNS_LOCK, &ring->lock);
457
458 HA_RWLOCK_RDLOCK(DNS_LOCK, &ring->lock);
459
460 /* explanation for the initialization below: it would be better to do
461 * this in the parsing function but this would occasionally result in
462 * dropped events because we'd take a reference on the oldest message
463 * and keep it while being scheduled. Thus instead let's take it the
464 * first time we enter here so that we have a chance to pass many
465 * existing messages before grabbing a reference to a location. This
466 * value cannot be produced after initialization.
467 */
468 if (unlikely(ofs == ~0)) {
469 ofs = 0;
470
471 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
472 ofs += ring->ofs;
473 }
474
475 /* in this loop, ofs always points to the counter byte that precedes
476 * the message so that we can take our reference there if we have to
477 * stop before the end (ret=0).
478 */
479 if (si_opposite(si)->state == SI_ST_EST) {
480 /* we were already there, adjust the offset to be relative to
481 * the buffer's head and remove us from the counter.
482 */
483 ofs -= ring->ofs;
484 BUG_ON(ofs >= buf->size);
485 HA_ATOMIC_SUB(b_peek(buf, ofs), 1);
486
487 ret = 1;
488 while (ofs + 1 < b_data(buf)) {
489 struct dns_query *query;
490 uint16_t original_qid;
491 uint16_t new_qid;
492
493 cnt = 1;
494 len = b_peek_varint(buf, ofs + cnt, &msg_len);
495 if (!len)
496 break;
497 cnt += len;
498 BUG_ON(msg_len + ofs + cnt + 1 > b_data(buf));
499
500 /* retrieve available room on output channel */
501 available_room = channel_recv_max(si_ic(si));
502
503 /* tx_msg_offset null means we are at the start of a new message */
504 if (!ds->tx_msg_offset) {
505 uint16_t slen;
506
507 /* check if there is enough room to put message len and query id */
508 if (available_room < sizeof(slen) + sizeof(new_qid)) {
509 si_rx_room_blk(si);
510 ret = 0;
511 break;
512 }
513
514 /* put msg len into then channel */
515 slen = (uint16_t)msg_len;
516 slen = htons(slen);
517 ci_putblk(si_ic(si), (char *)&slen, sizeof(slen));
518 available_room -= sizeof(slen);
519
520 /* backup original query id */
521 len = b_getblk(buf, (char *)&original_qid, sizeof(original_qid), ofs + cnt);
Emeric Brun538bb042021-02-15 13:58:06 +0100522 if (!len) {
523 /* should never happen since messages are atomically
524 * written into ring
525 */
526 ret = 0;
527 break;
528 }
Emeric Brunfd647d52021-02-12 20:03:38 +0100529
530 /* generates new query id */
531 new_qid = ++ds->query_counter;
532 new_qid = htons(new_qid);
533
534 /* put new query id into the channel */
535 ci_putblk(si_ic(si), (char *)&new_qid, sizeof(new_qid));
536 available_room -= sizeof(new_qid);
537
538 /* keep query id mapping */
539
540 query = pool_alloc(dns_query_pool);
541 if (query) {
542 query->qid.key = new_qid;
543 query->original_qid = original_qid;
544 query->expire = tick_add(now_ms, 5000);
545 LIST_INIT(&query->list);
546 if (LIST_ISEMPTY(&ds->queries)) {
547 /* enable task to handle expire */
548 ds->task_exp->expire = query->expire;
549 /* ensure this will be executed by the same
550 * thread than ds_session_release
551 * to ensure session_release is free
552 * to destroy the task */
553 task_queue(ds->task_exp);
554 }
555 LIST_ADDQ(&ds->queries, &query->list);
556 eb32_insert(&ds->query_ids, &query->qid);
557 ds->onfly_queries++;
558 }
559
560 /* update the tx_offset to handle output in 16k streams */
561 ds->tx_msg_offset = sizeof(original_qid);
562
563 }
564
565 /* check if it remains available room on output chan */
566 if (unlikely(!available_room)) {
567 si_rx_room_blk(si);
568 ret = 0;
569 break;
570 }
571
572 chunk_reset(&trash);
573 if ((msg_len - ds->tx_msg_offset) > available_room) {
574 /* remaining msg data is too large to be written in output channel at one time */
575
576 len = b_getblk(buf, trash.area, available_room, ofs + cnt + ds->tx_msg_offset);
577
578 /* update offset to complete mesg forwarding later */
579 ds->tx_msg_offset += len;
580 }
581 else {
582 /* remaining msg data can be written in output channel at one time */
583 len = b_getblk(buf, trash.area, msg_len - ds->tx_msg_offset, ofs + cnt + ds->tx_msg_offset);
584
585 /* reset tx_msg_offset to mark forward fully processed */
586 ds->tx_msg_offset = 0;
587 }
588 trash.data += len;
589
Emeric Brun743afee2021-02-15 14:12:06 +0100590 if (ci_putchk(si_ic(si), &trash) == -1) {
591 /* should never happen since we
592 * check available_room is large
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +0500593 * enough here.
Emeric Brun743afee2021-02-15 14:12:06 +0100594 */
595 si_rx_room_blk(si);
596 ret = 0;
597 break;
598 }
Emeric Brunfd647d52021-02-12 20:03:38 +0100599
600 if (ds->tx_msg_offset) {
601 /* msg was not fully processed, we must be awake to drain pending data */
602
603 si_rx_room_blk(si);
604 ret = 0;
605 break;
606 }
607 /* switch to next message */
608 ofs += cnt + msg_len;
609 }
610
611 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
612 ofs += ring->ofs;
613 ds->ofs = ofs;
614 }
615 HA_RWLOCK_RDUNLOCK(DNS_LOCK, &ring->lock);
616
617 if (ret) {
618 /* let's be woken up once new request to write arrived */
619 HA_RWLOCK_WRLOCK(DNS_LOCK, &ring->lock);
620 LIST_ADDQ(&ring->waiters, &appctx->wait_entry);
621 HA_RWLOCK_WRUNLOCK(DNS_LOCK, &ring->lock);
622 si_rx_endp_done(si);
623 }
624
625read:
626
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +0500627 /* if session is not a waiter it means there is no committed
Emeric Brunfd647d52021-02-12 20:03:38 +0100628 * message into rx_buf and we are free to use it
629 * Note: we need a load barrier here to not miss the
630 * delete from the list
631 */
632 __ha_barrier_load();
633 if (!LIST_ADDED(&ds->waiter)) {
634 while (1) {
635 uint16_t query_id;
636 struct eb32_node *eb;
637 struct dns_query *query;
638
639 if (!ds->rx_msg.len) {
640 /* next message len is not fully available into the channel */
641 if (co_data(si_oc(si)) < 2)
642 break;
643
644 /* retrieve message len */
645 co_getblk(si_oc(si), (char *)&msg_len, 2, 0);
646
647 /* mark as consumed */
648 co_skip(si_oc(si), 2);
649
650 /* store message len */
651 ds->rx_msg.len = ntohs(msg_len);
652 }
653
654 if (!co_data(si_oc(si))) {
655 /* we need more data but nothing is available */
656 break;
657 }
658
659 if (co_data(si_oc(si)) + ds->rx_msg.offset < ds->rx_msg.len) {
660 /* message only partially available */
661
662 /* read available data */
663 co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, co_data(si_oc(si)), 0);
664
665 /* update message offset */
666 ds->rx_msg.offset += co_data(si_oc(si));
667
668 /* consume all pending data from the channel */
669 co_skip(si_oc(si), co_data(si_oc(si)));
670
671 /* we need to wait for more data */
672 break;
673 }
674
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +0500675 /* enough data is available into the channel to read the message until the end */
Emeric Brunfd647d52021-02-12 20:03:38 +0100676
677 /* read from the channel until the end of the message */
678 co_getblk(si_oc(si), ds->rx_msg.area + ds->rx_msg.offset, ds->rx_msg.len - ds->rx_msg.offset, 0);
679
680 /* consume all data until the end of the message from the channel */
681 co_skip(si_oc(si), ds->rx_msg.len - ds->rx_msg.offset);
682
683 /* reset reader offset to 0 for next message reand */
684 ds->rx_msg.offset = 0;
685
686 /* try remap query id to original */
687 memcpy(&query_id, ds->rx_msg.area, sizeof(query_id));
688 eb = eb32_lookup(&ds->query_ids, query_id);
689 if (!eb) {
690 /* query id not found means we have an unknown corresponding
691 * request, perhaps server's bug or or the query reached
692 * timeout
693 */
694 ds->rx_msg.len = 0;
695 continue;
696 }
697
698 /* re-map the original query id set by the requester */
699 query = eb32_entry(eb, struct dns_query, qid);
700 memcpy(ds->rx_msg.area, &query->original_qid, sizeof(query->original_qid));
701
702 /* remove query ids mapping from pending queries list/tree */
703 eb32_delete(&query->qid);
704 LIST_DEL(&query->list);
705 pool_free(dns_query_pool, query);
706 ds->onfly_queries--;
707
708 /* lock the dns_stream_server containing lists heads */
709 HA_SPIN_LOCK(DNS_LOCK, &ds->dss->lock);
710
711 /* the dns_session is also added in queue of the
712 * wait_sess list where the task processing
713 * response will pop available responses
714 */
715 LIST_ADDQ(&ds->dss->wait_sess, &ds->waiter);
716
717 /* lock the dns_stream_server containing lists heads */
718 HA_SPIN_UNLOCK(DNS_LOCK, &ds->dss->lock);
719
720 /* awake the task processing the responses */
721 task_wakeup(ds->dss->task_rsp, TASK_WOKEN_INIT);
722
723 break;
724 }
725
726 if (!LIST_ADDED(&ds->waiter)) {
727 /* there is no more pending data to read and the con was closed by the server side */
728 if (!co_data(si_oc(si)) && (si_oc(si)->flags & CF_SHUTW)) {
729 goto close;
730 }
731 }
732
733 }
734
735
736 return;
737close:
738 si_shutw(si);
739 si_shutr(si);
740 si_ic(si)->flags |= CF_READ_NULL;
741}
742
743void dns_queries_flush(struct dns_session *ds)
744{
745 struct dns_query *query, *queryb;
746
747 list_for_each_entry_safe(query, queryb, &ds->queries, list) {
748 eb32_delete(&query->qid);
749 LIST_DEL(&query->list);
750 pool_free(dns_query_pool, query);
751 }
752}
753
754void dns_session_free(struct dns_session *ds)
755{
756 if (ds->rx_msg.area)
757 pool_free(dns_msg_buf, ds->rx_msg.area);
758 if (ds->tx_ring_area)
759 pool_free(dns_msg_buf, ds->tx_ring_area);
760 if (ds->task_exp)
761 task_destroy(ds->task_exp);
762
763 dns_queries_flush(ds);
764
765 ds->dss->cur_conns--;
766 /* Note: this is useless to update
767 * max_active_conns here because
768 * we decrease the value
769 */
770 pool_free(dns_session_pool, ds);
771}
772
773static struct appctx *dns_session_create(struct dns_session *ds);
774
775/*
776 * Function to release a DNS tcp session
777 */
778static void dns_session_release(struct appctx *appctx)
779{
780 struct dns_session *ds = appctx->ctx.sft.ptr;
Willy Tarreaue3e648c2021-02-24 17:38:46 +0100781 struct dns_stream_server *dss __maybe_unused;
Emeric Brunfd647d52021-02-12 20:03:38 +0100782
783 if (!ds)
784 return;
785
786 dss = ds->dss;
787
788 HA_SPIN_LOCK(DNS_LOCK, &dss->lock);
789 LIST_DEL_INIT(&ds->list);
790
791 if (stopping) {
792 dns_session_free(ds);
793 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
794 return;
795 }
796
797 if (!ds->nb_queries) {
798 /* this is an idle session */
799 /* Note: this is useless to update max_active_sess
800 * here because we decrease idle_conns but
801 * dns_session_free decrease curconns
802 */
803
804 ds->dss->idle_conns--;
805 dns_session_free(ds);
806 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
807 return;
808 }
809
810 if (ds->onfly_queries == ds->nb_queries) {
811 /* the session can be released because
812 * it means that all queries AND
813 * responses are in fly */
814 dns_session_free(ds);
815 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
816 return;
817 }
818
819 /* We do not call ring_appctx_detach here
820 * because we want to keep readers counters
821 * to retry a con with a different appctx*/
822 HA_RWLOCK_WRLOCK(DNS_LOCK, &ds->ring.lock);
823 LIST_DEL_INIT(&appctx->wait_entry);
824 HA_RWLOCK_WRUNLOCK(DNS_LOCK, &ds->ring.lock);
825
826 /* if there is no pending complete response
827 * message, ensure to reset
828 * message offsets if the session
829 * was closed with an incomplete pending response
830 */
831 if (!LIST_ADDED(&ds->waiter))
832 ds->rx_msg.len = ds->rx_msg.offset = 0;
833
834 /* we flush pending sent queries because we never
835 * have responses
836 */
837 ds->nb_queries -= ds->onfly_queries;
838 dns_queries_flush(ds);
839
840 /* reset offset to be sure to start from message start */
841 ds->tx_msg_offset = 0;
842
843 /* here the ofs and the attached counter
844 * are kept unchanged
845 */
846
847 /* Create a new appctx, We hope we can
848 * create from the release callback! */
849 ds->appctx = dns_session_create(ds);
850 if (!ds->appctx) {
851 dns_session_free(ds);
852 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
853 return;
854 }
855
856 if (ds->nb_queries < DNS_STREAM_MAX_PIPELINED_REQ)
857 LIST_ADD(&ds->dss->free_sess, &ds->list);
858
859 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
860}
861
862/* DNS tcp session applet */
863static struct applet dns_session_applet = {
864 .obj_type = OBJ_TYPE_APPLET,
865 .name = "<STRMDNS>", /* used for logging */
866 .fct = dns_session_io_handler,
867 .release = dns_session_release,
868};
869
870/*
871 * Function used to create an appctx for a DNS session
872 */
873static struct appctx *dns_session_create(struct dns_session *ds)
874{
875 struct appctx *appctx;
876 struct session *sess;
877 struct stream *s;
878 struct applet *applet = &dns_session_applet;
879
880 appctx = appctx_new(applet, tid_bit);
881 if (!appctx)
882 goto out_close;
883
884 appctx->ctx.sft.ptr = (void *)ds;
885
886 sess = session_new(ds->dss->srv->proxy, NULL, &appctx->obj_type);
887 if (!sess) {
888 ha_alert("out of memory in peer_session_create().\n");
889 goto out_free_appctx;
890 }
891
892 if ((s = stream_new(sess, &appctx->obj_type, &BUF_NULL)) == NULL) {
893 ha_alert("Failed to initialize stream in peer_session_create().\n");
894 goto out_free_sess;
895 }
896
897
898 s->target = &ds->dss->srv->obj_type;
899 if (!sockaddr_alloc(&s->target_addr, &ds->dss->srv->addr, sizeof(ds->dss->srv->addr)))
900 goto out_free_strm;
901 s->flags = SF_ASSIGNED|SF_ADDR_SET;
902 s->si[1].flags |= SI_FL_NOLINGER;
903
904 s->do_log = NULL;
905 s->uniq_id = 0;
906
907 s->res.flags |= CF_READ_DONTWAIT;
908 /* for rto and rex to eternity to not expire on idle recv:
909 * We are using a syslog server.
910 */
911 s->res.rto = TICK_ETERNITY;
912 s->res.rex = TICK_ETERNITY;
913 ds->appctx = appctx;
914 task_wakeup(s->task, TASK_WOKEN_INIT);
915 return appctx;
916
917 /* Error unrolling */
918 out_free_strm:
919 LIST_DEL(&s->list);
920 pool_free(pool_head_stream, s);
921 out_free_sess:
922 session_free(sess);
923 out_free_appctx:
924 appctx_free(appctx);
925 out_close:
926 return NULL;
927}
928
929/* Task processing expiration of unresponded queries, this one is supposed
930 * to be stuck on the same thread than the appctx handler
931 */
932static struct task *dns_process_query_exp(struct task *t, void *context, unsigned short state)
933{
934 struct dns_session *ds = (struct dns_session *)context;
935 struct dns_query *query, *queryb;
936
937 t->expire = TICK_ETERNITY;
938
939 list_for_each_entry_safe(query, queryb, &ds->queries, list) {
940 if (tick_is_expired(query->expire, now_ms)) {
941 eb32_delete(&query->qid);
942 LIST_DEL(&query->list);
943 pool_free(dns_query_pool, query);
944 ds->onfly_queries--;
945 }
946 else {
947 t->expire = query->expire;
948 break;
949 }
950 }
951
952 return t;
953}
954
955/* Task processing expiration of idle sessions */
956static struct task *dns_process_idle_exp(struct task *t, void *context, unsigned short state)
957{
958 struct dns_stream_server *dss = (struct dns_stream_server *)context;
959 struct dns_session *ds, *dsb;
960 int target = 0;
961 int cur_active_conns;
962
963 HA_SPIN_LOCK(DNS_LOCK, &dss->lock);
964
965
966 cur_active_conns = dss->cur_conns - dss->idle_conns;
967 if (cur_active_conns > dss->max_active_conns)
968 dss->max_active_conns = cur_active_conns;
969
970 target = (dss->max_active_conns - cur_active_conns) / 2;
971 list_for_each_entry_safe(ds, dsb, &dss->idle_sess, list) {
972 if (!target)
973 break;
974
975 /* remove conn to pending list to ensure it won't be reused */
976 LIST_DEL_INIT(&ds->list);
977
978 /* force session shutdown */
979 ds->shutdown = 1;
980
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +0500981 /* to be sure that the appctx won't miss shutdown */
Emeric Brunfd647d52021-02-12 20:03:38 +0100982 __ha_barrier_store();
983
984 /* wake appctx to perform the shutdown */
985 appctx_wakeup(ds->appctx);
986 }
987
988 /* reset max to current active conns */
989 dss->max_active_conns = cur_active_conns;
990
991 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
992
993 t->expire = tick_add(now_ms, 5000);
994
995 return t;
996}
997
998struct dns_session *dns_session_new(struct dns_stream_server *dss)
999{
1000 struct dns_session *ds;
1001
1002 if (dss->maxconn && (dss->maxconn <= dss->cur_conns))
1003 return NULL;
1004
1005 ds = pool_alloc(dns_session_pool);
1006 if (!ds)
1007 return NULL;
1008
1009 ds->ofs = ~0;
1010 ds->dss = dss;
1011 LIST_INIT(&ds->list);
1012 LIST_INIT(&ds->queries);
1013 LIST_INIT(&ds->waiter);
1014 ds->rx_msg.offset = ds->rx_msg.len = 0;
1015 ds->rx_msg.area = NULL;
1016 ds->tx_ring_area = NULL;
1017 ds->task_exp = NULL;
1018 ds->appctx = NULL;
1019 ds->shutdown = 0;
1020 ds->nb_queries = 0;
1021 ds->query_ids = EB_ROOT_UNIQUE;
1022 ds->rx_msg.area = pool_alloc(dns_msg_buf);
1023 if (!ds->rx_msg.area)
1024 goto error;
1025
1026 ds->tx_ring_area = pool_alloc(dns_msg_buf);
1027 if (!ds->tx_ring_area)
1028 goto error;
1029
1030 ring_init(&ds->ring, ds->tx_ring_area, DNS_TCP_MSG_RING_MAX_SIZE);
Emeric Brun0e40fda2021-02-15 15:13:31 +01001031 if (!ring_attach(&ds->ring)) {
1032 /* Should never happen
1033 * since we are the first attached
1034 * here
1035 */
1036 goto error;
1037 }
Emeric Brunfd647d52021-02-12 20:03:38 +01001038
1039 if ((ds->task_exp = task_new(tid_bit)) == NULL)
1040 goto error;
1041
1042 ds->task_exp->process = dns_process_query_exp;
1043 ds->task_exp->context = ds;
1044
1045 ds->appctx = dns_session_create(ds);
1046 if (!ds->appctx)
1047 goto error;
1048
1049 dss->cur_conns++;
1050
1051 return ds;
1052
1053error:
1054 if (ds->task_exp)
1055 task_destroy(ds->task_exp);
1056 if (ds->rx_msg.area)
1057 pool_free(dns_msg_buf, ds->rx_msg.area);
1058 if (ds->tx_ring_area)
1059 pool_free(dns_msg_buf, ds->tx_ring_area);
1060
1061 pool_free(dns_session_pool, ds);
1062
1063 return NULL;
1064}
1065
1066/*
1067 * Task used to consume pending messages from nameserver ring
1068 * and forward them to dns_session ring.
1069 * Note: If no slot found a new dns_session is allocated
1070 */
1071static struct task *dns_process_req(struct task *t, void *context, unsigned short state)
1072{
1073 struct dns_nameserver *ns = (struct dns_nameserver *)context;
1074 struct dns_stream_server *dss = ns->stream;
1075 struct ring *ring = dss->ring_req;
1076 struct buffer *buf = &ring->buf;
1077 uint64_t msg_len;
1078 size_t len, cnt, ofs;
1079 struct dns_session *ds, *ads;
1080 HA_SPIN_LOCK(DNS_LOCK, &dss->lock);
1081
1082 ofs = dss->ofs_req;
1083
1084 HA_RWLOCK_RDLOCK(DNS_LOCK, &ring->lock);
1085
1086 /* explanation for the initialization below: it would be better to do
1087 * this in the parsing function but this would occasionally result in
1088 * dropped events because we'd take a reference on the oldest message
1089 * and keep it while being scheduled. Thus instead let's take it the
1090 * first time we enter here so that we have a chance to pass many
1091 * existing messages before grabbing a reference to a location. This
1092 * value cannot be produced after initialization.
1093 */
1094 if (unlikely(ofs == ~0)) {
1095 ofs = 0;
1096 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
1097 ofs += ring->ofs;
1098 }
1099
1100 /* we were already there, adjust the offset to be relative to
1101 * the buffer's head and remove us from the counter.
1102 */
1103 ofs -= ring->ofs;
1104 BUG_ON(ofs >= buf->size);
1105 HA_ATOMIC_SUB(b_peek(buf, ofs), 1);
1106
1107 while (ofs + 1 < b_data(buf)) {
1108 struct ist myist;
1109
1110 cnt = 1;
1111 len = b_peek_varint(buf, ofs + cnt, &msg_len);
1112 if (!len)
1113 break;
1114 cnt += len;
1115 BUG_ON(msg_len + ofs + cnt + 1 > b_data(buf));
1116 if (unlikely(msg_len > DNS_TCP_MSG_MAX_SIZE)) {
1117 /* too large a message to ever fit, let's skip it */
1118 ofs += cnt + msg_len;
1119 continue;
1120 }
1121
1122 len = b_getblk(buf, dns_msg_trash, msg_len, ofs + cnt);
1123
Tim Duesterhus92c696e2021-02-28 16:11:36 +01001124 myist = ist2(dns_msg_trash, len);
Emeric Brunfd647d52021-02-12 20:03:38 +01001125
1126 ads = NULL;
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +05001127 /* try to push request into active sess with free slot */
Emeric Brunfd647d52021-02-12 20:03:38 +01001128 if (!LIST_ISEMPTY(&dss->free_sess)) {
1129 ds = LIST_NEXT(&dss->free_sess, struct dns_session *, list);
1130
1131 if (ring_write(&ds->ring, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1) > 0) {
1132 ds->nb_queries++;
1133 if (ds->nb_queries >= DNS_STREAM_MAX_PIPELINED_REQ)
1134 LIST_DEL_INIT(&ds->list);
1135 ads = ds;
1136 }
1137 else {
1138 /* it means we were unable to put a request in this slot,
1139 * it may be close to be full so we put it at the end
1140 * of free conn list */
1141 LIST_DEL_INIT(&ds->list);
1142 LIST_ADDQ(&dss->free_sess, &ds->list);
1143 }
1144 }
1145
1146 if (!ads) {
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +05001147 /* try to push request into idle, this one should have enough free space */
Emeric Brunfd647d52021-02-12 20:03:38 +01001148 if (!LIST_ISEMPTY(&dss->idle_sess)) {
1149 ds = LIST_NEXT(&dss->idle_sess, struct dns_session *, list);
1150
1151 /* ring is empty so this ring_write should never fail */
1152 ring_write(&ds->ring, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
1153 ds->nb_queries++;
1154 LIST_DEL_INIT(&ds->list);
1155
1156 ds->dss->idle_conns--;
1157
1158 /* we may have to update the max_active_conns */
1159 if (ds->dss->max_active_conns < ds->dss->cur_conns - ds->dss->idle_conns)
1160 ds->dss->max_active_conns = ds->dss->cur_conns - ds->dss->idle_conns;
1161
1162 /* since we may unable to find a free list to handle
1163 * this request, this request may be large and fill
1164 * the ring buffer so we prefer to put at the end of free
1165 * list. */
1166 LIST_ADDQ(&dss->free_sess, &ds->list);
1167 ads = ds;
1168 }
1169 }
1170
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +05001171 /* we didn't find a session available with large enough room */
Emeric Brunfd647d52021-02-12 20:03:38 +01001172 if (!ads) {
1173 /* allocate a new session */
1174 ads = dns_session_new(dss);
1175 if (ads) {
1176 /* ring is empty so this ring_write should never fail */
1177 ring_write(&ads->ring, DNS_TCP_MSG_MAX_SIZE, NULL, 0, &myist, 1);
1178 ads->nb_queries++;
1179 LIST_ADD(&dss->free_sess, &ads->list);
1180 }
1181 else
1182 ns->counters->snd_error++;
1183 }
1184
1185 if (ads)
1186 ns->counters->sent++;
1187
1188 ofs += cnt + len;
1189 }
1190
1191 HA_ATOMIC_ADD(b_peek(buf, ofs), 1);
1192 ofs += ring->ofs;
1193 dss->ofs_req = ofs;
1194 HA_RWLOCK_RDUNLOCK(DNS_LOCK, &ring->lock);
1195
1196
1197 HA_SPIN_UNLOCK(DNS_LOCK, &dss->lock);
1198 return t;
1199}
1200
1201/*
1202 * Task used to consume response
1203 * Note: upper layer callback is called
1204 */
1205static struct task *dns_process_rsp(struct task *t, void *context, unsigned short state)
1206{
1207 struct dns_nameserver *ns = (struct dns_nameserver *)context;
1208
1209 ns->process_responses(ns);
1210
1211 return t;
1212}
1213
1214/* Function used to initialize an TCP nameserver */
1215int dns_stream_init(struct dns_nameserver *ns, struct server *srv)
1216{
1217 struct dns_stream_server *dss = NULL;
1218
1219 dss = calloc(1, sizeof(*dss));
1220 if (!dss) {
1221 ha_alert("memory allocation error initializing dns tcp server '%s'.\n", srv->id);
1222 goto out;
1223 }
1224
1225 dss->srv = srv;
1226 dss->maxconn = srv->maxconn;
1227
1228 dss->ofs_req = ~0; /* init ring offset */
1229 dss->ring_req = ring_new(2*DNS_TCP_MSG_RING_MAX_SIZE);
1230 if (!dss->ring_req) {
1231 ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
1232 goto out;
1233 }
1234 /* Create the task associated to the resolver target handling conns */
1235 if ((dss->task_req = task_new(MAX_THREADS_MASK)) == NULL) {
1236 ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
1237 goto out;
1238 }
1239
1240 /* Update task's parameters */
1241 dss->task_req->process = dns_process_req;
1242 dss->task_req->context = ns;
1243
1244 /* attach the task as reader */
1245 if (!ring_attach(dss->ring_req)) {
1246 /* mark server attached to the ring */
1247 ha_alert("server '%s': too many watchers for ring. this should never happen.\n", srv->id);
1248 goto out;
1249 }
1250
1251 /* Create the task associated to the resolver target handling conns */
1252 if ((dss->task_rsp = task_new(MAX_THREADS_MASK)) == NULL) {
1253 ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
1254 goto out;
1255 }
1256
1257 /* Update task's parameters */
1258 dss->task_rsp->process = dns_process_rsp;
1259 dss->task_rsp->context = ns;
1260
1261 /* Create the task associated to the resolver target handling conns */
1262 if ((dss->task_idle = task_new(MAX_THREADS_MASK)) == NULL) {
1263 ha_alert("memory allocation error initializing the ring for dns tcp server '%s'.\n", srv->id);
1264 goto out;
1265 }
1266
1267 /* Update task's parameters */
1268 dss->task_idle->process = dns_process_idle_exp;
1269 dss->task_idle->context = dss;
1270 dss->task_idle->expire = tick_add(now_ms, 5000);
1271
Ilya Shipitsin0de36ad2021-02-20 00:23:36 +05001272 /* let start the task to free idle conns immediately */
Emeric Brunfd647d52021-02-12 20:03:38 +01001273 task_queue(dss->task_idle);
1274
1275 LIST_INIT(&dss->free_sess);
1276 LIST_INIT(&dss->idle_sess);
1277 LIST_INIT(&dss->wait_sess);
1278 HA_SPIN_INIT(&dss->lock);
1279 ns->stream = dss;
1280 return 0;
1281out:
1282 if (dss && dss->task_rsp)
1283 task_destroy(dss->task_rsp);
1284 if (dss && dss->task_req)
1285 task_destroy(dss->task_req);
1286 if (dss && dss->ring_req)
1287 ring_free(dss->ring_req);
1288
1289 free(dss);
Emeric Brunc9437992021-02-12 19:42:55 +01001290 return -1;
Christopher Faulet67957bd2017-09-27 11:00:59 +02001291}
1292
Emeric Brunc9437992021-02-12 19:42:55 +01001293int init_dns_buffers()
Baptiste Assmann325137d2015-04-13 23:40:55 +02001294{
Emeric Brunc9437992021-02-12 19:42:55 +01001295 dns_msg_trash = malloc(DNS_TCP_MSG_MAX_SIZE);
1296 if (!dns_msg_trash)
1297 return 0;
Baptiste Assmann325137d2015-04-13 23:40:55 +02001298
Emeric Brunc9437992021-02-12 19:42:55 +01001299 return 1;
1300}
Baptiste Assmannc1ce5f32016-05-14 11:26:22 +02001301
Emeric Brunc9437992021-02-12 19:42:55 +01001302void deinit_dns_buffers()
1303{
Willy Tarreau61cfdf42021-02-20 10:46:51 +01001304 ha_free(&dns_msg_trash);
Emeric Brunc9437992021-02-12 19:42:55 +01001305}
Emeric Brund26a6232021-01-04 13:32:20 +01001306
1307REGISTER_PER_THREAD_ALLOC(init_dns_buffers);
1308REGISTER_PER_THREAD_FREE(deinit_dns_buffers);