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