LCOV - code coverage report
Current view: top level - third_party/resolv_wrapper - resolv_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 340 888 38.3 %
Date: 2024-04-21 15:09:00 Functions: 30 55 54.5 %

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

Generated by: LCOV version 1.14