LCOV - code coverage report
Current view: top level - third_party/resolv_wrapper - resolv_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 175 802 21.8 %
Date: 2021-09-23 10:06:22 Functions: 17 55 30.9 %

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

Generated by: LCOV version 1.13