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