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