2 * Copyright (c) 2014-2018 Andreas Schneider <asn@samba.org>
3 * Copyright (c) 2014-2016 Jakub Hrozek <jakub.hrozek@posteo.se>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
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
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>
55 #if defined(HAVE_RES_STATE_U_EXT_NSADDRS) || defined(HAVE_RES_SOCKADDR_UNION_SIN6)
56 #define HAVE_RESOLV_IPV6_NSADDRS 1
59 /* GCC has printf type attribute check. */
60 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
61 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
63 #define PRINTF_ATTRIBUTE(a,b)
64 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
66 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
67 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
69 #define DESTRUCTOR_ATTRIBUTE
70 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
72 #ifndef RWRAP_DEFAULT_FAKE_TTL
73 #define RWRAP_DEFAULT_FAKE_TTL 600
74 #endif /* RWRAP_DEFAULT_FAKE_TTL */
76 #ifndef HAVE_NS_NAME_COMPRESS
77 #define ns_name_compress dn_comp
90 #ifndef HAVE_GETPROGNAME
91 static const char *getprogname(void)
93 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
94 return program_invocation_short_name
;
95 #elif defined(HAVE_GETEXECNAME)
99 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
101 #endif /* HAVE_GETPROGNAME */
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__)
106 static void rwrap_log(enum rwrap_dbglvl_e dbglvl
,
108 const char *format
, ...)
113 unsigned int lvl
= 0;
114 const char *prefix
= NULL
;
115 const char *progname
= NULL
;
117 d
= getenv("RESOLV_WRAPPER_DEBUGLEVEL");
126 va_start(va
, format
);
127 vsnprintf(buffer
, sizeof(buffer
), format
, va
);
131 case RWRAP_LOG_ERROR
:
132 prefix
= "RWRAP_ERROR";
135 prefix
= "RWRAP_WARN";
137 case RWRAP_LOG_NOTICE
:
138 prefix
= "RWRAP_NOTICE";
140 case RWRAP_LOG_DEBUG
:
141 prefix
= "RWRAP_DEBUG";
143 case RWRAP_LOG_TRACE
:
144 prefix
= "RWRAP_TRACE";
148 progname
= getprogname();
149 if (progname
== NULL
) {
150 progname
= "<unknown>";
154 "%s[%s (%u)] - %s: %s\n",
157 (unsigned int)getpid(),
163 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
166 #define NEXT_KEY(buf, key) do { \
167 (key) = (buf) ? strpbrk((buf), " \t") : NULL; \
168 if ((key) != NULL) { \
172 while ((key) != NULL \
173 && (isblank((int)(key)[0]))) { \
178 #define RWRAP_MAX_RECURSION 64
180 union rwrap_sockaddr
{
182 struct sockaddr_in in
;
183 struct sockaddr_in6 in6
;
186 /* Priority and weight can be omitted from the hosts file, but need to be part
189 #define DFL_SRV_PRIO 1
190 #define DFL_SRV_WEIGHT 100
191 #define DFL_URI_PRIO 1
192 #define DFL_URI_WEIGHT 100
194 struct rwrap_srv_rrdata
{
198 char hostname
[MAXDNAME
];
201 struct rwrap_uri_rrdata
{
207 struct rwrap_soa_rrdata
{
213 char nameserver
[MAXDNAME
];
214 char mailbox
[MAXDNAME
];
217 struct rwrap_fake_rr
{
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
];
230 int type
; /* ns_t_* */
233 static void rwrap_fake_rr_init(struct rwrap_fake_rr
*rr
, size_t len
)
237 for (i
= 0; i
< len
; i
++) {
238 rr
[i
].type
= ns_t_invalid
;
242 static int rwrap_create_fake_a_rr(const char *key
,
244 struct rwrap_fake_rr
*rr
)
248 ok
= inet_pton(AF_INET
, value
, &rr
->rrdata
.a_rec
);
250 RWRAP_LOG(RWRAP_LOG_ERROR
,
251 "Failed to convert [%s] to binary\n", value
);
255 memcpy(rr
->key
, key
, strlen(key
) + 1);
260 static int rwrap_create_fake_aaaa_rr(const char *key
,
262 struct rwrap_fake_rr
*rr
)
266 ok
= inet_pton(AF_INET6
, value
, &rr
->rrdata
.aaaa_rec
);
268 RWRAP_LOG(RWRAP_LOG_ERROR
,
269 "Failed to convert [%s] to binary\n", value
);
273 memcpy(rr
->key
, key
, strlen(key
) + 1);
274 rr
->type
= ns_t_aaaa
;
277 static int rwrap_create_fake_ns_rr(const char *key
,
279 struct rwrap_fake_rr
*rr
)
281 memcpy(rr
->rrdata
.srv_rec
.hostname
, value
, strlen(value
) + 1);
282 memcpy(rr
->key
, key
, strlen(key
) + 1);
287 static int rwrap_create_fake_srv_rr(const char *key
,
289 struct rwrap_fake_rr
*rr
)
294 const char *hostname
;
296 /* parse the value into priority, weight, port and hostname
297 * and check the validity */
299 NEXT_KEY(hostname
, str_port
);
300 NEXT_KEY(str_port
, str_prio
);
301 NEXT_KEY(str_prio
, str_weight
);
302 if (str_port
== NULL
|| hostname
== NULL
) {
303 RWRAP_LOG(RWRAP_LOG_ERROR
,
304 "Malformed SRV entry [%s]\n", value
);
309 rr
->rrdata
.srv_rec
.prio
= atoi(str_prio
);
311 rr
->rrdata
.srv_rec
.prio
= DFL_SRV_PRIO
;
314 rr
->rrdata
.srv_rec
.weight
= atoi(str_weight
);
316 rr
->rrdata
.srv_rec
.weight
= DFL_SRV_WEIGHT
;
318 rr
->rrdata
.srv_rec
.port
= atoi(str_port
);
319 memcpy(rr
->rrdata
.srv_rec
.hostname
, hostname
, strlen(hostname
) + 1);
321 memcpy(rr
->key
, key
, strlen(key
) + 1);
326 static int rwrap_create_fake_uri_rr(const char *key
,
328 struct rwrap_fake_rr
*rr
)
334 /* parse the value into priority, weight, and uri
335 * and check the validity */
337 NEXT_KEY(uri
, str_prio
);
338 NEXT_KEY(str_prio
, str_weight
);
340 RWRAP_LOG(RWRAP_LOG_ERROR
,
341 "Malformed URI entry [<null>]\n");
346 rr
->rrdata
.uri_rec
.prio
= atoi(str_prio
);
348 rr
->rrdata
.uri_rec
.prio
= DFL_URI_PRIO
;
351 rr
->rrdata
.uri_rec
.weight
= atoi(str_weight
);
353 rr
->rrdata
.uri_rec
.weight
= DFL_URI_WEIGHT
;
355 memcpy(rr
->rrdata
.uri_rec
.uri
, uri
, strlen(uri
) + 1);
357 memcpy(rr
->key
, key
, strlen(key
) + 1);
362 static int rwrap_create_fake_txt_rr(const char *key
,
364 struct rwrap_fake_rr
*rr
)
366 memcpy(rr
->rrdata
.txt_rec
, value
, strlen(value
) + 1);
368 memcpy(rr
->key
, key
, strlen(key
) + 1);
373 static int rwrap_create_fake_soa_rr(const char *key
,
375 struct rwrap_fake_rr
*rr
)
377 const char *nameserver
;
385 /* parse the value into nameserver, mailbox, serial, refresh,
386 * retry, expire, minimum and check the validity
389 NEXT_KEY(nameserver
, mailbox
);
390 NEXT_KEY(mailbox
, str_serial
);
391 NEXT_KEY(str_serial
, str_refresh
);
392 NEXT_KEY(str_refresh
, str_retry
);
393 NEXT_KEY(str_retry
, str_expire
);
394 NEXT_KEY(str_expire
, str_minimum
);
395 if (nameserver
== NULL
|| mailbox
== NULL
|| str_serial
== NULL
||
396 str_refresh
== NULL
|| str_retry
== NULL
|| str_expire
== NULL
||
397 str_minimum
== NULL
) {
398 RWRAP_LOG(RWRAP_LOG_ERROR
,
399 "Malformed SOA entry [%s]\n", value
);
403 memcpy(rr
->rrdata
.soa_rec
.nameserver
, nameserver
, strlen(nameserver
)+1);
404 memcpy(rr
->rrdata
.soa_rec
.mailbox
, mailbox
, strlen(mailbox
)+1);
406 rr
->rrdata
.soa_rec
.serial
= atoi(str_serial
);
407 rr
->rrdata
.soa_rec
.refresh
= atoi(str_refresh
);
408 rr
->rrdata
.soa_rec
.retry
= atoi(str_retry
);
409 rr
->rrdata
.soa_rec
.expire
= atoi(str_expire
);
410 rr
->rrdata
.soa_rec
.minimum
= atoi(str_minimum
);
412 memcpy(rr
->key
, key
, strlen(key
) + 1);
417 static int rwrap_create_fake_cname_rr(const char *key
,
419 struct rwrap_fake_rr
*rr
)
421 memcpy(rr
->rrdata
.cname_rec
, value
, strlen(value
) + 1);
422 memcpy(rr
->key
, key
, strlen(key
) + 1);
423 rr
->type
= ns_t_cname
;
427 static int rwrap_create_fake_ptr_rr(const char *key
,
429 struct rwrap_fake_rr
*rr
)
431 memcpy(rr
->rrdata
.ptr_rec
, value
, strlen(value
) + 1);
432 memcpy(rr
->key
, key
, strlen(key
) + 1);
437 /* Prepares a fake header with a single response. Advances header_blob */
438 static ssize_t
rwrap_fake_header(uint8_t **header_blob
, size_t remaining
,
439 size_t ancount
, size_t arcount
)
446 if (remaining
< NS_HFIXEDSZ
) {
447 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
451 h
.blob
= *header_blob
;
452 memset(h
.blob
, 0, NS_HFIXEDSZ
);
454 h
.header
->id
= res_randomid(); /* random query ID */
455 h
.header
->qr
= 1; /* response flag */
456 h
.header
->rd
= 1; /* recursion desired */
457 h
.header
->ra
= 1; /* recursion available */
459 h
.header
->qdcount
= htons(1); /* no. of questions */
460 h
.header
->ancount
= htons(ancount
); /* no. of answers */
461 h
.header
->arcount
= htons(arcount
); /* no. of add'tl records */
463 /* move past the header */
464 *header_blob
= h
.blob
+= NS_HFIXEDSZ
;
469 static ssize_t
rwrap_fake_question(const char *question
,
471 uint8_t **question_ptr
,
474 uint8_t *qb
= *question_ptr
;
477 n
= ns_name_compress(question
, qb
, remaining
, NULL
, NULL
);
479 RWRAP_LOG(RWRAP_LOG_ERROR
,
480 "Failed to compress [%s]\n", question
);
487 if (remaining
< 2 * sizeof(uint16_t)) {
488 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
493 NS_PUT16(ns_c_in
, qb
);
496 return n
+ 2 * sizeof(uint16_t);
499 static ssize_t
rwrap_fake_rdata_common(uint16_t type
,
505 uint8_t *rd
= *rdata_ptr
;
508 written
= ns_name_compress(key
, rd
, remaining
, NULL
, NULL
);
510 RWRAP_LOG(RWRAP_LOG_ERROR
,
511 "Failed to compress [%s]\n", key
);
515 remaining
-= written
;
517 if (remaining
< 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
518 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
523 NS_PUT16(ns_c_in
, rd
);
524 NS_PUT32(RWRAP_DEFAULT_FAKE_TTL
, rd
);
525 NS_PUT16(rdata_size
, rd
);
527 if (remaining
< rdata_size
) {
528 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
533 return written
+ 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size
;
536 static ssize_t
rwrap_fake_a(struct rwrap_fake_rr
*rr
,
540 uint8_t *a
= answer_ptr
;
543 if (rr
->type
!= ns_t_a
) {
544 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
547 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding A RR");
549 resp_size
= rwrap_fake_rdata_common(ns_t_a
, sizeof(struct in_addr
), rr
->key
,
555 memcpy(a
, &rr
->rrdata
.a_rec
, sizeof(struct in_addr
));
560 static ssize_t
rwrap_fake_aaaa(struct rwrap_fake_rr
*rr
,
567 if (rr
->type
!= ns_t_aaaa
) {
568 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
571 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding AAAA RR");
573 resp_size
= rwrap_fake_rdata_common(ns_t_aaaa
, sizeof(struct in6_addr
),
574 rr
->key
, anslen
, &a
);
579 memcpy(a
, &rr
->rrdata
.aaaa_rec
, sizeof(struct in6_addr
));
584 static ssize_t
rwrap_fake_ns(struct rwrap_fake_rr
*rr
,
589 ssize_t resp_size
= 0;
591 unsigned char hostname_compressed
[MAXDNAME
];
592 ssize_t compressed_len
;
594 if (rr
->type
!= ns_t_ns
) {
595 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
598 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding NS RR");
600 /* Prepare the data to write */
601 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
606 if (compressed_len
< 0) {
610 /* Is this enough? */
611 rdata_size
= compressed_len
;
613 resp_size
= rwrap_fake_rdata_common(ns_t_ns
, rdata_size
,
614 rr
->key
, anslen
, &a
);
619 memcpy(a
, hostname_compressed
, compressed_len
);
624 static ssize_t
rwrap_fake_srv(struct rwrap_fake_rr
*rr
,
631 unsigned char hostname_compressed
[MAXDNAME
];
632 ssize_t compressed_len
;
634 if (rr
->type
!= ns_t_srv
) {
635 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
638 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SRV RR");
639 rdata_size
= 3 * sizeof(uint16_t);
641 /* Prepare the data to write */
642 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
643 hostname_compressed
, MAXDNAME
,
645 if (compressed_len
< 0) {
648 rdata_size
+= compressed_len
;
650 resp_size
= rwrap_fake_rdata_common(ns_t_srv
, rdata_size
,
651 rr
->key
, anslen
, &a
);
656 NS_PUT16(rr
->rrdata
.srv_rec
.prio
, a
);
657 NS_PUT16(rr
->rrdata
.srv_rec
.weight
, a
);
658 NS_PUT16(rr
->rrdata
.srv_rec
.port
, a
);
659 memcpy(a
, hostname_compressed
, compressed_len
);
664 static ssize_t
rwrap_fake_uri(struct rwrap_fake_rr
*rr
,
673 if (rr
->type
!= ns_t_uri
) {
674 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
677 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding URI RR");
678 rdata_size
= 3 * sizeof(uint16_t);
679 uri_len
= strlen(rr
->rrdata
.uri_rec
.uri
) + 1;
680 rdata_size
+= uri_len
;
682 resp_size
= rwrap_fake_rdata_common(ns_t_uri
, rdata_size
,
683 rr
->key
, anslen
, &a
);
688 NS_PUT16(rr
->rrdata
.uri_rec
.prio
, a
);
689 NS_PUT16(rr
->rrdata
.uri_rec
.weight
, a
);
690 memcpy(a
, rr
->rrdata
.uri_rec
.uri
, uri_len
);
695 static ssize_t
rwrap_fake_txt(struct rwrap_fake_rr
*rr
,
704 if (rr
->type
!= ns_t_txt
) {
705 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
708 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding TXT RR");
709 txt_len
= strlen(rr
->rrdata
.txt_rec
) + 1;
710 rdata_size
= txt_len
;
712 resp_size
= rwrap_fake_rdata_common(ns_t_txt
, rdata_size
,
713 rr
->key
, anslen
, &a
);
718 memcpy(a
, rr
->rrdata
.txt_rec
, txt_len
);
723 static ssize_t
rwrap_fake_soa(struct rwrap_fake_rr
*rr
,
730 unsigned char nameser_compressed
[MAXDNAME
];
731 ssize_t compressed_ns_len
;
732 unsigned char mailbox_compressed
[MAXDNAME
];
733 ssize_t compressed_mb_len
;
735 if (rr
->type
!= ns_t_soa
) {
736 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
739 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SOA RR");
740 rdata_size
= 5 * sizeof(uint16_t);
742 compressed_ns_len
= ns_name_compress(rr
->rrdata
.soa_rec
.nameserver
,
744 MAXDNAME
, NULL
, NULL
);
745 if (compressed_ns_len
< 0) {
748 rdata_size
+= compressed_ns_len
;
750 compressed_mb_len
= ns_name_compress(rr
->rrdata
.soa_rec
.mailbox
,
752 MAXDNAME
, NULL
, NULL
);
753 if (compressed_mb_len
< 0) {
756 rdata_size
+= compressed_mb_len
;
758 resp_size
= rwrap_fake_rdata_common(ns_t_soa
, rdata_size
,
759 rr
->key
, anslen
, &a
);
764 memcpy(a
, nameser_compressed
, compressed_ns_len
);
765 a
+= compressed_ns_len
;
766 memcpy(a
, mailbox_compressed
, compressed_mb_len
);
767 a
+= compressed_mb_len
;
768 NS_PUT32(rr
->rrdata
.soa_rec
.serial
, a
);
769 NS_PUT32(rr
->rrdata
.soa_rec
.refresh
, a
);
770 NS_PUT32(rr
->rrdata
.soa_rec
.retry
, a
);
771 NS_PUT32(rr
->rrdata
.soa_rec
.expire
, a
);
772 NS_PUT32(rr
->rrdata
.soa_rec
.minimum
, a
);
777 static ssize_t
rwrap_fake_cname(struct rwrap_fake_rr
*rr
,
783 unsigned char hostname_compressed
[MAXDNAME
];
786 if (rr
->type
!= ns_t_cname
) {
787 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
790 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding CNAME RR");
792 /* Prepare the data to write */
793 rdata_size
= ns_name_compress(rr
->rrdata
.cname_rec
,
794 hostname_compressed
, MAXDNAME
,
796 if (rdata_size
< 0) {
800 resp_size
= rwrap_fake_rdata_common(ns_t_cname
, rdata_size
,
801 rr
->key
, anslen
, &a
);
806 memcpy(a
, hostname_compressed
, rdata_size
);
811 static ssize_t
rwrap_fake_ptr(struct rwrap_fake_rr
*rr
,
818 unsigned char hostname_compressed
[MAXDNAME
];
820 if (rr
->type
!= ns_t_ptr
) {
821 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
824 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding PTR RR");
826 /* Prepare the data to write */
827 rdata_size
= ns_name_compress(rr
->rrdata
.ptr_rec
,
828 hostname_compressed
, MAXDNAME
,
830 if (rdata_size
< 0) {
834 resp_size
= rwrap_fake_rdata_common(ns_t_ptr
, rdata_size
,
835 rr
->key
, anslen
, &a
);
840 memcpy(a
, hostname_compressed
, rdata_size
);
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'))
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)
856 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
857 const char *query
, int type
,
858 struct rwrap_fake_rr
*rr
);
860 static int rwrap_uri_recurse(const char *hostfile
, unsigned recursion
,
861 const char *query
, struct rwrap_fake_rr
*rr
)
865 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_uri
, rr
);
873 static int rwrap_srv_recurse(const char *hostfile
, unsigned recursion
,
874 const char *query
, struct rwrap_fake_rr
*rr
)
878 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
879 if (rc
== 0) return 0;
881 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
882 if (rc
== ENOENT
) rc
= 0;
887 static int rwrap_cname_recurse(const char *hostfile
, unsigned recursion
,
888 const char *query
, struct rwrap_fake_rr
*rr
)
892 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
893 if (rc
== 0) return 0;
895 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
896 if (rc
== 0) return 0;
898 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_cname
, rr
);
899 if (rc
== ENOENT
) rc
= 0;
904 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
905 const char *query
, int type
,
906 struct rwrap_fake_rr
*rr
)
913 unsigned num_uris
= 0;
915 if (recursion
>= RWRAP_MAX_RECURSION
) {
916 RWRAP_LOG(RWRAP_LOG_ERROR
, "Recursed too deep!\n");
920 RWRAP_LOG(RWRAP_LOG_TRACE
,
921 "Searching in fake hosts file %s for %s:%d\n", hostfile
,
924 fp
= fopen(hostfile
, "r");
926 RWRAP_LOG(RWRAP_LOG_WARN
,
927 "Opening %s failed: %s",
928 hostfile
, strerror(errno
));
932 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
939 NEXT_KEY(rec_type
, key
);
940 NEXT_KEY(key
, value
);
942 if (key
== NULL
|| value
== NULL
) {
943 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\"");
950 while(q
[0] != '\n' && q
[0] != '\0') {
955 if (type
== ns_t_uri
&& recursion
> 0) {
956 /* Skip non-URI records. */
957 if (!TYPE_MATCH(type
, ns_t_uri
, rec_type
, "URI", key
, query
)) {
960 /* Skip previous records based on the recurse depth. */
962 if (num_uris
<= recursion
) {
967 if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "A", key
, query
)) {
968 rc
= rwrap_create_fake_a_rr(key
, value
, rr
);
970 } else if (TYPE_MATCH(type
, ns_t_aaaa
,
971 rec_type
, "AAAA", key
, query
)) {
972 rc
= rwrap_create_fake_aaaa_rr(key
, value
, rr
);
974 } else if (TYPE_MATCH(type
, ns_t_ns
,
975 rec_type
, "NS", key
, query
)) {
976 rc
= rwrap_create_fake_ns_rr(key
, value
, rr
);
978 } else if (TYPE_MATCH(type
, ns_t_srv
,
979 rec_type
, "SRV", key
, query
)) {
980 rc
= rwrap_create_fake_srv_rr(key
, value
, rr
);
982 rc
= rwrap_srv_recurse(hostfile
, recursion
+1,
983 rr
->rrdata
.srv_rec
.hostname
,
987 } else if (TYPE_MATCH(type
, ns_t_uri
,
988 rec_type
, "URI", key
, query
)) {
989 rc
= rwrap_create_fake_uri_rr(key
, value
, rr
);
991 /* Recurse to collect multiple URI answers under a single key. */
992 rc
= rwrap_uri_recurse(hostfile
, recursion
+ 1, key
, rr
+ 1);
995 } else if (TYPE_MATCH(type
, ns_t_soa
,
996 rec_type
, "SOA", key
, query
)) {
997 rc
= rwrap_create_fake_soa_rr(key
, value
, rr
);
999 } else if (TYPE_MATCH(type
, ns_t_cname
,
1000 rec_type
, "CNAME", key
, query
)) {
1001 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
1003 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
1007 } else if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "CNAME", key
, query
)) {
1008 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
1010 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
1014 } else if (TYPE_MATCH(type
, ns_t_ptr
,
1015 rec_type
, "PTR", key
, query
)) {
1016 rc
= rwrap_create_fake_ptr_rr(key
, value
, rr
);
1019 else if (TYPE_MATCH(type
, ns_t_txt
,
1020 rec_type
, "TXT", key
, query
)) {
1021 rc
= rwrap_create_fake_txt_rr(key
, value
, rr
);
1026 if (rc
== ENOENT
&& recursion
== 0 && key
!= NULL
) {
1027 RWRAP_LOG(RWRAP_LOG_TRACE
, "Record for [%s] not found\n", query
);
1028 memcpy(rr
->key
, key
, strlen(key
) + 1);
1035 static ssize_t
rwrap_fake_empty(int type
,
1036 const char *question
,
1041 size_t remaining
= anslen
;
1043 resp_data
= rwrap_fake_header(&answer
, remaining
, 0, 0);
1044 if (resp_data
< 0) {
1047 remaining
-= resp_data
;
1049 resp_data
+= rwrap_fake_question(question
, type
, &answer
, remaining
);
1050 if (resp_data
< 0) {
1053 remaining
-= resp_data
;
1055 resp_data
+= rwrap_fake_rdata_common(type
, 0, question
,
1056 remaining
, &answer
);
1057 if (resp_data
< 0) {
1064 static inline bool rwrap_known_type(int type
)
1082 static int rwrap_ancount(struct rwrap_fake_rr
*rrs
, int qtype
)
1087 /* For URI return the number of URIs. */
1088 if (qtype
== ns_t_uri
) {
1089 for (i
= 0; i
< RWRAP_MAX_RECURSION
; i
++) {
1090 if (rwrap_known_type(rrs
[i
].type
) &&
1091 rrs
[i
].type
== qtype
) {
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
1102 for (i
= 0; i
< RWRAP_MAX_RECURSION
; i
++) {
1105 if (rwrap_known_type(rrs
[i
].type
) &&
1106 rrs
[i
].type
== qtype
) {
1111 /* Return 0 records if the sought type wasn't in the stack */
1112 return i
< RWRAP_MAX_RECURSION
? ancount
: 0;
1115 static int rwrap_arcount(struct rwrap_fake_rr
*rrs
, int ancount
)
1120 /* start from index ancount */
1121 for (i
= ancount
; i
< RWRAP_MAX_RECURSION
; i
++) {
1122 if (rwrap_known_type(rrs
[i
].type
)) {
1130 static ssize_t
rwrap_add_rr(struct rwrap_fake_rr
*rr
,
1137 RWRAP_LOG(RWRAP_LOG_ERROR
, "Internal error!\n");
1143 resp_data
= rwrap_fake_a(rr
, answer
, anslen
);
1146 resp_data
= rwrap_fake_aaaa(rr
, answer
, anslen
);
1149 resp_data
= rwrap_fake_ns(rr
, answer
, anslen
);
1152 resp_data
= rwrap_fake_srv(rr
, answer
, anslen
);
1155 resp_data
= rwrap_fake_uri(rr
, answer
, anslen
);
1158 resp_data
= rwrap_fake_soa(rr
, answer
, anslen
);
1161 resp_data
= rwrap_fake_cname(rr
, answer
, anslen
);
1164 resp_data
= rwrap_fake_ptr(rr
, answer
, anslen
);
1167 resp_data
= rwrap_fake_txt(rr
, answer
, anslen
);
1176 static ssize_t
rwrap_fake_answer(struct rwrap_fake_rr
*rrs
,
1184 size_t remaining
= anslen
;
1189 ancount
= rwrap_ancount(rrs
, type
);
1190 arcount
= rwrap_arcount(rrs
, ancount
);
1191 RWRAP_LOG(RWRAP_LOG_TRACE
,
1192 "Got %d answers and %d additional records\n", ancount
, arcount
);
1194 resp_data
= rwrap_fake_header(&answer
, remaining
, ancount
, arcount
);
1195 if (resp_data
< 0) {
1198 remaining
-= resp_data
;
1200 resp_data
+= rwrap_fake_question(rrs
->key
, rrs
->type
, &answer
, remaining
);
1201 if (resp_data
< 0) {
1204 remaining
-= resp_data
;
1207 for (i
= 0; i
< ancount
; i
++) {
1208 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
1217 /* add authoritative NS here? */
1219 /* additional records */
1220 for (i
= ancount
; i
< ancount
+ arcount
; i
++) {
1221 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
1233 /* Reads in a file in the following format:
1236 * Malformed entries are silently skipped.
1237 * Allocates answer buffer of size anslen that has to be freed after use.
1239 static int rwrap_res_fake_hosts(const char *hostfile
,
1242 unsigned char *answer
,
1246 char *query_name
= NULL
;
1247 size_t qlen
= strlen(query
);
1248 struct rwrap_fake_rr rrs
[RWRAP_MAX_RECURSION
];
1251 RWRAP_LOG(RWRAP_LOG_TRACE
,
1252 "Searching in fake hosts file %s\n", hostfile
);
1254 if (qlen
> 0 && query
[qlen
-1] == '.') {
1258 query_name
= strndup(query
, qlen
);
1259 if (query_name
== NULL
) {
1263 rwrap_fake_rr_init(rrs
, RWRAP_MAX_RECURSION
);
1265 rc
= rwrap_get_record(hostfile
, 0, query_name
, type
, rrs
);
1268 RWRAP_LOG(RWRAP_LOG_TRACE
,
1269 "Found record for [%s]\n", query_name
);
1270 resp_size
= rwrap_fake_answer(rrs
, type
, answer
, anslen
);
1273 RWRAP_LOG(RWRAP_LOG_TRACE
,
1274 "No record for [%s]\n", query_name
);
1275 resp_size
= rwrap_fake_empty(type
, rrs
->key
, answer
, anslen
);
1278 RWRAP_LOG(RWRAP_LOG_NOTICE
,
1279 "Searching for [%s] did not return any results\n",
1285 switch (resp_size
) {
1287 RWRAP_LOG(RWRAP_LOG_ERROR
,
1288 "Error faking answer for [%s]\n", query_name
);
1291 RWRAP_LOG(RWRAP_LOG_TRACE
,
1292 "Successfully faked answer for [%s]\n",
1301 /*********************************************************
1302 * RWRAP LOADING LIBC FUNCTIONS
1303 *********************************************************/
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
,
1315 unsigned char *answer
,
1317 typedef int (*__libc___res_nquery
)(struct __res_state
*state
,
1321 unsigned char *answer
,
1323 typedef int (*__libc_res_nsearch
)(struct __res_state
*state
,
1327 unsigned char *answer
,
1329 typedef int (*__libc___res_nsearch
)(struct __res_state
*state
,
1333 unsigned char *answer
,
1336 #define RWRAP_SYMBOL_ENTRY(i) \
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
);
1352 #undef RWRAP_SYMBOL_ENTRY
1357 struct rwrap_libc_symbols symbols
;
1362 struct rwrap_libc_symbols symbols
;
1371 static struct rwrap rwrap
;
1378 static const char *rwrap_str_lib(enum rwrap_lib lib
)
1383 case RWRAP_LIBRESOLV
:
1387 /* Compiler would warn us about unhandled enum value if we get here */
1391 static void *rwrap_load_lib_handle(enum rwrap_lib lib
)
1393 int flags
= RTLD_LAZY
;
1394 void *handle
= NULL
;
1397 #ifdef RTLD_DEEPBIND
1398 const char *env_preload
= getenv("LD_PRELOAD");
1399 const char *env_deepbind
= getenv("RESOLV_WRAPPER_DISABLE_DEEPBIND");
1400 bool enable_deepbind
= true;
1402 /* Don't do a deepbind if we run with libasan */
1403 if (env_preload
!= NULL
&& strlen(env_preload
) < 1024) {
1404 const char *p
= strstr(env_preload
, "libasan.so");
1406 enable_deepbind
= false;
1410 if (env_deepbind
!= NULL
&& strlen(env_deepbind
) >= 1) {
1411 enable_deepbind
= false;
1414 if (enable_deepbind
) {
1415 flags
|= RTLD_DEEPBIND
;
1420 case RWRAP_LIBRESOLV
:
1421 #ifdef HAVE_LIBRESOLV
1422 handle
= rwrap
.libresolv
.handle
;
1423 if (handle
== NULL
) {
1424 for (i
= 10; i
>= 0; i
--) {
1425 char soname
[256] = {0};
1427 snprintf(soname
, sizeof(soname
), "libresolv.so.%d", i
);
1428 handle
= dlopen(soname
, flags
);
1429 if (handle
!= NULL
) {
1434 rwrap
.libresolv
.handle
= handle
;
1440 handle
= rwrap
.libc
.handle
;
1442 if (handle
== NULL
) {
1443 handle
= dlopen(LIBC_SO
, flags
);
1445 rwrap
.libc
.handle
= handle
;
1448 if (handle
== NULL
) {
1449 for (i
= 10; i
>= 0; i
--) {
1450 char soname
[256] = {0};
1452 snprintf(soname
, sizeof(soname
), "libc.so.%d", i
);
1453 handle
= dlopen(soname
, flags
);
1454 if (handle
!= NULL
) {
1459 rwrap
.libc
.handle
= handle
;
1464 if (handle
== NULL
) {
1466 handle
= rwrap
.libc
.handle
= rwrap
.libresolv
.handle
= RTLD_NEXT
;
1468 RWRAP_LOG(RWRAP_LOG_ERROR
,
1469 "Failed to dlopen library: %s\n",
1478 static void *_rwrap_bind_symbol(enum rwrap_lib lib
, const char *fn_name
)
1483 handle
= rwrap_load_lib_handle(lib
);
1485 func
= dlsym(handle
, fn_name
);
1487 RWRAP_LOG(RWRAP_LOG_ERROR
,
1488 "Failed to find %s: %s\n",
1489 fn_name
, dlerror());
1493 RWRAP_LOG(RWRAP_LOG_TRACE
,
1494 "Loaded %s from %s",
1495 fn_name
, rwrap_str_lib(lib
));
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); \
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); \
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.
1520 static int libc_res_ninit(struct __res_state
*state
)
1522 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1523 rwrap_bind_symbol_libresolv(res_ninit
);
1525 return rwrap
.libresolv
.symbols
._libc_res_ninit
.f(state
);
1526 #elif defined(HAVE___RES_NINIT)
1527 rwrap_bind_symbol_libresolv(__res_ninit
);
1529 return rwrap
.libresolv
.symbols
._libc___res_ninit
.f(state
);
1531 #error "No res_ninit function"
1535 static void libc_res_nclose(struct __res_state
*state
)
1537 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1538 rwrap_bind_symbol_libresolv(res_nclose
);
1540 rwrap
.libresolv
.symbols
._libc_res_nclose
.f(state
);
1542 #elif defined(HAVE___RES_NCLOSE)
1543 rwrap_bind_symbol_libresolv(__res_nclose
);
1545 rwrap
.libresolv
.symbols
._libc___res_nclose
.f(state
);
1547 #error "No res_nclose function"
1551 static int libc_res_nquery(struct __res_state
*state
,
1555 unsigned char *answer
,
1558 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1559 rwrap_bind_symbol_libresolv(res_nquery
);
1561 return rwrap
.libresolv
.symbols
._libc_res_nquery
.f(state
,
1567 #elif defined(HAVE___RES_NQUERY)
1568 rwrap_bind_symbol_libresolv(__res_nquery
);
1570 return rwrap
.libresolv
.symbols
._libc___res_nquery
.f(state
,
1577 #error "No res_nquery function"
1581 static int libc_res_nsearch(struct __res_state
*state
,
1585 unsigned char *answer
,
1588 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1589 rwrap_bind_symbol_libresolv(res_nsearch
);
1591 return rwrap
.libresolv
.symbols
._libc_res_nsearch
.f(state
,
1597 #elif defined(HAVE___RES_NSEARCH)
1598 rwrap_bind_symbol_libresolv(__res_nsearch
);
1600 return rwrap
.libresolv
.symbols
._libc___res_nsearch
.f(state
,
1607 #error "No res_nsearch function"
1611 /****************************************************************************
1613 ***************************************************************************/
1615 static size_t rwrap_get_nameservers(struct __res_state
*state
,
1617 union rwrap_sockaddr
*nsaddrs
)
1619 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1620 union res_sockaddr_union set
[MAXNS
];
1624 memset(set
, 0, sizeof(set
));
1625 memset(nsaddrs
, 0, sizeof(*nsaddrs
) * nserv
);
1627 if (nserv
> MAXNS
) {
1631 rc
= res_getservers(state
, set
, nserv
);
1639 for (i
= 0; i
< nserv
; i
++) {
1640 switch (set
[i
].sin
.sin_family
) {
1642 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1646 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1648 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1657 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1660 memset(nsaddrs
, 0, sizeof(*nsaddrs
) * nserv
);
1662 if (nserv
> (size_t)state
->nscount
) {
1663 nserv
= (size_t)state
->nscount
;
1666 for (i
= 0; i
< nserv
; i
++) {
1667 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1668 if (state
->_u
._ext
.nsaddrs
[i
] != NULL
) {
1669 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1670 .in6
= *state
->_u
._ext
.nsaddrs
[i
],
1673 #endif /* HAVE_RES_STATE_U_EXT_NSADDRS */
1675 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1676 .in
= state
->nsaddr_list
[i
],
1682 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1685 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl
,
1687 struct __res_state
*state
)
1689 union rwrap_sockaddr nsaddrs
[MAXNS
];
1690 size_t nserv
= MAXNS
;
1693 memset(nsaddrs
, 0, sizeof(nsaddrs
));
1694 nserv
= rwrap_get_nameservers(state
, nserv
, nsaddrs
);
1695 for (i
= 0; i
< nserv
; i
++) {
1696 char ip
[INET6_ADDRSTRLEN
];
1698 switch (nsaddrs
[i
].sa
.sa_family
) {
1700 inet_ntop(AF_INET
, &(nsaddrs
[i
].in
.sin_addr
),
1704 inet_ntop(AF_INET6
, &(nsaddrs
[i
].in6
.sin6_addr
),
1708 snprintf(ip
, sizeof(ip
), "<unknown sa_family=%d",
1709 nsaddrs
[i
].sa
.sa_family
);
1713 rwrap_log(dbglvl
, func
,
1719 static void rwrap_reset_nameservers(struct __res_state
*state
)
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
1727 for (i
= 0; i
< (size_t)state
->nscount
; i
++) {
1728 if (state
->_u
._ext
.nssocks
[i
] != -1) {
1729 close(state
->_u
._ext
.nssocks
[i
]);
1730 state
->_u
._ext
.nssocks
[i
] = -1;
1732 SAFE_FREE(state
->_u
._ext
.nsaddrs
[i
]);
1734 memset(&state
->_u
._ext
, 0, sizeof(state
->_u
._ext
));
1735 for (i
= 0; i
< MAXNS
; i
++) {
1736 state
->_u
._ext
.nssocks
[i
] = -1;
1737 state
->_u
._ext
.nsmap
[i
] = MAXNS
+ 1;
1739 state
->ipv6_unavail
= false;
1741 memset(state
->nsaddr_list
, 0, sizeof(state
->nsaddr_list
));
1743 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1746 static int rwrap_set_nameservers(struct __res_state
*state
,
1748 const union rwrap_sockaddr
*nsaddrs
)
1750 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1751 union res_sockaddr_union set
[MAXNS
];
1754 memset(set
, 0, sizeof(set
));
1756 if (nserv
> MAXNS
) {
1760 rwrap_reset_nameservers(state
);
1762 for (i
= 0; i
< nserv
; i
++) {
1763 switch (nsaddrs
[i
].sa
.sa_family
) {
1765 set
[i
] = (union res_sockaddr_union
) {
1766 .sin
= nsaddrs
[i
].in
,
1769 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1771 set
[i
] = (union res_sockaddr_union
) {
1772 .sin6
= nsaddrs
[i
].in6
,
1777 RWRAP_LOG(RWRAP_LOG_ERROR
,
1778 "Internal error unhandled sa_family=%d",
1779 nsaddrs
[i
].sa
.sa_family
);
1785 res_setservers(state
, set
, nserv
);
1787 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1790 if (nserv
> MAXNS
) {
1793 rwrap_reset_nameservers(state
);
1795 for (i
= 0; i
< nserv
; i
++) {
1796 switch (nsaddrs
[i
].sa
.sa_family
) {
1798 state
->nsaddr_list
[i
] = nsaddrs
[i
].in
;
1800 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1802 state
->_u
._ext
.nsaddrs
[i
] = malloc(sizeof(nsaddrs
[i
].in6
));
1803 if (state
->_u
._ext
.nsaddrs
[i
] == NULL
) {
1804 rwrap_reset_nameservers(state
);
1808 *state
->_u
._ext
.nsaddrs
[i
] = nsaddrs
[i
].in6
;
1809 state
->_u
._ext
.nssocks
[i
] = -1;
1810 state
->_u
._ext
.nsmap
[i
] = MAXNS
+ 1;
1811 state
->_u
._ext
.nscount6
++;
1815 RWRAP_LOG(RWRAP_LOG_ERROR
,
1816 "Internal error unhandled sa_family=%d",
1817 nsaddrs
[i
].sa
.sa_family
);
1818 rwrap_reset_nameservers(state
);
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.
1832 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1835 static int rwrap_parse_resolv_conf(struct __res_state
*state
,
1836 const char *resolv_conf
)
1841 union rwrap_sockaddr nsaddrs
[MAXNS
];
1843 memset(nsaddrs
, 0, sizeof(nsaddrs
));
1845 fp
= fopen(resolv_conf
, "r");
1847 RWRAP_LOG(RWRAP_LOG_WARN
,
1848 "Opening %s failed: %s",
1849 resolv_conf
, strerror(errno
));
1853 while(fgets(buf
, sizeof(buf
), fp
) != NULL
) {
1856 /* Ignore comments */
1857 if (buf
[0] == '#' || buf
[0] == ';') {
1861 if (RESOLV_MATCH(buf
, "nameserver") && nserv
< MAXNS
) {
1867 p
= buf
+ strlen("nameserver");
1869 /* Skip spaces and tabs */
1870 while(isblank((int)p
[0])) {
1875 while(q
[0] != '\n' && q
[0] != '\0') {
1880 ok
= inet_pton(AF_INET
, p
, &a
);
1882 nsaddrs
[nserv
] = (union rwrap_sockaddr
) {
1884 .sin_family
= AF_INET
,
1886 .sin_port
= htons(53),
1895 ok
= inet_pton(AF_INET6
, p
, &a6
);
1897 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1898 nsaddrs
[nserv
] = (union rwrap_sockaddr
) {
1901 .sin6_family
= AF_INET6
,
1902 .sin6_port
= htons(53),
1909 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1910 RWRAP_LOG(RWRAP_LOG_WARN
,
1911 "resolve_wrapper does not support "
1912 "IPv6 on this platform");
1917 RWRAP_LOG(RWRAP_LOG_ERROR
, "Malformed DNS server[%s]", p
);
1919 } /* TODO: match other keywords */
1923 RWRAP_LOG(RWRAP_LOG_ERROR
,
1924 "Reading from %s failed",
1933 RWRAP_LOG(RWRAP_LOG_WARN
,
1934 "No usable nameservers found in %s",
1940 return rwrap_set_nameservers(state
, nserv
, nsaddrs
);
1943 /****************************************************************************
1945 ***************************************************************************/
1947 static int rwrap_res_ninit(struct __res_state
*state
)
1951 rc
= libc_res_ninit(state
);
1953 const char *resolv_conf
= getenv("RESOLV_WRAPPER_CONF");
1955 if (resolv_conf
!= NULL
) {
1956 rc
= rwrap_parse_resolv_conf(state
, resolv_conf
);
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
)
1969 return rwrap_res_ninit(state
);
1972 /****************************************************************************
1974 ***************************************************************************/
1976 static struct __res_state rwrap_res_state
;
1978 static int rwrap_res_init(void)
1982 rc
= rwrap_res_ninit(&rwrap_res_state
);
1987 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1989 #elif defined(HAVE___RES_INIT)
1990 int __res_init(void)
1993 return rwrap_res_init();
1996 /****************************************************************************
1998 ***************************************************************************/
2000 static void rwrap_res_nclose(struct __res_state
*state
)
2002 rwrap_reset_nameservers(state
);
2003 libc_res_nclose(state
);
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
)
2012 rwrap_res_nclose(state
);
2015 /****************************************************************************
2017 ***************************************************************************/
2019 static void rwrap_res_close(void)
2021 rwrap_res_nclose(&rwrap_res_state
);
2024 #if defined(HAVE_RES_CLOSE)
2025 void res_close(void)
2026 #elif defined(HAVE___RES_CLOSE)
2027 void __res_close(void)
2033 /****************************************************************************
2035 ***************************************************************************/
2037 static int rwrap_res_nquery(struct __res_state
*state
,
2041 unsigned char *answer
,
2045 const char *fake_hosts
;
2047 RWRAP_LOG(RWRAP_LOG_TRACE
,
2048 "Resolve the domain name [%s] - class=%d, type=%d",
2049 dname
, class, type
);
2050 rwrap_log_nameservers(RWRAP_LOG_TRACE
, __func__
, state
);
2052 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
2053 if (fake_hosts
!= NULL
) {
2054 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
2056 rc
= libc_res_nquery(state
, dname
, class, type
, answer
, anslen
);
2060 RWRAP_LOG(RWRAP_LOG_TRACE
,
2061 "The returned response length is: %d",
2067 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
2068 int res_nquery(struct __res_state
*state
,
2072 unsigned char *answer
,
2074 #elif defined(HAVE___RES_NQUERY)
2075 int __res_nquery(struct __res_state
*state
,
2079 unsigned char *answer
,
2083 return rwrap_res_nquery(state
, dname
, class, type
, answer
, anslen
);
2086 /****************************************************************************
2088 ***************************************************************************/
2090 static int rwrap_res_query(const char *dname
,
2093 unsigned char *answer
,
2098 rc
= rwrap_res_ninit(&rwrap_res_state
);
2103 rc
= rwrap_res_nquery(&rwrap_res_state
,
2113 #if !defined(res_query) && defined(HAVE_RES_QUERY)
2114 int res_query(const char *dname
,
2117 unsigned char *answer
,
2119 #elif defined(HAVE___RES_QUERY)
2120 int __res_query(const char *dname
,
2123 unsigned char *answer
,
2127 return rwrap_res_query(dname
, class, type
, answer
, anslen
);
2130 /****************************************************************************
2132 ***************************************************************************/
2134 static int rwrap_res_nsearch(struct __res_state
*state
,
2138 unsigned char *answer
,
2142 const char *fake_hosts
;
2144 RWRAP_LOG(RWRAP_LOG_TRACE
,
2145 "Resolve the domain name [%s] - class=%d, type=%d",
2146 dname
, class, type
);
2147 rwrap_log_nameservers(RWRAP_LOG_TRACE
, __func__
, state
);
2149 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
2150 if (fake_hosts
!= NULL
) {
2151 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
2153 rc
= libc_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
2156 RWRAP_LOG(RWRAP_LOG_TRACE
,
2157 "The returned response length is: %d",
2163 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
2164 int res_nsearch(struct __res_state
*state
,
2168 unsigned char *answer
,
2170 #elif defined(HAVE___RES_NSEARCH)
2171 int __res_nsearch(struct __res_state
*state
,
2175 unsigned char *answer
,
2179 return rwrap_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
2182 /****************************************************************************
2184 ***************************************************************************/
2186 static int rwrap_res_search(const char *dname
,
2189 unsigned char *answer
,
2194 rc
= rwrap_res_ninit(&rwrap_res_state
);
2199 rc
= rwrap_res_nsearch(&rwrap_res_state
,
2209 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
2210 int res_search(const char *dname
,
2213 unsigned char *answer
,
2215 #elif defined(HAVE___RES_SEARCH)
2216 int __res_search(const char *dname
,
2219 unsigned char *answer
,
2223 return rwrap_res_search(dname
, class, type
, answer
, anslen
);