librpc:ndr: Don’t unnecessarily parenthesize macro arguments
[Samba.git] / third_party / resolv_wrapper / resolv_wrapper.c
blob899f4ccc7a97ce55ad9dcc00f75ac480db85f3ae
1 /*
2 * Copyright (c) 2014-2018 Andreas Schneider <asn@samba.org>
3 * Copyright (c) 2014-2016 Jakub Hrozek <jakub.hrozek@posteo.se>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include "config.h"
37 #include <errno.h>
38 #include <arpa/inet.h>
39 #ifdef HAVE_ARPA_NAMESER_H
40 #include <arpa/nameser.h>
41 #endif /* HAVE_ARPA_NAMESER_H */
42 #include <netinet/in.h>
43 #include <sys/socket.h>
44 #include <sys/types.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <stdbool.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <ctype.h>
53 #include <resolv.h>
55 #if defined(HAVE_RES_STATE_U_EXT_NSADDRS) || defined(HAVE_RES_SOCKADDR_UNION_SIN6)
56 #define HAVE_RESOLV_IPV6_NSADDRS 1
57 #endif
59 /* GCC has printf type attribute check. */
60 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
61 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
62 #else
63 #define PRINTF_ATTRIBUTE(a,b)
64 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
66 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
67 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
68 #else
69 #define DESTRUCTOR_ATTRIBUTE
70 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
72 #ifndef RWRAP_DEFAULT_FAKE_TTL
73 #define RWRAP_DEFAULT_FAKE_TTL 600
74 #endif /* RWRAP_DEFAULT_FAKE_TTL */
76 #ifndef HAVE_NS_NAME_COMPRESS
77 #define ns_name_compress dn_comp
78 #endif
80 #define ns_t_uri 256
82 enum rwrap_dbglvl_e {
83 RWRAP_LOG_ERROR = 0,
84 RWRAP_LOG_WARN,
85 RWRAP_LOG_NOTICE,
86 RWRAP_LOG_DEBUG,
87 RWRAP_LOG_TRACE
90 #ifndef HAVE_GETPROGNAME
91 static const char *getprogname(void)
93 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
94 return program_invocation_short_name;
95 #elif defined(HAVE_GETEXECNAME)
96 return getexecname();
97 #else
98 return NULL;
99 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
101 #endif /* HAVE_GETPROGNAME */
103 static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
104 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
106 static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
107 const char *func,
108 const char *format, ...)
110 char buffer[1024];
111 va_list va;
112 const char *d;
113 unsigned int lvl = 0;
114 const char *prefix = NULL;
115 const char *progname = NULL;
117 d = getenv("RESOLV_WRAPPER_DEBUGLEVEL");
118 if (d != NULL) {
119 lvl = atoi(d);
122 if (lvl < dbglvl) {
123 return;
126 va_start(va, format);
127 vsnprintf(buffer, sizeof(buffer), format, va);
128 va_end(va);
130 switch (dbglvl) {
131 case RWRAP_LOG_ERROR:
132 prefix = "RWRAP_ERROR";
133 break;
134 case RWRAP_LOG_WARN:
135 prefix = "RWRAP_WARN";
136 break;
137 case RWRAP_LOG_NOTICE:
138 prefix = "RWRAP_NOTICE";
139 break;
140 case RWRAP_LOG_DEBUG:
141 prefix = "RWRAP_DEBUG";
142 break;
143 case RWRAP_LOG_TRACE:
144 prefix = "RWRAP_TRACE";
145 break;
148 progname = getprogname();
149 if (progname == NULL) {
150 progname = "<unknown>";
153 fprintf(stderr,
154 "%s[%s (%u)] - %s: %s\n",
155 prefix,
156 progname,
157 (unsigned int)getpid(),
158 func,
159 buffer);
162 #ifndef SAFE_FREE
163 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
164 #endif
166 #define NEXT_KEY(buf, key) do { \
167 (key) = (buf) ? strpbrk((buf), " \t") : NULL; \
168 if ((key) != NULL) { \
169 (key)[0] = '\0'; \
170 (key)++; \
172 while ((key) != NULL \
173 && (isblank((int)(key)[0]))) { \
174 (key)++; \
176 } while(0);
178 #define RWRAP_MAX_RECURSION 64
180 union rwrap_sockaddr {
181 struct sockaddr sa;
182 struct sockaddr_in in;
183 struct sockaddr_in6 in6;
186 /* Priority and weight can be omitted from the hosts file, but need to be part
187 * of the output
189 #define DFL_SRV_PRIO 1
190 #define DFL_SRV_WEIGHT 100
191 #define DFL_URI_PRIO 1
192 #define DFL_URI_WEIGHT 100
194 struct rwrap_srv_rrdata {
195 uint16_t port;
196 uint16_t prio;
197 uint16_t weight;
198 char hostname[MAXDNAME];
201 struct rwrap_uri_rrdata {
202 uint16_t prio;
203 uint16_t weight;
204 char uri[MAXDNAME];
207 struct rwrap_soa_rrdata {
208 uint32_t serial;
209 uint32_t refresh;
210 uint32_t retry;
211 uint32_t expire;
212 uint32_t minimum;
213 char nameserver[MAXDNAME];
214 char mailbox[MAXDNAME];
217 struct rwrap_fake_rr {
218 union fake_rrdata {
219 struct in_addr a_rec;
220 struct in6_addr aaaa_rec;
221 struct rwrap_srv_rrdata srv_rec;
222 struct rwrap_uri_rrdata uri_rec;
223 struct rwrap_soa_rrdata soa_rec;
224 char cname_rec[MAXDNAME];
225 char ptr_rec[MAXDNAME];
226 char txt_rec[MAXDNAME];
227 } rrdata;
229 char key[MAXDNAME];
230 int type; /* ns_t_* */
233 static void rwrap_fake_rr_init(struct rwrap_fake_rr *rr, size_t len)
235 size_t i;
237 for (i = 0; i < len; i++) {
238 rr[i].type = ns_t_invalid;
242 static int rwrap_create_fake_a_rr(const char *key,
243 const char *value,
244 struct rwrap_fake_rr *rr)
246 int ok;
248 ok = inet_pton(AF_INET, value, &rr->rrdata.a_rec);
249 if (!ok) {
250 RWRAP_LOG(RWRAP_LOG_ERROR,
251 "Failed to convert [%s] to binary\n", value);
252 return -1;
255 memcpy(rr->key, key, strlen(key) + 1);
256 rr->type = ns_t_a;
257 return 0;
260 static int rwrap_create_fake_aaaa_rr(const char *key,
261 const char *value,
262 struct rwrap_fake_rr *rr)
264 int ok;
266 ok = inet_pton(AF_INET6, value, &rr->rrdata.aaaa_rec);
267 if (!ok) {
268 RWRAP_LOG(RWRAP_LOG_ERROR,
269 "Failed to convert [%s] to binary\n", value);
270 return -1;
273 memcpy(rr->key, key, strlen(key) + 1);
274 rr->type = ns_t_aaaa;
275 return 0;
277 static int rwrap_create_fake_ns_rr(const char *key,
278 const char *value,
279 struct rwrap_fake_rr *rr)
281 memcpy(rr->rrdata.srv_rec.hostname, value, strlen(value) + 1);
282 memcpy(rr->key, key, strlen(key) + 1);
283 rr->type = ns_t_ns;
284 return 0;
287 static int rwrap_create_fake_srv_rr(const char *key,
288 const char *value,
289 struct rwrap_fake_rr *rr)
291 char *str_prio;
292 char *str_weight;
293 char *str_port;
294 const char *hostname;
296 /* parse the value into priority, weight, port and hostname
297 * and check the validity */
298 hostname = value;
299 NEXT_KEY(hostname, str_port);
300 NEXT_KEY(str_port, str_prio);
301 NEXT_KEY(str_prio, str_weight);
302 if (str_port == NULL || hostname == NULL) {
303 RWRAP_LOG(RWRAP_LOG_ERROR,
304 "Malformed SRV entry [%s]\n", value);
305 return -1;
308 if (str_prio) {
309 rr->rrdata.srv_rec.prio = atoi(str_prio);
310 } else {
311 rr->rrdata.srv_rec.prio = DFL_SRV_PRIO;
313 if (str_weight) {
314 rr->rrdata.srv_rec.weight = atoi(str_weight);
315 } else {
316 rr->rrdata.srv_rec.weight = DFL_SRV_WEIGHT;
318 rr->rrdata.srv_rec.port = atoi(str_port);
319 memcpy(rr->rrdata.srv_rec.hostname , hostname, strlen(hostname) + 1);
321 memcpy(rr->key, key, strlen(key) + 1);
322 rr->type = ns_t_srv;
323 return 0;
326 static int rwrap_create_fake_uri_rr(const char *key,
327 const char *value,
328 struct rwrap_fake_rr *rr)
330 char *str_prio;
331 char *str_weight;
332 const char *uri;
334 /* parse the value into priority, weight, and uri
335 * and check the validity */
336 uri = value;
337 NEXT_KEY(uri, str_prio);
338 NEXT_KEY(str_prio, str_weight);
339 if (uri == NULL) {
340 RWRAP_LOG(RWRAP_LOG_ERROR,
341 "Malformed URI entry [<null>]\n");
342 return -1;
345 if (str_prio) {
346 rr->rrdata.uri_rec.prio = atoi(str_prio);
347 } else {
348 rr->rrdata.uri_rec.prio = DFL_URI_PRIO;
350 if (str_weight) {
351 rr->rrdata.uri_rec.weight = atoi(str_weight);
352 } else {
353 rr->rrdata.uri_rec.weight = DFL_URI_WEIGHT;
355 memcpy(rr->rrdata.uri_rec.uri, uri, strlen(uri) + 1);
357 memcpy(rr->key, key, strlen(key) + 1);
358 rr->type = ns_t_uri;
359 return 0;
362 static int rwrap_create_fake_txt_rr(const char *key,
363 const char *value,
364 struct rwrap_fake_rr *rr)
366 memcpy(rr->rrdata.txt_rec, value, strlen(value) + 1);
368 memcpy(rr->key, key, strlen(key) + 1);
369 rr->type = ns_t_txt;
370 return 0;
373 static int rwrap_create_fake_soa_rr(const char *key,
374 const char *value,
375 struct rwrap_fake_rr *rr)
377 const char *nameserver;
378 char *mailbox;
379 char *str_serial;
380 char *str_refresh;
381 char *str_retry;
382 char *str_expire;
383 char *str_minimum;
385 /* parse the value into nameserver, mailbox, serial, refresh,
386 * retry, expire, minimum and check the validity
388 nameserver = value;
389 NEXT_KEY(nameserver, mailbox);
390 NEXT_KEY(mailbox, str_serial);
391 NEXT_KEY(str_serial, str_refresh);
392 NEXT_KEY(str_refresh, str_retry);
393 NEXT_KEY(str_retry, str_expire);
394 NEXT_KEY(str_expire, str_minimum);
395 if (nameserver == NULL || mailbox == NULL || str_serial == NULL ||
396 str_refresh == NULL || str_retry == NULL || str_expire == NULL ||
397 str_minimum == NULL) {
398 RWRAP_LOG(RWRAP_LOG_ERROR,
399 "Malformed SOA entry [%s]\n", value);
400 return -1;
403 memcpy(rr->rrdata.soa_rec.nameserver, nameserver, strlen(nameserver)+1);
404 memcpy(rr->rrdata.soa_rec.mailbox, mailbox, strlen(mailbox)+1);
406 rr->rrdata.soa_rec.serial = atoi(str_serial);
407 rr->rrdata.soa_rec.refresh = atoi(str_refresh);
408 rr->rrdata.soa_rec.retry = atoi(str_retry);
409 rr->rrdata.soa_rec.expire = atoi(str_expire);
410 rr->rrdata.soa_rec.minimum = atoi(str_minimum);
412 memcpy(rr->key, key, strlen(key) + 1);
413 rr->type = ns_t_soa;
414 return 0;
417 static int rwrap_create_fake_cname_rr(const char *key,
418 const char *value,
419 struct rwrap_fake_rr *rr)
421 memcpy(rr->rrdata.cname_rec , value, strlen(value) + 1);
422 memcpy(rr->key, key, strlen(key) + 1);
423 rr->type = ns_t_cname;
424 return 0;
427 static int rwrap_create_fake_ptr_rr(const char *key,
428 const char *value,
429 struct rwrap_fake_rr *rr)
431 memcpy(rr->rrdata.ptr_rec , value, strlen(value) + 1);
432 memcpy(rr->key, key, strlen(key) + 1);
433 rr->type = ns_t_ptr;
434 return 0;
437 #define rwrap_randomid() 0xffff & getpid()
439 /* Prepares a fake header with a single response. Advances header_blob */
440 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
441 size_t ancount, size_t arcount)
443 union {
444 uint8_t *blob;
445 HEADER *header;
446 } h;
448 if (remaining < NS_HFIXEDSZ) {
449 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
450 return -1;
453 h.blob = *header_blob;
454 memset(h.blob, 0, NS_HFIXEDSZ);
456 h.header->id = rwrap_randomid(); /* random query ID */
457 h.header->qr = 1; /* response flag */
458 h.header->rd = 1; /* recursion desired */
459 h.header->ra = 1; /* recursion available */
461 h.header->qdcount = htons(1); /* no. of questions */
462 h.header->ancount = htons(ancount); /* no. of answers */
463 h.header->arcount = htons(arcount); /* no. of add'tl records */
465 /* move past the header */
466 *header_blob = h.blob += NS_HFIXEDSZ;
468 return NS_HFIXEDSZ;
471 static ssize_t rwrap_fake_question(const char *question,
472 uint16_t type,
473 uint8_t **question_ptr,
474 size_t remaining)
476 uint8_t *qb = *question_ptr;
477 int n;
479 n = ns_name_compress(question, qb, remaining, NULL, NULL);
480 if (n < 0) {
481 RWRAP_LOG(RWRAP_LOG_ERROR,
482 "Failed to compress [%s]\n", question);
483 return -1;
486 qb += n;
487 remaining -= n;
489 if (remaining < 2 * sizeof(uint16_t)) {
490 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
491 return -1;
494 NS_PUT16(type, qb);
495 NS_PUT16(ns_c_in, qb);
497 *question_ptr = qb;
498 return n + 2 * sizeof(uint16_t);
501 static ssize_t rwrap_fake_rdata_common(uint16_t type,
502 size_t rdata_size,
503 const char *key,
504 size_t remaining,
505 uint8_t **rdata_ptr)
507 uint8_t *rd = *rdata_ptr;
508 ssize_t written = 0;
510 written = ns_name_compress(key, rd, remaining, NULL, NULL);
511 if (written < 0) {
512 RWRAP_LOG(RWRAP_LOG_ERROR,
513 "Failed to compress [%s]\n", key);
514 return -1;
516 rd += written;
517 remaining -= written;
519 if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
520 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
521 return -1;
524 NS_PUT16(type, rd);
525 NS_PUT16(ns_c_in, rd);
526 NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd);
527 NS_PUT16(rdata_size, rd);
529 if (remaining < rdata_size) {
530 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
531 return -1;
534 *rdata_ptr = rd;
535 return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size;
538 static ssize_t rwrap_fake_a(struct rwrap_fake_rr *rr,
539 uint8_t *answer_ptr,
540 size_t anslen)
542 uint8_t *a = answer_ptr;
543 ssize_t resp_size;
545 if (rr->type != ns_t_a) {
546 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
547 return -1;
549 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding A RR");
551 resp_size = rwrap_fake_rdata_common(ns_t_a, sizeof(struct in_addr), rr->key,
552 anslen, &a);
553 if (resp_size < 0) {
554 return -1;
557 memcpy(a, &rr->rrdata.a_rec, sizeof(struct in_addr));
559 return resp_size;
562 static ssize_t rwrap_fake_aaaa(struct rwrap_fake_rr *rr,
563 uint8_t *answer,
564 size_t anslen)
566 uint8_t *a = answer;
567 ssize_t resp_size;
569 if (rr->type != ns_t_aaaa) {
570 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
571 return -1;
573 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding AAAA RR");
575 resp_size = rwrap_fake_rdata_common(ns_t_aaaa, sizeof(struct in6_addr),
576 rr->key, anslen, &a);
577 if (resp_size < 0) {
578 return -1;
581 memcpy(a, &rr->rrdata.aaaa_rec, sizeof(struct in6_addr));
583 return resp_size;
586 static ssize_t rwrap_fake_ns(struct rwrap_fake_rr *rr,
587 uint8_t *answer,
588 size_t anslen)
590 uint8_t *a = answer;
591 ssize_t resp_size = 0;
592 size_t rdata_size;
593 unsigned char hostname_compressed[MAXDNAME];
594 ssize_t compressed_len;
596 if (rr->type != ns_t_ns) {
597 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
598 return -1;
600 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding NS RR");
602 /* Prepare the data to write */
603 compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
604 hostname_compressed,
605 MAXDNAME,
606 NULL,
607 NULL);
608 if (compressed_len < 0) {
609 return -1;
612 /* Is this enough? */
613 rdata_size = compressed_len;
615 resp_size = rwrap_fake_rdata_common(ns_t_ns, rdata_size,
616 rr->key, anslen, &a);
617 if (resp_size < 0) {
618 return -1;
621 memcpy(a, hostname_compressed, compressed_len);
623 return resp_size;
626 static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr,
627 uint8_t *answer,
628 size_t anslen)
630 uint8_t *a = answer;
631 ssize_t resp_size;
632 size_t rdata_size;
633 unsigned char hostname_compressed[MAXDNAME];
634 ssize_t compressed_len;
636 if (rr->type != ns_t_srv) {
637 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
638 return -1;
640 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SRV RR");
641 rdata_size = 3 * sizeof(uint16_t);
643 /* Prepare the data to write */
644 compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
645 hostname_compressed, MAXDNAME,
646 NULL, NULL);
647 if (compressed_len < 0) {
648 return -1;
650 rdata_size += compressed_len;
652 resp_size = rwrap_fake_rdata_common(ns_t_srv, rdata_size,
653 rr->key, anslen, &a);
654 if (resp_size < 0) {
655 return -1;
658 NS_PUT16(rr->rrdata.srv_rec.prio, a);
659 NS_PUT16(rr->rrdata.srv_rec.weight, a);
660 NS_PUT16(rr->rrdata.srv_rec.port, a);
661 memcpy(a, hostname_compressed, compressed_len);
663 return resp_size;
666 static ssize_t rwrap_fake_uri(struct rwrap_fake_rr *rr,
667 uint8_t *answer,
668 size_t anslen)
670 uint8_t *a = answer;
671 ssize_t resp_size;
672 size_t rdata_size;
673 size_t uri_len;
675 if (rr->type != ns_t_uri) {
676 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
677 return -1;
679 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding URI RR");
680 rdata_size = 3 * sizeof(uint16_t);
681 uri_len = strlen(rr->rrdata.uri_rec.uri) + 1;
682 rdata_size += uri_len;
684 resp_size = rwrap_fake_rdata_common(ns_t_uri, rdata_size,
685 rr->key, anslen, &a);
686 if (resp_size < 0) {
687 return -1;
690 NS_PUT16(rr->rrdata.uri_rec.prio, a);
691 NS_PUT16(rr->rrdata.uri_rec.weight, a);
692 memcpy(a, rr->rrdata.uri_rec.uri, uri_len);
694 return resp_size;
697 static ssize_t rwrap_fake_txt(struct rwrap_fake_rr *rr,
698 uint8_t *answer,
699 size_t anslen)
701 uint8_t *a = answer;
702 ssize_t resp_size;
703 size_t rdata_size;
704 size_t txt_len;
706 if (rr->type != ns_t_txt) {
707 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
708 return -1;
710 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding TXT RR");
711 txt_len = strlen(rr->rrdata.txt_rec) + 1;
712 rdata_size = txt_len;
714 resp_size = rwrap_fake_rdata_common(ns_t_txt, rdata_size,
715 rr->key, anslen, &a);
716 if (resp_size < 0) {
717 return -1;
720 memcpy(a, rr->rrdata.txt_rec, txt_len);
722 return resp_size;
725 static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr,
726 uint8_t *answer,
727 size_t anslen)
729 uint8_t *a = answer;
730 ssize_t resp_size;
731 size_t rdata_size;
732 unsigned char nameser_compressed[MAXDNAME];
733 ssize_t compressed_ns_len;
734 unsigned char mailbox_compressed[MAXDNAME];
735 ssize_t compressed_mb_len;
737 if (rr->type != ns_t_soa) {
738 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
739 return -1;
741 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SOA RR");
742 rdata_size = 5 * sizeof(uint16_t);
744 compressed_ns_len = ns_name_compress(rr->rrdata.soa_rec.nameserver,
745 nameser_compressed,
746 MAXDNAME, NULL, NULL);
747 if (compressed_ns_len < 0) {
748 return -1;
750 rdata_size += compressed_ns_len;
752 compressed_mb_len = ns_name_compress(rr->rrdata.soa_rec.mailbox,
753 mailbox_compressed,
754 MAXDNAME, NULL, NULL);
755 if (compressed_mb_len < 0) {
756 return -1;
758 rdata_size += compressed_mb_len;
760 resp_size = rwrap_fake_rdata_common(ns_t_soa, rdata_size,
761 rr->key, anslen, &a);
762 if (resp_size < 0) {
763 return -1;
766 memcpy(a, nameser_compressed, compressed_ns_len);
767 a += compressed_ns_len;
768 memcpy(a, mailbox_compressed, compressed_mb_len);
769 a += compressed_mb_len;
770 NS_PUT32(rr->rrdata.soa_rec.serial, a);
771 NS_PUT32(rr->rrdata.soa_rec.refresh, a);
772 NS_PUT32(rr->rrdata.soa_rec.retry, a);
773 NS_PUT32(rr->rrdata.soa_rec.expire, a);
774 NS_PUT32(rr->rrdata.soa_rec.minimum, a);
776 return resp_size;
779 static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr,
780 uint8_t *answer,
781 size_t anslen)
783 uint8_t *a = answer;
784 ssize_t resp_size;
785 unsigned char hostname_compressed[MAXDNAME];
786 ssize_t rdata_size;
788 if (rr->type != ns_t_cname) {
789 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
790 return -1;
792 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding CNAME RR");
794 /* Prepare the data to write */
795 rdata_size = ns_name_compress(rr->rrdata.cname_rec,
796 hostname_compressed, MAXDNAME,
797 NULL, NULL);
798 if (rdata_size < 0) {
799 return -1;
802 resp_size = rwrap_fake_rdata_common(ns_t_cname, rdata_size,
803 rr->key, anslen, &a);
804 if (resp_size < 0) {
805 return -1;
808 memcpy(a, hostname_compressed, rdata_size);
810 return resp_size;
813 static ssize_t rwrap_fake_ptr(struct rwrap_fake_rr *rr,
814 uint8_t *answer,
815 size_t anslen)
817 uint8_t *a = answer;
818 ssize_t rdata_size;
819 ssize_t resp_size;
820 unsigned char hostname_compressed[MAXDNAME];
822 if (rr->type != ns_t_ptr) {
823 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
824 return -1;
826 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding PTR RR");
828 /* Prepare the data to write */
829 rdata_size = ns_name_compress(rr->rrdata.ptr_rec,
830 hostname_compressed, MAXDNAME,
831 NULL, NULL);
832 if (rdata_size < 0) {
833 return -1;
836 resp_size = rwrap_fake_rdata_common(ns_t_ptr, rdata_size,
837 rr->key, anslen, &a);
838 if (resp_size < 0) {
839 return -1;
842 memcpy(a, hostname_compressed, rdata_size);
844 return resp_size;
847 #define RESOLV_MATCH(line, name) \
848 (strncmp(line, name, sizeof(name) - 1) == 0 && \
849 (line[sizeof(name) - 1] == ' ' || \
850 line[sizeof(name) - 1] == '\t'))
852 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
853 ((type) == (ns_type) && \
854 (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
855 (strcasecmp(key, query)) == 0)
858 static int rwrap_get_record(const char *hostfile, unsigned recursion,
859 const char *query, int type,
860 struct rwrap_fake_rr *rr);
862 static int rwrap_uri_recurse(const char *hostfile, unsigned recursion,
863 const char *query, struct rwrap_fake_rr *rr)
865 int rc;
867 rc = rwrap_get_record(hostfile, recursion, query, ns_t_uri, rr);
868 if (rc == ENOENT) {
869 rc = 0;
872 return rc;
875 static int rwrap_srv_recurse(const char *hostfile, unsigned recursion,
876 const char *query, struct rwrap_fake_rr *rr)
878 int rc;
880 rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
881 if (rc == 0) return 0;
883 rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
884 if (rc == ENOENT) rc = 0;
886 return rc;
889 static int rwrap_cname_recurse(const char *hostfile, unsigned recursion,
890 const char *query, struct rwrap_fake_rr *rr)
892 int rc;
894 rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
895 if (rc == 0) return 0;
897 rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
898 if (rc == 0) return 0;
900 rc = rwrap_get_record(hostfile, recursion, query, ns_t_cname, rr);
901 if (rc == ENOENT) rc = 0;
903 return rc;
906 static int rwrap_get_record(const char *hostfile, unsigned recursion,
907 const char *query, int type,
908 struct rwrap_fake_rr *rr)
910 FILE *fp = NULL;
911 char buf[BUFSIZ];
912 char *key = NULL;
913 char *value = NULL;
914 int rc = ENOENT;
915 unsigned num_uris = 0;
917 if (recursion >= RWRAP_MAX_RECURSION) {
918 RWRAP_LOG(RWRAP_LOG_ERROR, "Recursed too deep!\n");
919 return -1;
922 RWRAP_LOG(RWRAP_LOG_TRACE,
923 "Searching in fake hosts file %s for %s:%d\n", hostfile,
924 query, type);
926 fp = fopen(hostfile, "r");
927 if (fp == NULL) {
928 RWRAP_LOG(RWRAP_LOG_WARN,
929 "Opening %s failed: %s",
930 hostfile, strerror(errno));
931 return -1;
934 while (fgets(buf, sizeof(buf), fp) != NULL) {
935 char *rec_type;
936 char *q;
938 rec_type = buf;
939 key = value = NULL;
941 NEXT_KEY(rec_type, key);
942 NEXT_KEY(key, value);
944 if (key == NULL || value == NULL) {
945 RWRAP_LOG(RWRAP_LOG_WARN,
946 "Malformed line: not enough parts, use \"rec_type key data\n"
947 "For example \"A cwrap.org 10.10.10.10\"");
948 continue;
951 q = value;
952 while(q[0] != '\n' && q[0] != '\0') {
953 q++;
955 q[0] = '\0';
957 if (type == ns_t_uri && recursion > 0) {
958 /* Skip non-URI records. */
959 if (!TYPE_MATCH(type, ns_t_uri, rec_type, "URI", key, query)) {
960 continue;
962 /* Skip previous records based on the recurse depth. */
963 num_uris++;
964 if (num_uris <= recursion) {
965 continue;
969 if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) {
970 rc = rwrap_create_fake_a_rr(key, value, rr);
971 break;
972 } else if (TYPE_MATCH(type, ns_t_aaaa,
973 rec_type, "AAAA", key, query)) {
974 rc = rwrap_create_fake_aaaa_rr(key, value, rr);
975 break;
976 } else if (TYPE_MATCH(type, ns_t_ns,
977 rec_type, "NS", key, query)) {
978 rc = rwrap_create_fake_ns_rr(key, value, rr);
979 break;
980 } else if (TYPE_MATCH(type, ns_t_srv,
981 rec_type, "SRV", key, query)) {
982 rc = rwrap_create_fake_srv_rr(key, value, rr);
983 if (rc == 0) {
984 rc = rwrap_srv_recurse(hostfile, recursion+1,
985 rr->rrdata.srv_rec.hostname,
986 rr + 1);
988 break;
989 } else if (TYPE_MATCH(type, ns_t_uri,
990 rec_type, "URI", key, query)) {
991 rc = rwrap_create_fake_uri_rr(key, value, rr);
992 if (rc == 0) {
993 /* Recurse to collect multiple URI answers under a single key. */
994 rc = rwrap_uri_recurse(hostfile, recursion + 1, key, rr + 1);
996 break;
997 } else if (TYPE_MATCH(type, ns_t_soa,
998 rec_type, "SOA", key, query)) {
999 rc = rwrap_create_fake_soa_rr(key, value, rr);
1000 break;
1001 } else if (TYPE_MATCH(type, ns_t_cname,
1002 rec_type, "CNAME", key, query)) {
1003 rc = rwrap_create_fake_cname_rr(key, value, rr);
1004 if (rc == 0) {
1005 rc = rwrap_cname_recurse(hostfile, recursion+1,
1006 value, rr + 1);
1008 break;
1009 } else if (TYPE_MATCH(type, ns_t_a, rec_type, "CNAME", key, query)) {
1010 rc = rwrap_create_fake_cname_rr(key, value, rr);
1011 if (rc == 0) {
1012 rc = rwrap_cname_recurse(hostfile, recursion+1,
1013 value, rr + 1);
1015 break;
1016 } else if (TYPE_MATCH(type, ns_t_ptr,
1017 rec_type, "PTR", key, query)) {
1018 rc = rwrap_create_fake_ptr_rr(key, value, rr);
1019 break;
1021 else if (TYPE_MATCH(type, ns_t_txt,
1022 rec_type, "TXT", key, query)) {
1023 rc = rwrap_create_fake_txt_rr(key, value, rr);
1024 break;
1028 if (rc == ENOENT && recursion == 0 && key != NULL) {
1029 RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query);
1030 memcpy(rr->key, key, strlen(key) + 1);
1033 fclose(fp);
1034 return rc;
1037 static ssize_t rwrap_fake_empty(int type,
1038 const char *question,
1039 uint8_t *answer,
1040 size_t anslen)
1042 ssize_t resp_data;
1043 size_t remaining = anslen;
1045 resp_data = rwrap_fake_header(&answer, remaining, 0, 0);
1046 if (resp_data < 0) {
1047 return -1;
1049 remaining -= resp_data;
1051 resp_data += rwrap_fake_question(question, type, &answer, remaining);
1052 if (resp_data < 0) {
1053 return -1;
1055 remaining -= resp_data;
1057 resp_data += rwrap_fake_rdata_common(type, 0, question,
1058 remaining, &answer);
1059 if (resp_data < 0) {
1060 return -1;
1063 return resp_data;
1066 static inline bool rwrap_known_type(int type)
1068 switch (type) {
1069 case ns_t_a:
1070 case ns_t_aaaa:
1071 case ns_t_ns:
1072 case ns_t_srv:
1073 case ns_t_uri:
1074 case ns_t_soa:
1075 case ns_t_cname:
1076 case ns_t_ptr:
1077 case ns_t_txt:
1078 return true;
1081 return false;
1084 static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype)
1086 int i;
1087 int ancount = 0;
1089 /* For URI return the number of URIs. */
1090 if (qtype == ns_t_uri) {
1091 for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1092 if (rwrap_known_type(rrs[i].type) &&
1093 rrs[i].type == qtype) {
1094 ancount++;
1097 return ancount;
1100 /* Include all RRs in the stack until the sought type
1101 * in the answer section. This is the case i.e. when looking
1102 * up an A record but the name points to a CNAME
1104 for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1105 ancount++;
1107 if (rwrap_known_type(rrs[i].type) &&
1108 rrs[i].type == qtype) {
1109 break;
1113 /* Return 0 records if the sought type wasn't in the stack */
1114 return i < RWRAP_MAX_RECURSION ? ancount : 0;
1117 static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount)
1119 int i;
1120 int arcount = 0;
1122 /* start from index ancount */
1123 for (i = ancount; i < RWRAP_MAX_RECURSION; i++) {
1124 if (rwrap_known_type(rrs[i].type)) {
1125 arcount++;
1129 return arcount;
1132 static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
1133 uint8_t *answer,
1134 size_t anslen)
1136 ssize_t resp_data;
1138 if (rr == NULL) {
1139 RWRAP_LOG(RWRAP_LOG_ERROR, "Internal error!\n");
1140 return -1;
1143 switch (rr->type) {
1144 case ns_t_a:
1145 resp_data = rwrap_fake_a(rr, answer, anslen);
1146 break;
1147 case ns_t_aaaa:
1148 resp_data = rwrap_fake_aaaa(rr, answer, anslen);
1149 break;
1150 case ns_t_ns:
1151 resp_data = rwrap_fake_ns(rr, answer, anslen);
1152 break;
1153 case ns_t_srv:
1154 resp_data = rwrap_fake_srv(rr, answer, anslen);
1155 break;
1156 case ns_t_uri:
1157 resp_data = rwrap_fake_uri(rr, answer, anslen);
1158 break;
1159 case ns_t_soa:
1160 resp_data = rwrap_fake_soa(rr, answer, anslen);
1161 break;
1162 case ns_t_cname:
1163 resp_data = rwrap_fake_cname(rr, answer, anslen);
1164 break;
1165 case ns_t_ptr:
1166 resp_data = rwrap_fake_ptr(rr, answer, anslen);
1167 break;
1168 case ns_t_txt:
1169 resp_data = rwrap_fake_txt(rr, answer, anslen);
1170 break;
1171 default:
1172 return -1;
1175 return resp_data;
1178 static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs,
1179 int type,
1180 uint8_t *answer,
1181 size_t anslen)
1184 ssize_t resp_data;
1185 ssize_t rrlen;
1186 size_t remaining = anslen;
1187 int ancount;
1188 int arcount;
1189 int i;
1191 ancount = rwrap_ancount(rrs, type);
1192 arcount = rwrap_arcount(rrs, ancount);
1193 RWRAP_LOG(RWRAP_LOG_TRACE,
1194 "Got %d answers and %d additional records\n", ancount, arcount);
1196 resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount);
1197 if (resp_data < 0) {
1198 return -1;
1200 remaining -= resp_data;
1202 resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining);
1203 if (resp_data < 0) {
1204 return -1;
1206 remaining -= resp_data;
1208 /* answer */
1209 for (i = 0; i < ancount; i++) {
1210 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1211 if (rrlen < 0) {
1212 return -1;
1214 remaining -= rrlen;
1215 answer += rrlen;
1216 resp_data += rrlen;
1219 /* add authoritative NS here? */
1221 /* additional records */
1222 for (i = ancount; i < ancount + arcount; i++) {
1223 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1224 if (rrlen < 0) {
1225 return -1;
1227 remaining -= rrlen;
1228 answer += rrlen;
1229 resp_data += rrlen;
1232 return resp_data;
1235 /* Reads in a file in the following format:
1236 * TYPE RDATA
1238 * Malformed entries are silently skipped.
1239 * Allocates answer buffer of size anslen that has to be freed after use.
1241 static int rwrap_res_fake_hosts(const char *hostfile,
1242 const char *query,
1243 int type,
1244 unsigned char *answer,
1245 size_t anslen)
1247 int rc = ENOENT;
1248 char *query_name = NULL;
1249 size_t qlen = strlen(query);
1250 struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION];
1251 ssize_t resp_size;
1253 RWRAP_LOG(RWRAP_LOG_TRACE,
1254 "Searching in fake hosts file %s\n", hostfile);
1256 if (qlen > 0 && query[qlen-1] == '.') {
1257 qlen--;
1260 query_name = strndup(query, qlen);
1261 if (query_name == NULL) {
1262 return -1;
1265 rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION);
1267 rc = rwrap_get_record(hostfile, 0, query_name, type, rrs);
1268 switch (rc) {
1269 case 0:
1270 RWRAP_LOG(RWRAP_LOG_TRACE,
1271 "Found record for [%s]\n", query_name);
1272 resp_size = rwrap_fake_answer(rrs, type, answer, anslen);
1273 break;
1274 case ENOENT:
1275 RWRAP_LOG(RWRAP_LOG_TRACE,
1276 "No record for [%s]\n", query_name);
1277 resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen);
1278 break;
1279 default:
1280 RWRAP_LOG(RWRAP_LOG_NOTICE,
1281 "Searching for [%s] did not return any results\n",
1282 query_name);
1283 free(query_name);
1284 return -1;
1287 switch (resp_size) {
1288 case -1:
1289 RWRAP_LOG(RWRAP_LOG_ERROR,
1290 "Error faking answer for [%s]\n", query_name);
1291 break;
1292 default:
1293 RWRAP_LOG(RWRAP_LOG_TRACE,
1294 "Successfully faked answer for [%s]\n",
1295 query_name);
1296 break;
1299 free(query_name);
1300 return resp_size;
1303 /*********************************************************
1304 * RWRAP LOADING LIBC FUNCTIONS
1305 *********************************************************/
1307 #include <dlfcn.h>
1309 typedef int (*__libc_res_ninit)(struct __res_state *state);
1310 typedef int (*__libc___res_ninit)(struct __res_state *state);
1311 typedef void (*__libc_res_nclose)(struct __res_state *state);
1312 typedef void (*__libc___res_nclose)(struct __res_state *state);
1313 typedef int (*__libc_res_nquery)(struct __res_state *state,
1314 const char *dname,
1315 int class,
1316 int type,
1317 unsigned char *answer,
1318 int anslen);
1319 typedef int (*__libc___res_nquery)(struct __res_state *state,
1320 const char *dname,
1321 int class,
1322 int type,
1323 unsigned char *answer,
1324 int anslen);
1325 typedef int (*__libc_res_nsearch)(struct __res_state *state,
1326 const char *dname,
1327 int class,
1328 int type,
1329 unsigned char *answer,
1330 int anslen);
1331 typedef int (*__libc___res_nsearch)(struct __res_state *state,
1332 const char *dname,
1333 int class,
1334 int type,
1335 unsigned char *answer,
1336 int anslen);
1338 #define RWRAP_SYMBOL_ENTRY(i) \
1339 union { \
1340 __libc_##i f; \
1341 void *obj; \
1342 } _libc_##i
1344 struct rwrap_libc_symbols {
1345 RWRAP_SYMBOL_ENTRY(res_ninit);
1346 RWRAP_SYMBOL_ENTRY(__res_ninit);
1347 RWRAP_SYMBOL_ENTRY(res_nclose);
1348 RWRAP_SYMBOL_ENTRY(__res_nclose);
1349 RWRAP_SYMBOL_ENTRY(res_nquery);
1350 RWRAP_SYMBOL_ENTRY(__res_nquery);
1351 RWRAP_SYMBOL_ENTRY(res_nsearch);
1352 RWRAP_SYMBOL_ENTRY(__res_nsearch);
1354 #undef RWRAP_SYMBOL_ENTRY
1356 struct rwrap {
1357 struct {
1358 void *handle;
1359 struct rwrap_libc_symbols symbols;
1360 } libc;
1362 struct {
1363 void *handle;
1364 struct rwrap_libc_symbols symbols;
1365 } libresolv;
1367 bool initialised;
1368 bool enabled;
1370 char *socket_dir;
1373 static struct rwrap rwrap;
1375 enum rwrap_lib {
1376 RWRAP_LIBC,
1377 RWRAP_LIBRESOLV
1380 static const char *rwrap_str_lib(enum rwrap_lib lib)
1382 switch (lib) {
1383 case RWRAP_LIBC:
1384 return "libc";
1385 case RWRAP_LIBRESOLV:
1386 return "libresolv";
1389 /* Compiler would warn us about unhandled enum value if we get here */
1390 return "unknown";
1393 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
1395 int flags = RTLD_LAZY;
1396 void *handle = NULL;
1397 int i;
1399 #ifdef RTLD_DEEPBIND
1400 const char *env_preload = getenv("LD_PRELOAD");
1401 const char *env_deepbind = getenv("RESOLV_WRAPPER_DISABLE_DEEPBIND");
1402 bool enable_deepbind = true;
1404 /* Don't do a deepbind if we run with libasan */
1405 if (env_preload != NULL && strlen(env_preload) < 1024) {
1406 const char *p = strstr(env_preload, "libasan.so");
1407 if (p != NULL) {
1408 enable_deepbind = false;
1412 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
1413 enable_deepbind = false;
1416 if (enable_deepbind) {
1417 flags |= RTLD_DEEPBIND;
1419 #endif
1421 switch (lib) {
1422 case RWRAP_LIBRESOLV:
1423 #ifdef HAVE_LIBRESOLV
1424 handle = rwrap.libresolv.handle;
1425 if (handle == NULL) {
1426 for (i = 10; i >= 0; i--) {
1427 char soname[256] = {0};
1429 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
1430 handle = dlopen(soname, flags);
1431 if (handle != NULL) {
1432 break;
1436 rwrap.libresolv.handle = handle;
1438 break;
1439 #endif
1440 /* FALL TROUGH */
1441 case RWRAP_LIBC:
1442 handle = rwrap.libc.handle;
1443 #ifdef LIBC_SO
1444 if (handle == NULL) {
1445 handle = dlopen(LIBC_SO, flags);
1447 rwrap.libc.handle = handle;
1449 #endif
1450 if (handle == NULL) {
1451 for (i = 10; i >= 0; i--) {
1452 char soname[256] = {0};
1454 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1455 handle = dlopen(soname, flags);
1456 if (handle != NULL) {
1457 break;
1461 rwrap.libc.handle = handle;
1463 break;
1466 if (handle == NULL) {
1467 #ifdef RTLD_NEXT
1468 handle = rwrap.libc.handle = rwrap.libresolv.handle = RTLD_NEXT;
1469 #else
1470 RWRAP_LOG(RWRAP_LOG_ERROR,
1471 "Failed to dlopen library: %s\n",
1472 dlerror());
1473 exit(-1);
1474 #endif
1477 return handle;
1480 static void *_rwrap_bind_symbol(enum rwrap_lib lib, const char *fn_name)
1482 void *handle;
1483 void *func;
1485 handle = rwrap_load_lib_handle(lib);
1487 func = dlsym(handle, fn_name);
1488 if (func == NULL) {
1489 RWRAP_LOG(RWRAP_LOG_ERROR,
1490 "Failed to find %s: %s\n",
1491 fn_name, dlerror());
1492 exit(-1);
1495 RWRAP_LOG(RWRAP_LOG_TRACE,
1496 "Loaded %s from %s",
1497 fn_name, rwrap_str_lib(lib));
1498 return func;
1501 #define rwrap_bind_symbol_libc(sym_name) \
1502 if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
1503 rwrap.libc.symbols._libc_##sym_name.obj = \
1504 _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
1507 #define rwrap_bind_symbol_libresolv(sym_name) \
1508 if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
1509 rwrap.libresolv.symbols._libc_##sym_name.obj = \
1510 _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
1514 * IMPORTANT
1516 * Functions especially from libc need to be loaded individually, you can't load
1517 * all at once or gdb will segfault at startup. The same applies to valgrind and
1518 * has probably something todo with with the linker.
1519 * So we need load each function at the point it is called the first time.
1522 static int libc_res_ninit(struct __res_state *state)
1524 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1525 rwrap_bind_symbol_libresolv(res_ninit);
1527 return rwrap.libresolv.symbols._libc_res_ninit.f(state);
1528 #elif defined(HAVE___RES_NINIT)
1529 rwrap_bind_symbol_libresolv(__res_ninit);
1531 return rwrap.libresolv.symbols._libc___res_ninit.f(state);
1532 #else
1533 #error "No res_ninit function"
1534 #endif
1537 static void libc_res_nclose(struct __res_state *state)
1539 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1540 rwrap_bind_symbol_libresolv(res_nclose);
1542 rwrap.libresolv.symbols._libc_res_nclose.f(state);
1543 return;
1544 #elif defined(HAVE___RES_NCLOSE)
1545 rwrap_bind_symbol_libresolv(__res_nclose);
1547 rwrap.libresolv.symbols._libc___res_nclose.f(state);
1548 #else
1549 #error "No res_nclose function"
1550 #endif
1553 static int libc_res_nquery(struct __res_state *state,
1554 const char *dname,
1555 int class,
1556 int type,
1557 unsigned char *answer,
1558 int anslen)
1560 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1561 rwrap_bind_symbol_libresolv(res_nquery);
1563 return rwrap.libresolv.symbols._libc_res_nquery.f(state,
1564 dname,
1565 class,
1566 type,
1567 answer,
1568 anslen);
1569 #elif defined(HAVE___RES_NQUERY)
1570 rwrap_bind_symbol_libresolv(__res_nquery);
1572 return rwrap.libresolv.symbols._libc___res_nquery.f(state,
1573 dname,
1574 class,
1575 type,
1576 answer,
1577 anslen);
1578 #else
1579 #error "No res_nquery function"
1580 #endif
1583 static int libc_res_nsearch(struct __res_state *state,
1584 const char *dname,
1585 int class,
1586 int type,
1587 unsigned char *answer,
1588 int anslen)
1590 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1591 rwrap_bind_symbol_libresolv(res_nsearch);
1593 return rwrap.libresolv.symbols._libc_res_nsearch.f(state,
1594 dname,
1595 class,
1596 type,
1597 answer,
1598 anslen);
1599 #elif defined(HAVE___RES_NSEARCH)
1600 rwrap_bind_symbol_libresolv(__res_nsearch);
1602 return rwrap.libresolv.symbols._libc___res_nsearch.f(state,
1603 dname,
1604 class,
1605 type,
1606 answer,
1607 anslen);
1608 #else
1609 #error "No res_nsearch function"
1610 #endif
1613 /****************************************************************************
1614 * RES_HELPER
1615 ***************************************************************************/
1617 static size_t rwrap_get_nameservers(struct __res_state *state,
1618 size_t nserv,
1619 union rwrap_sockaddr *nsaddrs)
1621 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1622 union res_sockaddr_union set[MAXNS];
1623 size_t i;
1624 int rc;
1626 memset(set, 0, sizeof(set));
1627 memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1629 if (nserv > MAXNS) {
1630 nserv = MAXNS;
1633 rc = res_getservers(state, set, nserv);
1634 if (rc <= 0) {
1635 return 0;
1637 if (rc < nserv) {
1638 nserv = rc;
1641 for (i = 0; i < nserv; i++) {
1642 switch (set[i].sin.sin_family) {
1643 case AF_INET:
1644 nsaddrs[i] = (union rwrap_sockaddr) {
1645 .in = set[i].sin,
1647 break;
1648 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1649 case AF_INET6:
1650 nsaddrs[i] = (union rwrap_sockaddr) {
1651 .in6 = set[i].sin6,
1653 break;
1654 #endif
1658 return nserv;
1659 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1660 size_t i;
1662 memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1664 if (nserv > (size_t)state->nscount) {
1665 nserv = (size_t)state->nscount;
1668 for (i = 0; i < nserv; i++) {
1669 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1670 if (state->_u._ext.nsaddrs[i] != NULL) {
1671 nsaddrs[i] = (union rwrap_sockaddr) {
1672 .in6 = *state->_u._ext.nsaddrs[i],
1674 } else
1675 #endif /* HAVE_RES_STATE_U_EXT_NSADDRS */
1677 nsaddrs[i] = (union rwrap_sockaddr) {
1678 .in = state->nsaddr_list[i],
1683 return nserv;
1684 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1687 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl,
1688 const char *func,
1689 struct __res_state *state)
1691 union rwrap_sockaddr nsaddrs[MAXNS];
1692 size_t nserv = MAXNS;
1693 size_t i;
1695 memset(nsaddrs, 0, sizeof(nsaddrs));
1696 nserv = rwrap_get_nameservers(state, nserv, nsaddrs);
1697 for (i = 0; i < nserv; i++) {
1698 char ip[INET6_ADDRSTRLEN];
1700 switch (nsaddrs[i].sa.sa_family) {
1701 case AF_INET:
1702 inet_ntop(AF_INET, &(nsaddrs[i].in.sin_addr),
1703 ip, sizeof(ip));
1704 break;
1705 case AF_INET6:
1706 inet_ntop(AF_INET6, &(nsaddrs[i].in6.sin6_addr),
1707 ip, sizeof(ip));
1708 break;
1709 default:
1710 snprintf(ip, sizeof(ip), "<unknown sa_family=%d",
1711 nsaddrs[i].sa.sa_family);
1712 break;
1715 rwrap_log(dbglvl, func,
1716 " nameserver: %s",
1717 ip);
1721 static void rwrap_reset_nameservers(struct __res_state *state)
1723 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1724 res_setservers(state, NULL, 0);
1725 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1726 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1727 size_t i;
1729 for (i = 0; i < (size_t)state->nscount; i++) {
1730 if (state->_u._ext.nssocks[i] != -1) {
1731 close(state->_u._ext.nssocks[i]);
1732 state->_u._ext.nssocks[i] = -1;
1734 SAFE_FREE(state->_u._ext.nsaddrs[i]);
1736 memset(&state->_u._ext, 0, sizeof(state->_u._ext));
1737 for (i = 0; i < MAXNS; i++) {
1738 state->_u._ext.nssocks[i] = -1;
1739 state->_u._ext.nsmap[i] = MAXNS + 1;
1741 state->ipv6_unavail = false;
1742 #endif
1743 memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1744 state->nscount = 0;
1745 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1748 static int rwrap_set_nameservers(struct __res_state *state,
1749 size_t nserv,
1750 const union rwrap_sockaddr *nsaddrs)
1752 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1753 union res_sockaddr_union set[MAXNS];
1754 size_t i;
1756 memset(set, 0, sizeof(set));
1758 if (nserv > MAXNS) {
1759 nserv = MAXNS;
1762 rwrap_reset_nameservers(state);
1764 for (i = 0; i < nserv; i++) {
1765 switch (nsaddrs[i].sa.sa_family) {
1766 case AF_INET:
1767 set[i] = (union res_sockaddr_union) {
1768 .sin = nsaddrs[i].in,
1770 break;
1771 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1772 case AF_INET6:
1773 set[i] = (union res_sockaddr_union) {
1774 .sin6 = nsaddrs[i].in6,
1776 break;
1777 #endif
1778 default:
1779 RWRAP_LOG(RWRAP_LOG_ERROR,
1780 "Internal error unhandled sa_family=%d",
1781 nsaddrs[i].sa.sa_family);
1782 errno = ENOSYS;
1783 return -1;
1787 res_setservers(state, set, nserv);
1788 return 0;
1789 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1790 size_t i;
1792 if (nserv > MAXNS) {
1793 nserv = MAXNS;
1795 rwrap_reset_nameservers(state);
1797 for (i = 0; i < nserv; i++) {
1798 switch (nsaddrs[i].sa.sa_family) {
1799 case AF_INET:
1800 state->nsaddr_list[i] = nsaddrs[i].in;
1801 break;
1802 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1803 case AF_INET6:
1804 state->_u._ext.nsaddrs[i] = malloc(sizeof(nsaddrs[i].in6));
1805 if (state->_u._ext.nsaddrs[i] == NULL) {
1806 rwrap_reset_nameservers(state);
1807 errno = ENOMEM;
1808 return -1;
1810 *state->_u._ext.nsaddrs[i] = nsaddrs[i].in6;
1811 state->_u._ext.nssocks[i] = -1;
1812 state->_u._ext.nsmap[i] = MAXNS + 1;
1813 state->_u._ext.nscount6++;
1814 break;
1815 #endif
1816 default:
1817 RWRAP_LOG(RWRAP_LOG_ERROR,
1818 "Internal error unhandled sa_family=%d",
1819 nsaddrs[i].sa.sa_family);
1820 rwrap_reset_nameservers(state);
1821 errno = ENOSYS;
1822 return -1;
1827 * note that state->_u._ext.nscount is left as 0,
1828 * this matches glibc and allows resolv wrapper
1829 * to work with most (maybe all) glibc versions.
1831 state->nscount = i;
1833 return 0;
1834 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1837 static int rwrap_parse_resolv_conf(struct __res_state *state,
1838 const char *resolv_conf)
1840 FILE *fp;
1841 char buf[BUFSIZ];
1842 size_t nserv = 0;
1843 union rwrap_sockaddr nsaddrs[MAXNS];
1845 memset(nsaddrs, 0, sizeof(nsaddrs));
1847 fp = fopen(resolv_conf, "r");
1848 if (fp == NULL) {
1849 RWRAP_LOG(RWRAP_LOG_WARN,
1850 "Opening %s failed: %s",
1851 resolv_conf, strerror(errno));
1852 return -1;
1855 while(fgets(buf, sizeof(buf), fp) != NULL) {
1856 char *p;
1858 /* Ignore comments */
1859 if (buf[0] == '#' || buf[0] == ';') {
1860 continue;
1863 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
1864 struct in_addr a;
1865 struct in6_addr a6;
1866 char *q;
1867 int ok;
1869 p = buf + strlen("nameserver");
1871 /* Skip spaces and tabs */
1872 while(isblank((int)p[0])) {
1873 p++;
1876 q = p;
1877 while(q[0] != '\n' && q[0] != '\0') {
1878 q++;
1880 q[0] = '\0';
1882 ok = inet_pton(AF_INET, p, &a);
1883 if (ok) {
1884 nsaddrs[nserv] = (union rwrap_sockaddr) {
1885 .in = {
1886 .sin_family = AF_INET,
1887 .sin_addr = a,
1888 .sin_port = htons(53),
1889 .sin_zero = { 0 },
1893 nserv++;
1894 continue;
1897 ok = inet_pton(AF_INET6, p, &a6);
1898 if (ok) {
1899 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1900 nsaddrs[nserv] = (union rwrap_sockaddr) {
1901 .in6 = {
1903 .sin6_family = AF_INET6,
1904 .sin6_port = htons(53),
1905 .sin6_flowinfo = 0,
1906 .sin6_addr = a6,
1909 nserv++;
1910 continue;
1911 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1912 RWRAP_LOG(RWRAP_LOG_WARN,
1913 "resolve_wrapper does not support "
1914 "IPv6 on this platform");
1915 continue;
1916 #endif
1919 RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed DNS server[%s]", p);
1920 continue;
1921 } /* TODO: match other keywords */
1924 if (ferror(fp)) {
1925 RWRAP_LOG(RWRAP_LOG_ERROR,
1926 "Reading from %s failed",
1927 resolv_conf);
1928 fclose(fp);
1929 return -1;
1932 fclose(fp);
1934 if (nserv == 0) {
1935 RWRAP_LOG(RWRAP_LOG_WARN,
1936 "No usable nameservers found in %s",
1937 resolv_conf);
1938 errno = ESRCH;
1939 return -1;
1942 return rwrap_set_nameservers(state, nserv, nsaddrs);
1945 /****************************************************************************
1946 * RES_NINIT
1947 ***************************************************************************/
1949 static int rwrap_res_ninit(struct __res_state *state)
1951 int rc;
1953 rc = libc_res_ninit(state);
1954 if (rc == 0) {
1955 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1957 if (resolv_conf != NULL) {
1958 rc = rwrap_parse_resolv_conf(state, resolv_conf);
1962 return rc;
1965 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1966 int res_ninit(struct __res_state *state)
1967 #elif defined(HAVE___RES_NINIT)
1968 int __res_ninit(struct __res_state *state)
1969 #endif
1971 return rwrap_res_ninit(state);
1974 /****************************************************************************
1975 * RES_INIT
1976 ***************************************************************************/
1978 static struct __res_state rwrap_res_state;
1980 static int rwrap_res_init(void)
1982 int rc;
1984 rc = rwrap_res_ninit(&rwrap_res_state);
1986 return rc;
1989 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1990 int res_init(void)
1991 #elif defined(HAVE___RES_INIT)
1992 int __res_init(void)
1993 #endif
1995 return rwrap_res_init();
1998 /****************************************************************************
1999 * RES_NCLOSE
2000 ***************************************************************************/
2002 static void rwrap_res_nclose(struct __res_state *state)
2004 rwrap_reset_nameservers(state);
2005 libc_res_nclose(state);
2008 #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
2009 void res_nclose(struct __res_state *state)
2010 #elif defined(HAVE___RES_NCLOSE)
2011 void __res_nclose(struct __res_state *state)
2012 #endif
2014 rwrap_res_nclose(state);
2017 /****************************************************************************
2018 * RES_CLOSE
2019 ***************************************************************************/
2021 static void rwrap_res_close(void)
2023 rwrap_res_nclose(&rwrap_res_state);
2026 #if defined(HAVE_RES_CLOSE)
2027 void res_close(void)
2028 #elif defined(HAVE___RES_CLOSE)
2029 void __res_close(void)
2030 #endif
2032 rwrap_res_close();
2035 /****************************************************************************
2036 * RES_NQUERY
2037 ***************************************************************************/
2039 static int rwrap_res_nquery(struct __res_state *state,
2040 const char *dname,
2041 int class,
2042 int type,
2043 unsigned char *answer,
2044 int anslen)
2046 int rc;
2047 const char *fake_hosts;
2049 RWRAP_LOG(RWRAP_LOG_TRACE,
2050 "Resolve the domain name [%s] - class=%d, type=%d",
2051 dname, class, type);
2052 rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2054 fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2055 if (fake_hosts != NULL) {
2056 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2057 } else {
2058 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
2062 RWRAP_LOG(RWRAP_LOG_TRACE,
2063 "The returned response length is: %d",
2064 rc);
2066 return rc;
2069 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
2070 int res_nquery(struct __res_state *state,
2071 const char *dname,
2072 int class,
2073 int type,
2074 unsigned char *answer,
2075 int anslen)
2076 #elif defined(HAVE___RES_NQUERY)
2077 int __res_nquery(struct __res_state *state,
2078 const char *dname,
2079 int class,
2080 int type,
2081 unsigned char *answer,
2082 int anslen)
2083 #endif
2085 return rwrap_res_nquery(state, dname, class, type, answer, anslen);
2088 /****************************************************************************
2089 * RES_QUERY
2090 ***************************************************************************/
2092 static int rwrap_res_query(const char *dname,
2093 int class,
2094 int type,
2095 unsigned char *answer,
2096 int anslen)
2098 int rc;
2100 rc = rwrap_res_ninit(&rwrap_res_state);
2101 if (rc != 0) {
2102 return rc;
2105 rc = rwrap_res_nquery(&rwrap_res_state,
2106 dname,
2107 class,
2108 type,
2109 answer,
2110 anslen);
2112 return rc;
2115 #if !defined(res_query) && defined(HAVE_RES_QUERY)
2116 int res_query(const char *dname,
2117 int class,
2118 int type,
2119 unsigned char *answer,
2120 int anslen)
2121 #elif defined(HAVE___RES_QUERY)
2122 int __res_query(const char *dname,
2123 int class,
2124 int type,
2125 unsigned char *answer,
2126 int anslen)
2127 #endif
2129 return rwrap_res_query(dname, class, type, answer, anslen);
2132 /****************************************************************************
2133 * RES_NSEARCH
2134 ***************************************************************************/
2136 static int rwrap_res_nsearch(struct __res_state *state,
2137 const char *dname,
2138 int class,
2139 int type,
2140 unsigned char *answer,
2141 int anslen)
2143 int rc;
2144 const char *fake_hosts;
2146 RWRAP_LOG(RWRAP_LOG_TRACE,
2147 "Resolve the domain name [%s] - class=%d, type=%d",
2148 dname, class, type);
2149 rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2151 fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2152 if (fake_hosts != NULL) {
2153 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2154 } else {
2155 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
2158 RWRAP_LOG(RWRAP_LOG_TRACE,
2159 "The returned response length is: %d",
2160 rc);
2162 return rc;
2165 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
2166 int res_nsearch(struct __res_state *state,
2167 const char *dname,
2168 int class,
2169 int type,
2170 unsigned char *answer,
2171 int anslen)
2172 #elif defined(HAVE___RES_NSEARCH)
2173 int __res_nsearch(struct __res_state *state,
2174 const char *dname,
2175 int class,
2176 int type,
2177 unsigned char *answer,
2178 int anslen)
2179 #endif
2181 return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
2184 /****************************************************************************
2185 * RES_SEARCH
2186 ***************************************************************************/
2188 static int rwrap_res_search(const char *dname,
2189 int class,
2190 int type,
2191 unsigned char *answer,
2192 int anslen)
2194 int rc;
2196 rc = rwrap_res_ninit(&rwrap_res_state);
2197 if (rc != 0) {
2198 return rc;
2201 rc = rwrap_res_nsearch(&rwrap_res_state,
2202 dname,
2203 class,
2204 type,
2205 answer,
2206 anslen);
2208 return rc;
2211 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
2212 int res_search(const char *dname,
2213 int class,
2214 int type,
2215 unsigned char *answer,
2216 int anslen)
2217 #elif defined(HAVE___RES_SEARCH)
2218 int __res_search(const char *dname,
2219 int class,
2220 int type,
2221 unsigned char *answer,
2222 int anslen)
2223 #endif
2225 return rwrap_res_search(dname, class, type, answer, anslen);