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