8d0d67e4b1eb54c484ceb192d83efa792ef09d8a
[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 = 1;                      /* response flag */
167         h->rd = 1;                      /* recursion desired */
168         h->ra = 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
836 #if defined(HAVE_RES_NINIT_IN_LIBRESOLV)
837         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_ninit);
838 #else /* HAVE_RES_NINIT_IN_LIBRESOLV */
839         rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
840 #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */
841
842         return rwrap.fns.libc_res_ninit(state);
843 #elif defined(HAVE___RES_NINIT)
844         rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
845
846         return rwrap.fns.libc___res_ninit(state);
847 #else
848 #error "No res_ninit function"
849 #endif
850 }
851
852 static void libc_res_nclose(struct __res_state *state)
853 {
854 #if defined(HAVE_RES_NCLOSE)
855
856 #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV)
857         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nclose);
858 #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
859         rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
860 #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
861
862         rwrap.fns.libc_res_nclose(state);
863 #elif defined(HAVE___RES_NCLOSE)
864         rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
865
866         rwrap.fns.libc___res_nclose(state);
867 #else
868 #error "No res_nclose function"
869 #endif
870 }
871
872 static int libc_res_nquery(struct __res_state *state,
873                            const char *dname,
874                            int class,
875                            int type,
876                            unsigned char *answer,
877                            int anslen)
878 {
879 #if defined(HAVE_RES_NQUERY)
880         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
881
882         return rwrap.fns.libc_res_nquery(state,
883                                          dname,
884                                          class,
885                                          type,
886                                          answer,
887                                          anslen);
888 #elif defined(HAVE___RES_NQUERY)
889         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
890
891         return rwrap.fns.libc___res_nquery(state,
892                                            dname,
893                                            class,
894                                            type,
895                                            answer,
896                                            anslen);
897 #else
898 #error "No res_nquery function"
899 #endif
900 }
901
902 static int libc_res_nsearch(struct __res_state *state,
903                             const char *dname,
904                             int class,
905                             int type,
906                             unsigned char *answer,
907                             int anslen)
908 {
909 #if defined(HAVE_RES_NSEARCH)
910         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
911
912         return rwrap.fns.libc_res_nsearch(state,
913                                           dname,
914                                           class,
915                                           type,
916                                           answer,
917                                           anslen);
918 #elif defined(HAVE___RES_NSEARCH)
919         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
920
921         return rwrap.fns.libc___res_nsearch(state,
922                                             dname,
923                                             class,
924                                             type,
925                                             answer,
926                                             anslen);
927 #else
928 #error "No res_nsearch function"
929 #endif
930 }
931
932 /****************************************************************************
933  *   RES_HELPER
934  ***************************************************************************/
935
936 static int rwrap_parse_resolv_conf(struct __res_state *state,
937                                    const char *resolv_conf)
938 {
939         FILE *fp;
940         char buf[BUFSIZ];
941         int nserv = 0;
942
943         fp = fopen(resolv_conf, "r");
944         if (fp == NULL) {
945                 RWRAP_LOG(RWRAP_LOG_ERROR,
946                           "Opening %s failed: %s",
947                           resolv_conf, strerror(errno));
948                 return -1;
949         }
950
951         while(fgets(buf, sizeof(buf), fp) != NULL) {
952                 char *p;
953
954                 /* Ignore comments */
955                 if (buf[0] == '#' || buf[0] == ';') {
956                         continue;
957                 }
958
959                 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
960                         struct in_addr a;
961                         char *q;
962                         int ok;
963
964                         p = buf + strlen("nameserver");
965
966                         /* Skip spaces and tabs */
967                         while(isblank((int)p[0])) {
968                                 p++;
969                         }
970
971                         q = p;
972                         while(q[0] != '\n' && q[0] != '\0') {
973                                 q++;
974                         }
975                         q[0] = '\0';
976
977                         ok = inet_pton(AF_INET, p, &a);
978                         if (ok) {
979                                 state->nsaddr_list[state->nscount] = (struct sockaddr_in) {
980                                         .sin_family = AF_INET,
981                                         .sin_addr = a,
982                                         .sin_port = htons(53),
983                                         .sin_zero = { 0 },
984                                 };
985
986                                 state->nscount++;
987                                 nserv++;
988                         } else {
989 #ifdef HAVE_RESOLV_IPV6_NSADDRS
990                                 /* IPv6 */
991                                 struct in6_addr a6;
992                                 ok = inet_pton(AF_INET6, p, &a6);
993                                 if (ok) {
994                                         struct sockaddr_in6 *sa6;
995
996                                         sa6 = malloc(sizeof(*sa6));
997                                         if (sa6 == NULL) {
998                                                 fclose(fp);
999                                                 return -1;
1000                                         }
1001
1002                                         sa6->sin6_family = AF_INET6;
1003                                         sa6->sin6_port = htons(53);
1004                                         sa6->sin6_flowinfo = 0;
1005                                         sa6->sin6_addr = a6;
1006
1007                                         state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6;
1008                                         state->_u._ext.nssocks[state->_u._ext.nscount] = -1;
1009                                         state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1;
1010
1011                                         state->_u._ext.nscount++;
1012                                         nserv++;
1013                                 } else {
1014                                         RWRAP_LOG(RWRAP_LOG_ERROR,
1015                                                 "Malformed DNS server");
1016                                         continue;
1017                                 }
1018 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1019                                 /*
1020                                  * BSD uses an opaque structure to store the
1021                                  * IPv6 addresses. So we can not simply store
1022                                  * these addresses the same way as above.
1023                                  */
1024                                 RWRAP_LOG(RWRAP_LOG_WARN,
1025                                           "resolve_wrapper does not support "
1026                                           "IPv6 on this platform");
1027                                         continue;
1028 #endif
1029                         }
1030                         continue;
1031                 } /* TODO: match other keywords */
1032         }
1033
1034         if (ferror(fp)) {
1035                 RWRAP_LOG(RWRAP_LOG_ERROR,
1036                           "Reading from %s failed",
1037                           resolv_conf);
1038                 fclose(fp);
1039                 return -1;
1040         }
1041
1042         fclose(fp);
1043         return 0;
1044 }
1045
1046 /****************************************************************************
1047  *   RES_NINIT
1048  ***************************************************************************/
1049
1050 static int rwrap_res_ninit(struct __res_state *state)
1051 {
1052         int rc;
1053
1054         rc = libc_res_ninit(state);
1055         if (rc == 0) {
1056                 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1057
1058                 if (resolv_conf != NULL) {
1059                         uint16_t i;
1060
1061                         (void)i; /* maybe unused */
1062
1063                         /* Delete name servers */
1064                         state->nscount = 0;
1065                         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1066
1067                         state->_u._ext.nscount = 0;
1068 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1069                         for (i = 0; i < state->_u._ext.nscount; i++) {
1070                                 free(state->_u._ext.nsaddrs[i]);
1071                                 state->_u._ext.nssocks[i] = 0;
1072                         }
1073 #endif
1074
1075                         rc = rwrap_parse_resolv_conf(state, resolv_conf);
1076                 }
1077         }
1078
1079         return rc;
1080 }
1081
1082 #if defined(HAVE_RES_NINIT)
1083 int res_ninit(struct __res_state *state)
1084 #elif defined(HAVE___RES_NINIT)
1085 int __res_ninit(struct __res_state *state)
1086 #endif
1087 {
1088         return rwrap_res_ninit(state);
1089 }
1090
1091 /****************************************************************************
1092  *   RES_INIT
1093  ***************************************************************************/
1094
1095 static struct __res_state rwrap_res_state;
1096
1097 static int rwrap_res_init(void)
1098 {
1099         int rc;
1100
1101         rc = rwrap_res_ninit(&rwrap_res_state);
1102
1103         return rc;
1104 }
1105
1106 #if defined(HAVE_RES_INIT)
1107 int res_init(void)
1108 #elif defined(HAVE___RES_INIT)
1109 int __res_init(void)
1110 #endif
1111 {
1112         return rwrap_res_init();
1113 }
1114
1115 /****************************************************************************
1116  *   RES_NCLOSE
1117  ***************************************************************************/
1118
1119 static void rwrap_res_nclose(struct __res_state *state)
1120 {
1121 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1122         int i;
1123
1124         if (state != NULL) {
1125                 for (i = 0; i < state->_u._ext.nscount; i++) {
1126                         SAFE_FREE(state->_u._ext.nsaddrs[i]);
1127                         state->_u._ext.nssocks[i] = 0;
1128                 }
1129         }
1130 #endif
1131         libc_res_nclose(state);
1132 }
1133
1134 #if defined(HAVE_RES_NCLOSE)
1135 void res_nclose(struct __res_state *state)
1136 #elif defined(HAVE___RES_NCLOSE)
1137 void __res_nclose(struct __res_state *state)
1138 #endif
1139 {
1140         libc_res_nclose(state);
1141 }
1142
1143 /****************************************************************************
1144  *   RES_CLOSE
1145  ***************************************************************************/
1146
1147 static void rwrap_res_close(void)
1148 {
1149         rwrap_res_nclose(&rwrap_res_state);
1150 }
1151
1152 #if defined(HAVE_RES_CLOSE)
1153 void res_close(void)
1154 #elif defined(HAVE___RES_CLOSE)
1155 void __res_close(void)
1156 #endif
1157 {
1158         rwrap_res_close();
1159 }
1160
1161 /****************************************************************************
1162  *   RES_NQUERY
1163  ***************************************************************************/
1164
1165 static int rwrap_res_nquery(struct __res_state *state,
1166                             const char *dname,
1167                             int class,
1168                             int type,
1169                             unsigned char *answer,
1170                             int anslen)
1171 {
1172         int rc;
1173         const char *fake_hosts;
1174 #ifndef NDEBUG
1175         int i;
1176 #endif
1177
1178         RWRAP_LOG(RWRAP_LOG_TRACE,
1179                   "Resolve the domain name [%s] - class=%d, type=%d",
1180                   dname, class, type);
1181 #ifndef NDEBUG
1182         for (i = 0; i < state->nscount; i++) {
1183                 char ip[INET6_ADDRSTRLEN];
1184
1185                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1186                 RWRAP_LOG(RWRAP_LOG_TRACE,
1187                           "        nameserver: %s",
1188                           ip);
1189         }
1190 #endif
1191
1192         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1193         if (fake_hosts != NULL) {
1194                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1195         } else {
1196                 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
1197         }
1198
1199
1200         RWRAP_LOG(RWRAP_LOG_TRACE,
1201                   "The returned response length is: %d",
1202                   rc);
1203
1204         return rc;
1205 }
1206
1207 #if defined(HAVE_RES_NQUERY)
1208 int res_nquery(struct __res_state *state,
1209                const char *dname,
1210                int class,
1211                int type,
1212                unsigned char *answer,
1213                int anslen)
1214 #elif defined(HAVE___RES_NQUERY)
1215 int __res_nquery(struct __res_state *state,
1216                  const char *dname,
1217                  int class,
1218                  int type,
1219                  unsigned char *answer,
1220                  int anslen)
1221 #endif
1222 {
1223         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
1224 }
1225
1226 /****************************************************************************
1227  *   RES_QUERY
1228  ***************************************************************************/
1229
1230 static int rwrap_res_query(const char *dname,
1231                            int class,
1232                            int type,
1233                            unsigned char *answer,
1234                            int anslen)
1235 {
1236         int rc;
1237
1238         rc = rwrap_res_ninit(&rwrap_res_state);
1239         if (rc != 0) {
1240                 return rc;
1241         }
1242
1243         rc = rwrap_res_nquery(&rwrap_res_state,
1244                               dname,
1245                               class,
1246                               type,
1247                               answer,
1248                               anslen);
1249
1250         return rc;
1251 }
1252
1253 #if defined(HAVE_RES_QUERY)
1254 int res_query(const char *dname,
1255               int class,
1256               int type,
1257               unsigned char *answer,
1258               int anslen)
1259 #elif defined(HAVE___RES_QUERY)
1260 int __res_query(const char *dname,
1261                 int class,
1262                 int type,
1263                 unsigned char *answer,
1264                 int anslen)
1265 #endif
1266 {
1267         return rwrap_res_query(dname, class, type, answer, anslen);
1268 }
1269
1270 /****************************************************************************
1271  *   RES_NSEARCH
1272  ***************************************************************************/
1273
1274 static int rwrap_res_nsearch(struct __res_state *state,
1275                              const char *dname,
1276                              int class,
1277                              int type,
1278                              unsigned char *answer,
1279                              int anslen)
1280 {
1281         int rc;
1282         const char *fake_hosts;
1283 #ifndef NDEBUG
1284         int i;
1285 #endif
1286
1287         RWRAP_LOG(RWRAP_LOG_TRACE,
1288                   "Resolve the domain name [%s] - class=%d, type=%d",
1289                   dname, class, type);
1290 #ifndef NDEBUG
1291         for (i = 0; i < state->nscount; i++) {
1292                 char ip[INET6_ADDRSTRLEN];
1293
1294                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1295                 RWRAP_LOG(RWRAP_LOG_TRACE,
1296                           "        nameserver: %s",
1297                           ip);
1298         }
1299 #endif
1300
1301         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1302         if (fake_hosts != NULL) {
1303                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1304         } else {
1305                 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
1306         }
1307
1308         RWRAP_LOG(RWRAP_LOG_TRACE,
1309                   "The returned response length is: %d",
1310                   rc);
1311
1312         return rc;
1313 }
1314
1315 #if defined(HAVE_RES_NSEARCH)
1316 int res_nsearch(struct __res_state *state,
1317                 const char *dname,
1318                 int class,
1319                 int type,
1320                 unsigned char *answer,
1321                 int anslen)
1322 #elif defined(HAVE___RES_NSEARCH)
1323 int __res_nsearch(struct __res_state *state,
1324                   const char *dname,
1325                   int class,
1326                   int type,
1327                   unsigned char *answer,
1328                   int anslen)
1329 #endif
1330 {
1331         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
1332 }
1333
1334 /****************************************************************************
1335  *   RES_QUERY
1336  ***************************************************************************/
1337
1338 static int rwrap_res_search(const char *dname,
1339                             int class,
1340                             int type,
1341                             unsigned char *answer,
1342                             int anslen)
1343 {
1344         int rc;
1345
1346         rc = rwrap_res_ninit(&rwrap_res_state);
1347         if (rc != 0) {
1348                 return rc;
1349         }
1350
1351         rc = rwrap_res_nsearch(&rwrap_res_state,
1352                                dname,
1353                                class,
1354                                type,
1355                                answer,
1356                                anslen);
1357
1358         return rc;
1359 }
1360
1361 #if defined(HAVE_RES_SEARCH)
1362 int res_search(const char *dname,
1363                int class,
1364                int type,
1365                unsigned char *answer,
1366                int anslen)
1367 #elif defined(HAVE___RES_SEARCH)
1368 int __res_search(const char *dname,
1369                  int class,
1370                  int type,
1371                  unsigned char *answer,
1372                  int anslen)
1373 #endif
1374 {
1375         return rwrap_res_search(dname, class, type, answer, anslen);
1376 }