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