69f4484fe0660d3107942dc51b6c1592945b4377
[obnox/samba/samba-obnox.git] / lib / resolv_wrapper / 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 #define RWRAP_MAX_RECURSION 5
145
146 /* Priority and weight can be omitted from the hosts file, but need to be part
147  * of the output
148  */
149 #define DFL_SRV_PRIO    1
150 #define DFL_SRV_WEIGHT  100
151
152 struct rwrap_srv_rrdata {
153         uint16_t port;
154         uint16_t prio;
155         uint16_t weight;
156         char hostname[MAXDNAME];
157 };
158
159 struct rwrap_soa_rrdata {
160         uint32_t serial;
161         uint32_t refresh;
162         uint32_t retry;
163         uint32_t expire;
164         uint32_t minimum;
165         char nameserver[MAXDNAME];
166         char mailbox[MAXDNAME];
167 };
168
169 struct rwrap_fake_rr {
170         union fake_rrdata {
171                 struct in_addr a_rec;
172                 struct in6_addr aaaa_rec;
173                 struct rwrap_srv_rrdata srv_rec;
174                 struct rwrap_soa_rrdata soa_rec;
175                 char cname_rec[MAXDNAME];
176         } rrdata;
177
178         char key[MAXDNAME];
179         int type; /* ns_t_* */
180 };
181
182 static void rwrap_fake_rr_init(struct rwrap_fake_rr *rr, size_t len)
183 {
184         size_t i;
185
186         for (i = 0; i < len; i++) {
187                 rr[i].type = ns_t_invalid;
188         }
189 }
190
191 static int rwrap_create_fake_a_rr(const char *key,
192                                   const char *value,
193                                   struct rwrap_fake_rr *rr)
194 {
195         int ok;
196
197         ok = inet_pton(AF_INET, value, &rr->rrdata.a_rec);
198         if (!ok) {
199                 RWRAP_LOG(RWRAP_LOG_ERROR,
200                           "Failed to convert [%s] to binary\n", value);
201                 return -1;
202         }
203
204         memcpy(rr->key, key, strlen(key) + 1);
205         rr->type = ns_t_a;
206         return 0;
207 }
208
209 static int rwrap_create_fake_aaaa_rr(const char *key,
210                                      const char *value,
211                                      struct rwrap_fake_rr *rr)
212 {
213         int ok;
214
215         ok = inet_pton(AF_INET6, value, &rr->rrdata.aaaa_rec);
216         if (!ok) {
217                 RWRAP_LOG(RWRAP_LOG_ERROR,
218                           "Failed to convert [%s] to binary\n", value);
219                 return -1;
220         }
221
222         memcpy(rr->key, key, strlen(key) + 1);
223         rr->type = ns_t_aaaa;
224         return 0;
225 }
226
227 static int rwrap_create_fake_srv_rr(const char *key,
228                                     const char *value,
229                                     struct rwrap_fake_rr *rr)
230 {
231         char *str_prio;
232         char *str_weight;
233         char *str_port;
234         const char *hostname;
235
236         /* parse the value into priority, weight, port and hostname
237          * and check the validity */
238         hostname = value;
239         NEXT_KEY(hostname, str_port);
240         NEXT_KEY(str_port, str_prio);
241         NEXT_KEY(str_prio, str_weight);
242         if (str_port == NULL || hostname == NULL) {
243                 RWRAP_LOG(RWRAP_LOG_ERROR,
244                           "Malformed SRV entry [%s]\n", value);
245                 return -1;
246         }
247
248         if (str_prio) {
249                 rr->rrdata.srv_rec.prio = atoi(str_prio);
250         } else {
251                 rr->rrdata.srv_rec.prio = DFL_SRV_PRIO;
252         }
253         if (str_weight) {
254                 rr->rrdata.srv_rec.weight = atoi(str_weight);
255         } else {
256                 rr->rrdata.srv_rec.weight = DFL_SRV_WEIGHT;
257         }
258         rr->rrdata.srv_rec.port = atoi(str_port);
259         memcpy(rr->rrdata.srv_rec.hostname , hostname, strlen(hostname) + 1);
260
261         memcpy(rr->key, key, strlen(key) + 1);
262         rr->type = ns_t_srv;
263         return 0;
264 }
265
266 static int rwrap_create_fake_soa_rr(const char *key,
267                                     const char *value,
268                                     struct rwrap_fake_rr *rr)
269 {
270         const char *nameserver;
271         char *mailbox;
272         char *str_serial;
273         char *str_refresh;
274         char *str_retry;
275         char *str_expire;
276         char *str_minimum;
277
278         /* parse the value into nameserver, mailbox, serial, refresh,
279          * retry, expire, minimum and check the validity
280          */
281         nameserver = value;
282         NEXT_KEY(nameserver, mailbox);
283         NEXT_KEY(mailbox, str_serial);
284         NEXT_KEY(str_serial, str_refresh);
285         NEXT_KEY(str_refresh, str_retry);
286         NEXT_KEY(str_retry, str_expire);
287         NEXT_KEY(str_expire, str_minimum);
288         if (nameserver == NULL || mailbox == NULL || str_serial == NULL ||
289             str_refresh == NULL || str_retry == NULL || str_expire == NULL ||
290             str_minimum == NULL) {
291                 RWRAP_LOG(RWRAP_LOG_ERROR,
292                           "Malformed SOA entry [%s]\n", value);
293                 return -1;
294         }
295
296         memcpy(rr->rrdata.soa_rec.nameserver, nameserver, strlen(nameserver)+1);
297         memcpy(rr->rrdata.soa_rec.mailbox, mailbox, strlen(mailbox)+1);
298
299         rr->rrdata.soa_rec.serial = atoi(str_serial);
300         rr->rrdata.soa_rec.refresh = atoi(str_refresh);
301         rr->rrdata.soa_rec.retry = atoi(str_retry);
302         rr->rrdata.soa_rec.expire = atoi(str_expire);
303         rr->rrdata.soa_rec.minimum = atoi(str_minimum);
304
305         memcpy(rr->key, key, strlen(key) + 1);
306         rr->type = ns_t_soa;
307         return 0;
308 }
309
310 static int rwrap_create_fake_cname_rr(const char *key,
311                                       const char *value,
312                                       struct rwrap_fake_rr *rr)
313 {
314         memcpy(rr->rrdata.cname_rec , value, strlen(value) + 1);
315         memcpy(rr->key, key, strlen(key) + 1);
316         rr->type = ns_t_cname;
317         return 0;
318 }
319
320 /* Prepares a fake header with a single response. Advances header_blob */
321 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
322                                  size_t ancount, size_t arcount)
323 {
324         uint8_t *hb;
325         HEADER *h;
326
327         if (remaining < NS_HFIXEDSZ) {
328                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
329                 return -1;
330         }
331
332         hb = *header_blob;
333         memset(hb, 0, NS_HFIXEDSZ);
334
335         h = (HEADER *) hb;
336         h->id = res_randomid();         /* random query ID */
337         h->qr = 1;                      /* response flag */
338         h->rd = 1;                      /* recursion desired */
339         h->ra = 1;                      /* resursion available */
340
341         h->qdcount = htons(1);          /* no. of questions */
342         h->ancount = htons(ancount);    /* no. of answers */
343         h->arcount = htons(arcount);    /* no. of add'tl records */
344
345         hb += NS_HFIXEDSZ;              /* move past the header */
346         *header_blob = hb;
347
348         return NS_HFIXEDSZ;
349 }
350
351 static ssize_t rwrap_fake_question(const char *question,
352                                    uint16_t type,
353                                    uint8_t **question_ptr,
354                                    size_t remaining)
355 {
356         uint8_t *qb = *question_ptr;
357         int n;
358
359         n = ns_name_compress(question, qb, remaining, NULL, NULL);
360         if (n < 0) {
361                 RWRAP_LOG(RWRAP_LOG_ERROR,
362                           "Failed to compress [%s]\n", question);
363                 return -1;
364         }
365
366         qb += n;
367         remaining -= n;
368
369         if (remaining < 2 * sizeof(uint16_t)) {
370                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
371                 return -1;
372         }
373
374         NS_PUT16(type, qb);
375         NS_PUT16(ns_c_in, qb);
376
377         *question_ptr = qb;
378         return n + 2 * sizeof(uint16_t);
379 }
380
381 static ssize_t rwrap_fake_rdata_common(uint16_t type,
382                                        size_t rdata_size,
383                                        const char *key,
384                                        size_t remaining,
385                                        uint8_t **rdata_ptr)
386 {
387         uint8_t *rd = *rdata_ptr;
388         ssize_t written = 0;
389
390         written = ns_name_compress(key, rd, remaining, NULL, NULL);
391         if (written < 0) {
392                 RWRAP_LOG(RWRAP_LOG_ERROR,
393                           "Failed to compress [%s]\n", key);
394                 return -1;
395         }
396         rd += written;
397         remaining -= written;
398
399         if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
400                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
401                 return -1;
402         }
403
404         NS_PUT16(type, rd);
405         NS_PUT16(ns_c_in, rd);
406         NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd);
407         NS_PUT16(rdata_size, rd);
408
409         if (remaining < rdata_size) {
410                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
411                 return -1;
412         }
413
414         *rdata_ptr = rd;
415         return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size;
416 }
417
418 static ssize_t rwrap_fake_a(struct rwrap_fake_rr *rr,
419                             uint8_t *answer_ptr,
420                             size_t anslen)
421 {
422         uint8_t *a = answer_ptr;
423         ssize_t resp_size;
424
425         if (rr == NULL || rr->type != ns_t_a) {
426                 RWRAP_LOG(RWRAP_LOG_ERROR,
427                           "Malformed record, no or wrong value!\n");
428                 return -1;
429         }
430         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding A RR");
431
432         resp_size = rwrap_fake_rdata_common(ns_t_a, sizeof(struct in_addr), rr->key,
433                                             anslen, &a);
434         if (resp_size < 0) {
435                 return -1;
436         }
437
438         memcpy(a, &rr->rrdata.a_rec, sizeof(struct in_addr));
439
440         return resp_size;
441 }
442
443 static ssize_t rwrap_fake_aaaa(struct rwrap_fake_rr *rr,
444                                uint8_t *answer,
445                                size_t anslen)
446 {
447         uint8_t *a = answer;
448         ssize_t resp_size;
449
450         if (rr == NULL || rr->type != ns_t_aaaa) {
451                 RWRAP_LOG(RWRAP_LOG_ERROR,
452                           "Malformed record, no or wrong value!\n");
453                 return -1;
454         }
455         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding AAAA RR");
456
457         resp_size = rwrap_fake_rdata_common(ns_t_aaaa, sizeof(struct in6_addr),
458                                             rr->key, anslen, &a);
459         if (resp_size < 0) {
460                 return -1;
461         }
462
463         memcpy(a, &rr->rrdata.aaaa_rec, sizeof(struct in6_addr));
464
465         return resp_size;
466 }
467
468 static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr,
469                               uint8_t *answer,
470                               size_t anslen)
471 {
472         uint8_t *a = answer;
473         ssize_t resp_size;
474         size_t rdata_size;
475         unsigned char hostname_compressed[MAXDNAME];
476         ssize_t compressed_len;
477
478         if (rr == NULL || rr->type != ns_t_srv) {
479                 RWRAP_LOG(RWRAP_LOG_ERROR,
480                           "Malformed record, no or wrong value!\n");
481                 return -1;
482         }
483         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SRV RR");
484         rdata_size = 3 * sizeof(uint16_t);
485
486         /* Prepare the data to write */
487         compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
488                                           hostname_compressed, MAXDNAME,
489                                           NULL, NULL);
490         if (compressed_len < 0) {
491                 return -1;
492         }
493         rdata_size += compressed_len;
494
495         resp_size = rwrap_fake_rdata_common(ns_t_srv, rdata_size,
496                                             rr->key, anslen, &a);
497         if (resp_size < 0) {
498                 return -1;
499         }
500
501         NS_PUT16(rr->rrdata.srv_rec.prio, a);
502         NS_PUT16(rr->rrdata.srv_rec.weight, a);
503         NS_PUT16(rr->rrdata.srv_rec.port, a);
504         memcpy(a, hostname_compressed, compressed_len);
505
506         return resp_size;
507 }
508
509 static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr,
510                               uint8_t *answer,
511                               size_t anslen)
512 {
513         uint8_t *a = answer;
514         ssize_t resp_size;
515         size_t rdata_size;
516         unsigned char nameser_compressed[MAXDNAME];
517         ssize_t compressed_ns_len;
518         unsigned char mailbox_compressed[MAXDNAME];
519         ssize_t compressed_mb_len;
520
521         if (rr == NULL || rr->type != ns_t_soa) {
522                 RWRAP_LOG(RWRAP_LOG_ERROR,
523                           "Malformed record, no or wrong value!\n");
524                 return -1;
525         }
526         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SOA RR");
527         rdata_size = 5 * sizeof(uint16_t);
528
529         compressed_ns_len = ns_name_compress(rr->rrdata.soa_rec.nameserver,
530                                              nameser_compressed,
531                                              MAXDNAME, NULL, NULL);
532         if (compressed_ns_len < 0) {
533                 return -1;
534         }
535         rdata_size += compressed_ns_len;
536
537         compressed_mb_len = ns_name_compress(rr->rrdata.soa_rec.mailbox,
538                                              mailbox_compressed,
539                                              MAXDNAME, NULL, NULL);
540         if (compressed_mb_len < 0) {
541                 return -1;
542         }
543         rdata_size += compressed_mb_len;
544
545         resp_size = rwrap_fake_rdata_common(ns_t_soa, rdata_size,
546                                             rr->key, anslen, &a);
547         if (resp_size < 0) {
548                 return -1;
549         }
550
551         memcpy(a, nameser_compressed, compressed_ns_len);
552         a += compressed_ns_len;
553         memcpy(a, mailbox_compressed, compressed_mb_len);
554         a += compressed_mb_len;
555         NS_PUT32(rr->rrdata.soa_rec.serial, a);
556         NS_PUT32(rr->rrdata.soa_rec.refresh, a);
557         NS_PUT32(rr->rrdata.soa_rec.retry, a);
558         NS_PUT32(rr->rrdata.soa_rec.expire, a);
559         NS_PUT32(rr->rrdata.soa_rec.minimum, a);
560
561         return resp_size;
562 }
563
564 static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr,
565                                 uint8_t *answer,
566                                 size_t anslen)
567 {
568         uint8_t *a = answer;
569         ssize_t resp_size;
570         unsigned char hostname_compressed[MAXDNAME];
571         ssize_t rdata_size;
572
573         if (rr == NULL || rr->type != ns_t_cname) {
574                 RWRAP_LOG(RWRAP_LOG_ERROR,
575                           "Malformed record, no or wrong value!\n");
576                 return -1;
577         }
578         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding CNAME RR");
579
580         /* Prepare the data to write */
581         rdata_size = ns_name_compress(rr->rrdata.cname_rec,
582                                       hostname_compressed, MAXDNAME,
583                                       NULL, NULL);
584         if (rdata_size < 0) {
585                 return -1;
586         }
587
588         resp_size = rwrap_fake_rdata_common(ns_t_cname, rdata_size,
589                                             rr->key, anslen, &a);
590         if (resp_size < 0) {
591                 return -1;
592         }
593
594         memcpy(a, hostname_compressed, rdata_size);
595
596         return resp_size;
597 }
598
599 #define RESOLV_MATCH(line, name) \
600         (strncmp(line, name, sizeof(name) - 1) == 0 && \
601         (line[sizeof(name) - 1] == ' ' || \
602          line[sizeof(name) - 1] == '\t'))
603
604 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
605         ((type) == (ns_type) && \
606          (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
607          (strcasecmp(key, query)) == 0)
608
609
610 static int rwrap_get_record(const char *hostfile, unsigned recursion,
611                             const char *query, int type,
612                             struct rwrap_fake_rr *rr);
613
614 static int rwrap_srv_recurse(const char *hostfile, unsigned recursion,
615                              const char *query, struct rwrap_fake_rr *rr)
616 {
617         int rc;
618
619         rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
620         if (rc == 0) return 0;
621
622         rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
623         if (rc == ENOENT) rc = 0;
624
625         return rc;
626 }
627
628 static int rwrap_cname_recurse(const char *hostfile, unsigned recursion,
629                                const char *query, struct rwrap_fake_rr *rr)
630 {
631         int rc;
632
633         rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
634         if (rc == 0) return 0;
635
636         rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
637         if (rc == 0) return 0;
638
639         rc = rwrap_get_record(hostfile, recursion, query, ns_t_cname, rr);
640         if (rc == ENOENT) rc = 0;
641
642         return rc;
643 }
644
645 static int rwrap_get_record(const char *hostfile, unsigned recursion,
646                             const char *query, int type,
647                             struct rwrap_fake_rr *rr)
648 {
649         FILE *fp = NULL;
650         char buf[BUFSIZ];
651         char *key = NULL;
652         char *value = NULL;
653         int rc = ENOENT;
654
655         if (recursion >= RWRAP_MAX_RECURSION) {
656                 RWRAP_LOG(RWRAP_LOG_ERROR, "Recursed too deep!\n");
657                 return -1;
658         }
659
660         RWRAP_LOG(RWRAP_LOG_TRACE,
661                   "Searching in fake hosts file %s\n", hostfile);
662
663         fp = fopen(hostfile, "r");
664         if (fp == NULL) {
665                 RWRAP_LOG(RWRAP_LOG_ERROR,
666                           "Opening %s failed: %s",
667                           hostfile, strerror(errno));
668                 return -1;
669         }
670
671         while (fgets(buf, sizeof(buf), fp) != NULL) {
672                 char *rec_type;
673                 char *q;
674
675                 rec_type = buf;
676                 key = value = NULL;
677
678                 NEXT_KEY(rec_type, key);
679                 NEXT_KEY(key, value);
680
681                 q = value;
682                 while(q[0] != '\n' && q[0] != '\0') {
683                         q++;
684                 }
685                 q[0] = '\0';
686
687                 if (key == NULL || value == NULL) {
688                         RWRAP_LOG(RWRAP_LOG_WARN,
689                                 "Malformed line: not enough parts, use \"rec_type key data\n"
690                                 "For example \"A cwrap.org 10.10.10.10\"");
691                         continue;
692                 }
693
694                 if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) {
695                         rc = rwrap_create_fake_a_rr(key, value, rr);
696                         break;
697                 } else if (TYPE_MATCH(type, ns_t_aaaa,
698                                       rec_type, "AAAA", key, query)) {
699                         rc = rwrap_create_fake_aaaa_rr(key, value, rr);
700                         break;
701                 } else if (TYPE_MATCH(type, ns_t_srv,
702                                       rec_type, "SRV", key, query)) {
703                         rc = rwrap_create_fake_srv_rr(key, value, rr);
704                         if (rc == 0) {
705                                 rc = rwrap_srv_recurse(hostfile, recursion+1,
706                                                 rr->rrdata.srv_rec.hostname,
707                                                 rr + 1);
708                         }
709                         break;
710                 } else if (TYPE_MATCH(type, ns_t_soa,
711                                       rec_type, "SOA", key, query)) {
712                         rc = rwrap_create_fake_soa_rr(key, value, rr);
713                         break;
714                 } else if (TYPE_MATCH(type, ns_t_cname,
715                                       rec_type, "CNAME", key, query)) {
716                         rc = rwrap_create_fake_cname_rr(key, value, rr);
717                         if (rc == 0) {
718                                 rc = rwrap_cname_recurse(hostfile, recursion+1,
719                                                          value, rr + 1);
720                         }
721                         break;
722                 }
723         }
724
725         if (rc == ENOENT && recursion == 0) {
726                 RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query);
727                 memcpy(rr->key, key, strlen(key) + 1);
728         }
729
730         fclose(fp);
731         return rc;
732 }
733
734 static ssize_t rwrap_fake_empty(int type,
735                                 const char *question,
736                                 uint8_t *answer,
737                                 size_t anslen)
738 {
739         ssize_t resp_data;
740         size_t remaining = anslen;
741
742         resp_data = rwrap_fake_header(&answer, remaining, 0, 0);
743         if (resp_data < 0) {
744                 return -1;
745         }
746         remaining -= resp_data;
747
748         resp_data += rwrap_fake_question(question, type, &answer, remaining);
749         if (resp_data < 0) {
750                 return -1;
751         }
752         remaining -= resp_data;
753
754         resp_data += rwrap_fake_rdata_common(type, 0, question,
755                                             remaining, &answer);
756         if (resp_data < 0) {
757                 return -1;
758         }
759
760         return resp_data;
761 }
762
763 static inline bool rwrap_known_type(int type)
764 {
765         switch (type) {
766         case ns_t_a:
767         case ns_t_aaaa:
768         case ns_t_srv:
769         case ns_t_soa:
770         case ns_t_cname:
771                 return true;
772         }
773
774         return false;
775 }
776
777 static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype)
778 {
779         int i;
780         int ancount = 0;
781
782         /* Include all RRs in the stack until the sought type
783          * in the answer section. This is the case i.e. when looking
784          * up an A record but the name points to a CNAME
785          */
786         for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
787                 ancount++;
788
789                 if (rwrap_known_type(rrs[i].type) &&
790                     rrs[i].type == qtype) {
791                         break;
792                 }
793         }
794
795         /* Return 0 records if the sought type wasn't in the stack */
796         return i < RWRAP_MAX_RECURSION ? ancount : 0;
797 }
798
799 static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount)
800 {
801         int i;
802         int arcount = 0;
803
804         /* start from index ancount */
805         for (i = ancount; i < RWRAP_MAX_RECURSION; i++) {
806                 if (rwrap_known_type(rrs[i].type)) {
807                         arcount++;
808                 }
809         }
810
811         return arcount;
812 }
813
814 static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
815                             uint8_t *answer,
816                             size_t anslen)
817 {
818         ssize_t resp_data;
819
820         switch (rr->type) {
821         case ns_t_a:
822                 resp_data = rwrap_fake_a(rr, answer, anslen);
823                 break;
824         case ns_t_aaaa:
825                 resp_data = rwrap_fake_aaaa(rr, answer, anslen);
826                 break;
827         case ns_t_srv:
828                 resp_data = rwrap_fake_srv(rr, answer, anslen);
829                 break;
830         case ns_t_soa:
831                 resp_data = rwrap_fake_soa(rr, answer, anslen);
832                 break;
833         case ns_t_cname:
834                 resp_data = rwrap_fake_cname(rr, answer, anslen);
835                 break;
836         default:
837                 return -1;
838         }
839
840         return resp_data;
841 }
842
843 static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs,
844                                  int type,
845                                  uint8_t *answer,
846                                  size_t anslen)
847
848 {
849         ssize_t resp_data;
850         ssize_t rrlen;
851         size_t remaining = anslen;
852         int ancount;
853         int arcount;
854         int i;
855
856         ancount = rwrap_ancount(rrs, type);
857         arcount = rwrap_arcount(rrs, ancount);
858         RWRAP_LOG(RWRAP_LOG_TRACE,
859                   "Got %d answers and %d additional records\n", ancount, arcount);
860
861         resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount);
862         if (resp_data < 0) {
863                 return -1;
864         }
865         remaining -= resp_data;
866
867         resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining);
868         if (resp_data < 0) {
869                 return -1;
870         }
871         remaining -= resp_data;
872
873         /* answer */
874         for (i = 0; i < ancount; i++) {
875                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
876                 if (rrlen < 0) {
877                         return -1;
878                 }
879                 remaining -= rrlen;
880                 answer += rrlen;
881                 resp_data += rrlen;
882         }
883
884         /* add authoritative NS here? */
885
886         /* additional records */
887         for (i = ancount; i < ancount + arcount; i++) {
888                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
889                 if (rrlen < 0) {
890                         return -1;
891                 }
892                 remaining -= rrlen;
893                 answer += rrlen;
894                 resp_data += rrlen;
895         }
896
897         return resp_data;
898 }
899
900 /* Reads in a file in the following format:
901  * TYPE RDATA
902  *
903  * Malformed entried are silently skipped.
904  * Allocates answer buffer of size anslen that has to be freed after use.
905  */
906 static int rwrap_res_fake_hosts(const char *hostfile,
907                                 const char *query,
908                                 int type,
909                                 unsigned char *answer,
910                                 size_t anslen)
911 {
912         int rc = ENOENT;
913         char *query_name = NULL;
914         size_t qlen = strlen(query);
915         struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION];
916         ssize_t resp_size;
917
918         RWRAP_LOG(RWRAP_LOG_TRACE,
919                   "Searching in fake hosts file %s\n", hostfile);
920
921         if (qlen > 0 && query[qlen-1] == '.') {
922                 qlen--;
923         }
924
925         query_name = strndup(query, qlen);
926         if (query_name == NULL) {
927                 return -1;
928         }
929
930         rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION);
931
932         rc = rwrap_get_record(hostfile, 0, query_name, type, rrs);
933         switch (rc) {
934         case 0:
935                 RWRAP_LOG(RWRAP_LOG_TRACE,
936                                 "Found record for [%s]\n", query_name);
937                 resp_size = rwrap_fake_answer(rrs, type, answer, anslen);
938                 break;
939         case ENOENT:
940                 RWRAP_LOG(RWRAP_LOG_TRACE,
941                                 "No record for [%s]\n", query_name);
942                 resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen);
943                 break;
944         default:
945                 RWRAP_LOG(RWRAP_LOG_ERROR,
946                                 "Error searching for [%s]\n", query_name);
947                 free(query_name);
948                 return -1;
949         }
950
951         switch (resp_size) {
952         case -1:
953                 RWRAP_LOG(RWRAP_LOG_ERROR,
954                                 "Error faking answer for [%s]\n", query_name);
955                 break;
956         default:
957                 RWRAP_LOG(RWRAP_LOG_TRACE,
958                                 "Successfully faked answer for [%s]\n",
959                                 query_name);
960                 break;
961         }
962
963         free(query_name);
964         return resp_size;
965 }
966
967 /*********************************************************
968  * RWRAP LOADING LIBC FUNCTIONS
969  *********************************************************/
970
971 #include <dlfcn.h>
972
973 struct rwrap_libc_fns {
974         int (*libc_res_init)(void);
975         int (*libc___res_init)(void);
976         int (*libc_res_ninit)(struct __res_state *state);
977         int (*libc___res_ninit)(struct __res_state *state);
978         void (*libc_res_nclose)(struct __res_state *state);
979         void (*libc___res_nclose)(struct __res_state *state);
980         void (*libc_res_close)(void);
981         void (*libc___res_close)(void);
982         int (*libc_res_nquery)(struct __res_state *state,
983                                const char *dname,
984                                int class,
985                                int type,
986                                unsigned char *answer,
987                                int anslen);
988         int (*libc___res_nquery)(struct __res_state *state,
989                                  const char *dname,
990                                  int class,
991                                  int type,
992                                  unsigned char *answer,
993                                  int anslen);
994         int (*libc_res_nsearch)(struct __res_state *state,
995                                 const char *dname,
996                                 int class,
997                                 int type,
998                                 unsigned char *answer,
999                                 int anslen);
1000         int (*libc___res_nsearch)(struct __res_state *state,
1001                                   const char *dname,
1002                                   int class,
1003                                   int type,
1004                                   unsigned char *answer,
1005                                   int anslen);
1006 };
1007
1008 struct rwrap {
1009         void *libc_handle;
1010         void *libresolv_handle;
1011
1012         bool initialised;
1013         bool enabled;
1014
1015         char *socket_dir;
1016
1017         struct rwrap_libc_fns fns;
1018 };
1019
1020 static struct rwrap rwrap;
1021
1022 enum rwrap_lib {
1023     RWRAP_LIBC,
1024     RWRAP_LIBRESOLV
1025 };
1026
1027 #ifndef NDEBUG
1028 static const char *rwrap_str_lib(enum rwrap_lib lib)
1029 {
1030         switch (lib) {
1031         case RWRAP_LIBC:
1032                 return "libc";
1033         case RWRAP_LIBRESOLV:
1034                 return "libresolv";
1035         }
1036
1037         /* Compiler would warn us about unhandled enum value if we get here */
1038         return "unknown";
1039 }
1040 #endif
1041
1042 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
1043 {
1044         int flags = RTLD_LAZY;
1045         void *handle = NULL;
1046         int i;
1047
1048 #ifdef RTLD_DEEPBIND
1049         flags |= RTLD_DEEPBIND;
1050 #endif
1051
1052         switch (lib) {
1053         case RWRAP_LIBRESOLV:
1054 #ifdef HAVE_LIBRESOLV
1055                 handle = rwrap.libresolv_handle;
1056                 if (handle == NULL) {
1057                         for (i = 10; i >= 0; i--) {
1058                                 char soname[256] = {0};
1059
1060                                 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
1061                                 handle = dlopen(soname, flags);
1062                                 if (handle != NULL) {
1063                                         break;
1064                                 }
1065                         }
1066
1067                         rwrap.libresolv_handle = handle;
1068                 }
1069                 break;
1070 #endif
1071                 /* FALL TROUGH */
1072         case RWRAP_LIBC:
1073                 handle = rwrap.libc_handle;
1074 #ifdef LIBC_SO
1075                 if (handle == NULL) {
1076                         handle = dlopen(LIBC_SO, flags);
1077
1078                         rwrap.libc_handle = handle;
1079                 }
1080 #endif
1081                 if (handle == NULL) {
1082                         for (i = 10; i >= 0; i--) {
1083                                 char soname[256] = {0};
1084
1085                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1086                                 handle = dlopen(soname, flags);
1087                                 if (handle != NULL) {
1088                                         break;
1089                                 }
1090                         }
1091
1092                         rwrap.libc_handle = handle;
1093                 }
1094                 break;
1095         }
1096
1097         if (handle == NULL) {
1098 #ifdef RTLD_NEXT
1099                 handle = rwrap.libc_handle = rwrap.libresolv_handle = RTLD_NEXT;
1100 #else
1101                 RWRAP_LOG(RWRAP_LOG_ERROR,
1102                           "Failed to dlopen library: %s\n",
1103                           dlerror());
1104                 exit(-1);
1105 #endif
1106         }
1107
1108         return handle;
1109 }
1110
1111 static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
1112 {
1113         void *handle;
1114         void *func;
1115
1116         handle = rwrap_load_lib_handle(lib);
1117
1118         func = dlsym(handle, fn_name);
1119         if (func == NULL) {
1120                 RWRAP_LOG(RWRAP_LOG_ERROR,
1121                                 "Failed to find %s: %s\n",
1122                                 fn_name, dlerror());
1123                 exit(-1);
1124         }
1125
1126         RWRAP_LOG(RWRAP_LOG_TRACE,
1127                         "Loaded %s from %s",
1128                         fn_name, rwrap_str_lib(lib));
1129         return func;
1130 }
1131
1132 #define rwrap_load_lib_function(lib, fn_name) \
1133         if (rwrap.fns.libc_##fn_name == NULL) { \
1134                 *(void **) (&rwrap.fns.libc_##fn_name) = \
1135                         _rwrap_load_lib_function(lib, #fn_name); \
1136         }
1137
1138 /*
1139  * IMPORTANT
1140  *
1141  * Functions especially from libc need to be loaded individually, you can't load
1142  * all at once or gdb will segfault at startup. The same applies to valgrind and
1143  * has probably something todo with with the linker.
1144  * So we need load each function at the point it is called the first time.
1145  */
1146 #if 0
1147 static int libc_res_init(void)
1148 {
1149 #if defined(HAVE_RES_INIT)
1150         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_init);
1151
1152         return rwrap.fns.libc_res_init();
1153 #elif defined(HAVE___RES_INIT)
1154         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_init);
1155
1156         return rwrap.fns.libc___res_init();
1157 #endif
1158 }
1159 #endif
1160
1161 static int libc_res_ninit(struct __res_state *state)
1162 {
1163 #if defined(HAVE_RES_NINIT)
1164
1165 #if defined(HAVE_RES_NINIT_IN_LIBRESOLV)
1166         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_ninit);
1167 #else /* HAVE_RES_NINIT_IN_LIBRESOLV */
1168         rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
1169 #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */
1170
1171         return rwrap.fns.libc_res_ninit(state);
1172 #elif defined(HAVE___RES_NINIT)
1173         rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
1174
1175         return rwrap.fns.libc___res_ninit(state);
1176 #else
1177 #error "No res_ninit function"
1178 #endif
1179 }
1180
1181 static void libc_res_nclose(struct __res_state *state)
1182 {
1183 #if defined(HAVE_RES_NCLOSE)
1184
1185 #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV)
1186         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nclose);
1187 #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1188         rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
1189 #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1190
1191         rwrap.fns.libc_res_nclose(state);
1192 #elif defined(HAVE___RES_NCLOSE)
1193         rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
1194
1195         rwrap.fns.libc___res_nclose(state);
1196 #else
1197 #error "No res_nclose function"
1198 #endif
1199 }
1200
1201 static int libc_res_nquery(struct __res_state *state,
1202                            const char *dname,
1203                            int class,
1204                            int type,
1205                            unsigned char *answer,
1206                            int anslen)
1207 {
1208 #if defined(HAVE_RES_NQUERY)
1209         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
1210
1211         return rwrap.fns.libc_res_nquery(state,
1212                                          dname,
1213                                          class,
1214                                          type,
1215                                          answer,
1216                                          anslen);
1217 #elif defined(HAVE___RES_NQUERY)
1218         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
1219
1220         return rwrap.fns.libc___res_nquery(state,
1221                                            dname,
1222                                            class,
1223                                            type,
1224                                            answer,
1225                                            anslen);
1226 #else
1227 #error "No res_nquery function"
1228 #endif
1229 }
1230
1231 static int libc_res_nsearch(struct __res_state *state,
1232                             const char *dname,
1233                             int class,
1234                             int type,
1235                             unsigned char *answer,
1236                             int anslen)
1237 {
1238 #if defined(HAVE_RES_NSEARCH)
1239         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
1240
1241         return rwrap.fns.libc_res_nsearch(state,
1242                                           dname,
1243                                           class,
1244                                           type,
1245                                           answer,
1246                                           anslen);
1247 #elif defined(HAVE___RES_NSEARCH)
1248         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
1249
1250         return rwrap.fns.libc___res_nsearch(state,
1251                                             dname,
1252                                             class,
1253                                             type,
1254                                             answer,
1255                                             anslen);
1256 #else
1257 #error "No res_nsearch function"
1258 #endif
1259 }
1260
1261 /****************************************************************************
1262  *   RES_HELPER
1263  ***************************************************************************/
1264
1265 static int rwrap_parse_resolv_conf(struct __res_state *state,
1266                                    const char *resolv_conf)
1267 {
1268         FILE *fp;
1269         char buf[BUFSIZ];
1270         int nserv = 0;
1271
1272         fp = fopen(resolv_conf, "r");
1273         if (fp == NULL) {
1274                 RWRAP_LOG(RWRAP_LOG_ERROR,
1275                           "Opening %s failed: %s",
1276                           resolv_conf, strerror(errno));
1277                 return -1;
1278         }
1279
1280         while(fgets(buf, sizeof(buf), fp) != NULL) {
1281                 char *p;
1282
1283                 /* Ignore comments */
1284                 if (buf[0] == '#' || buf[0] == ';') {
1285                         continue;
1286                 }
1287
1288                 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
1289                         struct in_addr a;
1290                         char *q;
1291                         int ok;
1292
1293                         p = buf + strlen("nameserver");
1294
1295                         /* Skip spaces and tabs */
1296                         while(isblank((int)p[0])) {
1297                                 p++;
1298                         }
1299
1300                         q = p;
1301                         while(q[0] != '\n' && q[0] != '\0') {
1302                                 q++;
1303                         }
1304                         q[0] = '\0';
1305
1306                         ok = inet_pton(AF_INET, p, &a);
1307                         if (ok) {
1308                                 state->nsaddr_list[state->nscount] = (struct sockaddr_in) {
1309                                         .sin_family = AF_INET,
1310                                         .sin_addr = a,
1311                                         .sin_port = htons(53),
1312                                         .sin_zero = { 0 },
1313                                 };
1314
1315                                 state->nscount++;
1316                                 nserv++;
1317                         } else {
1318 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1319                                 /* IPv6 */
1320                                 struct in6_addr a6;
1321                                 ok = inet_pton(AF_INET6, p, &a6);
1322                                 if (ok) {
1323                                         struct sockaddr_in6 *sa6;
1324
1325                                         sa6 = malloc(sizeof(*sa6));
1326                                         if (sa6 == NULL) {
1327                                                 fclose(fp);
1328                                                 return -1;
1329                                         }
1330
1331                                         sa6->sin6_family = AF_INET6;
1332                                         sa6->sin6_port = htons(53);
1333                                         sa6->sin6_flowinfo = 0;
1334                                         sa6->sin6_addr = a6;
1335
1336                                         state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6;
1337                                         state->_u._ext.nssocks[state->_u._ext.nscount] = -1;
1338                                         state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1;
1339
1340                                         state->_u._ext.nscount++;
1341                                         nserv++;
1342                                 } else {
1343                                         RWRAP_LOG(RWRAP_LOG_ERROR,
1344                                                 "Malformed DNS server");
1345                                         continue;
1346                                 }
1347 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1348                                 /*
1349                                  * BSD uses an opaque structure to store the
1350                                  * IPv6 addresses. So we can not simply store
1351                                  * these addresses the same way as above.
1352                                  */
1353                                 RWRAP_LOG(RWRAP_LOG_WARN,
1354                                           "resolve_wrapper does not support "
1355                                           "IPv6 on this platform");
1356                                         continue;
1357 #endif
1358                         }
1359                         continue;
1360                 } /* TODO: match other keywords */
1361         }
1362
1363         if (ferror(fp)) {
1364                 RWRAP_LOG(RWRAP_LOG_ERROR,
1365                           "Reading from %s failed",
1366                           resolv_conf);
1367                 fclose(fp);
1368                 return -1;
1369         }
1370
1371         fclose(fp);
1372         return 0;
1373 }
1374
1375 /****************************************************************************
1376  *   RES_NINIT
1377  ***************************************************************************/
1378
1379 static int rwrap_res_ninit(struct __res_state *state)
1380 {
1381         int rc;
1382
1383         rc = libc_res_ninit(state);
1384         if (rc == 0) {
1385                 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1386
1387                 if (resolv_conf != NULL) {
1388                         uint16_t i;
1389
1390                         (void)i; /* maybe unused */
1391
1392                         /* Delete name servers */
1393                         state->nscount = 0;
1394                         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1395
1396                         state->_u._ext.nscount = 0;
1397 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1398                         for (i = 0; i < state->_u._ext.nscount; i++) {
1399                                 SAFE_FREE(state->_u._ext.nsaddrs[i]);
1400                         }
1401 #endif
1402
1403                         rc = rwrap_parse_resolv_conf(state, resolv_conf);
1404                 }
1405         }
1406
1407         return rc;
1408 }
1409
1410 #if defined(HAVE_RES_NINIT)
1411 int res_ninit(struct __res_state *state)
1412 #elif defined(HAVE___RES_NINIT)
1413 int __res_ninit(struct __res_state *state)
1414 #endif
1415 {
1416         return rwrap_res_ninit(state);
1417 }
1418
1419 /****************************************************************************
1420  *   RES_INIT
1421  ***************************************************************************/
1422
1423 static struct __res_state rwrap_res_state;
1424
1425 static int rwrap_res_init(void)
1426 {
1427         int rc;
1428
1429         rc = rwrap_res_ninit(&rwrap_res_state);
1430
1431         return rc;
1432 }
1433
1434 #if defined(HAVE_RES_INIT)
1435 int res_init(void)
1436 #elif defined(HAVE___RES_INIT)
1437 int __res_init(void)
1438 #endif
1439 {
1440         return rwrap_res_init();
1441 }
1442
1443 /****************************************************************************
1444  *   RES_NCLOSE
1445  ***************************************************************************/
1446
1447 static void rwrap_res_nclose(struct __res_state *state)
1448 {
1449 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1450         int i;
1451 #endif
1452
1453         libc_res_nclose(state);
1454
1455 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1456         if (state != NULL) {
1457                 for (i = 0; i < state->_u._ext.nscount; i++) {
1458                         SAFE_FREE(state->_u._ext.nsaddrs[i]);
1459                 }
1460         }
1461 #endif
1462 }
1463
1464 #if defined(HAVE_RES_NCLOSE)
1465 void res_nclose(struct __res_state *state)
1466 #elif defined(HAVE___RES_NCLOSE)
1467 void __res_nclose(struct __res_state *state)
1468 #endif
1469 {
1470         rwrap_res_nclose(state);
1471 }
1472
1473 /****************************************************************************
1474  *   RES_CLOSE
1475  ***************************************************************************/
1476
1477 static void rwrap_res_close(void)
1478 {
1479         rwrap_res_nclose(&rwrap_res_state);
1480 }
1481
1482 #if defined(HAVE_RES_CLOSE)
1483 void res_close(void)
1484 #elif defined(HAVE___RES_CLOSE)
1485 void __res_close(void)
1486 #endif
1487 {
1488         rwrap_res_close();
1489 }
1490
1491 /****************************************************************************
1492  *   RES_NQUERY
1493  ***************************************************************************/
1494
1495 static int rwrap_res_nquery(struct __res_state *state,
1496                             const char *dname,
1497                             int class,
1498                             int type,
1499                             unsigned char *answer,
1500                             int anslen)
1501 {
1502         int rc;
1503         const char *fake_hosts;
1504 #ifndef NDEBUG
1505         int i;
1506 #endif
1507
1508         RWRAP_LOG(RWRAP_LOG_TRACE,
1509                   "Resolve the domain name [%s] - class=%d, type=%d",
1510                   dname, class, type);
1511 #ifndef NDEBUG
1512         for (i = 0; i < state->nscount; i++) {
1513                 char ip[INET6_ADDRSTRLEN];
1514
1515                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1516                 RWRAP_LOG(RWRAP_LOG_TRACE,
1517                           "        nameserver: %s",
1518                           ip);
1519         }
1520 #endif
1521
1522         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1523         if (fake_hosts != NULL) {
1524                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1525         } else {
1526                 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
1527         }
1528
1529
1530         RWRAP_LOG(RWRAP_LOG_TRACE,
1531                   "The returned response length is: %d",
1532                   rc);
1533
1534         return rc;
1535 }
1536
1537 #if defined(HAVE_RES_NQUERY)
1538 int res_nquery(struct __res_state *state,
1539                const char *dname,
1540                int class,
1541                int type,
1542                unsigned char *answer,
1543                int anslen)
1544 #elif defined(HAVE___RES_NQUERY)
1545 int __res_nquery(struct __res_state *state,
1546                  const char *dname,
1547                  int class,
1548                  int type,
1549                  unsigned char *answer,
1550                  int anslen)
1551 #endif
1552 {
1553         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
1554 }
1555
1556 /****************************************************************************
1557  *   RES_QUERY
1558  ***************************************************************************/
1559
1560 static int rwrap_res_query(const char *dname,
1561                            int class,
1562                            int type,
1563                            unsigned char *answer,
1564                            int anslen)
1565 {
1566         int rc;
1567
1568         rc = rwrap_res_ninit(&rwrap_res_state);
1569         if (rc != 0) {
1570                 return rc;
1571         }
1572
1573         rc = rwrap_res_nquery(&rwrap_res_state,
1574                               dname,
1575                               class,
1576                               type,
1577                               answer,
1578                               anslen);
1579
1580         return rc;
1581 }
1582
1583 #if defined(HAVE_RES_QUERY)
1584 int res_query(const char *dname,
1585               int class,
1586               int type,
1587               unsigned char *answer,
1588               int anslen)
1589 #elif defined(HAVE___RES_QUERY)
1590 int __res_query(const char *dname,
1591                 int class,
1592                 int type,
1593                 unsigned char *answer,
1594                 int anslen)
1595 #endif
1596 {
1597         return rwrap_res_query(dname, class, type, answer, anslen);
1598 }
1599
1600 /****************************************************************************
1601  *   RES_NSEARCH
1602  ***************************************************************************/
1603
1604 static int rwrap_res_nsearch(struct __res_state *state,
1605                              const char *dname,
1606                              int class,
1607                              int type,
1608                              unsigned char *answer,
1609                              int anslen)
1610 {
1611         int rc;
1612         const char *fake_hosts;
1613 #ifndef NDEBUG
1614         int i;
1615 #endif
1616
1617         RWRAP_LOG(RWRAP_LOG_TRACE,
1618                   "Resolve the domain name [%s] - class=%d, type=%d",
1619                   dname, class, type);
1620 #ifndef NDEBUG
1621         for (i = 0; i < state->nscount; i++) {
1622                 char ip[INET6_ADDRSTRLEN];
1623
1624                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1625                 RWRAP_LOG(RWRAP_LOG_TRACE,
1626                           "        nameserver: %s",
1627                           ip);
1628         }
1629 #endif
1630
1631         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1632         if (fake_hosts != NULL) {
1633                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1634         } else {
1635                 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
1636         }
1637
1638         RWRAP_LOG(RWRAP_LOG_TRACE,
1639                   "The returned response length is: %d",
1640                   rc);
1641
1642         return rc;
1643 }
1644
1645 #if defined(HAVE_RES_NSEARCH)
1646 int res_nsearch(struct __res_state *state,
1647                 const char *dname,
1648                 int class,
1649                 int type,
1650                 unsigned char *answer,
1651                 int anslen)
1652 #elif defined(HAVE___RES_NSEARCH)
1653 int __res_nsearch(struct __res_state *state,
1654                   const char *dname,
1655                   int class,
1656                   int type,
1657                   unsigned char *answer,
1658                   int anslen)
1659 #endif
1660 {
1661         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
1662 }
1663
1664 /****************************************************************************
1665  *   RES_QUERY
1666  ***************************************************************************/
1667
1668 static int rwrap_res_search(const char *dname,
1669                             int class,
1670                             int type,
1671                             unsigned char *answer,
1672                             int anslen)
1673 {
1674         int rc;
1675
1676         rc = rwrap_res_ninit(&rwrap_res_state);
1677         if (rc != 0) {
1678                 return rc;
1679         }
1680
1681         rc = rwrap_res_nsearch(&rwrap_res_state,
1682                                dname,
1683                                class,
1684                                type,
1685                                answer,
1686                                anslen);
1687
1688         return rc;
1689 }
1690
1691 #if defined(HAVE_RES_SEARCH)
1692 int res_search(const char *dname,
1693                int class,
1694                int type,
1695                unsigned char *answer,
1696                int anslen)
1697 #elif defined(HAVE___RES_SEARCH)
1698 int __res_search(const char *dname,
1699                  int class,
1700                  int type,
1701                  unsigned char *answer,
1702                  int anslen)
1703 #endif
1704 {
1705         return rwrap_res_search(dname, class, type, answer, anslen);
1706 }