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