cmake: Fix cmocka >= 1.1.6 find_package() in CONFIG mode
[resolv_wrapper.git] / src / resolv_wrapper.c
1 /*
2  * Copyright (c) 2014-2018 Andreas Schneider <asn@samba.org>
3  * Copyright (c) 2014-2016 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 #if defined(HAVE_RES_STATE_U_EXT_NSADDRS) || defined(HAVE_RES_SOCKADDR_UNION_SIN6)
56 #define HAVE_RESOLV_IPV6_NSADDRS 1
57 #endif
58
59 /* GCC has printf type attribute check. */
60 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
61 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
62 #else
63 #define PRINTF_ATTRIBUTE(a,b)
64 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
65
66 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
67 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
68 #else
69 #define DESTRUCTOR_ATTRIBUTE
70 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
71
72 #ifndef RWRAP_DEFAULT_FAKE_TTL
73 #define RWRAP_DEFAULT_FAKE_TTL 600
74 #endif  /* RWRAP_DEFAULT_FAKE_TTL */
75
76 #ifndef HAVE_NS_NAME_COMPRESS
77 #define ns_name_compress dn_comp
78 #endif
79
80 #define ns_t_uri 256
81
82 enum rwrap_dbglvl_e {
83         RWRAP_LOG_ERROR = 0,
84         RWRAP_LOG_WARN,
85         RWRAP_LOG_NOTICE,
86         RWRAP_LOG_DEBUG,
87         RWRAP_LOG_TRACE
88 };
89
90 #ifndef HAVE_GETPROGNAME
91 static const char *getprogname(void)
92 {
93 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
94         return program_invocation_short_name;
95 #elif defined(HAVE_GETEXECNAME)
96         return getexecname();
97 #else
98         return NULL;
99 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
100 }
101 #endif /* HAVE_GETPROGNAME */
102
103 static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
104 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
105
106 static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
107                       const char *func,
108                       const char *format, ...)
109 {
110         char buffer[1024];
111         va_list va;
112         const char *d;
113         unsigned int lvl = 0;
114         const char *prefix = NULL;
115         const char *progname = NULL;
116
117         d = getenv("RESOLV_WRAPPER_DEBUGLEVEL");
118         if (d != NULL) {
119                 lvl = atoi(d);
120         }
121
122         if (lvl < dbglvl) {
123                 return;
124         }
125
126         va_start(va, format);
127         vsnprintf(buffer, sizeof(buffer), format, va);
128         va_end(va);
129
130         switch (dbglvl) {
131                 case RWRAP_LOG_ERROR:
132                         prefix = "RWRAP_ERROR";
133                         break;
134                 case RWRAP_LOG_WARN:
135                         prefix = "RWRAP_WARN";
136                         break;
137                 case RWRAP_LOG_NOTICE:
138                         prefix = "RWRAP_NOTICE";
139                         break;
140                 case RWRAP_LOG_DEBUG:
141                         prefix = "RWRAP_DEBUG";
142                         break;
143                 case RWRAP_LOG_TRACE:
144                         prefix = "RWRAP_TRACE";
145                         break;
146         }
147
148         progname = getprogname();
149         if (progname == NULL) {
150                 progname = "<unknown>";
151         }
152
153         fprintf(stderr,
154                 "%s[%s (%u)] - %s: %s\n",
155                 prefix,
156                 progname,
157                 (unsigned int)getpid(),
158                 func,
159                 buffer);
160 }
161
162 #ifndef SAFE_FREE
163 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
164 #endif
165
166 #define NEXT_KEY(buf, key) do {                                 \
167         (key) = (buf) ? strpbrk((buf), " \t") : NULL;           \
168         if ((key) != NULL) {                                    \
169                 (key)[0] = '\0';                                \
170                 (key)++;                                        \
171         }                                                       \
172         while ((key) != NULL                                    \
173                && (isblank((int)(key)[0]))) {                   \
174                 (key)++;                                        \
175         }                                                       \
176 } while(0);
177
178 #define RWRAP_MAX_RECURSION 64
179
180 union rwrap_sockaddr {
181         struct sockaddr sa;
182         struct sockaddr_in in;
183         struct sockaddr_in6 in6;
184 };
185
186 /* Priority and weight can be omitted from the hosts file, but need to be part
187  * of the output
188  */
189 #define DFL_SRV_PRIO    1
190 #define DFL_SRV_WEIGHT  100
191 #define DFL_URI_PRIO    1
192 #define DFL_URI_WEIGHT  100
193
194 struct rwrap_srv_rrdata {
195         uint16_t port;
196         uint16_t prio;
197         uint16_t weight;
198         char hostname[MAXDNAME];
199 };
200
201 struct rwrap_uri_rrdata {
202         uint16_t prio;
203         uint16_t weight;
204         char uri[MAXDNAME];
205 };
206
207 struct rwrap_soa_rrdata {
208         uint32_t serial;
209         uint32_t refresh;
210         uint32_t retry;
211         uint32_t expire;
212         uint32_t minimum;
213         char nameserver[MAXDNAME];
214         char mailbox[MAXDNAME];
215 };
216
217 struct rwrap_fake_rr {
218         union fake_rrdata {
219                 struct in_addr a_rec;
220                 struct in6_addr aaaa_rec;
221                 struct rwrap_srv_rrdata srv_rec;
222                 struct rwrap_uri_rrdata uri_rec;
223                 struct rwrap_soa_rrdata soa_rec;
224                 char cname_rec[MAXDNAME];
225                 char ptr_rec[MAXDNAME];
226                 char txt_rec[MAXDNAME];
227         } rrdata;
228
229         char key[MAXDNAME];
230         int type; /* ns_t_* */
231 };
232
233 static void rwrap_fake_rr_init(struct rwrap_fake_rr *rr, size_t len)
234 {
235         size_t i;
236
237         for (i = 0; i < len; i++) {
238                 rr[i].type = ns_t_invalid;
239         }
240 }
241
242 static int rwrap_create_fake_a_rr(const char *key,
243                                   const char *value,
244                                   struct rwrap_fake_rr *rr)
245 {
246         int ok;
247
248         ok = inet_pton(AF_INET, value, &rr->rrdata.a_rec);
249         if (!ok) {
250                 RWRAP_LOG(RWRAP_LOG_ERROR,
251                           "Failed to convert [%s] to binary\n", value);
252                 return -1;
253         }
254
255         memcpy(rr->key, key, strlen(key) + 1);
256         rr->type = ns_t_a;
257         return 0;
258 }
259
260 static int rwrap_create_fake_aaaa_rr(const char *key,
261                                      const char *value,
262                                      struct rwrap_fake_rr *rr)
263 {
264         int ok;
265
266         ok = inet_pton(AF_INET6, value, &rr->rrdata.aaaa_rec);
267         if (!ok) {
268                 RWRAP_LOG(RWRAP_LOG_ERROR,
269                           "Failed to convert [%s] to binary\n", value);
270                 return -1;
271         }
272
273         memcpy(rr->key, key, strlen(key) + 1);
274         rr->type = ns_t_aaaa;
275         return 0;
276 }
277 static int rwrap_create_fake_ns_rr(const char *key,
278                                    const char *value,
279                                    struct rwrap_fake_rr *rr)
280 {
281         memcpy(rr->rrdata.srv_rec.hostname, value, strlen(value) + 1);
282         memcpy(rr->key, key, strlen(key) + 1);
283         rr->type = ns_t_ns;
284         return 0;
285 }
286
287 static int rwrap_create_fake_srv_rr(const char *key,
288                                     const char *value,
289                                     struct rwrap_fake_rr *rr)
290 {
291         char *str_prio;
292         char *str_weight;
293         char *str_port;
294         const char *hostname;
295
296         /* parse the value into priority, weight, port and hostname
297          * and check the validity */
298         hostname = value;
299         NEXT_KEY(hostname, str_port);
300         NEXT_KEY(str_port, str_prio);
301         NEXT_KEY(str_prio, str_weight);
302         if (str_port == NULL || hostname == NULL) {
303                 RWRAP_LOG(RWRAP_LOG_ERROR,
304                           "Malformed SRV entry [%s]\n", value);
305                 return -1;
306         }
307
308         if (str_prio) {
309                 rr->rrdata.srv_rec.prio = atoi(str_prio);
310         } else {
311                 rr->rrdata.srv_rec.prio = DFL_SRV_PRIO;
312         }
313         if (str_weight) {
314                 rr->rrdata.srv_rec.weight = atoi(str_weight);
315         } else {
316                 rr->rrdata.srv_rec.weight = DFL_SRV_WEIGHT;
317         }
318         rr->rrdata.srv_rec.port = atoi(str_port);
319         memcpy(rr->rrdata.srv_rec.hostname , hostname, strlen(hostname) + 1);
320
321         memcpy(rr->key, key, strlen(key) + 1);
322         rr->type = ns_t_srv;
323         return 0;
324 }
325
326 static int rwrap_create_fake_uri_rr(const char *key,
327                                     const char *value,
328                                     struct rwrap_fake_rr *rr)
329 {
330         char *str_prio;
331         char *str_weight;
332         const char *uri;
333
334         /* parse the value into priority, weight, and uri
335          * and check the validity */
336         uri = value;
337         NEXT_KEY(uri, str_prio);
338         NEXT_KEY(str_prio, str_weight);
339         if (uri == NULL) {
340                 RWRAP_LOG(RWRAP_LOG_ERROR,
341                           "Malformed URI entry [<null>]\n");
342                 return -1;
343         }
344
345         if (str_prio) {
346                 rr->rrdata.uri_rec.prio = atoi(str_prio);
347         } else {
348                 rr->rrdata.uri_rec.prio = DFL_URI_PRIO;
349         }
350         if (str_weight) {
351                 rr->rrdata.uri_rec.weight = atoi(str_weight);
352         } else {
353                 rr->rrdata.uri_rec.weight = DFL_URI_WEIGHT;
354         }
355         memcpy(rr->rrdata.uri_rec.uri, uri, strlen(uri) + 1);
356
357         memcpy(rr->key, key, strlen(key) + 1);
358         rr->type = ns_t_uri;
359         return 0;
360 }
361
362 static int rwrap_create_fake_txt_rr(const char *key,
363                                     const char *value,
364                                     struct rwrap_fake_rr *rr)
365 {
366         memcpy(rr->rrdata.txt_rec, value, strlen(value) + 1);
367
368         memcpy(rr->key, key, strlen(key) + 1);
369         rr->type = ns_t_txt;
370         return 0;
371 }
372
373 static int rwrap_create_fake_soa_rr(const char *key,
374                                     const char *value,
375                                     struct rwrap_fake_rr *rr)
376 {
377         const char *nameserver;
378         char *mailbox;
379         char *str_serial;
380         char *str_refresh;
381         char *str_retry;
382         char *str_expire;
383         char *str_minimum;
384
385         /* parse the value into nameserver, mailbox, serial, refresh,
386          * retry, expire, minimum and check the validity
387          */
388         nameserver = value;
389         NEXT_KEY(nameserver, mailbox);
390         NEXT_KEY(mailbox, str_serial);
391         NEXT_KEY(str_serial, str_refresh);
392         NEXT_KEY(str_refresh, str_retry);
393         NEXT_KEY(str_retry, str_expire);
394         NEXT_KEY(str_expire, str_minimum);
395         if (nameserver == NULL || mailbox == NULL || str_serial == NULL ||
396             str_refresh == NULL || str_retry == NULL || str_expire == NULL ||
397             str_minimum == NULL) {
398                 RWRAP_LOG(RWRAP_LOG_ERROR,
399                           "Malformed SOA entry [%s]\n", value);
400                 return -1;
401         }
402
403         memcpy(rr->rrdata.soa_rec.nameserver, nameserver, strlen(nameserver)+1);
404         memcpy(rr->rrdata.soa_rec.mailbox, mailbox, strlen(mailbox)+1);
405
406         rr->rrdata.soa_rec.serial = atoi(str_serial);
407         rr->rrdata.soa_rec.refresh = atoi(str_refresh);
408         rr->rrdata.soa_rec.retry = atoi(str_retry);
409         rr->rrdata.soa_rec.expire = atoi(str_expire);
410         rr->rrdata.soa_rec.minimum = atoi(str_minimum);
411
412         memcpy(rr->key, key, strlen(key) + 1);
413         rr->type = ns_t_soa;
414         return 0;
415 }
416
417 static int rwrap_create_fake_cname_rr(const char *key,
418                                       const char *value,
419                                       struct rwrap_fake_rr *rr)
420 {
421         memcpy(rr->rrdata.cname_rec , value, strlen(value) + 1);
422         memcpy(rr->key, key, strlen(key) + 1);
423         rr->type = ns_t_cname;
424         return 0;
425 }
426
427 static int rwrap_create_fake_ptr_rr(const char *key,
428                                     const char *value,
429                                     struct rwrap_fake_rr *rr)
430 {
431         memcpy(rr->rrdata.ptr_rec , value, strlen(value) + 1);
432         memcpy(rr->key, key, strlen(key) + 1);
433         rr->type = ns_t_ptr;
434         return 0;
435 }
436
437 #define rwrap_randomid() 0xffff & getpid()
438
439 /* Prepares a fake header with a single response. Advances header_blob */
440 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
441                                  size_t ancount, size_t arcount)
442 {
443         union {
444                 uint8_t *blob;
445                 HEADER *header;
446         } h;
447
448         if (remaining < NS_HFIXEDSZ) {
449                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
450                 return -1;
451         }
452
453         h.blob = *header_blob;
454         memset(h.blob, 0, NS_HFIXEDSZ);
455
456         h.header->id = rwrap_randomid();        /* random query ID */
457         h.header->qr = 1;                       /* response flag */
458         h.header->rd = 1;                       /* recursion desired */
459         h.header->ra = 1;                       /* recursion available */
460
461         h.header->qdcount = htons(1);           /* no. of questions */
462         h.header->ancount = htons(ancount);     /* no. of answers */
463         h.header->arcount = htons(arcount);     /* no. of add'tl records */
464
465         /* move past the header */
466         *header_blob = h.blob += NS_HFIXEDSZ;
467
468         return NS_HFIXEDSZ;
469 }
470
471 static ssize_t rwrap_fake_question(const char *question,
472                                    uint16_t type,
473                                    uint8_t **question_ptr,
474                                    size_t remaining)
475 {
476         uint8_t *qb = *question_ptr;
477         int n;
478
479         n = ns_name_compress(question, qb, remaining, NULL, NULL);
480         if (n < 0) {
481                 RWRAP_LOG(RWRAP_LOG_ERROR,
482                           "Failed to compress [%s]\n", question);
483                 return -1;
484         }
485
486         qb += n;
487         remaining -= n;
488
489         if (remaining < 2 * sizeof(uint16_t)) {
490                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small!\n");
491                 return -1;
492         }
493
494         NS_PUT16(type, qb);
495         NS_PUT16(ns_c_in, qb);
496
497         *question_ptr = qb;
498         return n + 2 * sizeof(uint16_t);
499 }
500
501 static ssize_t rwrap_fake_rdata_common(uint16_t type,
502                                        size_t rdata_size,
503                                        const char *key,
504                                        size_t remaining,
505                                        uint8_t **rdata_ptr)
506 {
507         uint8_t *rd = *rdata_ptr;
508         ssize_t written = 0;
509
510         written = ns_name_compress(key, rd, remaining, NULL, NULL);
511         if (written < 0) {
512                 RWRAP_LOG(RWRAP_LOG_ERROR,
513                           "Failed to compress [%s]\n", key);
514                 return -1;
515         }
516         rd += written;
517         remaining -= written;
518
519         if (remaining < 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
520                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
521                 return -1;
522         }
523
524         NS_PUT16(type, rd);
525         NS_PUT16(ns_c_in, rd);
526         NS_PUT32(RWRAP_DEFAULT_FAKE_TTL, rd);
527         NS_PUT16(rdata_size, rd);
528
529         if (remaining < rdata_size) {
530                 RWRAP_LOG(RWRAP_LOG_ERROR, "Buffer too small\n");
531                 return -1;
532         }
533
534         *rdata_ptr = rd;
535         return written + 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size;
536 }
537
538 static ssize_t rwrap_fake_a(struct rwrap_fake_rr *rr,
539                             uint8_t *answer_ptr,
540                             size_t anslen)
541 {
542         uint8_t *a = answer_ptr;
543         ssize_t resp_size;
544
545         if (rr->type != ns_t_a) {
546                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
547                 return -1;
548         }
549         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding A RR");
550
551         resp_size = rwrap_fake_rdata_common(ns_t_a, sizeof(struct in_addr), rr->key,
552                                             anslen, &a);
553         if (resp_size < 0) {
554                 return -1;
555         }
556
557         memcpy(a, &rr->rrdata.a_rec, sizeof(struct in_addr));
558
559         return resp_size;
560 }
561
562 static ssize_t rwrap_fake_aaaa(struct rwrap_fake_rr *rr,
563                                uint8_t *answer,
564                                size_t anslen)
565 {
566         uint8_t *a = answer;
567         ssize_t resp_size;
568
569         if (rr->type != ns_t_aaaa) {
570                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
571                 return -1;
572         }
573         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding AAAA RR");
574
575         resp_size = rwrap_fake_rdata_common(ns_t_aaaa, sizeof(struct in6_addr),
576                                             rr->key, anslen, &a);
577         if (resp_size < 0) {
578                 return -1;
579         }
580
581         memcpy(a, &rr->rrdata.aaaa_rec, sizeof(struct in6_addr));
582
583         return resp_size;
584 }
585
586 static ssize_t rwrap_fake_ns(struct rwrap_fake_rr *rr,
587                              uint8_t *answer,
588                             size_t anslen)
589 {
590         uint8_t *a = answer;
591         ssize_t resp_size = 0;
592         size_t rdata_size;
593         unsigned char hostname_compressed[MAXDNAME];
594         ssize_t compressed_len;
595
596         if (rr->type != ns_t_ns) {
597                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
598                 return -1;
599         }
600         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding NS RR");
601
602         /* Prepare the data to write */
603         compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
604                                           hostname_compressed,
605                                           MAXDNAME,
606                                           NULL,
607                                           NULL);
608         if (compressed_len < 0) {
609                 return -1;
610         }
611
612         /* Is this enough? */
613         rdata_size = compressed_len;
614
615         resp_size = rwrap_fake_rdata_common(ns_t_ns, rdata_size,
616                                             rr->key, anslen, &a);
617         if (resp_size < 0) {
618                 return -1;
619         }
620
621         memcpy(a, hostname_compressed, compressed_len);
622
623         return resp_size;
624 }
625
626 static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr,
627                               uint8_t *answer,
628                               size_t anslen)
629 {
630         uint8_t *a = answer;
631         ssize_t resp_size;
632         size_t rdata_size;
633         unsigned char hostname_compressed[MAXDNAME];
634         ssize_t compressed_len;
635
636         if (rr->type != ns_t_srv) {
637                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
638                 return -1;
639         }
640         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SRV RR");
641         rdata_size = 3 * sizeof(uint16_t);
642
643         /* Prepare the data to write */
644         compressed_len = ns_name_compress(rr->rrdata.srv_rec.hostname,
645                                           hostname_compressed, MAXDNAME,
646                                           NULL, NULL);
647         if (compressed_len < 0) {
648                 return -1;
649         }
650         rdata_size += compressed_len;
651
652         resp_size = rwrap_fake_rdata_common(ns_t_srv, rdata_size,
653                                             rr->key, anslen, &a);
654         if (resp_size < 0) {
655                 return -1;
656         }
657
658         NS_PUT16(rr->rrdata.srv_rec.prio, a);
659         NS_PUT16(rr->rrdata.srv_rec.weight, a);
660         NS_PUT16(rr->rrdata.srv_rec.port, a);
661         memcpy(a, hostname_compressed, compressed_len);
662
663         return resp_size;
664 }
665
666 static ssize_t rwrap_fake_uri(struct rwrap_fake_rr *rr,
667                               uint8_t *answer,
668                               size_t anslen)
669 {
670         uint8_t *a = answer;
671         ssize_t resp_size;
672         size_t rdata_size;
673         size_t uri_len;
674
675         if (rr->type != ns_t_uri) {
676                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
677                 return -1;
678         }
679         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding URI RR");
680         rdata_size = 3 * sizeof(uint16_t);
681         uri_len = strlen(rr->rrdata.uri_rec.uri) + 1;
682         rdata_size += uri_len;
683
684         resp_size = rwrap_fake_rdata_common(ns_t_uri, rdata_size,
685                                             rr->key, anslen, &a);
686         if (resp_size < 0) {
687                 return -1;
688         }
689
690         NS_PUT16(rr->rrdata.uri_rec.prio, a);
691         NS_PUT16(rr->rrdata.uri_rec.weight, a);
692         memcpy(a, rr->rrdata.uri_rec.uri, uri_len);
693
694         return resp_size;
695 }
696
697 static ssize_t rwrap_fake_txt(struct rwrap_fake_rr *rr,
698                               uint8_t *answer,
699                               size_t anslen)
700 {
701         uint8_t *a = answer;
702         ssize_t resp_size;
703         size_t rdata_size;
704         size_t txt_len;
705
706         if (rr->type != ns_t_txt) {
707                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
708                 return -1;
709         }
710         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding TXT RR");
711         txt_len = strlen(rr->rrdata.txt_rec) + 1;
712         rdata_size = txt_len;
713
714         resp_size = rwrap_fake_rdata_common(ns_t_txt, rdata_size,
715                                             rr->key, anslen, &a);
716         if (resp_size < 0) {
717                 return -1;
718         }
719
720         memcpy(a, rr->rrdata.txt_rec, txt_len);
721
722         return resp_size;
723 }
724
725 static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr,
726                               uint8_t *answer,
727                               size_t anslen)
728 {
729         uint8_t *a = answer;
730         ssize_t resp_size;
731         size_t rdata_size;
732         unsigned char nameser_compressed[MAXDNAME];
733         ssize_t compressed_ns_len;
734         unsigned char mailbox_compressed[MAXDNAME];
735         ssize_t compressed_mb_len;
736
737         if (rr->type != ns_t_soa) {
738                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
739                 return -1;
740         }
741         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding SOA RR");
742         rdata_size = 5 * sizeof(uint16_t);
743
744         compressed_ns_len = ns_name_compress(rr->rrdata.soa_rec.nameserver,
745                                              nameser_compressed,
746                                              MAXDNAME, NULL, NULL);
747         if (compressed_ns_len < 0) {
748                 return -1;
749         }
750         rdata_size += compressed_ns_len;
751
752         compressed_mb_len = ns_name_compress(rr->rrdata.soa_rec.mailbox,
753                                              mailbox_compressed,
754                                              MAXDNAME, NULL, NULL);
755         if (compressed_mb_len < 0) {
756                 return -1;
757         }
758         rdata_size += compressed_mb_len;
759
760         resp_size = rwrap_fake_rdata_common(ns_t_soa, rdata_size,
761                                             rr->key, anslen, &a);
762         if (resp_size < 0) {
763                 return -1;
764         }
765
766         memcpy(a, nameser_compressed, compressed_ns_len);
767         a += compressed_ns_len;
768         memcpy(a, mailbox_compressed, compressed_mb_len);
769         a += compressed_mb_len;
770         NS_PUT32(rr->rrdata.soa_rec.serial, a);
771         NS_PUT32(rr->rrdata.soa_rec.refresh, a);
772         NS_PUT32(rr->rrdata.soa_rec.retry, a);
773         NS_PUT32(rr->rrdata.soa_rec.expire, a);
774         NS_PUT32(rr->rrdata.soa_rec.minimum, a);
775
776         return resp_size;
777 }
778
779 static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr,
780                                 uint8_t *answer,
781                                 size_t anslen)
782 {
783         uint8_t *a = answer;
784         ssize_t resp_size;
785         unsigned char hostname_compressed[MAXDNAME];
786         ssize_t rdata_size;
787
788         if (rr->type != ns_t_cname) {
789                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
790                 return -1;
791         }
792         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding CNAME RR");
793
794         /* Prepare the data to write */
795         rdata_size = ns_name_compress(rr->rrdata.cname_rec,
796                                       hostname_compressed, MAXDNAME,
797                                       NULL, NULL);
798         if (rdata_size < 0) {
799                 return -1;
800         }
801
802         resp_size = rwrap_fake_rdata_common(ns_t_cname, rdata_size,
803                                             rr->key, anslen, &a);
804         if (resp_size < 0) {
805                 return -1;
806         }
807
808         memcpy(a, hostname_compressed, rdata_size);
809
810         return resp_size;
811 }
812
813 static ssize_t rwrap_fake_ptr(struct rwrap_fake_rr *rr,
814                               uint8_t *answer,
815                               size_t anslen)
816 {
817         uint8_t *a = answer;
818         ssize_t rdata_size;
819         ssize_t resp_size;
820         unsigned char hostname_compressed[MAXDNAME];
821
822         if (rr->type != ns_t_ptr) {
823                 RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
824                 return -1;
825         }
826         RWRAP_LOG(RWRAP_LOG_TRACE, "Adding PTR RR");
827
828         /* Prepare the data to write */
829         rdata_size = ns_name_compress(rr->rrdata.ptr_rec,
830                                       hostname_compressed, MAXDNAME,
831                                       NULL, NULL);
832         if (rdata_size < 0) {
833                 return -1;
834         }
835
836         resp_size = rwrap_fake_rdata_common(ns_t_ptr, rdata_size,
837                                             rr->key, anslen, &a);
838         if (resp_size < 0) {
839                 return -1;
840         }
841
842         memcpy(a, hostname_compressed, rdata_size);
843
844         return resp_size;
845 }
846
847 #define RESOLV_MATCH(line, name) \
848         (strncmp(line, name, sizeof(name) - 1) == 0 && \
849         (line[sizeof(name) - 1] == ' ' || \
850          line[sizeof(name) - 1] == '\t'))
851
852 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
853         ((type) == (ns_type) && \
854          (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
855          (strcasecmp(key, query)) == 0)
856
857
858 static int rwrap_get_record(const char *hostfile, unsigned recursion,
859                             const char *query, int type,
860                             struct rwrap_fake_rr *rr);
861
862 static int rwrap_uri_recurse(const char *hostfile, unsigned recursion,
863                              const char *query, struct rwrap_fake_rr *rr)
864 {
865         int rc;
866
867         rc = rwrap_get_record(hostfile, recursion, query, ns_t_uri, rr);
868         if (rc == ENOENT) {
869                 rc = 0;
870         }
871
872         return rc;
873 }
874
875 static int rwrap_srv_recurse(const char *hostfile, unsigned recursion,
876                              const char *query, struct rwrap_fake_rr *rr)
877 {
878         int rc;
879
880         rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
881         if (rc == 0) return 0;
882
883         rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
884         if (rc == ENOENT) rc = 0;
885
886         return rc;
887 }
888
889 static int rwrap_cname_recurse(const char *hostfile, unsigned recursion,
890                                const char *query, struct rwrap_fake_rr *rr)
891 {
892         int rc;
893
894         rc = rwrap_get_record(hostfile, recursion, query, ns_t_a, rr);
895         if (rc == 0) return 0;
896
897         rc = rwrap_get_record(hostfile, recursion, query, ns_t_aaaa, rr);
898         if (rc == 0) return 0;
899
900         rc = rwrap_get_record(hostfile, recursion, query, ns_t_cname, rr);
901         if (rc == ENOENT) rc = 0;
902
903         return rc;
904 }
905
906 static int rwrap_get_record(const char *hostfile, unsigned recursion,
907                             const char *query, int type,
908                             struct rwrap_fake_rr *rr)
909 {
910         FILE *fp = NULL;
911         char buf[BUFSIZ];
912         char *key = NULL;
913         char *value = NULL;
914         int rc = ENOENT;
915         unsigned num_uris = 0;
916
917         if (recursion >= RWRAP_MAX_RECURSION) {
918                 RWRAP_LOG(RWRAP_LOG_ERROR, "Recursed too deep!\n");
919                 return -1;
920         }
921
922         RWRAP_LOG(RWRAP_LOG_TRACE,
923                   "Searching in fake hosts file %s for %s:%d\n", hostfile,
924                   query, type);
925
926         fp = fopen(hostfile, "r");
927         if (fp == NULL) {
928                 RWRAP_LOG(RWRAP_LOG_WARN,
929                           "Opening %s failed: %s",
930                           hostfile, strerror(errno));
931                 return -1;
932         }
933
934         while (fgets(buf, sizeof(buf), fp) != NULL) {
935                 char *rec_type;
936                 char *q;
937
938                 rec_type = buf;
939                 key = value = NULL;
940
941                 NEXT_KEY(rec_type, key);
942                 NEXT_KEY(key, value);
943
944                 if (key == NULL || value == NULL) {
945                         RWRAP_LOG(RWRAP_LOG_WARN,
946                                 "Malformed line: not enough parts, use \"rec_type key data\n"
947                                 "For example \"A cwrap.org 10.10.10.10\"");
948                         continue;
949                 }
950
951                 q = value;
952                 while(q[0] != '\n' && q[0] != '\0') {
953                         q++;
954                 }
955                 q[0] = '\0';
956
957                 if (type == ns_t_uri && recursion > 0) {
958                         /* Skip non-URI records. */
959                         if (!TYPE_MATCH(type, ns_t_uri, rec_type, "URI", key, query)) {
960                                 continue;
961                         }
962                         /* Skip previous records based on the recurse depth. */
963                         num_uris++;
964                         if (num_uris <= recursion) {
965                                 continue;
966                         }
967                 }
968
969                 if (TYPE_MATCH(type, ns_t_a, rec_type, "A", key, query)) {
970                         rc = rwrap_create_fake_a_rr(key, value, rr);
971                         break;
972                 } else if (TYPE_MATCH(type, ns_t_aaaa,
973                                       rec_type, "AAAA", key, query)) {
974                         rc = rwrap_create_fake_aaaa_rr(key, value, rr);
975                         break;
976                 } else if (TYPE_MATCH(type, ns_t_ns,
977                                       rec_type, "NS", key, query)) {
978                         rc = rwrap_create_fake_ns_rr(key, value, rr);
979                         break;
980                 } else if (TYPE_MATCH(type, ns_t_srv,
981                                       rec_type, "SRV", key, query)) {
982                         rc = rwrap_create_fake_srv_rr(key, value, rr);
983                         if (rc == 0) {
984                                 rc = rwrap_srv_recurse(hostfile, recursion+1,
985                                                 rr->rrdata.srv_rec.hostname,
986                                                 rr + 1);
987                         }
988                         break;
989                 } else if (TYPE_MATCH(type, ns_t_uri,
990                                       rec_type, "URI", key, query)) {
991                         rc = rwrap_create_fake_uri_rr(key, value, rr);
992                         if (rc == 0) {
993                                 /* Recurse to collect multiple URI answers under a single key. */
994                                 rc = rwrap_uri_recurse(hostfile, recursion + 1, key, rr + 1);
995                         }
996                         break;
997                 } else if (TYPE_MATCH(type, ns_t_soa,
998                                       rec_type, "SOA", key, query)) {
999                         rc = rwrap_create_fake_soa_rr(key, value, rr);
1000                         break;
1001                 } else if (TYPE_MATCH(type, ns_t_cname,
1002                                       rec_type, "CNAME", key, query)) {
1003                         rc = rwrap_create_fake_cname_rr(key, value, rr);
1004                         if (rc == 0) {
1005                                 rc = rwrap_cname_recurse(hostfile, recursion+1,
1006                                                          value, rr + 1);
1007                         }
1008                         break;
1009                 } else if (TYPE_MATCH(type, ns_t_a, rec_type, "CNAME", key, query)) {
1010                         rc = rwrap_create_fake_cname_rr(key, value, rr);
1011                         if (rc == 0) {
1012                                 rc = rwrap_cname_recurse(hostfile, recursion+1,
1013                                                          value, rr + 1);
1014                         }
1015                         break;
1016                 } else if (TYPE_MATCH(type, ns_t_ptr,
1017                                       rec_type, "PTR", key, query)) {
1018                         rc = rwrap_create_fake_ptr_rr(key, value, rr);
1019                         break;
1020                 }
1021                 else if (TYPE_MATCH(type, ns_t_txt,
1022                                       rec_type, "TXT", key, query)) {
1023                         rc = rwrap_create_fake_txt_rr(key, value, rr);
1024                         break;
1025                 }
1026         }
1027
1028         if (rc == ENOENT && recursion == 0 && key != NULL) {
1029                 RWRAP_LOG(RWRAP_LOG_TRACE, "Record for [%s] not found\n", query);
1030                 memcpy(rr->key, key, strlen(key) + 1);
1031         }
1032
1033         fclose(fp);
1034         return rc;
1035 }
1036
1037 static ssize_t rwrap_fake_empty(int type,
1038                                 const char *question,
1039                                 uint8_t *answer,
1040                                 size_t anslen)
1041 {
1042         ssize_t resp_data;
1043         size_t remaining = anslen;
1044
1045         resp_data = rwrap_fake_header(&answer, remaining, 0, 0);
1046         if (resp_data < 0) {
1047                 return -1;
1048         }
1049         remaining -= resp_data;
1050
1051         resp_data += rwrap_fake_question(question, type, &answer, remaining);
1052         if (resp_data < 0) {
1053                 return -1;
1054         }
1055         remaining -= resp_data;
1056
1057         resp_data += rwrap_fake_rdata_common(type, 0, question,
1058                                             remaining, &answer);
1059         if (resp_data < 0) {
1060                 return -1;
1061         }
1062
1063         return resp_data;
1064 }
1065
1066 static inline bool rwrap_known_type(int type)
1067 {
1068         switch (type) {
1069         case ns_t_a:
1070         case ns_t_aaaa:
1071         case ns_t_ns:
1072         case ns_t_srv:
1073         case ns_t_uri:
1074         case ns_t_soa:
1075         case ns_t_cname:
1076         case ns_t_ptr:
1077         case ns_t_txt:
1078                 return true;
1079         }
1080
1081         return false;
1082 }
1083
1084 static int rwrap_ancount(struct rwrap_fake_rr *rrs, int qtype)
1085 {
1086         int i;
1087         int ancount = 0;
1088
1089         /* For URI return the number of URIs. */
1090         if (qtype == ns_t_uri) {
1091                 for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1092                         if (rwrap_known_type(rrs[i].type) &&
1093                             rrs[i].type == qtype) {
1094                                 ancount++;
1095                         }
1096                 }
1097                 return ancount;
1098         }
1099
1100         /* Include all RRs in the stack until the sought type
1101          * in the answer section. This is the case i.e. when looking
1102          * up an A record but the name points to a CNAME
1103          */
1104         for (i = 0; i < RWRAP_MAX_RECURSION; i++) {
1105                 ancount++;
1106
1107                 if (rwrap_known_type(rrs[i].type) &&
1108                     rrs[i].type == qtype) {
1109                         break;
1110                 }
1111         }
1112
1113         /* Return 0 records if the sought type wasn't in the stack */
1114         return i < RWRAP_MAX_RECURSION ? ancount : 0;
1115 }
1116
1117 static int rwrap_arcount(struct rwrap_fake_rr *rrs, int ancount)
1118 {
1119         int i;
1120         int arcount = 0;
1121
1122         /* start from index ancount */
1123         for (i = ancount; i < RWRAP_MAX_RECURSION; i++) {
1124                 if (rwrap_known_type(rrs[i].type)) {
1125                         arcount++;
1126                 }
1127         }
1128
1129         return arcount;
1130 }
1131
1132 static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
1133                             uint8_t *answer,
1134                             size_t anslen)
1135 {
1136         ssize_t resp_data;
1137
1138         if (rr == NULL) {
1139                 RWRAP_LOG(RWRAP_LOG_ERROR, "Internal error!\n");
1140                 return -1;
1141         }
1142
1143         switch (rr->type) {
1144         case ns_t_a:
1145                 resp_data = rwrap_fake_a(rr, answer, anslen);
1146                 break;
1147         case ns_t_aaaa:
1148                 resp_data = rwrap_fake_aaaa(rr, answer, anslen);
1149                 break;
1150         case ns_t_ns:
1151                 resp_data = rwrap_fake_ns(rr, answer, anslen);
1152                 break;
1153         case ns_t_srv:
1154                 resp_data = rwrap_fake_srv(rr, answer, anslen);
1155                 break;
1156         case ns_t_uri:
1157                 resp_data = rwrap_fake_uri(rr, answer, anslen);
1158                 break;
1159         case ns_t_soa:
1160                 resp_data = rwrap_fake_soa(rr, answer, anslen);
1161                 break;
1162         case ns_t_cname:
1163                 resp_data = rwrap_fake_cname(rr, answer, anslen);
1164                 break;
1165         case ns_t_ptr:
1166                 resp_data = rwrap_fake_ptr(rr, answer, anslen);
1167                 break;
1168         case ns_t_txt:
1169                 resp_data = rwrap_fake_txt(rr, answer, anslen);
1170                 break;
1171         default:
1172                 return -1;
1173         }
1174
1175         return resp_data;
1176 }
1177
1178 static ssize_t rwrap_fake_answer(struct rwrap_fake_rr *rrs,
1179                                  int type,
1180                                  uint8_t *answer,
1181                                  size_t anslen)
1182
1183 {
1184         ssize_t resp_data;
1185         ssize_t rrlen;
1186         size_t remaining = anslen;
1187         int ancount;
1188         int arcount;
1189         int i;
1190
1191         ancount = rwrap_ancount(rrs, type);
1192         arcount = rwrap_arcount(rrs, ancount);
1193         RWRAP_LOG(RWRAP_LOG_TRACE,
1194                   "Got %d answers and %d additional records\n", ancount, arcount);
1195
1196         resp_data = rwrap_fake_header(&answer, remaining, ancount, arcount);
1197         if (resp_data < 0) {
1198                 return -1;
1199         }
1200         remaining -= resp_data;
1201
1202         resp_data += rwrap_fake_question(rrs->key, rrs->type, &answer, remaining);
1203         if (resp_data < 0) {
1204                 return -1;
1205         }
1206         remaining -= resp_data;
1207
1208         /* answer */
1209         for (i = 0; i < ancount; i++) {
1210                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1211                 if (rrlen < 0) {
1212                         return -1;
1213                 }
1214                 remaining -= rrlen;
1215                 answer += rrlen;
1216                 resp_data += rrlen;
1217         }
1218
1219         /* add authoritative NS here? */
1220
1221         /* additional records */
1222         for (i = ancount; i < ancount + arcount; i++) {
1223                 rrlen = rwrap_add_rr(&rrs[i], answer, remaining);
1224                 if (rrlen < 0) {
1225                         return -1;
1226                 }
1227                 remaining -= rrlen;
1228                 answer += rrlen;
1229                 resp_data += rrlen;
1230         }
1231
1232         return resp_data;
1233 }
1234
1235 /* Reads in a file in the following format:
1236  * TYPE RDATA
1237  *
1238  * Malformed entries are silently skipped.
1239  * Allocates answer buffer of size anslen that has to be freed after use.
1240  */
1241 static int rwrap_res_fake_hosts(const char *hostfile,
1242                                 const char *query,
1243                                 int type,
1244                                 unsigned char *answer,
1245                                 size_t anslen)
1246 {
1247         int rc = ENOENT;
1248         char *query_name = NULL;
1249         size_t qlen = strlen(query);
1250         struct rwrap_fake_rr rrs[RWRAP_MAX_RECURSION];
1251         ssize_t resp_size;
1252
1253         RWRAP_LOG(RWRAP_LOG_TRACE,
1254                   "Searching in fake hosts file %s\n", hostfile);
1255
1256         if (qlen > 0 && query[qlen-1] == '.') {
1257                 qlen--;
1258         }
1259
1260         query_name = strndup(query, qlen);
1261         if (query_name == NULL) {
1262                 return -1;
1263         }
1264
1265         rwrap_fake_rr_init(rrs, RWRAP_MAX_RECURSION);
1266
1267         rc = rwrap_get_record(hostfile, 0, query_name, type, rrs);
1268         switch (rc) {
1269         case 0:
1270                 RWRAP_LOG(RWRAP_LOG_TRACE,
1271                                 "Found record for [%s]\n", query_name);
1272                 resp_size = rwrap_fake_answer(rrs, type, answer, anslen);
1273                 break;
1274         case ENOENT:
1275                 RWRAP_LOG(RWRAP_LOG_TRACE,
1276                                 "No record for [%s]\n", query_name);
1277                 resp_size = rwrap_fake_empty(type, rrs->key, answer, anslen);
1278                 break;
1279         default:
1280                 RWRAP_LOG(RWRAP_LOG_NOTICE,
1281                           "Searching for [%s] did not return any results\n",
1282                           query_name);
1283                 free(query_name);
1284                 return -1;
1285         }
1286
1287         switch (resp_size) {
1288         case -1:
1289                 RWRAP_LOG(RWRAP_LOG_ERROR,
1290                                 "Error faking answer for [%s]\n", query_name);
1291                 break;
1292         default:
1293                 RWRAP_LOG(RWRAP_LOG_TRACE,
1294                                 "Successfully faked answer for [%s]\n",
1295                                 query_name);
1296                 break;
1297         }
1298
1299         free(query_name);
1300         return resp_size;
1301 }
1302
1303 /*********************************************************
1304  * RWRAP LOADING LIBC FUNCTIONS
1305  *********************************************************/
1306
1307 #include <dlfcn.h>
1308
1309 typedef int (*__libc_res_ninit)(struct __res_state *state);
1310 typedef int (*__libc___res_ninit)(struct __res_state *state);
1311 typedef void (*__libc_res_nclose)(struct __res_state *state);
1312 typedef void (*__libc___res_nclose)(struct __res_state *state);
1313 typedef int (*__libc_res_nquery)(struct __res_state *state,
1314                                  const char *dname,
1315                                  int class,
1316                                  int type,
1317                                  unsigned char *answer,
1318                                  int anslen);
1319 typedef int (*__libc___res_nquery)(struct __res_state *state,
1320                                    const char *dname,
1321                                    int class,
1322                                    int type,
1323                                    unsigned char *answer,
1324                                    int anslen);
1325 typedef int (*__libc_res_nsearch)(struct __res_state *state,
1326                                   const char *dname,
1327                                   int class,
1328                                   int type,
1329                                   unsigned char *answer,
1330                                   int anslen);
1331 typedef int (*__libc___res_nsearch)(struct __res_state *state,
1332                                     const char *dname,
1333                                     int class,
1334                                     int type,
1335                                     unsigned char *answer,
1336                                     int anslen);
1337
1338 #define RWRAP_SYMBOL_ENTRY(i) \
1339         union { \
1340                 __libc_##i f; \
1341                 void *obj; \
1342         } _libc_##i
1343
1344 struct rwrap_libc_symbols {
1345         RWRAP_SYMBOL_ENTRY(res_ninit);
1346         RWRAP_SYMBOL_ENTRY(__res_ninit);
1347         RWRAP_SYMBOL_ENTRY(res_nclose);
1348         RWRAP_SYMBOL_ENTRY(__res_nclose);
1349         RWRAP_SYMBOL_ENTRY(res_nquery);
1350         RWRAP_SYMBOL_ENTRY(__res_nquery);
1351         RWRAP_SYMBOL_ENTRY(res_nsearch);
1352         RWRAP_SYMBOL_ENTRY(__res_nsearch);
1353 };
1354 #undef RWRAP_SYMBOL_ENTRY
1355
1356 struct rwrap {
1357         struct {
1358                 void *handle;
1359                 struct rwrap_libc_symbols symbols;
1360         } libc;
1361
1362         struct {
1363                 void *handle;
1364                 struct rwrap_libc_symbols symbols;
1365         } libresolv;
1366
1367         bool initialised;
1368         bool enabled;
1369
1370         char *socket_dir;
1371 };
1372
1373 static struct rwrap rwrap;
1374
1375 enum rwrap_lib {
1376     RWRAP_LIBC,
1377     RWRAP_LIBRESOLV
1378 };
1379
1380 static const char *rwrap_str_lib(enum rwrap_lib lib)
1381 {
1382         switch (lib) {
1383         case RWRAP_LIBC:
1384                 return "libc";
1385         case RWRAP_LIBRESOLV:
1386                 return "libresolv";
1387         }
1388
1389         /* Compiler would warn us about unhandled enum value if we get here */
1390         return "unknown";
1391 }
1392
1393 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
1394 {
1395         int flags = RTLD_LAZY;
1396         void *handle = NULL;
1397         int i;
1398
1399 #ifdef RTLD_DEEPBIND
1400         const char *env_preload = getenv("LD_PRELOAD");
1401         const char *env_deepbind = getenv("RESOLV_WRAPPER_DISABLE_DEEPBIND");
1402         bool enable_deepbind = true;
1403
1404         /* Don't do a deepbind if we run with libasan */
1405         if (env_preload != NULL && strlen(env_preload) < 1024) {
1406                 const char *p = strstr(env_preload, "libasan.so");
1407                 if (p != NULL) {
1408                         enable_deepbind = false;
1409                 }
1410         }
1411
1412         if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
1413                 enable_deepbind = false;
1414         }
1415
1416         if (enable_deepbind) {
1417                 flags |= RTLD_DEEPBIND;
1418         }
1419 #endif
1420
1421         switch (lib) {
1422         case RWRAP_LIBRESOLV:
1423 #ifdef HAVE_LIBRESOLV
1424                 handle = rwrap.libresolv.handle;
1425                 if (handle == NULL) {
1426                         for (i = 10; i >= 0; i--) {
1427                                 char soname[256] = {0};
1428
1429                                 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
1430                                 handle = dlopen(soname, flags);
1431                                 if (handle != NULL) {
1432                                         break;
1433                                 }
1434                         }
1435
1436                         rwrap.libresolv.handle = handle;
1437                 }
1438                 break;
1439 #endif
1440                 /* FALL TROUGH */
1441         case RWRAP_LIBC:
1442                 handle = rwrap.libc.handle;
1443 #ifdef LIBC_SO
1444                 if (handle == NULL) {
1445                         handle = dlopen(LIBC_SO, flags);
1446
1447                         rwrap.libc.handle = handle;
1448                 }
1449 #endif
1450                 if (handle == NULL) {
1451                         for (i = 10; i >= 0; i--) {
1452                                 char soname[256] = {0};
1453
1454                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
1455                                 handle = dlopen(soname, flags);
1456                                 if (handle != NULL) {
1457                                         break;
1458                                 }
1459                         }
1460
1461                         rwrap.libc.handle = handle;
1462                 }
1463                 break;
1464         }
1465
1466         if (handle == NULL) {
1467 #ifdef RTLD_NEXT
1468                 handle = rwrap.libc.handle = rwrap.libresolv.handle = RTLD_NEXT;
1469 #else
1470                 RWRAP_LOG(RWRAP_LOG_ERROR,
1471                           "Failed to dlopen library: %s\n",
1472                           dlerror());
1473                 exit(-1);
1474 #endif
1475         }
1476
1477         return handle;
1478 }
1479
1480 static void *_rwrap_bind_symbol(enum rwrap_lib lib, const char *fn_name)
1481 {
1482         void *handle;
1483         void *func;
1484
1485         handle = rwrap_load_lib_handle(lib);
1486
1487         func = dlsym(handle, fn_name);
1488         if (func == NULL) {
1489                 RWRAP_LOG(RWRAP_LOG_ERROR,
1490                                 "Failed to find %s: %s\n",
1491                                 fn_name, dlerror());
1492                 exit(-1);
1493         }
1494
1495         RWRAP_LOG(RWRAP_LOG_TRACE,
1496                         "Loaded %s from %s",
1497                         fn_name, rwrap_str_lib(lib));
1498         return func;
1499 }
1500
1501 #define rwrap_bind_symbol_libc(sym_name) \
1502         if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
1503                 rwrap.libc.symbols._libc_##sym_name.obj = \
1504                         _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
1505         }
1506
1507 #define rwrap_bind_symbol_libresolv(sym_name) \
1508         if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
1509                 rwrap.libresolv.symbols._libc_##sym_name.obj = \
1510                         _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
1511         }
1512
1513 /*
1514  * IMPORTANT
1515  *
1516  * Functions especially from libc need to be loaded individually, you can't load
1517  * all at once or gdb will segfault at startup. The same applies to valgrind and
1518  * has probably something todo with with the linker.
1519  * So we need load each function at the point it is called the first time.
1520  */
1521
1522 static int libc_res_ninit(struct __res_state *state)
1523 {
1524 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1525         rwrap_bind_symbol_libresolv(res_ninit);
1526
1527         return rwrap.libresolv.symbols._libc_res_ninit.f(state);
1528 #elif defined(HAVE___RES_NINIT)
1529         rwrap_bind_symbol_libresolv(__res_ninit);
1530
1531         return rwrap.libresolv.symbols._libc___res_ninit.f(state);
1532 #else
1533 #error "No res_ninit function"
1534 #endif
1535 }
1536
1537 static void libc_res_nclose(struct __res_state *state)
1538 {
1539 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1540         rwrap_bind_symbol_libresolv(res_nclose);
1541
1542         rwrap.libresolv.symbols._libc_res_nclose.f(state);
1543         return;
1544 #elif defined(HAVE___RES_NCLOSE)
1545         rwrap_bind_symbol_libresolv(__res_nclose);
1546
1547         rwrap.libresolv.symbols._libc___res_nclose.f(state);
1548 #else
1549 #error "No res_nclose function"
1550 #endif
1551 }
1552
1553 static int libc_res_nquery(struct __res_state *state,
1554                            const char *dname,
1555                            int class,
1556                            int type,
1557                            unsigned char *answer,
1558                            int anslen)
1559 {
1560 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1561         rwrap_bind_symbol_libresolv(res_nquery);
1562
1563         return rwrap.libresolv.symbols._libc_res_nquery.f(state,
1564                                                           dname,
1565                                                           class,
1566                                                           type,
1567                                                           answer,
1568                                                           anslen);
1569 #elif defined(HAVE___RES_NQUERY)
1570         rwrap_bind_symbol_libresolv(__res_nquery);
1571
1572         return rwrap.libresolv.symbols._libc___res_nquery.f(state,
1573                                                             dname,
1574                                                             class,
1575                                                             type,
1576                                                             answer,
1577                                                             anslen);
1578 #else
1579 #error "No res_nquery function"
1580 #endif
1581 }
1582
1583 static int libc_res_nsearch(struct __res_state *state,
1584                             const char *dname,
1585                             int class,
1586                             int type,
1587                             unsigned char *answer,
1588                             int anslen)
1589 {
1590 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1591         rwrap_bind_symbol_libresolv(res_nsearch);
1592
1593         return rwrap.libresolv.symbols._libc_res_nsearch.f(state,
1594                                                            dname,
1595                                                            class,
1596                                                            type,
1597                                                            answer,
1598                                                            anslen);
1599 #elif defined(HAVE___RES_NSEARCH)
1600         rwrap_bind_symbol_libresolv(__res_nsearch);
1601
1602         return rwrap.libresolv.symbols._libc___res_nsearch.f(state,
1603                                                              dname,
1604                                                              class,
1605                                                              type,
1606                                                              answer,
1607                                                              anslen);
1608 #else
1609 #error "No res_nsearch function"
1610 #endif
1611 }
1612
1613 /****************************************************************************
1614  *   RES_HELPER
1615  ***************************************************************************/
1616
1617 static size_t rwrap_get_nameservers(struct __res_state *state,
1618                                     size_t nserv,
1619                                     union rwrap_sockaddr *nsaddrs)
1620 {
1621 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1622         union res_sockaddr_union set[MAXNS];
1623         size_t i;
1624         int rc;
1625
1626         memset(set, 0, sizeof(set));
1627         memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1628
1629         if (nserv > MAXNS) {
1630                 nserv = MAXNS;
1631         }
1632
1633         rc = res_getservers(state, set, nserv);
1634         if (rc <= 0) {
1635                 return 0;
1636         }
1637         if (rc < nserv) {
1638                 nserv = rc;
1639         }
1640
1641         for (i = 0; i < nserv; i++) {
1642                 switch (set[i].sin.sin_family) {
1643                 case AF_INET:
1644                         nsaddrs[i] = (union rwrap_sockaddr) {
1645                                 .in = set[i].sin,
1646                         };
1647                         break;
1648 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1649                 case AF_INET6:
1650                         nsaddrs[i] = (union rwrap_sockaddr) {
1651                                 .in6 = set[i].sin6,
1652                         };
1653                         break;
1654 #endif
1655                 }
1656         }
1657
1658         return nserv;
1659 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1660         size_t i;
1661
1662         memset(nsaddrs, 0, sizeof(*nsaddrs) * nserv);
1663
1664         if (nserv > (size_t)state->nscount) {
1665                 nserv = (size_t)state->nscount;
1666         }
1667
1668         for (i = 0; i < nserv; i++) {
1669 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1670                 if (state->_u._ext.nsaddrs[i] != NULL) {
1671                         nsaddrs[i] = (union rwrap_sockaddr) {
1672                                 .in6 = *state->_u._ext.nsaddrs[i],
1673                         };
1674                 } else
1675 #endif /* HAVE_RES_STATE_U_EXT_NSADDRS */
1676                 {
1677                         nsaddrs[i] = (union rwrap_sockaddr) {
1678                                 .in = state->nsaddr_list[i],
1679                         };
1680                 }
1681         }
1682
1683         return nserv;
1684 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1685 }
1686
1687 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl,
1688                                   const char *func,
1689                                   struct __res_state *state)
1690 {
1691         union rwrap_sockaddr nsaddrs[MAXNS];
1692         size_t nserv = MAXNS;
1693         size_t i;
1694
1695         memset(nsaddrs, 0, sizeof(nsaddrs));
1696         nserv = rwrap_get_nameservers(state, nserv, nsaddrs);
1697         for (i = 0; i < nserv; i++) {
1698                 char ip[INET6_ADDRSTRLEN];
1699
1700                 switch (nsaddrs[i].sa.sa_family) {
1701                 case AF_INET:
1702                         inet_ntop(AF_INET, &(nsaddrs[i].in.sin_addr),
1703                                   ip, sizeof(ip));
1704                         break;
1705                 case AF_INET6:
1706                         inet_ntop(AF_INET6, &(nsaddrs[i].in6.sin6_addr),
1707                                   ip, sizeof(ip));
1708                         break;
1709                 default:
1710                         snprintf(ip, sizeof(ip), "<unknown sa_family=%d",
1711                                  nsaddrs[i].sa.sa_family);
1712                         break;
1713                 }
1714
1715                 rwrap_log(dbglvl, func,
1716                           "        nameserver: %s",
1717                           ip);
1718         }
1719 }
1720
1721 static void rwrap_reset_nameservers(struct __res_state *state)
1722 {
1723 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1724         res_setservers(state, NULL, 0);
1725 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1726 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1727         size_t i;
1728
1729         for (i = 0; i < (size_t)state->nscount; i++) {
1730                 if (state->_u._ext.nssocks[i] != -1) {
1731                         close(state->_u._ext.nssocks[i]);
1732                         state->_u._ext.nssocks[i] = -1;
1733                 }
1734                 SAFE_FREE(state->_u._ext.nsaddrs[i]);
1735         }
1736         memset(&state->_u._ext, 0, sizeof(state->_u._ext));
1737         for (i = 0; i < MAXNS; i++) {
1738                 state->_u._ext.nssocks[i] = -1;
1739                 state->_u._ext.nsmap[i] = MAXNS + 1;
1740         }
1741         state->ipv6_unavail = false;
1742 #endif
1743         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
1744         state->nscount = 0;
1745 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1746 }
1747
1748 static int rwrap_set_nameservers(struct __res_state *state,
1749                                  size_t nserv,
1750                                  const union rwrap_sockaddr *nsaddrs)
1751 {
1752 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1753         union res_sockaddr_union set[MAXNS];
1754         size_t i;
1755
1756         memset(set, 0, sizeof(set));
1757
1758         if (nserv > MAXNS) {
1759                 nserv = MAXNS;
1760         }
1761
1762         rwrap_reset_nameservers(state);
1763
1764         for (i = 0; i < nserv; i++) {
1765                 switch (nsaddrs[i].sa.sa_family) {
1766                 case AF_INET:
1767                         set[i] = (union res_sockaddr_union) {
1768                                 .sin = nsaddrs[i].in,
1769                         };
1770                         break;
1771 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1772                 case AF_INET6:
1773                         set[i] = (union res_sockaddr_union) {
1774                                 .sin6 = nsaddrs[i].in6,
1775                         };
1776                         break;
1777 #endif
1778                 default:
1779                         RWRAP_LOG(RWRAP_LOG_ERROR,
1780                                   "Internal error unhandled sa_family=%d",
1781                                   nsaddrs[i].sa.sa_family);
1782                         errno = ENOSYS;
1783                         return -1;
1784                 }
1785         }
1786
1787         res_setservers(state, set, nserv);
1788         return 0;
1789 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1790         size_t i;
1791
1792         if (nserv > MAXNS) {
1793                 nserv = MAXNS;
1794         }
1795         rwrap_reset_nameservers(state);
1796
1797         for (i = 0; i < nserv; i++) {
1798                 switch (nsaddrs[i].sa.sa_family) {
1799                 case AF_INET:
1800                         state->nsaddr_list[i] = nsaddrs[i].in;
1801                         break;
1802 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1803                 case AF_INET6:
1804                         state->_u._ext.nsaddrs[i] = malloc(sizeof(nsaddrs[i].in6));
1805                         if (state->_u._ext.nsaddrs[i] == NULL) {
1806                                 rwrap_reset_nameservers(state);
1807                                 errno = ENOMEM;
1808                                 return -1;
1809                         }
1810                         *state->_u._ext.nsaddrs[i] = nsaddrs[i].in6;
1811                         state->_u._ext.nssocks[i] = -1;
1812                         state->_u._ext.nsmap[i] = MAXNS + 1;
1813                         state->_u._ext.nscount6++;
1814                         break;
1815 #endif
1816                 default:
1817                         RWRAP_LOG(RWRAP_LOG_ERROR,
1818                                   "Internal error unhandled sa_family=%d",
1819                                   nsaddrs[i].sa.sa_family);
1820                         rwrap_reset_nameservers(state);
1821                         errno = ENOSYS;
1822                         return -1;
1823                 }
1824         }
1825
1826         /*
1827          * note that state->_u._ext.nscount is left as 0,
1828          * this matches glibc and allows resolv wrapper
1829          * to work with most (maybe all) glibc versions.
1830          */
1831         state->nscount = i;
1832
1833         return 0;
1834 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1835 }
1836
1837 static int rwrap_parse_resolv_conf(struct __res_state *state,
1838                                    const char *resolv_conf)
1839 {
1840         FILE *fp;
1841         char buf[BUFSIZ];
1842         size_t nserv = 0;
1843         union rwrap_sockaddr nsaddrs[MAXNS];
1844
1845         memset(nsaddrs, 0, sizeof(nsaddrs));
1846
1847         fp = fopen(resolv_conf, "r");
1848         if (fp == NULL) {
1849                 RWRAP_LOG(RWRAP_LOG_WARN,
1850                           "Opening %s failed: %s",
1851                           resolv_conf, strerror(errno));
1852                 return -1;
1853         }
1854
1855         while(fgets(buf, sizeof(buf), fp) != NULL) {
1856                 char *p;
1857
1858                 /* Ignore comments */
1859                 if (buf[0] == '#' || buf[0] == ';') {
1860                         continue;
1861                 }
1862
1863                 if (RESOLV_MATCH(buf, "nameserver") && nserv < MAXNS) {
1864                         struct in_addr a;
1865                         struct in6_addr a6;
1866                         char *q;
1867                         int ok;
1868
1869                         p = buf + strlen("nameserver");
1870
1871                         /* Skip spaces and tabs */
1872                         while(isblank((int)p[0])) {
1873                                 p++;
1874                         }
1875
1876                         q = p;
1877                         while(q[0] != '\n' && q[0] != '\0') {
1878                                 q++;
1879                         }
1880                         q[0] = '\0';
1881
1882                         ok = inet_pton(AF_INET, p, &a);
1883                         if (ok) {
1884                                 nsaddrs[nserv] = (union rwrap_sockaddr) {
1885                                         .in = {
1886                                                 .sin_family = AF_INET,
1887                                                 .sin_addr = a,
1888                                                 .sin_port = htons(53),
1889                                                 .sin_zero = { 0 },
1890                                         },
1891                                 };
1892
1893                                 nserv++;
1894                                 continue;
1895                         }
1896
1897                         ok = inet_pton(AF_INET6, p, &a6);
1898                         if (ok) {
1899 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1900                                 nsaddrs[nserv] = (union rwrap_sockaddr) {
1901                                         .in6 = {
1902
1903                                                 .sin6_family = AF_INET6,
1904                                                 .sin6_port = htons(53),
1905                                                 .sin6_flowinfo = 0,
1906                                                 .sin6_addr = a6,
1907                                         },
1908                                 };
1909                                 nserv++;
1910                                 continue;
1911 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1912                                 RWRAP_LOG(RWRAP_LOG_WARN,
1913                                           "resolve_wrapper does not support "
1914                                           "IPv6 on this platform");
1915                                 continue;
1916 #endif
1917                         }
1918
1919                         RWRAP_LOG(RWRAP_LOG_ERROR, "Malformed DNS server[%s]", p);
1920                         continue;
1921                 } /* TODO: match other keywords */
1922         }
1923
1924         if (ferror(fp)) {
1925                 RWRAP_LOG(RWRAP_LOG_ERROR,
1926                           "Reading from %s failed",
1927                           resolv_conf);
1928                 fclose(fp);
1929                 return -1;
1930         }
1931
1932         fclose(fp);
1933
1934         if (nserv == 0) {
1935                 RWRAP_LOG(RWRAP_LOG_WARN,
1936                           "No usable nameservers found in %s",
1937                           resolv_conf);
1938                 errno = ESRCH;
1939                 return -1;
1940         }
1941
1942         return rwrap_set_nameservers(state, nserv, nsaddrs);
1943 }
1944
1945 /****************************************************************************
1946  *   RES_NINIT
1947  ***************************************************************************/
1948
1949 static int rwrap_res_ninit(struct __res_state *state)
1950 {
1951         int rc;
1952
1953         rc = libc_res_ninit(state);
1954         if (rc == 0) {
1955                 const char *resolv_conf = getenv("RESOLV_WRAPPER_CONF");
1956
1957                 if (resolv_conf != NULL) {
1958                         rc = rwrap_parse_resolv_conf(state, resolv_conf);
1959                 }
1960         }
1961
1962         return rc;
1963 }
1964
1965 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1966 int res_ninit(struct __res_state *state)
1967 #elif defined(HAVE___RES_NINIT)
1968 int __res_ninit(struct __res_state *state)
1969 #endif
1970 {
1971         return rwrap_res_ninit(state);
1972 }
1973
1974 /****************************************************************************
1975  *   RES_INIT
1976  ***************************************************************************/
1977
1978 static struct __res_state rwrap_res_state;
1979
1980 static int rwrap_res_init(void)
1981 {
1982         int rc;
1983
1984         rc = rwrap_res_ninit(&rwrap_res_state);
1985
1986         return rc;
1987 }
1988
1989 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1990 int res_init(void)
1991 #elif defined(HAVE___RES_INIT)
1992 int __res_init(void)
1993 #endif
1994 {
1995         return rwrap_res_init();
1996 }
1997
1998 /****************************************************************************
1999  *   RES_NCLOSE
2000  ***************************************************************************/
2001
2002 static void rwrap_res_nclose(struct __res_state *state)
2003 {
2004         rwrap_reset_nameservers(state);
2005         libc_res_nclose(state);
2006 }
2007
2008 #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
2009 void res_nclose(struct __res_state *state)
2010 #elif defined(HAVE___RES_NCLOSE)
2011 void __res_nclose(struct __res_state *state)
2012 #endif
2013 {
2014         rwrap_res_nclose(state);
2015 }
2016
2017 /****************************************************************************
2018  *   RES_CLOSE
2019  ***************************************************************************/
2020
2021 static void rwrap_res_close(void)
2022 {
2023         rwrap_res_nclose(&rwrap_res_state);
2024 }
2025
2026 #if defined(HAVE_RES_CLOSE)
2027 void res_close(void)
2028 #elif defined(HAVE___RES_CLOSE)
2029 void __res_close(void)
2030 #endif
2031 {
2032         rwrap_res_close();
2033 }
2034
2035 /****************************************************************************
2036  *   RES_NQUERY
2037  ***************************************************************************/
2038
2039 static int rwrap_res_nquery(struct __res_state *state,
2040                             const char *dname,
2041                             int class,
2042                             int type,
2043                             unsigned char *answer,
2044                             int anslen)
2045 {
2046         int rc;
2047         const char *fake_hosts;
2048
2049         RWRAP_LOG(RWRAP_LOG_TRACE,
2050                   "Resolve the domain name [%s] - class=%d, type=%d",
2051                   dname, class, type);
2052         rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2053
2054         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2055         if (fake_hosts != NULL) {
2056                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2057         } else {
2058                 rc = libc_res_nquery(state, dname, class, type, answer, anslen);
2059         }
2060
2061
2062         RWRAP_LOG(RWRAP_LOG_TRACE,
2063                   "The returned response length is: %d",
2064                   rc);
2065
2066         return rc;
2067 }
2068
2069 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
2070 int res_nquery(struct __res_state *state,
2071                const char *dname,
2072                int class,
2073                int type,
2074                unsigned char *answer,
2075                int anslen)
2076 #elif defined(HAVE___RES_NQUERY)
2077 int __res_nquery(struct __res_state *state,
2078                  const char *dname,
2079                  int class,
2080                  int type,
2081                  unsigned char *answer,
2082                  int anslen)
2083 #endif
2084 {
2085         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
2086 }
2087
2088 /****************************************************************************
2089  *   RES_QUERY
2090  ***************************************************************************/
2091
2092 static int rwrap_res_query(const char *dname,
2093                            int class,
2094                            int type,
2095                            unsigned char *answer,
2096                            int anslen)
2097 {
2098         int rc;
2099
2100         rc = rwrap_res_ninit(&rwrap_res_state);
2101         if (rc != 0) {
2102                 return rc;
2103         }
2104
2105         rc = rwrap_res_nquery(&rwrap_res_state,
2106                               dname,
2107                               class,
2108                               type,
2109                               answer,
2110                               anslen);
2111
2112         return rc;
2113 }
2114
2115 #if !defined(res_query) && defined(HAVE_RES_QUERY)
2116 int res_query(const char *dname,
2117               int class,
2118               int type,
2119               unsigned char *answer,
2120               int anslen)
2121 #elif defined(HAVE___RES_QUERY)
2122 int __res_query(const char *dname,
2123                 int class,
2124                 int type,
2125                 unsigned char *answer,
2126                 int anslen)
2127 #endif
2128 {
2129         return rwrap_res_query(dname, class, type, answer, anslen);
2130 }
2131
2132 /****************************************************************************
2133  *   RES_NSEARCH
2134  ***************************************************************************/
2135
2136 static int rwrap_res_nsearch(struct __res_state *state,
2137                              const char *dname,
2138                              int class,
2139                              int type,
2140                              unsigned char *answer,
2141                              int anslen)
2142 {
2143         int rc;
2144         const char *fake_hosts;
2145
2146         RWRAP_LOG(RWRAP_LOG_TRACE,
2147                   "Resolve the domain name [%s] - class=%d, type=%d",
2148                   dname, class, type);
2149         rwrap_log_nameservers(RWRAP_LOG_TRACE, __func__, state);
2150
2151         fake_hosts = getenv("RESOLV_WRAPPER_HOSTS");
2152         if (fake_hosts != NULL) {
2153                 rc = rwrap_res_fake_hosts(fake_hosts, dname, type, answer, anslen);
2154         } else {
2155                 rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
2156         }
2157
2158         RWRAP_LOG(RWRAP_LOG_TRACE,
2159                   "The returned response length is: %d",
2160                   rc);
2161
2162         return rc;
2163 }
2164
2165 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
2166 int res_nsearch(struct __res_state *state,
2167                 const char *dname,
2168                 int class,
2169                 int type,
2170                 unsigned char *answer,
2171                 int anslen)
2172 #elif defined(HAVE___RES_NSEARCH)
2173 int __res_nsearch(struct __res_state *state,
2174                   const char *dname,
2175                   int class,
2176                   int type,
2177                   unsigned char *answer,
2178                   int anslen)
2179 #endif
2180 {
2181         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
2182 }
2183
2184 /****************************************************************************
2185  *   RES_SEARCH
2186  ***************************************************************************/
2187
2188 static int rwrap_res_search(const char *dname,
2189                             int class,
2190                             int type,
2191                             unsigned char *answer,
2192                             int anslen)
2193 {
2194         int rc;
2195
2196         rc = rwrap_res_ninit(&rwrap_res_state);
2197         if (rc != 0) {
2198                 return rc;
2199         }
2200
2201         rc = rwrap_res_nsearch(&rwrap_res_state,
2202                                dname,
2203                                class,
2204                                type,
2205                                answer,
2206                                anslen);
2207
2208         return rc;
2209 }
2210
2211 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
2212 int res_search(const char *dname,
2213                int class,
2214                int type,
2215                unsigned char *answer,
2216                int anslen)
2217 #elif defined(HAVE___RES_SEARCH)
2218 int __res_search(const char *dname,
2219                  int class,
2220                  int type,
2221                  unsigned char *answer,
2222                  int anslen)
2223 #endif
2224 {
2225         return rwrap_res_search(dname, class, type, answer, anslen);
2226 }