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