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