gnutls: allow gnutls_aead_cipher_encryptv2 with gcm before 3.6.15
[Samba.git] / third_party / resolv_wrapper / resolv_wrapper.c
blobb69a55a80e0c437e1ed2b2e7c5c6480a64d57bf6
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 /* Prepares a fake header with a single response. Advances header_blob */
438 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
439 size_t ancount, size_t arcount)
441 union {
442 uint8_t *blob;
443 HEADER *header;
444 } h;
446 if (remaining < NS_HFIXEDSZ) {
447 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
448 return -1;
451 h.blob = *header_blob;
452 memset(h.blob, 0, NS_HFIXEDSZ);
454 h.header->id = res_randomid(); /* random query ID */
455 h.header->qr = 1; /* response flag */
456 h.header->rd = 1; /* recursion desired */
457 h.header->ra = 1; /* recursion available */
459 h.header->qdcount = htons(1); /* no. of questions */
460 h.header->ancount = htons(ancount); /* no. of answers */
461 h.header->arcount = htons(arcount); /* no. of add'tl records */
463 /* move past the header */
464 *header_blob = h.blob += NS_HFIXEDSZ;
466 return NS_HFIXEDSZ;
469 static ssize_t rwrap_fake_question(const char *question,
470 uint16_t type,
471 uint8_t **question_ptr,
472 size_t remaining)
474 uint8_t *qb = *question_ptr;
475 int n;
477 n = ns_name_compress(question, qb, remaining, NULL, NULL);
478 if (n < 0) {
479 RWRAP_LOG(RWRAP_LOG_ERROR,
480 "Failed to compress [%s]\n", question);
481 return -1;
484 qb += n;
485 remaining -= n;
487 if (remaining < 2 * sizeof(uint16_t)) {
488 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
489 return -1;
492 NS_PUT16(type, qb);
493 NS_PUT16(ns_c_in, qb);
495 *question_ptr = qb;
496 return n + 2 * sizeof(uint16_t);
499 static ssize_t rwrap_fake_rdata_common(uint16_t type,
500 size_t rdata_size,
501 const char *key,
502 size_t remaining,
503 uint8_t **rdata_ptr)
505 uint8_t *rd = *rdata_ptr;
506 ssize_t written = 0;
508 written = ns_name_compress(key, rd, remaining, NULL, NULL);
509 if (written < 0) {
510 RWRAP_LOG(RWRAP_LOG_ERROR,
511 "Failed to compress [%s]\n", key);
512 return -1;
514 rd += written;
515 remaining -= written;
517 if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
518 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
519 return -1;
522 NS_PUT16(type, rd);
523 NS_PUT16(ns_c_in, rd);
524 NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd);
525 NS_PUT16(rdata_size, rd);
527 if (remaining < rdata_size) {
528 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
529 return -1;
532 *rdata_ptr = rd;
533 return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size;
536 static ssize_t rwrap_fake_a(struct rwrap_fake_rr *rr,
537 uint8_t *answer_ptr,
538 size_t anslen)
540 uint8_t *a = answer_ptr;
541 ssize_t resp_size;
543 if (rr->type != ns_t_a) {
544 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
545 return -1;
547 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding A RR");
549 resp_size = rwrap_fake_rdata_common(ns_t_a, sizeof(struct in_addr), rr->key,
550 anslen, &a);
551 if (resp_size < 0) {
552 return -1;
555 memcpy(a, &rr->rrdata.a_rec, sizeof(struct in_addr));
557 return resp_size;
560 static ssize_t rwrap_fake_aaaa(struct rwrap_fake_rr *rr,
561 uint8_t *answer,
562 size_t anslen)
564 uint8_t *a = answer;
565 ssize_t resp_size;
567 if (rr->type != ns_t_aaaa) {
568 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
569 return -1;
571 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding AAAA RR");
573 resp_size = rwrap_fake_rdata_common(ns_t_aaaa, sizeof(struct in6_addr),
574 rr->key, anslen, &a);
575 if (resp_size < 0) {
576 return -1;
579 memcpy(a, &rr->rrdata.aaaa_rec, sizeof(struct in6_addr));
581 return resp_size;
584 static ssize_t rwrap_fake_ns(struct rwrap_fake_rr *rr,
585 uint8_t *answer,
586 size_t anslen)
588 uint8_t *a = answer;
589 ssize_t resp_size = 0;
590 size_t rdata_size;
591 unsigned char hostname_compressed[MAXDNAME];
592 ssize_t compressed_len;
594 if (rr->type != ns_t_ns) {
595 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
596 return -1;
598 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding NS RR");
600 /* Prepare the data to write */
601 compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
602 hostname_compressed,
603 MAXDNAME,
604 NULL,
605 NULL);
606 if (compressed_len < 0) {
607 return -1;
610 /* Is this enough? */
611 rdata_size = compressed_len;
613 resp_size = rwrap_fake_rdata_common(ns_t_ns, rdata_size,
614 rr->key, anslen, &a);
615 if (resp_size < 0) {
616 return -1;
619 memcpy(a, hostname_compressed, compressed_len);
621 return resp_size;
624 static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr,
625 uint8_t *answer,
626 size_t anslen)
628 uint8_t *a = answer;
629 ssize_t resp_size;
630 size_t rdata_size;
631 unsigned char hostname_compressed[MAXDNAME];
632 ssize_t compressed_len;
634 if (rr->type != ns_t_srv) {
635 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
636 return -1;
638 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SRV RR");
639 rdata_size = 3 * sizeof(uint16_t);
641 /* Prepare the data to write */
642 compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
643 hostname_compressed, MAXDNAME,
644 NULL, NULL);
645 if (compressed_len < 0) {
646 return -1;
648 rdata_size += compressed_len;
650 resp_size = rwrap_fake_rdata_common(ns_t_srv, rdata_size,
651 rr->key, anslen, &a);
652 if (resp_size < 0) {
653 return -1;
656 NS_PUT16(rr->rrdata.srv_rec.prio, a);
657 NS_PUT16(rr->rrdata.srv_rec.weight, a);
658 NS_PUT16(rr->rrdata.srv_rec.port, a);
659 memcpy(a, hostname_compressed, compressed_len);
661 return resp_size;
664 static ssize_t rwrap_fake_uri(struct rwrap_fake_rr *rr,
665 uint8_t *answer,
666 size_t anslen)
668 uint8_t *a = answer;
669 ssize_t resp_size;
670 size_t rdata_size;
671 size_t uri_len;
673 if (rr->type != ns_t_uri) {
674 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
675 return -1;
677 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding URI RR");
678 rdata_size = 3 * sizeof(uint16_t);
679 uri_len = strlen(rr->rrdata.uri_rec.uri) + 1;
680 rdata_size += uri_len;
682 resp_size = rwrap_fake_rdata_common(ns_t_uri, rdata_size,
683 rr->key, anslen, &a);
684 if (resp_size < 0) {
685 return -1;
688 NS_PUT16(rr->rrdata.uri_rec.prio, a);
689 NS_PUT16(rr->rrdata.uri_rec.weight, a);
690 memcpy(a, rr->rrdata.uri_rec.uri, uri_len);
692 return resp_size;
695 static ssize_t rwrap_fake_txt(struct rwrap_fake_rr *rr,
696 uint8_t *answer,
697 size_t anslen)
699 uint8_t *a = answer;
700 ssize_t resp_size;
701 size_t rdata_size;
702 size_t txt_len;
704 if (rr->type != ns_t_txt) {
705 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
706 return -1;
708 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding TXT RR");
709 txt_len = strlen(rr->rrdata.txt_rec) + 1;
710 rdata_size = txt_len;
712 resp_size = rwrap_fake_rdata_common(ns_t_txt, rdata_size,
713 rr->key, anslen, &a);
714 if (resp_size < 0) {
715 return -1;
718 memcpy(a, rr->rrdata.txt_rec, txt_len);
720 return resp_size;
723 static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr,
724 uint8_t *answer,
725 size_t anslen)
727 uint8_t *a = answer;
728 ssize_t resp_size;
729 size_t rdata_size;
730 unsigned char nameser_compressed[MAXDNAME];
731 ssize_t compressed_ns_len;
732 unsigned char mailbox_compressed[MAXDNAME];
733 ssize_t compressed_mb_len;
735 if (rr->type != ns_t_soa) {
736 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
737 return -1;
739 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SOA RR");
740 rdata_size = 5 * sizeof(uint16_t);
742 compressed_ns_len = ns_name_compress(rr->rrdata.soa_rec.nameserver,
743 nameser_compressed,
744 MAXDNAME, NULL, NULL);
745 if (compressed_ns_len < 0) {
746 return -1;
748 rdata_size += compressed_ns_len;
750 compressed_mb_len = ns_name_compress(rr->rrdata.soa_rec.mailbox,
751 mailbox_compressed,
752 MAXDNAME, NULL, NULL);
753 if (compressed_mb_len < 0) {
754 return -1;
756 rdata_size += compressed_mb_len;
758 resp_size = rwrap_fake_rdata_common(ns_t_soa, rdata_size,
759 rr->key, anslen, &a);
760 if (resp_size < 0) {
761 return -1;
764 memcpy(a, nameser_compressed, compressed_ns_len);
765 a += compressed_ns_len;
766 memcpy(a, mailbox_compressed, compressed_mb_len);
767 a += compressed_mb_len;
768 NS_PUT32(rr->rrdata.soa_rec.serial, a);
769 NS_PUT32(rr->rrdata.soa_rec.refresh, a);
770 NS_PUT32(rr->rrdata.soa_rec.retry, a);
771 NS_PUT32(rr->rrdata.soa_rec.expire, a);
772 NS_PUT32(rr->rrdata.soa_rec.minimum, a);
774 return resp_size;
777 static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr,
778 uint8_t *answer,
779 size_t anslen)
781 uint8_t *a = answer;
782 ssize_t resp_size;
783 unsigned char hostname_compressed[MAXDNAME];
784 ssize_t rdata_size;
786 if (rr->type != ns_t_cname) {
787 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
788 return -1;
790 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding CNAME RR");
792 /* Prepare the data to write */
793 rdata_size = ns_name_compress(rr->rrdata.cname_rec,
794 hostname_compressed, MAXDNAME,
795 NULL, NULL);
796 if (rdata_size < 0) {
797 return -1;
800 resp_size = rwrap_fake_rdata_common(ns_t_cname, rdata_size,
801 rr->key, anslen, &a);
802 if (resp_size < 0) {
803 return -1;
806 memcpy(a, hostname_compressed, rdata_size);
808 return resp_size;
811 static ssize_t rwrap_fake_ptr(struct rwrap_fake_rr *rr,
812 uint8_t *answer,
813 size_t anslen)
815 uint8_t *a = answer;
816 ssize_t rdata_size;
817 ssize_t resp_size;
818 unsigned char hostname_compressed[MAXDNAME];
820 if (rr->type != ns_t_ptr) {
821 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
822 return -1;
824 RWRAP_LOG(RWRAP_LOG_TRACE, "Adding PTR RR");
826 /* Prepare the data to write */
827 rdata_size = ns_name_compress(rr->rrdata.ptr_rec,
828 hostname_compressed, MAXDNAME,
829 NULL, NULL);
830 if (rdata_size < 0) {
831 return -1;
834 resp_size = rwrap_fake_rdata_common(ns_t_ptr, rdata_size,
835 rr->key, anslen, &a);
836 if (resp_size < 0) {
837 return -1;
840 memcpy(a, hostname_compressed, rdata_size);
842 return resp_size;
845 #define RESOLV_MATCH(line, name) \
846 (strncmp(line, name, sizeof(name) - 1) == 0 && \
847 (line[sizeof(name) - 1] == ' ' || \
848 line[sizeof(name) - 1] == '\t'))
850 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
851 ((type) == (ns_type) && \
852 (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
853 (strcasecmp(key, query)) == 0)
856 static int rwrap_get_record(const char *hostfile, unsigned recursion,
857 const char *query, int type,
858 struct rwrap_fake_rr *rr);
860 static int rwrap_uri_recurse(const char *hostfile, unsigned recursion,
861 const char *query, struct rwrap_fake_rr *rr)
863 int rc;
865 rc = rwrap_get_record(hostfile, recursion, query, ns_t_uri, rr);
866 if (rc == ENOENT) {
867 rc = 0;
870 return rc;
873 static int rwrap_srv_recurse(const char *hostfile, unsigned recursion,
874 const char *query, struct rwrap_fake_rr *rr)
876 int rc;
878 rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
879 if (rc == 0) return 0;
881 rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
882 if (rc == ENOENT) rc = 0;
884 return rc;
887 static int rwrap_cname_recurse(const char *hostfile, unsigned recursion,
888 const char *query, struct rwrap_fake_rr *rr)
890 int rc;
892 rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
893 if (rc == 0) return 0;
895 rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
896 if (rc == 0) return 0;
898 rc = rwrap_get_record(hostfile, recursion, query, ns_t_cname, rr);
899 if (rc == ENOENT) rc = 0;
901 return rc;
904 static int rwrap_get_record(const char *hostfile, unsigned recursion,
905 const char *query, int type,
906 struct rwrap_fake_rr *rr)
908 FILE *fp = NULL;
909 char buf[BUFSIZ];
910 char *key = NULL;
911 char *value = NULL;
912 int rc = ENOENT;
913 unsigned num_uris = 0;
915 if (recursion >= RWRAP_MAX_RECURSION) {
916 RWRAP_LOG(RWRAP_LOG_ERROR, "Recursed too deep!\n");
917 return -1;
920 RWRAP_LOG(RWRAP_LOG_TRACE,
921 "Searching in fake hosts file %s for %s:%d\n", hostfile,
922 query, type);
924 fp = fopen(hostfile, "r");
925 if (fp == NULL) {
926 RWRAP_LOG(RWRAP_LOG_WARN,
927 "Opening %s failed: %s",
928 hostfile, strerror(errno));
929 return -1;
932 while (fgets(buf, sizeof(buf), fp) != NULL) {
933 char *rec_type;
934 char *q;
936 rec_type = buf;
937 key = value = NULL;
939 NEXT_KEY(rec_type, key);
940 NEXT_KEY(key, value);
942 if (key == NULL || value == NULL) {
943 RWRAP_LOG(RWRAP_LOG_WARN,
944 "Malformed line: not enough parts, use \"rec_type key data\n"
945 "For example \"A cwrap.org 10.10.10.10\"");
946 continue;
949 q = value;
950 while(q[0] != '\n' && q[0] != '\0') {
951 q++;
953 q[0] = '\0';
955 if (type == ns_t_uri && recursion > 0) {
956 /* Skip non-URI records. */
957 if (!TYPE_MATCH(type, ns_t_uri, rec_type, "URI", key, query)) {
958 continue;
960 /* Skip previous records based on the recurse depth. */
961 num_uris++;
962 if (num_uris <= recursion) {
963 continue;
967 if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) {
968 rc = rwrap_create_fake_a_rr(key, value, rr);
969 break;
970 } else if (TYPE_MATCH(type, ns_t_aaaa,
971 rec_type, "AAAA", key, query)) {
972 rc = rwrap_create_fake_aaaa_rr(key, value, rr);
973 break;
974 } else if (TYPE_MATCH(type, ns_t_ns,
975 rec_type, "NS", key, query)) {
976 rc = rwrap_create_fake_ns_rr(key, value, rr);
977 break;
978 } else if (TYPE_MATCH(type, ns_t_srv,
979 rec_type, "SRV", key, query)) {
980 rc = rwrap_create_fake_srv_rr(key, value, rr);
981 if (rc == 0) {
982 rc = rwrap_srv_recurse(hostfile, recursion+1,
983 rr->rrdata.srv_rec.hostname,
984 rr + 1);
986 break;
987 } else if (TYPE_MATCH(type, ns_t_uri,
988 rec_type, "URI", key, query)) {
989 rc = rwrap_create_fake_uri_rr(key, value, rr);
990 if (rc == 0) {
991 /* Recurse to collect multiple URI answers under a single key. */
992 rc = rwrap_uri_recurse(hostfile, recursion + 1, key, rr + 1);
994 break;
995 } else if (TYPE_MATCH(type, ns_t_soa,
996 rec_type, "SOA", key, query)) {
997 rc = rwrap_create_fake_soa_rr(key, value, rr);
998 break;
999 } else if (TYPE_MATCH(type, ns_t_cname,
1000 rec_type, "CNAME", key, query)) {
1001 rc = rwrap_create_fake_cname_rr(key, value, rr);
1002 if (rc == 0) {
1003 rc = rwrap_cname_recurse(hostfile, recursion+1,
1004 value, rr + 1);
1006 break;
1007 } else if (TYPE_MATCH(type, ns_t_a, rec_type, "CNAME", key, query)) {
1008 rc = rwrap_create_fake_cname_rr(key, value, rr);
1009 if (rc == 0) {
1010 rc = rwrap_cname_recurse(hostfile, recursion+1,
1011 value, rr + 1);
1013 break;
1014 } else if (TYPE_MATCH(type, ns_t_ptr,
1015 rec_type, "PTR", key, query)) {
1016 rc = rwrap_create_fake_ptr_rr(key, value, rr);
1017 break;
1019 else if (TYPE_MATCH(type, ns_t_txt,
1020 rec_type, "TXT", key, query)) {
1021 rc = rwrap_create_fake_txt_rr(key, value, rr);
1022 break;
1026 if (rc == ENOENT && recursion == 0 && key != NULL) {
1027 RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query);
1028 memcpy(rr->key, key, strlen(key) + 1);
1031 fclose(fp);
1032 return rc;
1035 static ssize_t rwrap_fake_empty(int type,
1036 const char *question,
1037 uint8_t *answer,
1038 size_t anslen)
1040 ssize_t resp_data;
1041 size_t remaining = anslen;
1043 resp_data = rwrap_fake_header(&answer, remaining, 0, 0);
1044 if (resp_data < 0) {
1045 return -1;
1047 remaining -= resp_data;
1049 resp_data += rwrap_fake_question(question, type, &answer, remaining);
1050 if (resp_data < 0) {
1051 return -1;
1053 remaining -= resp_data;
1055 resp_data += rwrap_fake_rdata_common(type, 0, question,
1056 remaining, &answer);
1057 if (resp_data < 0) {
1058 return -1;
1061 return resp_data;
1064 static inline bool rwrap_known_type(int type)
1066 switch (type) {
1067 case ns_t_a:
1068 case ns_t_aaaa:
1069 case ns_t_ns:
1070 case ns_t_srv:
1071 case ns_t_uri:
1072 case ns_t_soa:
1073 case ns_t_cname:
1074 case ns_t_ptr:
1075 case ns_t_txt:
1076 return true;
1079 return false;
1082 static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype)
1084 int i;
1085 int ancount = 0;
1087 /* For URI return the number of URIs. */
1088 if (qtype == ns_t_uri) {
1089 for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1090 if (rwrap_known_type(rrs[i].type) &&
1091 rrs[i].type == qtype) {
1092 ancount++;
1095 return ancount;
1098 /* Include all RRs in the stack until the sought type
1099 * in the answer section. This is the case i.e. when looking
1100 * up an A record but the name points to a CNAME
1102 for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1103 ancount++;
1105 if (rwrap_known_type(rrs[i].type) &&
1106 rrs[i].type == qtype) {
1107 break;
1111 /* Return 0 records if the sought type wasn't in the stack */
1112 return i < RWRAP_MAX_RECURSION ? ancount : 0;
1115 static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount)
1117 int i;
1118 int arcount = 0;
1120 /* start from index ancount */
1121 for (i = ancount; i < RWRAP_MAX_RECURSION; i++) {
1122 if (rwrap_known_type(rrs[i].type)) {
1123 arcount++;
1127 return arcount;
1130 static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
1131 uint8_t *answer,
1132 size_t anslen)
1134 ssize_t resp_data;
1136 if (rr == NULL) {
1137 RWRAP_LOG(RWRAP_LOG_ERROR, "Internal error!\n");
1138 return -1;
1141 switch (rr->type) {
1142 case ns_t_a:
1143 resp_data = rwrap_fake_a(rr, answer, anslen);
1144 break;
1145 case ns_t_aaaa:
1146 resp_data = rwrap_fake_aaaa(rr, answer, anslen);
1147 break;
1148 case ns_t_ns:
1149 resp_data = rwrap_fake_ns(rr, answer, anslen);
1150 break;
1151 case ns_t_srv:
1152 resp_data = rwrap_fake_srv(rr, answer, anslen);
1153 break;
1154 case ns_t_uri:
1155 resp_data = rwrap_fake_uri(rr, answer, anslen);
1156 break;
1157 case ns_t_soa:
1158 resp_data = rwrap_fake_soa(rr, answer, anslen);
1159 break;
1160 case ns_t_cname:
1161 resp_data = rwrap_fake_cname(rr, answer, anslen);
1162 break;
1163 case ns_t_ptr:
1164 resp_data = rwrap_fake_ptr(rr, answer, anslen);
1165 break;
1166 case ns_t_txt:
1167 resp_data = rwrap_fake_txt(rr, answer, anslen);
1168 break;
1169 default:
1170 return -1;
1173 return resp_data;
1176 static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs,
1177 int type,
1178 uint8_t *answer,
1179 size_t anslen)
1182 ssize_t resp_data;
1183 ssize_t rrlen;
1184 size_t remaining = anslen;
1185 int ancount;
1186 int arcount;
1187 int i;
1189 ancount = rwrap_ancount(rrs, type);
1190 arcount = rwrap_arcount(rrs, ancount);
1191 RWRAP_LOG(RWRAP_LOG_TRACE,
1192 "Got %d answers and %d additional records\n", ancount, arcount);
1194 resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount);
1195 if (resp_data < 0) {
1196 return -1;
1198 remaining -= resp_data;
1200 resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining);
1201 if (resp_data < 0) {
1202 return -1;
1204 remaining -= resp_data;
1206 /* answer */
1207 for (i = 0; i < ancount; i++) {
1208 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1209 if (rrlen < 0) {
1210 return -1;
1212 remaining -= rrlen;
1213 answer += rrlen;
1214 resp_data += rrlen;
1217 /* add authoritative NS here? */
1219 /* additional records */
1220 for (i = ancount; i < ancount + arcount; i++) {
1221 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1222 if (rrlen < 0) {
1223 return -1;
1225 remaining -= rrlen;
1226 answer += rrlen;
1227 resp_data += rrlen;
1230 return resp_data;
1233 /* Reads in a file in the following format:
1234 * TYPE RDATA
1236 * Malformed entries are silently skipped.
1237 * Allocates answer buffer of size anslen that has to be freed after use.
1239 static int rwrap_res_fake_hosts(const char *hostfile,
1240 const char *query,
1241 int type,
1242 unsigned char *answer,
1243 size_t anslen)
1245 int rc = ENOENT;
1246 char *query_name = NULL;
1247 size_t qlen = strlen(query);
1248 struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION];
1249 ssize_t resp_size;
1251 RWRAP_LOG(RWRAP_LOG_TRACE,
1252 "Searching in fake hosts file %s\n", hostfile);
1254 if (qlen > 0 && query[qlen-1] == '.') {
1255 qlen--;
1258 query_name = strndup(query, qlen);
1259 if (query_name == NULL) {
1260 return -1;
1263 rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION);
1265 rc = rwrap_get_record(hostfile, 0, query_name, type, rrs);
1266 switch (rc) {
1267 case 0:
1268 RWRAP_LOG(RWRAP_LOG_TRACE,
1269 "Found record for [%s]\n", query_name);
1270 resp_size = rwrap_fake_answer(rrs, type, answer, anslen);
1271 break;
1272 case ENOENT:
1273 RWRAP_LOG(RWRAP_LOG_TRACE,
1274 "No record for [%s]\n", query_name);
1275 resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen);
1276 break;
1277 default:
1278 RWRAP_LOG(RWRAP_LOG_NOTICE,
1279 "Searching for [%s] did not return any results\n",
1280 query_name);
1281 free(query_name);
1282 return -1;
1285 switch (resp_size) {
1286 case -1:
1287 RWRAP_LOG(RWRAP_LOG_ERROR,
1288 "Error faking answer for [%s]\n", query_name);
1289 break;
1290 default:
1291 RWRAP_LOG(RWRAP_LOG_TRACE,
1292 "Successfully faked answer for [%s]\n",
1293 query_name);
1294 break;
1297 free(query_name);
1298 return resp_size;
1301 /*********************************************************
1302 * RWRAP LOADING LIBC FUNCTIONS
1303 *********************************************************/
1305 #include <dlfcn.h>
1307 typedef int (*__libc_res_ninit)(struct __res_state *state);
1308 typedef int (*__libc___res_ninit)(struct __res_state *state);
1309 typedef void (*__libc_res_nclose)(struct __res_state *state);
1310 typedef void (*__libc___res_nclose)(struct __res_state *state);
1311 typedef int (*__libc_res_nquery)(struct __res_state *state,
1312 const char *dname,
1313 int class,
1314 int type,
1315 unsigned char *answer,
1316 int anslen);
1317 typedef int (*__libc___res_nquery)(struct __res_state *state,
1318 const char *dname,
1319 int class,
1320 int type,
1321 unsigned char *answer,
1322 int anslen);
1323 typedef int (*__libc_res_nsearch)(struct __res_state *state,
1324 const char *dname,
1325 int class,
1326 int type,
1327 unsigned char *answer,
1328 int anslen);
1329 typedef int (*__libc___res_nsearch)(struct __res_state *state,
1330 const char *dname,
1331 int class,
1332 int type,
1333 unsigned char *answer,
1334 int anslen);
1336 #define RWRAP_SYMBOL_ENTRY(i) \
1337 union { \
1338 __libc_##i f; \
1339 void *obj; \
1340 } _libc_##i
1342 struct rwrap_libc_symbols {
1343 RWRAP_SYMBOL_ENTRY(res_ninit);
1344 RWRAP_SYMBOL_ENTRY(__res_ninit);
1345 RWRAP_SYMBOL_ENTRY(res_nclose);
1346 RWRAP_SYMBOL_ENTRY(__res_nclose);
1347 RWRAP_SYMBOL_ENTRY(res_nquery);
1348 RWRAP_SYMBOL_ENTRY(__res_nquery);
1349 RWRAP_SYMBOL_ENTRY(res_nsearch);
1350 RWRAP_SYMBOL_ENTRY(__res_nsearch);
1352 #undef RWRAP_SYMBOL_ENTRY
1354 struct rwrap {
1355 struct {
1356 void *handle;
1357 struct rwrap_libc_symbols symbols;
1358 } libc;
1360 struct {
1361 void *handle;
1362 struct rwrap_libc_symbols symbols;
1363 } libresolv;
1365 bool initialised;
1366 bool enabled;
1368 char *socket_dir;
1371 static struct rwrap rwrap;
1373 enum rwrap_lib {
1374 RWRAP_LIBC,
1375 RWRAP_LIBRESOLV
1378 static const char *rwrap_str_lib(enum rwrap_lib lib)
1380 switch (lib) {
1381 case RWRAP_LIBC:
1382 return "libc";
1383 case RWRAP_LIBRESOLV:
1384 return "libresolv";
1387 /* Compiler would warn us about unhandled enum value if we get here */
1388 return "unknown";
1391 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
1393 int flags = RTLD_LAZY;
1394 void *handle = NULL;
1395 int i;
1397 #ifdef RTLD_DEEPBIND
1398 const char *env_preload = getenv("LD_PRELOAD");
1399 const char *env_deepbind = getenv("RESOLV_WRAPPER_DISABLE_DEEPBIND");
1400 bool enable_deepbind = true;
1402 /* Don't do a deepbind if we run with libasan */
1403 if (env_preload != NULL && strlen(env_preload) < 1024) {
1404 const char *p = strstr(env_preload, "libasan.so");
1405 if (p != NULL) {
1406 enable_deepbind = false;
1410 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
1411 enable_deepbind = false;
1414 if (enable_deepbind) {
1415 flags |= RTLD_DEEPBIND;
1417 #endif
1419 switch (lib) {
1420 case RWRAP_LIBRESOLV:
1421 #ifdef HAVE_LIBRESOLV
1422 handle = rwrap.libresolv.handle;
1423 if (handle == NULL) {
1424 for (i = 10; i >= 0; i--) {
1425 char soname[256] = {0};
1427 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
1428 handle = dlopen(soname, flags);
1429 if (handle != NULL) {
1430 break;
1434 rwrap.libresolv.handle = handle;
1436 break;
1437 #endif
1438 /* FALL TROUGH */
1439 case RWRAP_LIBC:
1440 handle = rwrap.libc.handle;
1441 #ifdef LIBC_SO
1442 if (handle == NULL) {
1443 handle = dlopen(LIBC_SO, flags);
1445 rwrap.libc.handle = handle;
1447 #endif
1448 if (handle == NULL) {
1449 for (i = 10; i >= 0; i--) {
1450 char soname[256] = {0};
1452 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1453 handle = dlopen(soname, flags);
1454 if (handle != NULL) {
1455 break;
1459 rwrap.libc.handle = handle;
1461 break;
1464 if (handle == NULL) {
1465 #ifdef RTLD_NEXT
1466 handle = rwrap.libc.handle = rwrap.libresolv.handle = RTLD_NEXT;
1467 #else
1468 RWRAP_LOG(RWRAP_LOG_ERROR,
1469 "Failed to dlopen library: %s\n",
1470 dlerror());
1471 exit(-1);
1472 #endif
1475 return handle;
1478 static void *_rwrap_bind_symbol(enum rwrap_lib lib, const char *fn_name)
1480 void *handle;
1481 void *func;
1483 handle = rwrap_load_lib_handle(lib);
1485 func = dlsym(handle, fn_name);
1486 if (func == NULL) {
1487 RWRAP_LOG(RWRAP_LOG_ERROR,
1488 "Failed to find %s: %s\n",
1489 fn_name, dlerror());
1490 exit(-1);
1493 RWRAP_LOG(RWRAP_LOG_TRACE,
1494 "Loaded %s from %s",
1495 fn_name, rwrap_str_lib(lib));
1496 return func;
1499 #define rwrap_bind_symbol_libc(sym_name) \
1500 if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
1501 rwrap.libc.symbols._libc_##sym_name.obj = \
1502 _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
1505 #define rwrap_bind_symbol_libresolv(sym_name) \
1506 if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
1507 rwrap.libresolv.symbols._libc_##sym_name.obj = \
1508 _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
1512 * IMPORTANT
1514 * Functions especially from libc need to be loaded individually, you can't load
1515 * all at once or gdb will segfault at startup. The same applies to valgrind and
1516 * has probably something todo with with the linker.
1517 * So we need load each function at the point it is called the first time.
1520 static int libc_res_ninit(struct __res_state *state)
1522 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1523 rwrap_bind_symbol_libresolv(res_ninit);
1525 return rwrap.libresolv.symbols._libc_res_ninit.f(state);
1526 #elif defined(HAVE___RES_NINIT)
1527 rwrap_bind_symbol_libresolv(__res_ninit);
1529 return rwrap.libresolv.symbols._libc___res_ninit.f(state);
1530 #else
1531 #error "No res_ninit function"
1532 #endif
1535 static void libc_res_nclose(struct __res_state *state)
1537 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1538 rwrap_bind_symbol_libresolv(res_nclose);
1540 rwrap.libresolv.symbols._libc_res_nclose.f(state);
1541 return;
1542 #elif defined(HAVE___RES_NCLOSE)
1543 rwrap_bind_symbol_libresolv(__res_nclose);
1545 rwrap.libresolv.symbols._libc___res_nclose.f(state);
1546 #else
1547 #error "No res_nclose function"
1548 #endif
1551 static int libc_res_nquery(struct __res_state *state,
1552 const char *dname,
1553 int class,
1554 int type,
1555 unsigned char *answer,
1556 int anslen)
1558 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1559 rwrap_bind_symbol_libresolv(res_nquery);
1561 return rwrap.libresolv.symbols._libc_res_nquery.f(state,
1562 dname,
1563 class,
1564 type,
1565 answer,
1566 anslen);
1567 #elif defined(HAVE___RES_NQUERY)
1568 rwrap_bind_symbol_libresolv(__res_nquery);
1570 return rwrap.libresolv.symbols._libc___res_nquery.f(state,
1571 dname,
1572 class,
1573 type,
1574 answer,
1575 anslen);
1576 #else
1577 #error "No res_nquery function"
1578 #endif
1581 static int libc_res_nsearch(struct __res_state *state,
1582 const char *dname,
1583 int class,
1584 int type,
1585 unsigned char *answer,
1586 int anslen)
1588 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1589 rwrap_bind_symbol_libresolv(res_nsearch);
1591 return rwrap.libresolv.symbols._libc_res_nsearch.f(state,
1592 dname,
1593 class,
1594 type,
1595 answer,
1596 anslen);
1597 #elif defined(HAVE___RES_NSEARCH)
1598 rwrap_bind_symbol_libresolv(__res_nsearch);
1600 return rwrap.libresolv.symbols._libc___res_nsearch.f(state,
1601 dname,
1602 class,
1603 type,
1604 answer,
1605 anslen);
1606 #else
1607 #error "No res_nsearch function"
1608 #endif
1611 /****************************************************************************
1612 * RES_HELPER
1613 ***************************************************************************/
1615 static size_t rwrap_get_nameservers(struct __res_state *state,
1616 size_t nserv,
1617 union rwrap_sockaddr *nsaddrs)
1619 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1620 union res_sockaddr_union set[MAXNS];
1621 size_t i;
1622 int rc;
1624 memset(set, 0, sizeof(set));
1625 memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1627 if (nserv > MAXNS) {
1628 nserv = MAXNS;
1631 rc = res_getservers(state, set, nserv);
1632 if (rc <= 0) {
1633 return 0;
1635 if (rc < nserv) {
1636 nserv = rc;
1639 for (i = 0; i < nserv; i++) {
1640 switch (set[i].sin.sin_family) {
1641 case AF_INET:
1642 nsaddrs[i] = (union rwrap_sockaddr) {
1643 .in = set[i].sin,
1645 break;
1646 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1647 case AF_INET6:
1648 nsaddrs[i] = (union rwrap_sockaddr) {
1649 .in6 = set[i].sin6,
1651 break;
1652 #endif
1656 return nserv;
1657 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1658 size_t i;
1660 memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1662 if (nserv > (size_t)state->nscount) {
1663 nserv = (size_t)state->nscount;
1666 for (i = 0; i < nserv; i++) {
1667 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1668 if (state->_u._ext.nsaddrs[i] != NULL) {
1669 nsaddrs[i] = (union rwrap_sockaddr) {
1670 .in6 = *state->_u._ext.nsaddrs[i],
1672 } else
1673 #endif /* HAVE_RES_STATE_U_EXT_NSADDRS */
1675 nsaddrs[i] = (union rwrap_sockaddr) {
1676 .in = state->nsaddr_list[i],
1681 return nserv;
1682 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1685 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl,
1686 const char *func,
1687 struct __res_state *state)
1689 union rwrap_sockaddr nsaddrs[MAXNS];
1690 size_t nserv = MAXNS;
1691 size_t i;
1693 memset(nsaddrs, 0, sizeof(nsaddrs));
1694 nserv = rwrap_get_nameservers(state, nserv, nsaddrs);
1695 for (i = 0; i < nserv; i++) {
1696 char ip[INET6_ADDRSTRLEN];
1698 switch (nsaddrs[i].sa.sa_family) {
1699 case AF_INET:
1700 inet_ntop(AF_INET, &(nsaddrs[i].in.sin_addr),
1701 ip, sizeof(ip));
1702 break;
1703 case AF_INET6:
1704 inet_ntop(AF_INET6, &(nsaddrs[i].in6.sin6_addr),
1705 ip, sizeof(ip));
1706 break;
1707 default:
1708 snprintf(ip, sizeof(ip), "<unknown sa_family=%d",
1709 nsaddrs[i].sa.sa_family);
1710 break;
1713 rwrap_log(dbglvl, func,
1714 " nameserver: %s",
1715 ip);
1719 static void rwrap_reset_nameservers(struct __res_state *state)
1721 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1722 res_setservers(state, NULL, 0);
1723 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1724 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1725 size_t i;
1727 for (i = 0; i < (size_t)state->nscount; i++) {
1728 if (state->_u._ext.nssocks[i] != -1) {
1729 close(state->_u._ext.nssocks[i]);
1730 state->_u._ext.nssocks[i] = -1;
1732 SAFE_FREE(state->_u._ext.nsaddrs[i]);
1734 memset(&state->_u._ext, 0, sizeof(state->_u._ext));
1735 for (i = 0; i < MAXNS; i++) {
1736 state->_u._ext.nssocks[i] = -1;
1737 state->_u._ext.nsmap[i] = MAXNS + 1;
1739 state->ipv6_unavail = false;
1740 #endif
1741 memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1742 state->nscount = 0;
1743 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1746 static int rwrap_set_nameservers(struct __res_state *state,
1747 size_t nserv,
1748 const union rwrap_sockaddr *nsaddrs)
1750 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1751 union res_sockaddr_union set[MAXNS];
1752 size_t i;
1754 memset(set, 0, sizeof(set));
1756 if (nserv > MAXNS) {
1757 nserv = MAXNS;
1760 rwrap_reset_nameservers(state);
1762 for (i = 0; i < nserv; i++) {
1763 switch (nsaddrs[i].sa.sa_family) {
1764 case AF_INET:
1765 set[i] = (union res_sockaddr_union) {
1766 .sin = nsaddrs[i].in,
1768 break;
1769 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1770 case AF_INET6:
1771 set[i] = (union res_sockaddr_union) {
1772 .sin6 = nsaddrs[i].in6,
1774 break;
1775 #endif
1776 default:
1777 RWRAP_LOG(RWRAP_LOG_ERROR,
1778 "Internal error unhandled sa_family=%d",
1779 nsaddrs[i].sa.sa_family);
1780 errno = ENOSYS;
1781 return -1;
1785 res_setservers(state, set, nserv);
1786 return 0;
1787 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1788 size_t i;
1790 if (nserv > MAXNS) {
1791 nserv = MAXNS;
1793 rwrap_reset_nameservers(state);
1795 for (i = 0; i < nserv; i++) {
1796 switch (nsaddrs[i].sa.sa_family) {
1797 case AF_INET:
1798 state->nsaddr_list[i] = nsaddrs[i].in;
1799 break;
1800 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1801 case AF_INET6:
1802 state->_u._ext.nsaddrs[i] = malloc(sizeof(nsaddrs[i].in6));
1803 if (state->_u._ext.nsaddrs[i] == NULL) {
1804 rwrap_reset_nameservers(state);
1805 errno = ENOMEM;
1806 return -1;
1808 *state->_u._ext.nsaddrs[i] = nsaddrs[i].in6;
1809 state->_u._ext.nssocks[i] = -1;
1810 state->_u._ext.nsmap[i] = MAXNS + 1;
1811 state->_u._ext.nscount6++;
1812 break;
1813 #endif
1814 default:
1815 RWRAP_LOG(RWRAP_LOG_ERROR,
1816 "Internal error unhandled sa_family=%d",
1817 nsaddrs[i].sa.sa_family);
1818 rwrap_reset_nameservers(state);
1819 errno = ENOSYS;
1820 return -1;
1825 * note that state->_u._ext.nscount is left as 0,
1826 * this matches glibc and allows resolv wrapper
1827 * to work with most (maybe all) glibc versions.
1829 state->nscount = i;
1831 return 0;
1832 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1835 static int rwrap_parse_resolv_conf(struct __res_state *state,
1836 const char *resolv_conf)
1838 FILE *fp;
1839 char buf[BUFSIZ];
1840 size_t nserv = 0;
1841 union rwrap_sockaddr nsaddrs[MAXNS];
1843 memset(nsaddrs, 0, sizeof(nsaddrs));
1845 fp = fopen(resolv_conf, "r");
1846 if (fp == NULL) {
1847 RWRAP_LOG(RWRAP_LOG_WARN,
1848 "Opening %s failed: %s",
1849 resolv_conf, strerror(errno));
1850 return -1;
1853 while(fgets(buf, sizeof(buf), fp) != NULL) {
1854 char *p;
1856 /* Ignore comments */
1857 if (buf[0] == '#' || buf[0] == ';') {
1858 continue;
1861 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
1862 struct in_addr a;
1863 struct in6_addr a6;
1864 char *q;
1865 int ok;
1867 p = buf + strlen("nameserver");
1869 /* Skip spaces and tabs */
1870 while(isblank((int)p[0])) {
1871 p++;
1874 q = p;
1875 while(q[0] != '\n' && q[0] != '\0') {
1876 q++;
1878 q[0] = '\0';
1880 ok = inet_pton(AF_INET, p, &a);
1881 if (ok) {
1882 nsaddrs[nserv] = (union rwrap_sockaddr) {
1883 .in = {
1884 .sin_family = AF_INET,
1885 .sin_addr = a,
1886 .sin_port = htons(53),
1887 .sin_zero = { 0 },
1891 nserv++;
1892 continue;
1895 ok = inet_pton(AF_INET6, p, &a6);
1896 if (ok) {
1897 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1898 nsaddrs[nserv] = (union rwrap_sockaddr) {
1899 .in6 = {
1901 .sin6_family = AF_INET6,
1902 .sin6_port = htons(53),
1903 .sin6_flowinfo = 0,
1904 .sin6_addr = a6,
1907 nserv++;
1908 continue;
1909 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1910 RWRAP_LOG(RWRAP_LOG_WARN,
1911 "resolve_wrapper does not support "
1912 "IPv6 on this platform");
1913 continue;
1914 #endif
1917 RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed DNS server[%s]", p);
1918 continue;
1919 } /* TODO: match other keywords */
1922 if (ferror(fp)) {
1923 RWRAP_LOG(RWRAP_LOG_ERROR,
1924 "Reading from %s failed",
1925 resolv_conf);
1926 fclose(fp);
1927 return -1;
1930 fclose(fp);
1932 if (nserv == 0) {
1933 RWRAP_LOG(RWRAP_LOG_WARN,
1934 "No usable nameservers found in %s",
1935 resolv_conf);
1936 errno = ESRCH;
1937 return -1;
1940 return rwrap_set_nameservers(state, nserv, nsaddrs);
1943 /****************************************************************************
1944 * RES_NINIT
1945 ***************************************************************************/
1947 static int rwrap_res_ninit(struct __res_state *state)
1949 int rc;
1951 rc = libc_res_ninit(state);
1952 if (rc == 0) {
1953 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1955 if (resolv_conf != NULL) {
1956 rc = rwrap_parse_resolv_conf(state, resolv_conf);
1960 return rc;
1963 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1964 int res_ninit(struct __res_state *state)
1965 #elif defined(HAVE___RES_NINIT)
1966 int __res_ninit(struct __res_state *state)
1967 #endif
1969 return rwrap_res_ninit(state);
1972 /****************************************************************************
1973 * RES_INIT
1974 ***************************************************************************/
1976 static struct __res_state rwrap_res_state;
1978 static int rwrap_res_init(void)
1980 int rc;
1982 rc = rwrap_res_ninit(&rwrap_res_state);
1984 return rc;
1987 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1988 int res_init(void)
1989 #elif defined(HAVE___RES_INIT)
1990 int __res_init(void)
1991 #endif
1993 return rwrap_res_init();
1996 /****************************************************************************
1997 * RES_NCLOSE
1998 ***************************************************************************/
2000 static void rwrap_res_nclose(struct __res_state *state)
2002 rwrap_reset_nameservers(state);
2003 libc_res_nclose(state);
2006 #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
2007 void res_nclose(struct __res_state *state)
2008 #elif defined(HAVE___RES_NCLOSE)
2009 void __res_nclose(struct __res_state *state)
2010 #endif
2012 rwrap_res_nclose(state);
2015 /****************************************************************************
2016 * RES_CLOSE
2017 ***************************************************************************/
2019 static void rwrap_res_close(void)
2021 rwrap_res_nclose(&rwrap_res_state);
2024 #if defined(HAVE_RES_CLOSE)
2025 void res_close(void)
2026 #elif defined(HAVE___RES_CLOSE)
2027 void __res_close(void)
2028 #endif
2030 rwrap_res_close();
2033 /****************************************************************************
2034 * RES_NQUERY
2035 ***************************************************************************/
2037 static int rwrap_res_nquery(struct __res_state *state,
2038 const char *dname,
2039 int class,
2040 int type,
2041 unsigned char *answer,
2042 int anslen)
2044 int rc;
2045 const char *fake_hosts;
2047 RWRAP_LOG(RWRAP_LOG_TRACE,
2048 "Resolve the domain name [%s] - class=%d, type=%d",
2049 dname, class, type);
2050 rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2052 fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2053 if (fake_hosts != NULL) {
2054 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2055 } else {
2056 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
2060 RWRAP_LOG(RWRAP_LOG_TRACE,
2061 "The returned response length is: %d",
2062 rc);
2064 return rc;
2067 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
2068 int res_nquery(struct __res_state *state,
2069 const char *dname,
2070 int class,
2071 int type,
2072 unsigned char *answer,
2073 int anslen)
2074 #elif defined(HAVE___RES_NQUERY)
2075 int __res_nquery(struct __res_state *state,
2076 const char *dname,
2077 int class,
2078 int type,
2079 unsigned char *answer,
2080 int anslen)
2081 #endif
2083 return rwrap_res_nquery(state, dname, class, type, answer, anslen);
2086 /****************************************************************************
2087 * RES_QUERY
2088 ***************************************************************************/
2090 static int rwrap_res_query(const char *dname,
2091 int class,
2092 int type,
2093 unsigned char *answer,
2094 int anslen)
2096 int rc;
2098 rc = rwrap_res_ninit(&rwrap_res_state);
2099 if (rc != 0) {
2100 return rc;
2103 rc = rwrap_res_nquery(&rwrap_res_state,
2104 dname,
2105 class,
2106 type,
2107 answer,
2108 anslen);
2110 return rc;
2113 #if !defined(res_query) && defined(HAVE_RES_QUERY)
2114 int res_query(const char *dname,
2115 int class,
2116 int type,
2117 unsigned char *answer,
2118 int anslen)
2119 #elif defined(HAVE___RES_QUERY)
2120 int __res_query(const char *dname,
2121 int class,
2122 int type,
2123 unsigned char *answer,
2124 int anslen)
2125 #endif
2127 return rwrap_res_query(dname, class, type, answer, anslen);
2130 /****************************************************************************
2131 * RES_NSEARCH
2132 ***************************************************************************/
2134 static int rwrap_res_nsearch(struct __res_state *state,
2135 const char *dname,
2136 int class,
2137 int type,
2138 unsigned char *answer,
2139 int anslen)
2141 int rc;
2142 const char *fake_hosts;
2144 RWRAP_LOG(RWRAP_LOG_TRACE,
2145 "Resolve the domain name [%s] - class=%d, type=%d",
2146 dname, class, type);
2147 rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2149 fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2150 if (fake_hosts != NULL) {
2151 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2152 } else {
2153 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
2156 RWRAP_LOG(RWRAP_LOG_TRACE,
2157 "The returned response length is: %d",
2158 rc);
2160 return rc;
2163 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
2164 int res_nsearch(struct __res_state *state,
2165 const char *dname,
2166 int class,
2167 int type,
2168 unsigned char *answer,
2169 int anslen)
2170 #elif defined(HAVE___RES_NSEARCH)
2171 int __res_nsearch(struct __res_state *state,
2172 const char *dname,
2173 int class,
2174 int type,
2175 unsigned char *answer,
2176 int anslen)
2177 #endif
2179 return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
2182 /****************************************************************************
2183 * RES_SEARCH
2184 ***************************************************************************/
2186 static int rwrap_res_search(const char *dname,
2187 int class,
2188 int type,
2189 unsigned char *answer,
2190 int anslen)
2192 int rc;
2194 rc = rwrap_res_ninit(&rwrap_res_state);
2195 if (rc != 0) {
2196 return rc;
2199 rc = rwrap_res_nsearch(&rwrap_res_state,
2200 dname,
2201 class,
2202 type,
2203 answer,
2204 anslen);
2206 return rc;
2209 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
2210 int res_search(const char *dname,
2211 int class,
2212 int type,
2213 unsigned char *answer,
2214 int anslen)
2215 #elif defined(HAVE___RES_SEARCH)
2216 int __res_search(const char *dname,
2217 int class,
2218 int type,
2219 unsigned char *answer,
2220 int anslen)
2221 #endif
2223 return rwrap_res_search(dname, class, type, answer, anslen);