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