rwrap: Don't dereference NULL when skipping broken records
[resolv_wrapper.git] / src / resolv_wrapper.c
1 /*
2  * Copyright (c) 2014      Andreas Schneider <asn@samba.org>
3  * Copyright (c) 2014      Jakub Hrozek <jakub.hrozek@gmail.com>
4  *
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the author nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include "config.h"
36
37 #include <errno.h>
38 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <sys/types.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <stdbool.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <ctype.h>
48
49 #include <resolv.h>
50
51 /* GCC has printf type attribute check. */
52 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
53 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
54 #else
55 #define PRINTF_ATTRIBUTE(a,b)
56 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
57
58 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
59 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
60 #else
61 #define DESTRUCTOR_ATTRIBUTE
62 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
63
64 #ifndef RWRAP_DEFAULT_FAKE_TTL
65 #define RWRAP_DEFAULT_FAKE_TTL 600
66 #endif  /* RWRAP_DEFAULT_FAKE_TTL */
67
68 enum rwrap_dbglvl_e {
69         RWRAP_LOG_ERROR = 0,
70         RWRAP_LOG_WARN,
71         RWRAP_LOG_DEBUG,
72         RWRAP_LOG_TRACE
73 };
74
75 #ifdef NDEBUG
76 # define RWRAP_LOG(...)
77 #else /* NDEBUG */
78
79 static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
80 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
81
82 static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
83                       const char *func,
84                       const char *format, ...)
85 {
86         char buffer[1024];
87         va_list va;
88         const char *d;
89         unsigned int lvl = 0;
90         int pid = getpid();
91
92         d = getenv("RESOLV_WRAPPER_DEBUGLEVEL");
93         if (d != NULL) {
94                 lvl = atoi(d);
95         }
96
97         va_start(va, format);
98         vsnprintf(buffer, sizeof(buffer), format, va);
99         va_end(va);
100
101         if (lvl >= dbglvl) {
102                 switch (dbglvl) {
103                         case RWRAP_LOG_ERROR:
104                                 fprintf(stderr,
105                                         "RWRAP_ERROR(%d) - %s: %s\n",
106                                         pid, func, buffer);
107                                 break;
108                         case RWRAP_LOG_WARN:
109                                 fprintf(stderr,
110                                         "RWRAP_WARN(%d) - %s: %s\n",
111                                         pid, func, buffer);
112                                 break;
113                         case RWRAP_LOG_DEBUG:
114                                 fprintf(stderr,
115                                         "RWRAP_DEBUG(%d) - %s: %s\n",
116                                         pid, func, buffer);
117                                 break;
118                         case RWRAP_LOG_TRACE:
119                                 fprintf(stderr,
120                                         "RWRAP_TRACE(%d) - %s: %s\n",
121                                         pid, func, buffer);
122                                 break;
123                 }
124         }
125 }
126 #endif /* NDEBUG RWRAP_LOG */
127
128 #ifndef SAFE_FREE
129 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
130 #endif
131
132 #define NEXT_KEY(buf, key) do {                                 \
133         (key) = (buf) ? strpbrk((buf), " \t") : NULL;           \
134         if ((key) != NULL) {                                    \
135                 (key)[0] = '\0';                                \
136                 (key)++;                                        \
137         }                                                       \
138         while ((key) != NULL                                    \
139                && (isblank((int)(key)[0]))) {                   \
140                 (key)++;                                        \
141         }                                                       \
142 } while(0);
143
144 #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                 if (key == NULL || value == NULL) {
682                         RWRAP_LOG(RWRAP_LOG_WARN,
683                                 "Malformed line: not enough parts, use \"rec_type key data\n"
684                                 "For example \"A cwrap.org 10.10.10.10\"");
685                         continue;
686                 }
687
688                 q = value;
689                 while(q[0] != '\n' && q[0] != '\0') {
690                         q++;
691                 }
692                 q[0] = '\0';
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                 } else if (TYPE_MATCH(type, ns_t_a, rec_type, "CNAME", key, query)) {
723                         rc = rwrap_create_fake_cname_rr(key, value, rr);
724                         if (rc == 0) {
725                                 rc = rwrap_cname_recurse(hostfile, recursion+1,
726                                                          value, rr + 1);
727                         }
728                         break;
729                 }
730         }
731
732         if (rc == ENOENT && recursion == 0) {
733                 RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query);
734                 memcpy(rr->key, key, strlen(key) + 1);
735         }
736
737         fclose(fp);
738         return rc;
739 }
740
741 static ssize_t rwrap_fake_empty(int type,
742                                 const char *question,
743                                 uint8_t *answer,
744                                 size_t anslen)
745 {
746         ssize_t resp_data;
747         size_t remaining = anslen;
748
749         resp_data = rwrap_fake_header(&answer, remaining, 0, 0);
750         if (resp_data < 0) {
751                 return -1;
752         }
753         remaining -= resp_data;
754
755         resp_data += rwrap_fake_question(question, type, &answer, remaining);
756         if (resp_data < 0) {
757                 return -1;
758         }
759         remaining -= resp_data;
760
761         resp_data += rwrap_fake_rdata_common(type, 0, question,
762                                             remaining, &answer);
763         if (resp_data < 0) {
764                 return -1;
765         }
766
767         return resp_data;
768 }
769
770 static inline bool rwrap_known_type(int type)
771 {
772         switch (type) {
773         case ns_t_a:
774         case ns_t_aaaa:
775         case ns_t_srv:
776         case ns_t_soa:
777         case ns_t_cname:
778                 return true;
779         }
780
781         return false;
782 }
783
784 static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype)
785 {
786         int i;
787         int ancount = 0;
788
789         /* Include all RRs in the stack until the sought type
790          * in the answer section. This is the case i.e. when looking
791          * up an A record but the name points to a CNAME
792          */
793         for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
794                 ancount++;
795
796                 if (rwrap_known_type(rrs[i].type) &&
797                     rrs[i].type == qtype) {
798                         break;
799                 }
800         }
801
802         /* Return 0 records if the sought type wasn't in the stack */
803         return i < RWRAP_MAX_RECURSION ? ancount : 0;
804 }
805
806 static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount)
807 {
808         int i;
809         int arcount = 0;
810
811         /* start from index ancount */
812         for (i = ancount; i < RWRAP_MAX_RECURSION; i++) {
813                 if (rwrap_known_type(rrs[i].type)) {
814                         arcount++;
815                 }
816         }
817
818         return arcount;
819 }
820
821 static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
822                             uint8_t *answer,
823                             size_t anslen)
824 {
825         ssize_t resp_data;
826
827         switch (rr->type) {
828         case ns_t_a:
829                 resp_data = rwrap_fake_a(rr, answer, anslen);
830                 break;
831         case ns_t_aaaa:
832                 resp_data = rwrap_fake_aaaa(rr, answer, anslen);
833                 break;
834         case ns_t_srv:
835                 resp_data = rwrap_fake_srv(rr, answer, anslen);
836                 break;
837         case ns_t_soa:
838                 resp_data = rwrap_fake_soa(rr, answer, anslen);
839                 break;
840         case ns_t_cname:
841                 resp_data = rwrap_fake_cname(rr, answer, anslen);
842                 break;
843         default:
844                 return -1;
845         }
846
847         return resp_data;
848 }
849
850 static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs,
851                                  int type,
852                                  uint8_t *answer,
853                                  size_t anslen)
854
855 {
856         ssize_t resp_data;
857         ssize_t rrlen;
858         size_t remaining = anslen;
859         int ancount;
860         int arcount;
861         int i;
862
863         ancount = rwrap_ancount(rrs, type);
864         arcount = rwrap_arcount(rrs, ancount);
865         RWRAP_LOG(RWRAP_LOG_TRACE,
866                   "Got %d answers and %d additional records\n", ancount, arcount);
867
868         resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount);
869         if (resp_data < 0) {
870                 return -1;
871         }
872         remaining -= resp_data;
873
874         resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining);
875         if (resp_data < 0) {
876                 return -1;
877         }
878         remaining -= resp_data;
879
880         /* answer */
881         for (i = 0; i < ancount; i++) {
882                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
883                 if (rrlen < 0) {
884                         return -1;
885                 }
886                 remaining -= rrlen;
887                 answer += rrlen;
888                 resp_data += rrlen;
889         }
890
891         /* add authoritative NS here? */
892
893         /* additional records */
894         for (i = ancount; i < ancount + arcount; i++) {
895                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
896                 if (rrlen < 0) {
897                         return -1;
898                 }
899                 remaining -= rrlen;
900                 answer += rrlen;
901                 resp_data += rrlen;
902         }
903
904         return resp_data;
905 }
906
907 /* Reads in a file in the following format:
908  * TYPE RDATA
909  *
910  * Malformed entried are silently skipped.
911  * Allocates answer buffer of size anslen that has to be freed after use.
912  */
913 static int rwrap_res_fake_hosts(const char *hostfile,
914                                 const char *query,
915                                 int type,
916                                 unsigned char *answer,
917                                 size_t anslen)
918 {
919         int rc = ENOENT;
920         char *query_name = NULL;
921         size_t qlen = strlen(query);
922         struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION];
923         ssize_t resp_size;
924
925         RWRAP_LOG(RWRAP_LOG_TRACE,
926                   "Searching in fake hosts file %s\n", hostfile);
927
928         if (qlen > 0 && query[qlen-1] == '.') {
929                 qlen--;
930         }
931
932         query_name = strndup(query, qlen);
933         if (query_name == NULL) {
934                 return -1;
935         }
936
937         rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION);
938
939         rc = rwrap_get_record(hostfile, 0, query_name, type, rrs);
940         switch (rc) {
941         case 0:
942                 RWRAP_LOG(RWRAP_LOG_TRACE,
943                                 "Found record for [%s]\n", query_name);
944                 resp_size = rwrap_fake_answer(rrs, type, answer, anslen);
945                 break;
946         case ENOENT:
947                 RWRAP_LOG(RWRAP_LOG_TRACE,
948                                 "No record for [%s]\n", query_name);
949                 resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen);
950                 break;
951         default:
952                 RWRAP_LOG(RWRAP_LOG_ERROR,
953                                 "Error searching for [%s]\n", query_name);
954                 free(query_name);
955                 return -1;
956         }
957
958         switch (resp_size) {
959         case -1:
960                 RWRAP_LOG(RWRAP_LOG_ERROR,
961                                 "Error faking answer for [%s]\n", query_name);
962                 break;
963         default:
964                 RWRAP_LOG(RWRAP_LOG_TRACE,
965                                 "Successfully faked answer for [%s]\n",
966                                 query_name);
967                 break;
968         }
969
970         free(query_name);
971         return resp_size;
972 }
973
974 /*********************************************************
975  * RWRAP LOADING LIBC FUNCTIONS
976  *********************************************************/
977
978 #include <dlfcn.h>
979
980 struct rwrap_libc_fns {
981         int (*libc_res_init)(void);
982         int (*libc___res_init)(void);
983         int (*libc_res_ninit)(struct __res_state *state);
984         int (*libc___res_ninit)(struct __res_state *state);
985         void (*libc_res_nclose)(struct __res_state *state);
986         void (*libc___res_nclose)(struct __res_state *state);
987         void (*libc_res_close)(void);
988         void (*libc___res_close)(void);
989         int (*libc_res_nquery)(struct __res_state *state,
990                                const char *dname,
991                                int class,
992                                int type,
993                                unsigned char *answer,
994                                int anslen);
995         int (*libc___res_nquery)(struct __res_state *state,
996                                  const char *dname,
997                                  int class,
998                                  int type,
999                                  unsigned char *answer,
1000                                  int anslen);
1001         int (*libc_res_nsearch)(struct __res_state *state,
1002                                 const char *dname,
1003                                 int class,
1004                                 int type,
1005                                 unsigned char *answer,
1006                                 int anslen);
1007         int (*libc___res_nsearch)(struct __res_state *state,
1008                                   const char *dname,
1009                                   int class,
1010                                   int type,
1011                                   unsigned char *answer,
1012                                   int anslen);
1013 };
1014
1015 struct rwrap {
1016         void *libc_handle;
1017         void *libresolv_handle;
1018
1019         bool initialised;
1020         bool enabled;
1021
1022         char *socket_dir;
1023
1024         struct rwrap_libc_fns fns;
1025 };
1026
1027 static struct rwrap rwrap;
1028
1029 enum rwrap_lib {
1030     RWRAP_LIBC,
1031     RWRAP_LIBRESOLV
1032 };
1033
1034 #ifndef NDEBUG
1035 static const char *rwrap_str_lib(enum rwrap_lib lib)
1036 {
1037         switch (lib) {
1038         case RWRAP_LIBC:
1039                 return "libc";
1040         case RWRAP_LIBRESOLV:
1041                 return "libresolv";
1042         }
1043
1044         /* Compiler would warn us about unhandled enum value if we get here */
1045         return "unknown";
1046 }
1047 #endif
1048
1049 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
1050 {
1051         int flags = RTLD_LAZY;
1052         void *handle = NULL;
1053         int i;
1054
1055 #ifdef RTLD_DEEPBIND
1056         flags |= RTLD_DEEPBIND;
1057 #endif
1058
1059         switch (lib) {
1060         case RWRAP_LIBRESOLV:
1061 #ifdef HAVE_LIBRESOLV
1062                 handle = rwrap.libresolv_handle;
1063                 if (handle == NULL) {
1064                         for (i = 10; i >= 0; i--) {
1065                                 char soname[256] = {0};
1066
1067                                 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
1068                                 handle = dlopen(soname, flags);
1069                                 if (handle != NULL) {
1070                                         break;
1071                                 }
1072                         }
1073
1074                         rwrap.libresolv_handle = handle;
1075                 }
1076                 break;
1077 #endif
1078                 /* FALL TROUGH */
1079         case RWRAP_LIBC:
1080                 handle = rwrap.libc_handle;
1081 #ifdef LIBC_SO
1082                 if (handle == NULL) {
1083                         handle = dlopen(LIBC_SO, flags);
1084
1085                         rwrap.libc_handle = handle;
1086                 }
1087 #endif
1088                 if (handle == NULL) {
1089                         for (i = 10; i >= 0; i--) {
1090                                 char soname[256] = {0};
1091
1092                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1093                                 handle = dlopen(soname, flags);
1094                                 if (handle != NULL) {
1095                                         break;
1096                                 }
1097                         }
1098
1099                         rwrap.libc_handle = handle;
1100                 }
1101                 break;
1102         }
1103
1104         if (handle == NULL) {
1105 #ifdef RTLD_NEXT
1106                 handle = rwrap.libc_handle = rwrap.libresolv_handle = RTLD_NEXT;
1107 #else
1108                 RWRAP_LOG(RWRAP_LOG_ERROR,
1109                           "Failed to dlopen library: %s\n",
1110                           dlerror());
1111                 exit(-1);
1112 #endif
1113         }
1114
1115         return handle;
1116 }
1117
1118 static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
1119 {
1120         void *handle;
1121         void *func;
1122
1123         handle = rwrap_load_lib_handle(lib);
1124
1125         func = dlsym(handle, fn_name);
1126         if (func == NULL) {
1127                 RWRAP_LOG(RWRAP_LOG_ERROR,
1128                                 "Failed to find %s: %s\n",
1129                                 fn_name, dlerror());
1130                 exit(-1);
1131         }
1132
1133         RWRAP_LOG(RWRAP_LOG_TRACE,
1134                         "Loaded %s from %s",
1135                         fn_name, rwrap_str_lib(lib));
1136         return func;
1137 }
1138
1139 #define rwrap_load_lib_function(lib, fn_name) \
1140         if (rwrap.fns.libc_##fn_name == NULL) { \
1141                 *(void **) (&rwrap.fns.libc_##fn_name) = \
1142                         _rwrap_load_lib_function(lib, #fn_name); \
1143         }
1144
1145 /*
1146  * IMPORTANT
1147  *
1148  * Functions especially from libc need to be loaded individually, you can't load
1149  * all at once or gdb will segfault at startup. The same applies to valgrind and
1150  * has probably something todo with with the linker.
1151  * So we need load each function at the point it is called the first time.
1152  */
1153 #if 0
1154 static int libc_res_init(void)
1155 {
1156 #if defined(HAVE_RES_INIT)
1157         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_init);
1158
1159         return rwrap.fns.libc_res_init();
1160 #elif defined(HAVE___RES_INIT)
1161         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_init);
1162
1163         return rwrap.fns.libc___res_init();
1164 #endif
1165 }
1166 #endif
1167
1168 static int libc_res_ninit(struct __res_state *state)
1169 {
1170 #if defined(HAVE_RES_NINIT)
1171
1172 #if defined(HAVE_RES_NINIT_IN_LIBRESOLV)
1173         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_ninit);
1174 #else /* HAVE_RES_NINIT_IN_LIBRESOLV */
1175         rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
1176 #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */
1177
1178         return rwrap.fns.libc_res_ninit(state);
1179 #elif defined(HAVE___RES_NINIT)
1180         rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
1181
1182         return rwrap.fns.libc___res_ninit(state);
1183 #else
1184 #error "No res_ninit function"
1185 #endif
1186 }
1187
1188 static void libc_res_nclose(struct __res_state *state)
1189 {
1190 #if defined(HAVE_RES_NCLOSE)
1191
1192 #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV)
1193         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nclose);
1194 #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1195         rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
1196 #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1197
1198         rwrap.fns.libc_res_nclose(state);
1199 #elif defined(HAVE___RES_NCLOSE)
1200         rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
1201
1202         rwrap.fns.libc___res_nclose(state);
1203 #else
1204 #error "No res_nclose function"
1205 #endif
1206 }
1207
1208 static int libc_res_nquery(struct __res_state *state,
1209                            const char *dname,
1210                            int class,
1211                            int type,
1212                            unsigned char *answer,
1213                            int anslen)
1214 {
1215 #if defined(HAVE_RES_NQUERY)
1216         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
1217
1218         return rwrap.fns.libc_res_nquery(state,
1219                                          dname,
1220                                          class,
1221                                          type,
1222                                          answer,
1223                                          anslen);
1224 #elif defined(HAVE___RES_NQUERY)
1225         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
1226
1227         return rwrap.fns.libc___res_nquery(state,
1228                                            dname,
1229                                            class,
1230                                            type,
1231                                            answer,
1232                                            anslen);
1233 #else
1234 #error "No res_nquery function"
1235 #endif
1236 }
1237
1238 static int libc_res_nsearch(struct __res_state *state,
1239                             const char *dname,
1240                             int class,
1241                             int type,
1242                             unsigned char *answer,
1243                             int anslen)
1244 {
1245 #if defined(HAVE_RES_NSEARCH)
1246         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
1247
1248         return rwrap.fns.libc_res_nsearch(state,
1249                                           dname,
1250                                           class,
1251                                           type,
1252                                           answer,
1253                                           anslen);
1254 #elif defined(HAVE___RES_NSEARCH)
1255         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
1256
1257         return rwrap.fns.libc___res_nsearch(state,
1258                                             dname,
1259                                             class,
1260                                             type,
1261                                             answer,
1262                                             anslen);
1263 #else
1264 #error "No res_nsearch function"
1265 #endif
1266 }
1267
1268 /****************************************************************************
1269  *   RES_HELPER
1270  ***************************************************************************/
1271
1272 static int rwrap_parse_resolv_conf(struct __res_state *state,
1273                                    const char *resolv_conf)
1274 {
1275         FILE *fp;
1276         char buf[BUFSIZ];
1277         int nserv = 0;
1278
1279         fp = fopen(resolv_conf, "r");
1280         if (fp == NULL) {
1281                 RWRAP_LOG(RWRAP_LOG_ERROR,
1282                           "Opening %s failed: %s",
1283                           resolv_conf, strerror(errno));
1284                 return -1;
1285         }
1286
1287         while(fgets(buf, sizeof(buf), fp) != NULL) {
1288                 char *p;
1289
1290                 /* Ignore comments */
1291                 if (buf[0] == '#' || buf[0] == ';') {
1292                         continue;
1293                 }
1294
1295                 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
1296                         struct in_addr a;
1297                         char *q;
1298                         int ok;
1299
1300                         p = buf + strlen("nameserver");
1301
1302                         /* Skip spaces and tabs */
1303                         while(isblank((int)p[0])) {
1304                                 p++;
1305                         }
1306
1307                         q = p;
1308                         while(q[0] != '\n' && q[0] != '\0') {
1309                                 q++;
1310                         }
1311                         q[0] = '\0';
1312
1313                         ok = inet_pton(AF_INET, p, &a);
1314                         if (ok) {
1315                                 state->nsaddr_list[state->nscount] = (struct sockaddr_in) {
1316                                         .sin_family = AF_INET,
1317                                         .sin_addr = a,
1318                                         .sin_port = htons(53),
1319                                         .sin_zero = { 0 },
1320                                 };
1321
1322                                 state->nscount++;
1323                                 nserv++;
1324                         } else {
1325 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1326                                 /* IPv6 */
1327                                 struct in6_addr a6;
1328                                 ok = inet_pton(AF_INET6, p, &a6);
1329                                 if (ok) {
1330                                         struct sockaddr_in6 *sa6;
1331
1332                                         sa6 = malloc(sizeof(*sa6));
1333                                         if (sa6 == NULL) {
1334                                                 fclose(fp);
1335                                                 return -1;
1336                                         }
1337
1338                                         sa6->sin6_family = AF_INET6;
1339                                         sa6->sin6_port = htons(53);
1340                                         sa6->sin6_flowinfo = 0;
1341                                         sa6->sin6_addr = a6;
1342
1343                                         state->_u._ext.nsaddrs[state->_u._ext.nscount] = sa6;
1344                                         state->_u._ext.nssocks[state->_u._ext.nscount] = -1;
1345                                         state->_u._ext.nsmap[state->_u._ext.nscount] = MAXNS + 1;
1346
1347                                         state->_u._ext.nscount++;
1348                                         nserv++;
1349                                 } else {
1350                                         RWRAP_LOG(RWRAP_LOG_ERROR,
1351                                                 "Malformed DNS server");
1352                                         continue;
1353                                 }
1354 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1355                                 /*
1356                                  * BSD uses an opaque structure to store the
1357                                  * IPv6 addresses. So we can not simply store
1358                                  * these addresses the same way as above.
1359                                  */
1360                                 RWRAP_LOG(RWRAP_LOG_WARN,
1361                                           "resolve_wrapper does not support "
1362                                           "IPv6 on this platform");
1363                                         continue;
1364 #endif
1365                         }
1366                         continue;
1367                 } /* TODO: match other keywords */
1368         }
1369
1370         if (ferror(fp)) {
1371                 RWRAP_LOG(RWRAP_LOG_ERROR,
1372                           "Reading from %s failed",
1373                           resolv_conf);
1374                 fclose(fp);
1375                 return -1;
1376         }
1377
1378         fclose(fp);
1379         return 0;
1380 }
1381
1382 /****************************************************************************
1383  *   RES_NINIT
1384  ***************************************************************************/
1385
1386 static int rwrap_res_ninit(struct __res_state *state)
1387 {
1388         int rc;
1389
1390         rc = libc_res_ninit(state);
1391         if (rc == 0) {
1392                 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1393
1394                 if (resolv_conf != NULL) {
1395                         uint16_t i;
1396
1397                         (void)i; /* maybe unused */
1398
1399                         /* Delete name servers */
1400                         state->nscount = 0;
1401                         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1402
1403                         state->_u._ext.nscount = 0;
1404 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1405                         for (i = 0; i < state->_u._ext.nscount; i++) {
1406                                 SAFE_FREE(state->_u._ext.nsaddrs[i]);
1407                         }
1408 #endif
1409
1410                         rc = rwrap_parse_resolv_conf(state, resolv_conf);
1411                 }
1412         }
1413
1414         return rc;
1415 }
1416
1417 #if defined(HAVE_RES_NINIT)
1418 int res_ninit(struct __res_state *state)
1419 #elif defined(HAVE___RES_NINIT)
1420 int __res_ninit(struct __res_state *state)
1421 #endif
1422 {
1423         return rwrap_res_ninit(state);
1424 }
1425
1426 /****************************************************************************
1427  *   RES_INIT
1428  ***************************************************************************/
1429
1430 static struct __res_state rwrap_res_state;
1431
1432 static int rwrap_res_init(void)
1433 {
1434         int rc;
1435
1436         rc = rwrap_res_ninit(&rwrap_res_state);
1437
1438         return rc;
1439 }
1440
1441 #if defined(HAVE_RES_INIT)
1442 int res_init(void)
1443 #elif defined(HAVE___RES_INIT)
1444 int __res_init(void)
1445 #endif
1446 {
1447         return rwrap_res_init();
1448 }
1449
1450 /****************************************************************************
1451  *   RES_NCLOSE
1452  ***************************************************************************/
1453
1454 static void rwrap_res_nclose(struct __res_state *state)
1455 {
1456 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1457         int i;
1458 #endif
1459
1460         libc_res_nclose(state);
1461
1462 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1463         if (state != NULL) {
1464                 for (i = 0; i < state->_u._ext.nscount; i++) {
1465                         SAFE_FREE(state->_u._ext.nsaddrs[i]);
1466                 }
1467         }
1468 #endif
1469 }
1470
1471 #if defined(HAVE_RES_NCLOSE)
1472 void res_nclose(struct __res_state *state)
1473 #elif defined(HAVE___RES_NCLOSE)
1474 void __res_nclose(struct __res_state *state)
1475 #endif
1476 {
1477         rwrap_res_nclose(state);
1478 }
1479
1480 /****************************************************************************
1481  *   RES_CLOSE
1482  ***************************************************************************/
1483
1484 static void rwrap_res_close(void)
1485 {
1486         rwrap_res_nclose(&rwrap_res_state);
1487 }
1488
1489 #if defined(HAVE_RES_CLOSE)
1490 void res_close(void)
1491 #elif defined(HAVE___RES_CLOSE)
1492 void __res_close(void)
1493 #endif
1494 {
1495         rwrap_res_close();
1496 }
1497
1498 /****************************************************************************
1499  *   RES_NQUERY
1500  ***************************************************************************/
1501
1502 static int rwrap_res_nquery(struct __res_state *state,
1503                             const char *dname,
1504                             int class,
1505                             int type,
1506                             unsigned char *answer,
1507                             int anslen)
1508 {
1509         int rc;
1510         const char *fake_hosts;
1511 #ifndef NDEBUG
1512         int i;
1513 #endif
1514
1515         RWRAP_LOG(RWRAP_LOG_TRACE,
1516                   "Resolve the domain name [%s] - class=%d, type=%d",
1517                   dname, class, type);
1518 #ifndef NDEBUG
1519         for (i = 0; i < state->nscount; i++) {
1520                 char ip[INET6_ADDRSTRLEN];
1521
1522                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1523                 RWRAP_LOG(RWRAP_LOG_TRACE,
1524                           "        nameserver: %s",
1525                           ip);
1526         }
1527 #endif
1528
1529         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1530         if (fake_hosts != NULL) {
1531                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1532         } else {
1533                 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
1534         }
1535
1536
1537         RWRAP_LOG(RWRAP_LOG_TRACE,
1538                   "The returned response length is: %d",
1539                   rc);
1540
1541         return rc;
1542 }
1543
1544 #if 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 #elif defined(HAVE___RES_NQUERY)
1552 int __res_nquery(struct __res_state *state,
1553                  const char *dname,
1554                  int class,
1555                  int type,
1556                  unsigned char *answer,
1557                  int anslen)
1558 #endif
1559 {
1560         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
1561 }
1562
1563 /****************************************************************************
1564  *   RES_QUERY
1565  ***************************************************************************/
1566
1567 static int rwrap_res_query(const char *dname,
1568                            int class,
1569                            int type,
1570                            unsigned char *answer,
1571                            int anslen)
1572 {
1573         int rc;
1574
1575         rc = rwrap_res_ninit(&rwrap_res_state);
1576         if (rc != 0) {
1577                 return rc;
1578         }
1579
1580         rc = rwrap_res_nquery(&rwrap_res_state,
1581                               dname,
1582                               class,
1583                               type,
1584                               answer,
1585                               anslen);
1586
1587         return rc;
1588 }
1589
1590 #if defined(HAVE_RES_QUERY)
1591 int res_query(const char *dname,
1592               int class,
1593               int type,
1594               unsigned char *answer,
1595               int anslen)
1596 #elif defined(HAVE___RES_QUERY)
1597 int __res_query(const char *dname,
1598                 int class,
1599                 int type,
1600                 unsigned char *answer,
1601                 int anslen)
1602 #endif
1603 {
1604         return rwrap_res_query(dname, class, type, answer, anslen);
1605 }
1606
1607 /****************************************************************************
1608  *   RES_NSEARCH
1609  ***************************************************************************/
1610
1611 static int rwrap_res_nsearch(struct __res_state *state,
1612                              const char *dname,
1613                              int class,
1614                              int type,
1615                              unsigned char *answer,
1616                              int anslen)
1617 {
1618         int rc;
1619         const char *fake_hosts;
1620 #ifndef NDEBUG
1621         int i;
1622 #endif
1623
1624         RWRAP_LOG(RWRAP_LOG_TRACE,
1625                   "Resolve the domain name [%s] - class=%d, type=%d",
1626                   dname, class, type);
1627 #ifndef NDEBUG
1628         for (i = 0; i < state->nscount; i++) {
1629                 char ip[INET6_ADDRSTRLEN];
1630
1631                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
1632                 RWRAP_LOG(RWRAP_LOG_TRACE,
1633                           "        nameserver: %s",
1634                           ip);
1635         }
1636 #endif
1637
1638         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
1639         if (fake_hosts != NULL) {
1640                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
1641         } else {
1642                 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
1643         }
1644
1645         RWRAP_LOG(RWRAP_LOG_TRACE,
1646                   "The returned response length is: %d",
1647                   rc);
1648
1649         return rc;
1650 }
1651
1652 #if 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 #elif defined(HAVE___RES_NSEARCH)
1660 int __res_nsearch(struct __res_state *state,
1661                   const char *dname,
1662                   int class,
1663                   int type,
1664                   unsigned char *answer,
1665                   int anslen)
1666 #endif
1667 {
1668         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
1669 }
1670
1671 /****************************************************************************
1672  *   RES_QUERY
1673  ***************************************************************************/
1674
1675 static int rwrap_res_search(const char *dname,
1676                             int class,
1677                             int type,
1678                             unsigned char *answer,
1679                             int anslen)
1680 {
1681         int rc;
1682
1683         rc = rwrap_res_ninit(&rwrap_res_state);
1684         if (rc != 0) {
1685                 return rc;
1686         }
1687
1688         rc = rwrap_res_nsearch(&rwrap_res_state,
1689                                dname,
1690                                class,
1691                                type,
1692                                answer,
1693                                anslen);
1694
1695         return rc;
1696 }
1697
1698 #if defined(HAVE_RES_SEARCH)
1699 int res_search(const char *dname,
1700                int class,
1701                int type,
1702                unsigned char *answer,
1703                int anslen)
1704 #elif defined(HAVE___RES_SEARCH)
1705 int __res_search(const char *dname,
1706                  int class,
1707                  int type,
1708                  unsigned char *answer,
1709                  int anslen)
1710 #endif
1711 {
1712         return rwrap_res_search(dname, class, type, answer, anslen);
1713 }