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