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