rwrap: Move NEXT_KEY out of the NDEBUG ifdef.
[obnox/cwrap/resolv_wrapper.git] / src / resolv_wrapper.c
1 /*
2  * Copyright (c) 2014      Andreas Schneider <asn@samba.org>
3  * Copyright (c) 2014      Jakub Hrozek <jakub.hrozek@gmail.com>
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
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.
17  *
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.
21  *
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.
33  */
34
35 #include "config.h"
36
37 #include <errno.h>
38 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <sys/types.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <stdbool.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <ctype.h>
48
49 #include <resolv.h>
50
51 /* GCC has printf type attribute check. */
52 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
53 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
54 #else
55 #define PRINTF_ATTRIBUTE(a,b)
56 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
57
58 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
59 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
60 #else
61 #define DESTRUCTOR_ATTRIBUTE
62 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
63
64 #ifndef RWRAP_DEFAULT_FAKE_TTL
65 #define RWRAP_DEFAULT_FAKE_TTL 600
66 #endif  /* RWRAP_DEFAULT_FAKE_TTL */
67
68 enum rwrap_dbglvl_e {
69         RWRAP_LOG_ERROR = 0,
70         RWRAP_LOG_WARN,
71         RWRAP_LOG_DEBUG,
72         RWRAP_LOG_TRACE
73 };
74
75 #ifdef NDEBUG
76 # define RWRAP_LOG(...)
77 #else /* NDEBUG */
78
79 static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
80 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
81
82 static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
83                       const char *func,
84                       const char *format, ...)
85 {
86         char buffer[1024];
87         va_list va;
88         const char *d;
89         unsigned int lvl = 0;
90         int pid = getpid();
91
92         d = getenv("RESOLV_WRAPPER_DEBUGLEVEL");
93         if (d != NULL) {
94                 lvl = atoi(d);
95         }
96
97         va_start(va, format);
98         vsnprintf(buffer, sizeof(buffer), format, va);
99         va_end(va);
100
101         if (lvl >= dbglvl) {
102                 switch (dbglvl) {
103                         case RWRAP_LOG_ERROR:
104                                 fprintf(stderr,
105                                         "RWRAP_ERROR(%d) - %s: %s\n",
106                                         pid, func, buffer);
107                                 break;
108                         case RWRAP_LOG_WARN:
109                                 fprintf(stderr,
110                                         "RWRAP_WARN(%d) - %s: %s\n",
111                                         pid, func, buffer);
112                                 break;
113                         case RWRAP_LOG_DEBUG:
114                                 fprintf(stderr,
115                                         "RWRAP_DEBUG(%d) - %s: %s\n",
116                                         pid, func, buffer);
117                                 break;
118                         case RWRAP_LOG_TRACE:
119                                 fprintf(stderr,
120                                         "RWRAP_TRACE(%d) - %s: %s\n",
121                                         pid, func, buffer);
122                                 break;
123                 }
124         }
125 }
126 #endif /* NDEBUG RWRAP_LOG */
127
128 #define NEXT_KEY(buf, key) do {                                 \
129         (key) = (buf) ? strpbrk((buf), " \t") : NULL;           \
130         if ((key) != NULL) {                                    \
131                 (key)[0] = '\0';                                \
132                 (key)++;                                        \
133         }                                                       \
134         while ((key) != NULL                                    \
135                && (isblank((int)(key)[0]))) {                   \
136                 (key)++;                                        \
137         }                                                       \
138 } while(0);
139
140
141 /* Prepares a fake header with a single response. Advances header_blob */
142 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
143                                  size_t rdata_size)
144 {
145         uint8_t *hb;
146         HEADER *h;
147         int answers;
148
149         /* If rdata_size is zero, the answer is empty */
150         answers = rdata_size > 0 ? 1 : 0;
151
152         if (remaining < NS_HFIXEDSZ) {
153                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
154                 return -1;
155         }
156
157         hb = *header_blob;
158         memset(hb, 0, NS_HFIXEDSZ);
159
160         h = (HEADER *) hb;
161         h->id = res_randomid();         /* random query ID */
162         h->qr = htons(1);               /* response flag */
163         h->rd = htons(1);               /* recursion desired */
164         h->ra = htons(1);               /* resursion available */
165
166         h->qdcount = htons(1);          /* no. of questions */
167         h->ancount = htons(answers);    /* no. of answers */
168
169         hb += NS_HFIXEDSZ;              /* move past the header */
170         *header_blob = hb;
171
172         return NS_HFIXEDSZ;
173 }
174
175 static ssize_t rwrap_fake_question(const char *question,
176                                    uint16_t type,
177                                    uint8_t **question_ptr,
178                                    size_t remaining)
179 {
180         uint8_t *qb = *question_ptr;
181         int n;
182
183         n = ns_name_compress(question, qb, remaining, NULL, NULL);
184         if (n < 0) {
185                 RWRAP_LOG(RWRAP_LOG_ERROR,
186                           "Failed to compress [%s]\n", question);
187                 return -1;
188         }
189
190         qb += n;
191         remaining -= n;
192
193         if (remaining < 2 * sizeof(uint16_t)) {
194                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
195                 return -1;
196         }
197
198         NS_PUT16(type, qb);
199         NS_PUT16(ns_c_in, qb);
200
201         *question_ptr = qb;
202         return n + 2 * sizeof(uint16_t);
203 }
204
205 static ssize_t rwrap_fake_rdata_common(uint16_t type,
206                                        size_t rdata_size,
207                                        const char *key,
208                                        size_t remaining,
209                                        uint8_t **rdata_ptr)
210 {
211         uint8_t *rd = *rdata_ptr;
212         ssize_t written = 0;
213
214         written = ns_name_compress(key, rd, remaining, NULL, NULL);
215         if (written < 0) {
216                 RWRAP_LOG(RWRAP_LOG_ERROR,
217                           "Failed to compress [%s]\n", key);
218                 return -1;
219         }
220         rd += written;
221         remaining -= written;
222
223         if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
224                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
225                 return -1;
226         }
227
228         NS_PUT16(type, rd);
229         NS_PUT16(ns_c_in, rd);
230         NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd);
231         NS_PUT16(rdata_size, rd);
232
233         if (remaining < rdata_size) {
234                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
235                 return -1;
236         }
237
238         *rdata_ptr = rd;
239         return written + 3 * sizeof(uint16_t) + sizeof(uint32_t);
240 }
241
242 static ssize_t rwrap_fake_common(uint16_t type,
243                                  const char *question,
244                                  size_t rdata_size,
245                                  uint8_t **answer_ptr,
246                                  size_t anslen)
247 {
248         uint8_t *a = *answer_ptr;
249         ssize_t written;
250         size_t remaining;
251
252         remaining = anslen;
253
254         written = rwrap_fake_header(&a, remaining, rdata_size);
255         if (written < 0) {
256                 return -1;
257         }
258         remaining -= written;
259
260         written = rwrap_fake_question(question, type, &a, remaining);
261         if (written < 0) {
262                 return -1;
263         }
264         remaining -= written;
265
266         /* rdata_size = 0 denotes an empty answer */
267         if (rdata_size > 0) {
268                 written = rwrap_fake_rdata_common(type, rdata_size, question,
269                                                 remaining, &a);
270                 if (written < 0) {
271                         return -1;
272                 }
273         }
274
275         *answer_ptr = a;
276         return written;
277 }
278
279 static int rwrap_fake_a(const char *key,
280                         const char *value,
281                         uint8_t *answer_ptr,
282                         size_t anslen)
283 {
284         uint8_t *a = answer_ptr;
285         struct in_addr a_rec;
286         int rc;
287         int ok;
288
289         if (value == NULL) {
290                 RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed record, no value!\n");
291                 return -1;
292         }
293
294         rc = rwrap_fake_common(ns_t_a, key, sizeof(a_rec), &a, anslen);
295         if (rc < 0) {
296                 return -1;
297         }
298
299         ok = inet_pton(AF_INET, value, &a_rec);
300         if (!ok) {
301                 RWRAP_LOG(RWRAP_LOG_ERROR,
302                           "Failed to convert [%s] to binary\n", value);
303                 return -1;
304         }
305         memcpy(a, &a_rec, sizeof(struct in_addr));
306
307         return 0;
308 }
309
310 static int rwrap_fake_aaaa(const char *key,
311                            const char *value,
312                            uint8_t *answer,
313                            size_t anslen)
314 {
315         uint8_t *a = answer;
316         struct in6_addr aaaa_rec;
317         int rc;
318         int ok;
319
320         if (value == NULL) {
321                 RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed record, no value!\n");
322                 return -1;
323         }
324
325         rc = rwrap_fake_common(ns_t_aaaa, key, sizeof(aaaa_rec), &a, anslen);
326         if (rc < 0) {
327                 return -1;
328         }
329
330         ok = inet_pton(AF_INET6, value, &aaaa_rec);
331         if (!ok) {
332                 RWRAP_LOG(RWRAP_LOG_ERROR,
333                           "Failed to convert [%s] to binary\n", value);
334                 return -1;
335         }
336         memcpy(a, &aaaa_rec, sizeof(struct in6_addr));
337
338         return 0;
339 }
340
341 /*
342  * Priority and weight can be omitted from the hosts file, but need to be part
343  * of the output
344  */
345 #define DFL_SRV_PRIO    1
346 #define DFL_SRV_WEIGHT  100
347
348 static int rwrap_fake_srv(const char *key,
349                           const char *value,
350                           uint8_t *answer,
351                           size_t anslen)
352 {
353         uint8_t *a = answer;
354         int rv;
355         size_t rdata_size;
356         char *str_prio;
357         char *str_weight;
358         char *str_port;
359         const char *hostname;
360         unsigned char hostname_compressed[MAXDNAME];
361         ssize_t compressed_len;
362
363         /*
364          * Parse the value into priority, weight, port and hostname
365          * and check the validity.
366          */
367         hostname = value;
368         NEXT_KEY(hostname, str_port);
369         NEXT_KEY(str_port, str_prio);
370         NEXT_KEY(str_prio, str_weight);
371         if (str_port == NULL || hostname == NULL) {
372                 RWRAP_LOG(RWRAP_LOG_ERROR,
373                           "Malformed SRV entry [%s]\n", value);
374                 return -1;
375         }
376         rdata_size = 3 * sizeof(uint16_t);
377
378         /* Prepare the data to write */
379         compressed_len = ns_name_compress(hostname,
380                                           hostname_compressed, MAXDNAME,
381                                           NULL, NULL);
382         if (compressed_len < 0) {
383                 return -1;
384         }
385         rdata_size += compressed_len;
386
387         rv = rwrap_fake_common(ns_t_srv, key, rdata_size, &a, anslen);
388         if (rv < 0) {
389                 return -1;
390         }
391
392         if (str_prio) {
393                 NS_PUT16(atoi(str_prio), a);
394         } else {
395                 NS_PUT16(DFL_SRV_PRIO, a);
396         }
397         if (str_weight) {
398                 NS_PUT16(atoi(str_weight), a);
399         } else {
400                 NS_PUT16(DFL_SRV_WEIGHT, a);
401         }
402         NS_PUT16(atoi(str_port), a);
403         memcpy(a, hostname_compressed, compressed_len);
404
405         return 0;
406 }
407
408 static int rwrap_fake_soa(const char *key,
409                           const char *value,
410                           uint8_t *answer,
411                           size_t anslen)
412 {
413         uint8_t *a = answer;
414         int rv;
415         const char *nameserver;
416         char *mailbox;
417         char *str_serial;
418         char *str_refresh;
419         char *str_retry;
420         char *str_expire;
421         char *str_minimum;
422         size_t rdata_size;
423         unsigned char nameser_compressed[MAXDNAME];
424         ssize_t compressed_ns_len;
425         unsigned char mailbox_compressed[MAXDNAME];
426         ssize_t compressed_mb_len;
427
428         /*
429          * parse the value into nameserver, mailbox, serial, refresh,
430          * retry, expire, minimum and check the validity
431          */
432         nameserver = value;
433         NEXT_KEY(nameserver, mailbox);
434         NEXT_KEY(mailbox, str_serial);
435         NEXT_KEY(str_serial, str_refresh);
436         NEXT_KEY(str_refresh, str_retry);
437         NEXT_KEY(str_retry, str_expire);
438         NEXT_KEY(str_expire, str_minimum);
439         if (nameserver == NULL || mailbox == NULL || str_serial == NULL ||
440             str_refresh == NULL || str_retry == NULL || str_expire == NULL ||
441             str_minimum == NULL)
442         {
443                 RWRAP_LOG(RWRAP_LOG_ERROR,
444                           "Malformed SOA entry [%s]\n", value);
445                 return -1;
446         }
447         rdata_size = 5 * sizeof(uint16_t);
448
449         compressed_ns_len = ns_name_compress(nameserver, nameser_compressed,
450                                              MAXDNAME, NULL, NULL);
451         if (compressed_ns_len < 0) {
452                 return -1;
453         }
454         rdata_size += compressed_ns_len;
455
456         compressed_mb_len = ns_name_compress(mailbox, mailbox_compressed,
457                                              MAXDNAME, NULL, NULL);
458         if (compressed_mb_len < 0) {
459                 return -1;
460         }
461         rdata_size += compressed_mb_len;
462
463         rv = rwrap_fake_common(ns_t_soa, key, rdata_size, &a, anslen);
464         if (rv < 0) {
465                 return -1;
466         }
467
468         memcpy(a, nameser_compressed, compressed_ns_len);
469         a += compressed_ns_len;
470         memcpy(a, mailbox_compressed, compressed_mb_len);
471         a += compressed_mb_len;
472         NS_PUT32(atoi(str_serial), a);
473         NS_PUT32(atoi(str_refresh), a);
474         NS_PUT32(atoi(str_retry), a);
475         NS_PUT32(atoi(str_expire), a);
476         NS_PUT32(atoi(str_minimum), a);
477
478         return 0;
479 }
480
481 static int rwrap_fake_cname(const char *key,
482                             const char *value,
483                             uint8_t *answer,
484                             size_t anslen)
485 {
486         uint8_t *a = answer;
487         int rv;
488         unsigned char hostname_compressed[MAXDNAME];
489         ssize_t rdata_size;
490
491         if (value == NULL) {
492                 RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed record, no value!\n");
493                 return -1;
494         }
495
496         /* Prepare the data to write */
497         rdata_size = ns_name_compress(value,
498                                       hostname_compressed, MAXDNAME,
499                                       NULL, NULL);
500         if (rdata_size < 0) {
501                 return -1;
502         }
503
504         rv = rwrap_fake_common(ns_t_cname, key, rdata_size, &a, anslen);
505         if (rv < 0) {
506                 return -1;
507         }
508
509         memcpy(a, hostname_compressed, rdata_size);
510
511         return 0;
512 }
513
514 static int rwrap_fake_empty_query(const char *key,
515                                   uint16_t type,
516                                   uint8_t *answer,
517                                   size_t anslen)
518 {
519         int rc;
520
521         rc = rwrap_fake_common(type, key, 0, &answer, anslen);
522         if (rc < 0) {
523                 return -1;
524         }
525
526         return 0;
527 }
528
529 #define RESOLV_MATCH(line, name) \
530         (strncmp(line, name, sizeof(name) - 1) == 0 && \
531         (line[sizeof(name) - 1] == ' ' || \
532          line[sizeof(name) - 1] == '\t'))
533
534 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
535         ((type) == (ns_type) && \
536          (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
537          (strcmp(key, query)) == 0)
538
539
540 /* Reads in a file in the following format:
541  * TYPE RDATA
542  *
543  * Malformed entried are silently skipped.
544  * Allocates answer buffer of size anslen that has to be freed after use.
545  */
546 static int rwrap_res_fake_hosts(const char *hostfile,
547                                 const char *query,
548                                 int type,
549                                 unsigned char *answer,
550                                 size_t anslen)
551 {
552         FILE *fp = NULL;
553         char buf[BUFSIZ];
554         int rc = ENOENT;
555         char *key = NULL;
556         char *value = NULL;
557
558         RWRAP_LOG(RWRAP_LOG_TRACE,
559                   "Searching in fake hosts file %s\n", hostfile);
560
561         fp = fopen(hostfile, "r");
562         if (fp == NULL) {
563                 RWRAP_LOG(RWRAP_LOG_ERROR,
564                           "Opening %s failed: %s",
565                           hostfile, strerror(errno));
566                 return -1;
567         }
568
569         while (fgets(buf, sizeof(buf), fp) != NULL) {
570                 char *rec_type;
571                 char *q;
572
573                 rec_type = buf;
574                 key = value = NULL;
575
576                 NEXT_KEY(rec_type, key);
577                 NEXT_KEY(key, value);
578
579                 q = value;
580                 while(q[0] != '\n' && q[0] != '\0') {
581                         q++;
582                 }
583                 q[0] = '\0';
584
585                 if (key == NULL || value == NULL) {
586                         RWRAP_LOG(RWRAP_LOG_WARN,
587                                 "Malformed line: not enough parts, use \"rec_type key data\n"
588                                 "For example \"A cwrap.org 10.10.10.10\"");
589                         continue;
590                 }
591
592                 if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) {
593                         rc = rwrap_fake_a(key, value, answer, anslen);
594                         break;
595                 } else if (TYPE_MATCH(type, ns_t_aaaa,
596                                       rec_type, "AAAA", key, query)) {
597                         rc = rwrap_fake_aaaa(key, value, answer, anslen);
598                         break;
599                 } else if (TYPE_MATCH(type, ns_t_srv,
600                                       rec_type, "SRV", key, query)) {
601                         rc = rwrap_fake_srv(key, value, answer, anslen);
602                         break;
603                 } else if (TYPE_MATCH(type, ns_t_soa,
604                                       rec_type, "SOA", key, query)) {
605                         rc = rwrap_fake_soa(key, value, answer, anslen);
606                         break;
607                 } else if (TYPE_MATCH(type, ns_t_cname,
608                                       rec_type, "CNAME", key, query)) {
609                         rc = rwrap_fake_cname(key, value, answer, anslen);
610                         break;
611                 }
612         }
613
614         switch (rc) {
615         case 0:
616                 RWRAP_LOG(RWRAP_LOG_TRACE,
617                                 "Successfully faked answer for [%s]\n", query);
618                 break;
619         case -1:
620                 RWRAP_LOG(RWRAP_LOG_ERROR,
621                                 "Error faking answer for [%s]\n", query);
622                 break;
623         case ENOENT:
624                 RWRAP_LOG(RWRAP_LOG_TRACE,
625                                 "Record for [%s] not found\n", query);
626                 rc = rwrap_fake_empty_query(key, type, answer, anslen);
627                 break;
628         }
629
630         fclose(fp);
631         return rc;
632 }
633
634 /*********************************************************
635  * RWRAP LOADING LIBC FUNCTIONS
636  *********************************************************/
637
638 #include <dlfcn.h>
639
640 struct rwrap_libc_fns {
641         int (*libc_res_init)(void);
642         int (*libc___res_init)(void);
643         int (*libc_res_ninit)(struct __res_state *state);
644         int (*libc___res_ninit)(struct __res_state *state);
645         void (*libc_res_nclose)(struct __res_state *state);
646         void (*libc___res_nclose)(struct __res_state *state);
647         void (*libc_res_close)(void);
648         void (*libc___res_close)(void);
649         int (*libc_res_nquery)(struct __res_state *state,
650                                const char *dname,
651                                int class,
652                                int type,
653                                unsigned char *answer,
654                                int anslen);
655         int (*libc___res_nquery)(struct __res_state *state,
656                                  const char *dname,
657                                  int class,
658                                  int type,
659                                  unsigned char *answer,
660                                  int anslen);
661         int (*libc_res_nsearch)(struct __res_state *state,
662                                 const char *dname,
663                                 int class,
664                                 int type,
665                                 unsigned char *answer,
666                                 int anslen);
667         int (*libc___res_nsearch)(struct __res_state *state,
668                                   const char *dname,
669                                   int class,
670                                   int type,
671                                   unsigned char *answer,
672                                   int anslen);
673 };
674
675 struct rwrap {
676         void *libc_handle;
677         void *libresolv_handle;
678
679         bool initialised;
680         bool enabled;
681
682         char *socket_dir;
683
684         struct rwrap_libc_fns fns;
685 };
686
687 static struct rwrap rwrap;
688
689 enum rwrap_lib {
690     RWRAP_LIBC,
691     RWRAP_LIBRESOLV
692 };
693
694 #ifndef NDEBUG
695 static const char *rwrap_str_lib(enum rwrap_lib lib)
696 {
697         switch (lib) {
698         case RWRAP_LIBC:
699                 return "libc";
700         case RWRAP_LIBRESOLV:
701                 return "libresolv";
702         }
703
704         /* Compiler would warn us about unhandled enum value if we get here */
705         return "unknown";
706 }
707 #endif
708
709 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
710 {
711         int flags = RTLD_LAZY;
712         void *handle = NULL;
713         int i;
714
715 #ifdef RTLD_DEEPBIND
716         flags |= RTLD_DEEPBIND;
717 #endif
718
719         switch (lib) {
720         case RWRAP_LIBRESOLV:
721 #ifdef HAVE_LIBRESOLV
722                 handle = rwrap.libresolv_handle;
723                 if (handle == NULL) {
724                         for (i = 10; i >= 0; i--) {
725                                 char soname[256] = {0};
726
727                                 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
728                                 handle = dlopen(soname, flags);
729                                 if (handle != NULL) {
730                                         break;
731                                 }
732                         }
733
734                         rwrap.libresolv_handle = handle;
735                 }
736                 break;
737 #endif
738                 /* FALL TROUGH */
739         case RWRAP_LIBC:
740                 handle = rwrap.libc_handle;
741 #ifdef LIBC_SO
742                 if (handle == NULL) {
743                         handle = dlopen(LIBC_SO, flags);
744
745                         rwrap.libc_handle = handle;
746                 }
747 #endif
748                 if (handle == NULL) {
749                         for (i = 10; i >= 0; i--) {
750                                 char soname[256] = {0};
751
752                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
753                                 handle = dlopen(soname, flags);
754                                 if (handle != NULL) {
755                                         break;
756                                 }
757                         }
758
759                         rwrap.libc_handle = handle;
760                 }
761                 break;
762         }
763
764         if (handle == NULL) {
765 #ifdef RTLD_NEXT
766                 handle = rwrap.libc_handle = rwrap.libresolv_handle = RTLD_NEXT;
767 #else
768                 RWRAP_LOG(RWRAP_LOG_ERROR,
769                           "Failed to dlopen library: %s\n",
770                           dlerror());
771                 exit(-1);
772 #endif
773         }
774
775         return handle;
776 }
777
778 static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
779 {
780         void *handle;
781         void *func;
782
783         handle = rwrap_load_lib_handle(lib);
784
785         func = dlsym(handle, fn_name);
786         if (func == NULL) {
787                 RWRAP_LOG(RWRAP_LOG_ERROR,
788                                 "Failed to find %s: %s\n",
789                                 fn_name, dlerror());
790                 exit(-1);
791         }
792
793         RWRAP_LOG(RWRAP_LOG_TRACE,
794                         "Loaded %s from %s",
795                         fn_name, rwrap_str_lib(lib));
796         return func;
797 }
798
799 #define rwrap_load_lib_function(lib, fn_name) \
800         if (rwrap.fns.libc_##fn_name == NULL) { \
801                 *(void **) (&rwrap.fns.libc_##fn_name) = \
802                         _rwrap_load_lib_function(lib, #fn_name); \
803         }
804
805 /*
806  * IMPORTANT
807  *
808  * Functions especially from libc need to be loaded individually, you can't load
809  * all at once or gdb will segfault at startup. The same applies to valgrind and
810  * has probably something todo with with the linker.
811  * So we need load each function at the point it is called the first time.
812  */
813 #if 0
814 static int libc_res_init(void)
815 {
816 #if defined(HAVE_RES_INIT)
817         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_init);
818
819         return rwrap.fns.libc_res_init();
820 #elif defined(HAVE___RES_INIT)
821         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_init);
822
823         return rwrap.fns.libc___res_init();
824 #endif
825 }
826 #endif
827
828 static int libc_res_ninit(struct __res_state *state)
829 {
830 #if defined(HAVE_RES_NINIT)
831         rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
832
833         return rwrap.fns.libc_res_ninit(state);
834 #elif defined(HAVE___RES_NINIT)
835         rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
836
837         return rwrap.fns.libc___res_ninit(state);
838 #else
839 #error "No res_ninit function"
840 #endif
841 }
842
843 static void libc_res_nclose(struct __res_state *state)
844 {
845 #if defined(HAVE_RES_NCLOSE)
846         rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
847
848         rwrap.fns.libc_res_nclose(state);
849 #elif defined(HAVE___RES_NCLOSE)
850         rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
851
852         rwrap.fns.libc___res_nclose(state);
853 #else
854 #error "No res_nclose function"
855 #endif
856 }
857
858 static int libc_res_nquery(struct __res_state *state,
859                            const char *dname,
860                            int class,
861                            int type,
862                            unsigned char *answer,
863                            int anslen)
864 {
865 #if defined(HAVE_RES_NQUERY)
866         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
867
868         return rwrap.fns.libc_res_nquery(state,
869                                          dname,
870                                          class,
871                                          type,
872                                          answer,
873                                          anslen);
874 #elif defined(HAVE___RES_NQUERY)
875         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
876
877         return rwrap.fns.libc___res_nquery(state,
878                                            dname,
879                                            class,
880                                            type,
881                                            answer,
882                                            anslen);
883 #else
884 #error "No res_nquery function"
885 #endif
886 }
887
888 static int libc_res_nsearch(struct __res_state *state,
889                             const char *dname,
890                             int class,
891                             int type,
892                             unsigned char *answer,
893                             int anslen)
894 {
895 #if defined(HAVE_RES_NSEARCH)
896         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
897
898         return rwrap.fns.libc_res_nsearch(state,
899                                           dname,
900                                           class,
901                                           type,
902                                           answer,
903                                           anslen);
904 #elif defined(HAVE___RES_NSEARCH)
905         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
906
907         return rwrap.fns.libc___res_nsearch(state,
908                                             dname,
909                                             class,
910                                             type,
911                                             answer,
912                                             anslen);
913 #else
914 #error "No res_nsearch function"
915 #endif
916 }
917
918 /****************************************************************************
919  *   RES_HELPER
920  ***************************************************************************/
921
922 static int rwrap_parse_resolv_conf(struct __res_state *state,
923                                    const char *resolv_conf)
924 {
925         FILE *fp;
926         char buf[BUFSIZ];
927         int nserv = 0;
928
929         fp = fopen(resolv_conf, "r");
930         if (fp == NULL) {
931                 RWRAP_LOG(RWRAP_LOG_ERROR,
932                           "Opening %s failed: %s",
933                           resolv_conf, strerror(errno));
934                 return -1;
935         }
936
937         while(fgets(buf, sizeof(buf), fp) != NULL) {
938                 char *p;
939
940                 /* Ignore comments */
941                 if (buf[0] == '#' || buf[0] == ';') {
942                         continue;
943                 }
944
945                 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
946                         struct in_addr a;
947                         char *q;
948                         int ok;
949
950                         p = buf + strlen("nameserver");
951
952                         /* Skip spaces and tabs */
953                         while(isblank((int)p[0])) {
954                                 p++;
955                         }
956
957                         q = p;
958                         while(q[0] != '\n' && q[0] != '\0') {
959                                 q++;
960                         }
961                         q[0] = '\0';
962
963                         ok = inet_pton(AF_INET, p, &a);
964                         if (ok) {
965                                 state->nsaddr_list[state->nscount] = (struct sockaddr_in) {
966                                         .sin_family = AF_INET,
967                                         .sin_addr = a,
968                                         .sin_port = htons(53),
969                                 };
970
971                                 state->nscount++;
972                                 nserv++;
973                         } else {
974 #ifdef HAVE_RESOLV_IPV6_NSADDRS
975                                 /* IPv6 */
976                                 struct in6_addr a6;
977                                 ok = inet_pton(AF_INET6, p, &a6);
978                                 if (ok) {
979                                         struct sockaddr_in6 *sa6;
980
981                                         sa6 = malloc(sizeof(*sa6));
982                                         if (sa6 == NULL) {
983                                                 return -1;
984                                         }
985
986                                         sa6->sin6_family = AF_INET6;
987                                         sa6->sin6_port = htons(53);
988                                         sa6->sin6_flowinfo = 0;
989                                         sa6->sin6_addr = a6;
990
991                                         state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6;
992                                         state->_u._ext.nssocks[state->_u._ext.nscount] = -1;
993                                         state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1;
994
995                                         state->_u._ext.nscount++;
996                                         nserv++;
997                                 } else {
998                                         RWRAP_LOG(RWRAP_LOG_ERROR,
999                                                 "Malformed DNS server");
1000                                         continue;
1001                                 }
1002 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1003                                 /*
1004                                  * BSD uses an opaque structure to store the
1005                                  * IPv6 addresses. So we can not simply store
1006                                  * these addresses the same way as above.
1007                                  */
1008                                 RWRAP_LOG(RWRAP_LOG_WARN,
1009                                           "resolve_wrapper does not support "
1010                                           "IPv6 on this platform");
1011                                         continue;
1012 #endif
1013                         }
1014                         continue;
1015                 } /* TODO: match other keywords */
1016         }
1017
1018         if (ferror(fp)) {
1019                 RWRAP_LOG(RWRAP_LOG_ERROR,
1020                           "Reading from %s failed",
1021                           resolv_conf);
1022                 return -1;
1023         }
1024
1025         return 0;
1026 }
1027
1028 /****************************************************************************
1029  *   RES_NINIT
1030  ***************************************************************************/
1031
1032 static int rwrap_res_ninit(struct __res_state *state)
1033 {
1034         int rc;
1035
1036         rc = libc_res_ninit(state);
1037         if (rc == 0) {
1038                 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1039
1040                 if (resolv_conf != NULL) {
1041                         uint16_t i;
1042
1043                         (void)i; /* maybe unused */
1044
1045                         /* Delete name servers */
1046                         state->nscount = 0;
1047                         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1048
1049                         state->_u._ext.nscount = 0;
1050 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1051                         for (i = 0; i < state->_u._ext.nscount; i++) {
1052                                 free(state->_u._ext.nsaddrs[i]);
1053                                 state->_u._ext.nssocks[i] = 0;
1054                         }
1055 #endif
1056
1057                         rc = rwrap_parse_resolv_conf(state, resolv_conf);
1058                 }
1059         }
1060
1061         return rc;
1062 }
1063
1064 #if defined(HAVE_RES_NINIT)
1065 int res_ninit(struct __res_state *state)
1066 #elif defined(HAVE___RES_NINIT)
1067 int __res_ninit(struct __res_state *state)
1068 #endif
1069 {
1070         return rwrap_res_ninit(state);
1071 }
1072
1073 /****************************************************************************
1074  *   RES_INIT
1075  ***************************************************************************/
1076
1077 static struct __res_state rwrap_res_state;
1078
1079 static int rwrap_res_init(void)
1080 {
1081         int rc;
1082
1083         rc = rwrap_res_ninit(&rwrap_res_state);
1084
1085         return rc;
1086 }
1087
1088 #if defined(HAVE_RES_INIT)
1089 int res_init(void)
1090 #elif defined(HAVE___RES_INIT)
1091 int __res_init(void)
1092 #endif
1093 {
1094         return rwrap_res_init();
1095 }
1096
1097 /****************************************************************************
1098  *   RES_NCLOSE
1099  ***************************************************************************/
1100
1101 static void rwrap_res_nclose(struct __res_state *state)
1102 {
1103         libc_res_nclose(state);
1104 }
1105
1106 #if defined(HAVE_RES_NCLOSE)
1107 void res_nclose(struct __res_state *state)
1108 #elif defined(HAVE___RES_NCLOSE)
1109 void __res_nclose(struct __res_state *state)
1110 #endif
1111 {
1112         libc_res_nclose(state);
1113 }
1114
1115 /****************************************************************************
1116  *   RES_CLOSE
1117  ***************************************************************************/
1118
1119 static void rwrap_res_close(void)
1120 {
1121         rwrap_res_nclose(&rwrap_res_state);
1122 }
1123
1124 #if defined(HAVE_RES_CLOSE)
1125 void res_close(void)
1126 #elif defined(HAVE___RES_CLOSE)
1127 void __res_close(void)
1128 #endif
1129 {
1130         rwrap_res_close();
1131 }
1132
1133 /****************************************************************************
1134  *   RES_NQUERY
1135  ***************************************************************************/
1136
1137 static int rwrap_res_nquery(struct __res_state *state,
1138                             const char *dname,
1139                             int class,
1140                             int type,
1141                             unsigned char *answer,
1142                             int anslen)
1143 {
1144         int rc;
1145         const char *fake_hosts;
1146 #ifndef NDEBUG
1147         int i;
1148 #endif
1149
1150         RWRAP_LOG(RWRAP_LOG_TRACE,
1151                   "Resolve the domain name [%s] - class=%d, type=%d",
1152                   dname, class, type);
1153 #ifndef NDEBUG
1154         for (i = 0; i < state->nscount; i++) {
1155                 char ip[INET6_ADDRSTRLEN];
1156
1157                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1158                 RWRAP_LOG(RWRAP_LOG_TRACE,
1159                           "        nameserver: %s",
1160                           ip);
1161         }
1162 #endif
1163
1164         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1165         if (fake_hosts != NULL) {
1166                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1167         } else {
1168                 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
1169         }
1170
1171
1172         RWRAP_LOG(RWRAP_LOG_TRACE,
1173                   "The returned response length is: %d",
1174                   rc);
1175
1176         return rc;
1177 }
1178
1179 #if defined(HAVE_RES_NQUERY)
1180 int res_nquery(struct __res_state *state,
1181                const char *dname,
1182                int class,
1183                int type,
1184                unsigned char *answer,
1185                int anslen)
1186 #elif defined(HAVE___RES_NQUERY)
1187 int __res_nquery(struct __res_state *state,
1188                  const char *dname,
1189                  int class,
1190                  int type,
1191                  unsigned char *answer,
1192                  int anslen)
1193 #endif
1194 {
1195         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
1196 }
1197
1198 /****************************************************************************
1199  *   RES_QUERY
1200  ***************************************************************************/
1201
1202 static int rwrap_res_query(const char *dname,
1203                            int class,
1204                            int type,
1205                            unsigned char *answer,
1206                            int anslen)
1207 {
1208         int rc;
1209
1210         rc = rwrap_res_ninit(&rwrap_res_state);
1211         if (rc != 0) {
1212                 return rc;
1213         }
1214
1215         rc = rwrap_res_nquery(&rwrap_res_state,
1216                               dname,
1217                               class,
1218                               type,
1219                               answer,
1220                               anslen);
1221
1222         return rc;
1223 }
1224
1225 #if defined(HAVE_RES_QUERY)
1226 int res_query(const char *dname,
1227               int class,
1228               int type,
1229               unsigned char *answer,
1230               int anslen)
1231 #elif defined(HAVE___RES_QUERY)
1232 int __res_query(const char *dname,
1233                 int class,
1234                 int type,
1235                 unsigned char *answer,
1236                 int anslen)
1237 #endif
1238 {
1239         return rwrap_res_query(dname, class, type, answer, anslen);
1240 }
1241
1242 /****************************************************************************
1243  *   RES_NSEARCH
1244  ***************************************************************************/
1245
1246 static int rwrap_res_nsearch(struct __res_state *state,
1247                              const char *dname,
1248                              int class,
1249                              int type,
1250                              unsigned char *answer,
1251                              int anslen)
1252 {
1253         int rc;
1254         const char *fake_hosts;
1255 #ifndef NDEBUG
1256         int i;
1257 #endif
1258
1259         RWRAP_LOG(RWRAP_LOG_TRACE,
1260                   "Resolve the domain name [%s] - class=%d, type=%d",
1261                   dname, class, type);
1262 #ifndef NDEBUG
1263         for (i = 0; i < state->nscount; i++) {
1264                 char ip[INET6_ADDRSTRLEN];
1265
1266                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1267                 RWRAP_LOG(RWRAP_LOG_TRACE,
1268                           "        nameserver: %s",
1269                           ip);
1270         }
1271 #endif
1272
1273         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1274         if (fake_hosts != NULL) {
1275                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1276         } else {
1277                 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
1278         }
1279
1280         RWRAP_LOG(RWRAP_LOG_TRACE,
1281                   "The returned response length is: %d",
1282                   rc);
1283
1284         return rc;
1285 }
1286
1287 #if defined(HAVE_RES_NSEARCH)
1288 int res_nsearch(struct __res_state *state,
1289                 const char *dname,
1290                 int class,
1291                 int type,
1292                 unsigned char *answer,
1293                 int anslen)
1294 #elif defined(HAVE___RES_NSEARCH)
1295 int __res_nsearch(struct __res_state *state,
1296                   const char *dname,
1297                   int class,
1298                   int type,
1299                   unsigned char *answer,
1300                   int anslen)
1301 #endif
1302 {
1303         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
1304 }
1305
1306 /****************************************************************************
1307  *   RES_QUERY
1308  ***************************************************************************/
1309
1310 static int rwrap_res_search(const char *dname,
1311                             int class,
1312                             int type,
1313                             unsigned char *answer,
1314                             int anslen)
1315 {
1316         int rc;
1317
1318         rc = rwrap_res_ninit(&rwrap_res_state);
1319         if (rc != 0) {
1320                 return rc;
1321         }
1322
1323         rc = rwrap_res_nsearch(&rwrap_res_state,
1324                                dname,
1325                                class,
1326                                type,
1327                                answer,
1328                                anslen);
1329
1330         return rc;
1331 }
1332
1333 #if defined(HAVE_RES_SEARCH)
1334 int res_search(const char *dname,
1335                int class,
1336                int type,
1337                unsigned char *answer,
1338                int anslen)
1339 #elif defined(HAVE___RES_SEARCH)
1340 int __res_search(const char *dname,
1341                  int class,
1342                  int type,
1343                  unsigned char *answer,
1344                  int anslen)
1345 #endif
1346 {
1347         return rwrap_res_search(dname, class, type, answer, anslen);
1348 }