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