rwrap: Add support for res_[n]search().
[obnox/cwrap/resolv_wrapper.git] / src / resolv_wrapper.c
1 /*
2  * Copyright (c) 2014      Andreas Schneider <asn@samba.org>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the author nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "config.h"
35
36 #include <arpa/inet.h>
37 #include <sys/types.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <stdbool.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 #include <resolv.h>
46
47 /* GCC has printf type attribute check. */
48 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
49 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
50 #else
51 #define PRINTF_ATTRIBUTE(a,b)
52 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
53
54 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
55 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
56 #else
57 #define DESTRUCTOR_ATTRIBUTE
58 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
59
60 enum rwrap_dbglvl_e {
61         RWRAP_LOG_ERROR = 0,
62         RWRAP_LOG_WARN,
63         RWRAP_LOG_DEBUG,
64         RWRAP_LOG_TRACE
65 };
66
67 #ifdef NDEBUG
68 # define RWRAP_LOG(...)
69 #else
70
71 static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
72 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
73
74 static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
75                       const char *func,
76                       const char *format, ...)
77 {
78         char buffer[1024];
79         va_list va;
80         const char *d;
81         unsigned int lvl = 0;
82         int pid = getpid();
83
84         d = getenv("RESOLV_WRAPPER_DEBUGLEVEL");
85         if (d != NULL) {
86                 lvl = atoi(d);
87         }
88
89         va_start(va, format);
90         vsnprintf(buffer, sizeof(buffer), format, va);
91         va_end(va);
92
93         if (lvl >= dbglvl) {
94                 switch (dbglvl) {
95                         case RWRAP_LOG_ERROR:
96                                 fprintf(stderr,
97                                         "RWRAP_ERROR(%d) - %s: %s\n",
98                                         pid, func, buffer);
99                                 break;
100                         case RWRAP_LOG_WARN:
101                                 fprintf(stderr,
102                                         "RWRAP_WARN(%d) - %s: %s\n",
103                                         pid, func, buffer);
104                                 break;
105                         case RWRAP_LOG_DEBUG:
106                                 fprintf(stderr,
107                                         "RWRAP_DEBUG(%d) - %s: %s\n",
108                                         pid, func, buffer);
109                                 break;
110                         case RWRAP_LOG_TRACE:
111                                 fprintf(stderr,
112                                         "RWRAP_TRACE(%d) - %s: %s\n",
113                                         pid, func, buffer);
114                                 break;
115                 }
116         }
117 }
118 #endif /* NDEBUG RWRAP_LOG */
119
120 /*********************************************************
121  * RWRAP LOADING LIBC FUNCTIONS
122  *********************************************************/
123
124 #include <dlfcn.h>
125
126 struct rwrap_libc_fns {
127         int (*libc_res_init)(void);
128         int (*libc___res_init)(void);
129         int (*libc_res_ninit)(struct __res_state *state);
130         int (*libc___res_ninit)(struct __res_state *state);
131         void (*libc_res_nclose)(struct __res_state *state);
132         void (*libc___res_nclose)(struct __res_state *state);
133         void (*libc_res_close)(void);
134         void (*libc___res_close)(void);
135         int (*libc_res_nquery)(struct __res_state *state,
136                                const char *dname,
137                                int class,
138                                int type,
139                                unsigned char *answer,
140                                int anslen);
141         int (*libc___res_nquery)(struct __res_state *state,
142                                  const char *dname,
143                                  int class,
144                                  int type,
145                                  unsigned char *answer,
146                                  int anslen);
147         int (*libc_res_nsearch)(struct __res_state *state,
148                                 const char *dname,
149                                 int class,
150                                 int type,
151                                 unsigned char *answer,
152                                 int anslen);
153         int (*libc___res_nsearch)(struct __res_state *state,
154                                   const char *dname,
155                                   int class,
156                                   int type,
157                                   unsigned char *answer,
158                                   int anslen);
159 };
160
161 struct rwrap {
162         void *libc_handle;
163         void *libresolv_handle;
164
165         bool initialised;
166         bool enabled;
167
168         char *socket_dir;
169
170         struct rwrap_libc_fns fns;
171 };
172
173 static struct rwrap rwrap;
174
175 enum rwrap_lib {
176     RWRAP_LIBC,
177     RWRAP_LIBRESOLV
178 };
179
180 #ifndef NDEBUG
181 static const char *rwrap_str_lib(enum rwrap_lib lib)
182 {
183         switch (lib) {
184         case RWRAP_LIBC:
185                 return "libc";
186         case RWRAP_LIBRESOLV:
187                 return "libresolv";
188         }
189
190         /* Compiler would warn us about unhandled enum value if we get here */
191         return "unknown";
192 }
193 #endif
194
195 static void *rwrap_load_lib_handle(enum rwrap_lib lib)
196 {
197         int flags = RTLD_LAZY;
198         void *handle = NULL;
199         int i;
200
201 #ifdef RTLD_DEEPBIND
202         flags |= RTLD_DEEPBIND;
203 #endif
204
205         switch (lib) {
206         case RWRAP_LIBRESOLV:
207 #ifdef HAVE_LIBRESOLV
208                 handle = rwrap.libresolv_handle;
209                 if (handle == NULL) {
210                         for (i = 10; i >= 0; i--) {
211                                 char soname[256] = {0};
212
213                                 snprintf(soname, sizeof(soname), "libresolv.so.%d", i);
214                                 handle = dlopen(soname, flags);
215                                 if (handle != NULL) {
216                                         break;
217                                 }
218                         }
219
220                         rwrap.libresolv_handle = handle;
221                 }
222                 break;
223 #endif
224                 /* FALL TROUGH */
225         case RWRAP_LIBC:
226                 handle = rwrap.libc_handle;
227 #ifdef LIBC_SO
228                 if (handle == NULL) {
229                         handle = dlopen(LIBC_SO, flags);
230
231                         rwrap.libc_handle = handle;
232                 }
233 #endif
234                 if (handle == NULL) {
235                         for (i = 10; i >= 0; i--) {
236                                 char soname[256] = {0};
237
238                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
239                                 handle = dlopen(soname, flags);
240                                 if (handle != NULL) {
241                                         break;
242                                 }
243                         }
244
245                         rwrap.libc_handle = handle;
246                 }
247                 break;
248         }
249
250         if (handle == NULL) {
251 #ifdef RTLD_NEXT
252                 handle = rwrap.libc_handle = rwrap.libresolv_handle = RTLD_NEXT;
253 #else
254                 RWRAP_LOG(RWRAP_LOG_ERROR,
255                           "Failed to dlopen library: %s\n",
256                           dlerror());
257                 exit(-1);
258 #endif
259         }
260
261         return handle;
262 }
263
264 static void *_rwrap_load_lib_function(enum rwrap_lib lib, const char *fn_name)
265 {
266         void *handle;
267         void *func;
268
269         handle = rwrap_load_lib_handle(lib);
270
271         func = dlsym(handle, fn_name);
272         if (func == NULL) {
273                 RWRAP_LOG(RWRAP_LOG_ERROR,
274                                 "Failed to find %s: %s\n",
275                                 fn_name, dlerror());
276                 exit(-1);
277         }
278
279         RWRAP_LOG(RWRAP_LOG_TRACE,
280                         "Loaded %s from %s",
281                         fn_name, rwrap_str_lib(lib));
282         return func;
283 }
284
285 #define rwrap_load_lib_function(lib, fn_name) \
286         if (rwrap.fns.libc_##fn_name == NULL) { \
287                 *(void **) (&rwrap.fns.libc_##fn_name) = \
288                         _rwrap_load_lib_function(lib, #fn_name); \
289         }
290
291 /*
292  * IMPORTANT
293  *
294  * Functions especially from libc need to be loaded individually, you can't load
295  * all at once or gdb will segfault at startup. The same applies to valgrind and
296  * has probably something todo with with the linker.
297  * So we need load each function at the point it is called the first time.
298  */
299 #if 0
300 static int libc_res_init(void)
301 {
302 #if defined(HAVE_RES_INIT)
303         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_init);
304
305         return rwrap.fns.libc_res_init();
306 #elif defined(HAVE___RES_INIT)
307         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_init);
308
309         return rwrap.fns.libc___res_init();
310 #endif
311 }
312 #endif
313
314 static int libc_res_ninit(struct __res_state *state)
315 {
316 #if defined(HAVE_RES_NINIT)
317         rwrap_load_lib_function(RWRAP_LIBC, res_ninit);
318
319         return rwrap.fns.libc_res_ninit(state);
320 #elif defined(HAVE___RES_NINIT)
321         rwrap_load_lib_function(RWRAP_LIBC, __res_ninit);
322
323         return rwrap.fns.libc___res_ninit(state);
324 #else
325 #error "No res_ninit function"
326 #endif
327 }
328
329 static void libc_res_nclose(struct __res_state *state)
330 {
331 #if defined(HAVE_RES_NCLOSE)
332         rwrap_load_lib_function(RWRAP_LIBC, res_nclose);
333
334         rwrap.fns.libc_res_nclose(state);
335 #elif defined(HAVE___RES_NCLOSE)
336         rwrap_load_lib_function(RWRAP_LIBC, __res_nclose);
337
338         rwrap.fns.libc___res_nclose(state);
339 #else
340 #error "No res_nclose function"
341 #endif
342 }
343
344 static int libc_res_nquery(struct __res_state *state,
345                            const char *dname,
346                            int class,
347                            int type,
348                            unsigned char *answer,
349                            int anslen)
350 {
351 #if defined(HAVE_RES_NQUERY)
352         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nquery);
353
354         return rwrap.fns.libc_res_nquery(state,
355                                          dname,
356                                          class,
357                                          type,
358                                          answer,
359                                          anslen);
360 #elif defined(HAVE___RES_NQUERY)
361         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nquery);
362
363         return rwrap.fns.libc___res_nquery(state,
364                                            dname,
365                                            class,
366                                            type,
367                                            answer,
368                                            anslen);
369 #else
370 #error "No res_nquery function"
371 #endif
372 }
373
374 static int libc_res_nsearch(struct __res_state *state,
375                             const char *dname,
376                             int class,
377                             int type,
378                             unsigned char *answer,
379                             int anslen)
380 {
381 #if defined(HAVE_RES_NSEARCH)
382         rwrap_load_lib_function(RWRAP_LIBRESOLV, res_nsearch);
383
384         return rwrap.fns.libc_res_nsearch(state,
385                                           dname,
386                                           class,
387                                           type,
388                                           answer,
389                                           anslen);
390 #elif defined(HAVE___RES_NSEARCH)
391         rwrap_load_lib_function(RWRAP_LIBRESOLV, __res_nsearch);
392
393         return rwrap.fns.libc___res_nsearch(state,
394                                             dname,
395                                             class,
396                                             type,
397                                             answer,
398                                             anslen);
399 #else
400 #error "No res_nsearch function"
401 #endif
402 }
403
404
405 /****************************************************************************
406  *   RES_NINIT
407  ***************************************************************************/
408
409 static int rwrap_res_ninit(struct __res_state *state)
410 {
411         int rc;
412
413         rc = libc_res_ninit(state);
414         if (rc == 0) {
415                 const char *rwrap_ns_env = getenv("RESOLV_WRAPPER_NAMESERVER");
416
417                 if (rwrap_ns_env != NULL) {
418                         int ok;
419
420                         /* Delete name servers */
421                         state->nscount = 1;
422                         memset(state->nsaddr_list, 0, sizeof(state->nsaddr_list));
423
424                         /* Simply zero the the padding array in the union */
425                         memset(state->_u.pad, 0, sizeof(state->_u.pad));
426
427                         state->nsaddr_list[0] = (struct sockaddr_in) {
428                                 .sin_family = AF_INET,
429                                 .sin_port = htons(53),
430                         };
431
432                         ok = inet_pton(AF_INET, rwrap_ns_env, &state->nsaddr_list[0].sin_addr);
433                         if (!ok) {
434                                 return -1;
435                         }
436
437                         RWRAP_LOG(RWRAP_LOG_DEBUG,
438                                   "Using [%s] as new nameserver",
439                                   rwrap_ns_env);
440                 }
441         }
442
443         return rc;
444 }
445
446 #if defined(HAVE_RES_NINIT)
447 int res_ninit(struct __res_state *state)
448 #elif defined(HAVE___RES_NINIT)
449 int __res_ninit(struct __res_state *state)
450 #endif
451 {
452         return rwrap_res_ninit(state);
453 }
454
455 /****************************************************************************
456  *   RES_INIT
457  ***************************************************************************/
458
459 static struct __res_state rwrap_res_state;
460
461 static int rwrap_res_init(void)
462 {
463         int rc;
464
465         rc = rwrap_res_ninit(&rwrap_res_state);
466
467         return rc;
468 }
469
470 #if defined(HAVE_RES_INIT)
471 int res_init(void)
472 #elif defined(HAVE___RES_INIT)
473 int __res_init(void)
474 #endif
475 {
476         return rwrap_res_init();
477 }
478
479 /****************************************************************************
480  *   RES_NCLOSE
481  ***************************************************************************/
482
483 static void rwrap_res_nclose(struct __res_state *state)
484 {
485         libc_res_nclose(state);
486 }
487
488 #if defined(HAVE_RES_NCLOSE)
489 void res_nclose(struct __res_state *state)
490 #elif defined(HAVE___RES_NCLOSE)
491 void __res_nclose(struct __res_state *state)
492 #endif
493 {
494         libc_res_nclose(state);
495 }
496
497 /****************************************************************************
498  *   RES_CLOSE
499  ***************************************************************************/
500
501 static void rwrap_res_close(void)
502 {
503         rwrap_res_nclose(&rwrap_res_state);
504 }
505
506 #if defined(HAVE_RES_CLOSE)
507 void res_close(void)
508 #elif defined(HAVE___RES_CLOSE)
509 void __res_close(void)
510 #endif
511 {
512         rwrap_res_close();
513 }
514
515 /****************************************************************************
516  *   RES_NQUERY
517  ***************************************************************************/
518
519 static int rwrap_res_nquery(struct __res_state *state,
520                             const char *dname,
521                             int class,
522                             int type,
523                             unsigned char *answer,
524                             int anslen)
525 {
526         int rc;
527 #ifndef NDEBUG
528         int i;
529 #endif
530
531         RWRAP_LOG(RWRAP_LOG_TRACE,
532                   "Resolve the domain name [%s] - class=%d, type=%d",
533                   dname, class, type);
534 #ifndef NDEBUG
535         for (i = 0; i < state->nscount; i++) {
536                 char ip[INET6_ADDRSTRLEN];
537
538                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
539                 RWRAP_LOG(RWRAP_LOG_TRACE,
540                           "        nameserver: %s",
541                           ip);
542         }
543 #endif
544
545         rc = libc_res_nquery(state, dname, class, type, answer, anslen);
546
547         RWRAP_LOG(RWRAP_LOG_TRACE,
548                   "The returned response length is: %d",
549                   rc);
550
551         return rc;
552 }
553
554 #if defined(HAVE_RES_NQUERY)
555 int res_nquery(struct __res_state *state,
556                const char *dname,
557                int class,
558                int type,
559                unsigned char *answer,
560                int anslen)
561 #elif defined(HAVE___RES_NQUERY)
562 int __res_nquery(struct __res_state *state,
563                  const char *dname,
564                  int class,
565                  int type,
566                  unsigned char *answer,
567                  int anslen)
568 #endif
569 {
570         return rwrap_res_nquery(state, dname, class, type, answer, anslen);
571 }
572
573 /****************************************************************************
574  *   RES_QUERY
575  ***************************************************************************/
576
577 static int rwrap_res_query(const char *dname,
578                            int class,
579                            int type,
580                            unsigned char *answer,
581                            int anslen)
582 {
583         int rc;
584
585         rc = rwrap_res_ninit(&rwrap_res_state);
586         if (rc != 0) {
587                 return rc;
588         }
589
590         rc = rwrap_res_nquery(&rwrap_res_state,
591                               dname,
592                               class,
593                               type,
594                               answer,
595                               anslen);
596
597         return rc;
598 }
599
600 #if defined(HAVE_RES_QUERY)
601 int res_query(const char *dname,
602               int class,
603               int type,
604               unsigned char *answer,
605               int anslen)
606 #elif defined(HAVE___RES_QUERY)
607 int __res_query(const char *dname,
608                 int class,
609                 int type,
610                 unsigned char *answer,
611                 int anslen)
612 #endif
613 {
614         return rwrap_res_query(dname, class, type, answer, anslen);
615 }
616
617 /****************************************************************************
618  *   RES_NSEARCH
619  ***************************************************************************/
620
621 static int rwrap_res_nsearch(struct __res_state *state,
622                              const char *dname,
623                              int class,
624                              int type,
625                              unsigned char *answer,
626                              int anslen)
627 {
628         int rc;
629 #ifndef NDEBUG
630         int i;
631 #endif
632
633         RWRAP_LOG(RWRAP_LOG_TRACE,
634                   "Resolve the domain name [%s] - class=%d, type=%d",
635                   dname, class, type);
636 #ifndef NDEBUG
637         for (i = 0; i < state->nscount; i++) {
638                 char ip[INET6_ADDRSTRLEN];
639
640                 inet_ntop(AF_INET, &state->nsaddr_list[i].sin_addr, ip, sizeof(ip));
641                 RWRAP_LOG(RWRAP_LOG_TRACE,
642                           "        nameserver: %s",
643                           ip);
644         }
645 #endif
646
647         rc = libc_res_nsearch(state, dname, class, type, answer, anslen);
648
649         RWRAP_LOG(RWRAP_LOG_TRACE,
650                   "The returned response length is: %d",
651                   rc);
652
653         return rc;
654 }
655
656 #if defined(HAVE_RES_NSEARCH)
657 int res_nsearch(struct __res_state *state,
658                 const char *dname,
659                 int class,
660                 int type,
661                 unsigned char *answer,
662                 int anslen)
663 #elif defined(HAVE___RES_NSEARCH)
664 int __res_nsearch(struct __res_state *state,
665                   const char *dname,
666                   int class,
667                   int type,
668                   unsigned char *answer,
669                   int anslen)
670 #endif
671 {
672         return rwrap_res_nsearch(state, dname, class, type, answer, anslen);
673 }
674
675 /****************************************************************************
676  *   RES_QUERY
677  ***************************************************************************/
678
679 static int rwrap_res_search(const char *dname,
680                             int class,
681                             int type,
682                             unsigned char *answer,
683                             int anslen)
684 {
685         int rc;
686
687         rc = rwrap_res_ninit(&rwrap_res_state);
688         if (rc != 0) {
689                 return rc;
690         }
691
692         rc = rwrap_res_nsearch(&rwrap_res_state,
693                                dname,
694                                class,
695                                type,
696                                answer,
697                                anslen);
698
699         return rc;
700 }
701
702 #if defined(HAVE_RES_SEARCH)
703 int res_search(const char *dname,
704                int class,
705                int type,
706                unsigned char *answer,
707                int anslen)
708 #elif defined(HAVE___RES_SEARCH)
709 int __res_search(const char *dname,
710                  int class,
711                  int type,
712                  unsigned char *answer,
713                  int anslen)
714 #endif
715 {
716         return rwrap_res_search(dname, class, type, answer, anslen);
717 }