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 #define rwrap_randomid() 0xffff & getpid()
439 /* Prepares a fake header with a single response. Advances header_blob */
440 static ssize_t
rwrap_fake_header(uint8_t **header_blob
, size_t remaining
,
441 size_t ancount
, size_t arcount
)
448 if (remaining
< NS_HFIXEDSZ
) {
449 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
453 h
.blob
= *header_blob
;
454 memset(h
.blob
, 0, NS_HFIXEDSZ
);
456 h
.header
->id
= rwrap_randomid(); /* random query ID */
457 h
.header
->qr
= 1; /* response flag */
458 h
.header
->rd
= 1; /* recursion desired */
459 h
.header
->ra
= 1; /* recursion available */
461 h
.header
->qdcount
= htons(1); /* no. of questions */
462 h
.header
->ancount
= htons(ancount
); /* no. of answers */
463 h
.header
->arcount
= htons(arcount
); /* no. of add'tl records */
465 /* move past the header */
466 *header_blob
= h
.blob
+= NS_HFIXEDSZ
;
471 static ssize_t
rwrap_fake_question(const char *question
,
473 uint8_t **question_ptr
,
476 uint8_t *qb
= *question_ptr
;
479 n
= ns_name_compress(question
, qb
, remaining
, NULL
, NULL
);
481 RWRAP_LOG(RWRAP_LOG_ERROR
,
482 "Failed to compress [%s]\n", question
);
489 if (remaining
< 2 * sizeof(uint16_t)) {
490 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
495 NS_PUT16(ns_c_in
, qb
);
498 return n
+ 2 * sizeof(uint16_t);
501 static ssize_t
rwrap_fake_rdata_common(uint16_t type
,
507 uint8_t *rd
= *rdata_ptr
;
510 written
= ns_name_compress(key
, rd
, remaining
, NULL
, NULL
);
512 RWRAP_LOG(RWRAP_LOG_ERROR
,
513 "Failed to compress [%s]\n", key
);
517 remaining
-= written
;
519 if (remaining
< 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
520 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
525 NS_PUT16(ns_c_in
, rd
);
526 NS_PUT32(RWRAP_DEFAULT_FAKE_TTL
, rd
);
527 NS_PUT16(rdata_size
, rd
);
529 if (remaining
< rdata_size
) {
530 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
535 return written
+ 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size
;
538 static ssize_t
rwrap_fake_a(struct rwrap_fake_rr
*rr
,
542 uint8_t *a
= answer_ptr
;
545 if (rr
->type
!= ns_t_a
) {
546 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
549 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding A RR");
551 resp_size
= rwrap_fake_rdata_common(ns_t_a
, sizeof(struct in_addr
), rr
->key
,
557 memcpy(a
, &rr
->rrdata
.a_rec
, sizeof(struct in_addr
));
562 static ssize_t
rwrap_fake_aaaa(struct rwrap_fake_rr
*rr
,
569 if (rr
->type
!= ns_t_aaaa
) {
570 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
573 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding AAAA RR");
575 resp_size
= rwrap_fake_rdata_common(ns_t_aaaa
, sizeof(struct in6_addr
),
576 rr
->key
, anslen
, &a
);
581 memcpy(a
, &rr
->rrdata
.aaaa_rec
, sizeof(struct in6_addr
));
586 static ssize_t
rwrap_fake_ns(struct rwrap_fake_rr
*rr
,
591 ssize_t resp_size
= 0;
593 unsigned char hostname_compressed
[MAXDNAME
];
594 ssize_t compressed_len
;
596 if (rr
->type
!= ns_t_ns
) {
597 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
600 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding NS RR");
602 /* Prepare the data to write */
603 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
608 if (compressed_len
< 0) {
612 /* Is this enough? */
613 rdata_size
= compressed_len
;
615 resp_size
= rwrap_fake_rdata_common(ns_t_ns
, rdata_size
,
616 rr
->key
, anslen
, &a
);
621 memcpy(a
, hostname_compressed
, compressed_len
);
626 static ssize_t
rwrap_fake_srv(struct rwrap_fake_rr
*rr
,
633 unsigned char hostname_compressed
[MAXDNAME
];
634 ssize_t compressed_len
;
636 if (rr
->type
!= ns_t_srv
) {
637 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
640 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SRV RR");
641 rdata_size
= 3 * sizeof(uint16_t);
643 /* Prepare the data to write */
644 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
645 hostname_compressed
, MAXDNAME
,
647 if (compressed_len
< 0) {
650 rdata_size
+= compressed_len
;
652 resp_size
= rwrap_fake_rdata_common(ns_t_srv
, rdata_size
,
653 rr
->key
, anslen
, &a
);
658 NS_PUT16(rr
->rrdata
.srv_rec
.prio
, a
);
659 NS_PUT16(rr
->rrdata
.srv_rec
.weight
, a
);
660 NS_PUT16(rr
->rrdata
.srv_rec
.port
, a
);
661 memcpy(a
, hostname_compressed
, compressed_len
);
666 static ssize_t
rwrap_fake_uri(struct rwrap_fake_rr
*rr
,
675 if (rr
->type
!= ns_t_uri
) {
676 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
679 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding URI RR");
680 rdata_size
= 3 * sizeof(uint16_t);
681 uri_len
= strlen(rr
->rrdata
.uri_rec
.uri
) + 1;
682 rdata_size
+= uri_len
;
684 resp_size
= rwrap_fake_rdata_common(ns_t_uri
, rdata_size
,
685 rr
->key
, anslen
, &a
);
690 NS_PUT16(rr
->rrdata
.uri_rec
.prio
, a
);
691 NS_PUT16(rr
->rrdata
.uri_rec
.weight
, a
);
692 memcpy(a
, rr
->rrdata
.uri_rec
.uri
, uri_len
);
697 static ssize_t
rwrap_fake_txt(struct rwrap_fake_rr
*rr
,
706 if (rr
->type
!= ns_t_txt
) {
707 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
710 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding TXT RR");
711 txt_len
= strlen(rr
->rrdata
.txt_rec
) + 1;
712 rdata_size
= txt_len
;
714 resp_size
= rwrap_fake_rdata_common(ns_t_txt
, rdata_size
,
715 rr
->key
, anslen
, &a
);
720 memcpy(a
, rr
->rrdata
.txt_rec
, txt_len
);
725 static ssize_t
rwrap_fake_soa(struct rwrap_fake_rr
*rr
,
732 unsigned char nameser_compressed
[MAXDNAME
];
733 ssize_t compressed_ns_len
;
734 unsigned char mailbox_compressed
[MAXDNAME
];
735 ssize_t compressed_mb_len
;
737 if (rr
->type
!= ns_t_soa
) {
738 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
741 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SOA RR");
742 rdata_size
= 5 * sizeof(uint16_t);
744 compressed_ns_len
= ns_name_compress(rr
->rrdata
.soa_rec
.nameserver
,
746 MAXDNAME
, NULL
, NULL
);
747 if (compressed_ns_len
< 0) {
750 rdata_size
+= compressed_ns_len
;
752 compressed_mb_len
= ns_name_compress(rr
->rrdata
.soa_rec
.mailbox
,
754 MAXDNAME
, NULL
, NULL
);
755 if (compressed_mb_len
< 0) {
758 rdata_size
+= compressed_mb_len
;
760 resp_size
= rwrap_fake_rdata_common(ns_t_soa
, rdata_size
,
761 rr
->key
, anslen
, &a
);
766 memcpy(a
, nameser_compressed
, compressed_ns_len
);
767 a
+= compressed_ns_len
;
768 memcpy(a
, mailbox_compressed
, compressed_mb_len
);
769 a
+= compressed_mb_len
;
770 NS_PUT32(rr
->rrdata
.soa_rec
.serial
, a
);
771 NS_PUT32(rr
->rrdata
.soa_rec
.refresh
, a
);
772 NS_PUT32(rr
->rrdata
.soa_rec
.retry
, a
);
773 NS_PUT32(rr
->rrdata
.soa_rec
.expire
, a
);
774 NS_PUT32(rr
->rrdata
.soa_rec
.minimum
, a
);
779 static ssize_t
rwrap_fake_cname(struct rwrap_fake_rr
*rr
,
785 unsigned char hostname_compressed
[MAXDNAME
];
788 if (rr
->type
!= ns_t_cname
) {
789 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
792 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding CNAME RR");
794 /* Prepare the data to write */
795 rdata_size
= ns_name_compress(rr
->rrdata
.cname_rec
,
796 hostname_compressed
, MAXDNAME
,
798 if (rdata_size
< 0) {
802 resp_size
= rwrap_fake_rdata_common(ns_t_cname
, rdata_size
,
803 rr
->key
, anslen
, &a
);
808 memcpy(a
, hostname_compressed
, rdata_size
);
813 static ssize_t
rwrap_fake_ptr(struct rwrap_fake_rr
*rr
,
820 unsigned char hostname_compressed
[MAXDNAME
];
822 if (rr
->type
!= ns_t_ptr
) {
823 RWRAP_LOG(RWRAP_LOG_ERROR
, "Wrong type!\n");
826 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding PTR RR");
828 /* Prepare the data to write */
829 rdata_size
= ns_name_compress(rr
->rrdata
.ptr_rec
,
830 hostname_compressed
, MAXDNAME
,
832 if (rdata_size
< 0) {
836 resp_size
= rwrap_fake_rdata_common(ns_t_ptr
, rdata_size
,
837 rr
->key
, anslen
, &a
);
842 memcpy(a
, hostname_compressed
, rdata_size
);
847 #define RESOLV_MATCH(line, name) \
848 (strncmp(line, name, sizeof(name) - 1) == 0 && \
849 (line[sizeof(name) - 1] == ' ' || \
850 line[sizeof(name) - 1] == '\t'))
852 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
853 ((type) == (ns_type) && \
854 (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
855 (strcasecmp(key, query)) == 0)
858 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
859 const char *query
, int type
,
860 struct rwrap_fake_rr
*rr
);
862 static int rwrap_uri_recurse(const char *hostfile
, unsigned recursion
,
863 const char *query
, struct rwrap_fake_rr
*rr
)
867 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_uri
, rr
);
875 static int rwrap_srv_recurse(const char *hostfile
, unsigned recursion
,
876 const char *query
, struct rwrap_fake_rr
*rr
)
880 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
881 if (rc
== 0) return 0;
883 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
884 if (rc
== ENOENT
) rc
= 0;
889 static int rwrap_cname_recurse(const char *hostfile
, unsigned recursion
,
890 const char *query
, struct rwrap_fake_rr
*rr
)
894 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
895 if (rc
== 0) return 0;
897 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
898 if (rc
== 0) return 0;
900 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_cname
, rr
);
901 if (rc
== ENOENT
) rc
= 0;
906 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
907 const char *query
, int type
,
908 struct rwrap_fake_rr
*rr
)
915 unsigned num_uris
= 0;
917 if (recursion
>= RWRAP_MAX_RECURSION
) {
918 RWRAP_LOG(RWRAP_LOG_ERROR
, "Recursed too deep!\n");
922 RWRAP_LOG(RWRAP_LOG_TRACE
,
923 "Searching in fake hosts file %s for %s:%d\n", hostfile
,
926 fp
= fopen(hostfile
, "r");
928 RWRAP_LOG(RWRAP_LOG_WARN
,
929 "Opening %s failed: %s",
930 hostfile
, strerror(errno
));
934 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
941 NEXT_KEY(rec_type
, key
);
942 NEXT_KEY(key
, value
);
944 if (key
== NULL
|| value
== NULL
) {
945 RWRAP_LOG(RWRAP_LOG_WARN
,
946 "Malformed line: not enough parts, use \"rec_type key data\n"
947 "For example \"A cwrap.org 10.10.10.10\"");
952 while(q
[0] != '\n' && q
[0] != '\0') {
957 if (type
== ns_t_uri
&& recursion
> 0) {
958 /* Skip non-URI records. */
959 if (!TYPE_MATCH(type
, ns_t_uri
, rec_type
, "URI", key
, query
)) {
962 /* Skip previous records based on the recurse depth. */
964 if (num_uris
<= recursion
) {
969 if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "A", key
, query
)) {
970 rc
= rwrap_create_fake_a_rr(key
, value
, rr
);
972 } else if (TYPE_MATCH(type
, ns_t_aaaa
,
973 rec_type
, "AAAA", key
, query
)) {
974 rc
= rwrap_create_fake_aaaa_rr(key
, value
, rr
);
976 } else if (TYPE_MATCH(type
, ns_t_ns
,
977 rec_type
, "NS", key
, query
)) {
978 rc
= rwrap_create_fake_ns_rr(key
, value
, rr
);
980 } else if (TYPE_MATCH(type
, ns_t_srv
,
981 rec_type
, "SRV", key
, query
)) {
982 rc
= rwrap_create_fake_srv_rr(key
, value
, rr
);
984 rc
= rwrap_srv_recurse(hostfile
, recursion
+1,
985 rr
->rrdata
.srv_rec
.hostname
,
989 } else if (TYPE_MATCH(type
, ns_t_uri
,
990 rec_type
, "URI", key
, query
)) {
991 rc
= rwrap_create_fake_uri_rr(key
, value
, rr
);
993 /* Recurse to collect multiple URI answers under a single key. */
994 rc
= rwrap_uri_recurse(hostfile
, recursion
+ 1, key
, rr
+ 1);
997 } else if (TYPE_MATCH(type
, ns_t_soa
,
998 rec_type
, "SOA", key
, query
)) {
999 rc
= rwrap_create_fake_soa_rr(key
, value
, rr
);
1001 } else if (TYPE_MATCH(type
, ns_t_cname
,
1002 rec_type
, "CNAME", key
, query
)) {
1003 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
1005 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
1009 } else if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "CNAME", key
, query
)) {
1010 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
1012 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
1016 } else if (TYPE_MATCH(type
, ns_t_ptr
,
1017 rec_type
, "PTR", key
, query
)) {
1018 rc
= rwrap_create_fake_ptr_rr(key
, value
, rr
);
1021 else if (TYPE_MATCH(type
, ns_t_txt
,
1022 rec_type
, "TXT", key
, query
)) {
1023 rc
= rwrap_create_fake_txt_rr(key
, value
, rr
);
1028 if (rc
== ENOENT
&& recursion
== 0 && key
!= NULL
) {
1029 RWRAP_LOG(RWRAP_LOG_TRACE
, "Record for [%s] not found\n", query
);
1030 memcpy(rr
->key
, key
, strlen(key
) + 1);
1037 static ssize_t
rwrap_fake_empty(int type
,
1038 const char *question
,
1043 size_t remaining
= anslen
;
1045 resp_data
= rwrap_fake_header(&answer
, remaining
, 0, 0);
1046 if (resp_data
< 0) {
1049 remaining
-= resp_data
;
1051 resp_data
+= rwrap_fake_question(question
, type
, &answer
, remaining
);
1052 if (resp_data
< 0) {
1055 remaining
-= resp_data
;
1057 resp_data
+= rwrap_fake_rdata_common(type
, 0, question
,
1058 remaining
, &answer
);
1059 if (resp_data
< 0) {
1066 static inline bool rwrap_known_type(int type
)
1084 static int rwrap_ancount(struct rwrap_fake_rr
*rrs
, int qtype
)
1089 /* For URI return the number of URIs. */
1090 if (qtype
== ns_t_uri
) {
1091 for (i
= 0; i
< RWRAP_MAX_RECURSION
; i
++) {
1092 if (rwrap_known_type(rrs
[i
].type
) &&
1093 rrs
[i
].type
== qtype
) {
1100 /* Include all RRs in the stack until the sought type
1101 * in the answer section. This is the case i.e. when looking
1102 * up an A record but the name points to a CNAME
1104 for (i
= 0; i
< RWRAP_MAX_RECURSION
; i
++) {
1107 if (rwrap_known_type(rrs
[i
].type
) &&
1108 rrs
[i
].type
== qtype
) {
1113 /* Return 0 records if the sought type wasn't in the stack */
1114 return i
< RWRAP_MAX_RECURSION
? ancount
: 0;
1117 static int rwrap_arcount(struct rwrap_fake_rr
*rrs
, int ancount
)
1122 /* start from index ancount */
1123 for (i
= ancount
; i
< RWRAP_MAX_RECURSION
; i
++) {
1124 if (rwrap_known_type(rrs
[i
].type
)) {
1132 static ssize_t
rwrap_add_rr(struct rwrap_fake_rr
*rr
,
1139 RWRAP_LOG(RWRAP_LOG_ERROR
, "Internal error!\n");
1145 resp_data
= rwrap_fake_a(rr
, answer
, anslen
);
1148 resp_data
= rwrap_fake_aaaa(rr
, answer
, anslen
);
1151 resp_data
= rwrap_fake_ns(rr
, answer
, anslen
);
1154 resp_data
= rwrap_fake_srv(rr
, answer
, anslen
);
1157 resp_data
= rwrap_fake_uri(rr
, answer
, anslen
);
1160 resp_data
= rwrap_fake_soa(rr
, answer
, anslen
);
1163 resp_data
= rwrap_fake_cname(rr
, answer
, anslen
);
1166 resp_data
= rwrap_fake_ptr(rr
, answer
, anslen
);
1169 resp_data
= rwrap_fake_txt(rr
, answer
, anslen
);
1178 static ssize_t
rwrap_fake_answer(struct rwrap_fake_rr
*rrs
,
1186 size_t remaining
= anslen
;
1191 ancount
= rwrap_ancount(rrs
, type
);
1192 arcount
= rwrap_arcount(rrs
, ancount
);
1193 RWRAP_LOG(RWRAP_LOG_TRACE
,
1194 "Got %d answers and %d additional records\n", ancount
, arcount
);
1196 resp_data
= rwrap_fake_header(&answer
, remaining
, ancount
, arcount
);
1197 if (resp_data
< 0) {
1200 remaining
-= resp_data
;
1202 resp_data
+= rwrap_fake_question(rrs
->key
, rrs
->type
, &answer
, remaining
);
1203 if (resp_data
< 0) {
1206 remaining
-= resp_data
;
1209 for (i
= 0; i
< ancount
; i
++) {
1210 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
1219 /* add authoritative NS here? */
1221 /* additional records */
1222 for (i
= ancount
; i
< ancount
+ arcount
; i
++) {
1223 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
1235 /* Reads in a file in the following format:
1238 * Malformed entries are silently skipped.
1239 * Allocates answer buffer of size anslen that has to be freed after use.
1241 static int rwrap_res_fake_hosts(const char *hostfile
,
1244 unsigned char *answer
,
1248 char *query_name
= NULL
;
1249 size_t qlen
= strlen(query
);
1250 struct rwrap_fake_rr rrs
[RWRAP_MAX_RECURSION
];
1253 RWRAP_LOG(RWRAP_LOG_TRACE
,
1254 "Searching in fake hosts file %s\n", hostfile
);
1256 if (qlen
> 0 && query
[qlen
-1] == '.') {
1260 query_name
= strndup(query
, qlen
);
1261 if (query_name
== NULL
) {
1265 rwrap_fake_rr_init(rrs
, RWRAP_MAX_RECURSION
);
1267 rc
= rwrap_get_record(hostfile
, 0, query_name
, type
, rrs
);
1270 RWRAP_LOG(RWRAP_LOG_TRACE
,
1271 "Found record for [%s]\n", query_name
);
1272 resp_size
= rwrap_fake_answer(rrs
, type
, answer
, anslen
);
1275 RWRAP_LOG(RWRAP_LOG_TRACE
,
1276 "No record for [%s]\n", query_name
);
1277 resp_size
= rwrap_fake_empty(type
, rrs
->key
, answer
, anslen
);
1280 RWRAP_LOG(RWRAP_LOG_NOTICE
,
1281 "Searching for [%s] did not return any results\n",
1287 switch (resp_size
) {
1289 RWRAP_LOG(RWRAP_LOG_ERROR
,
1290 "Error faking answer for [%s]\n", query_name
);
1293 RWRAP_LOG(RWRAP_LOG_TRACE
,
1294 "Successfully faked answer for [%s]\n",
1303 /*********************************************************
1304 * RWRAP LOADING LIBC FUNCTIONS
1305 *********************************************************/
1309 typedef int (*__libc_res_ninit
)(struct __res_state
*state
);
1310 typedef int (*__libc___res_ninit
)(struct __res_state
*state
);
1311 typedef void (*__libc_res_nclose
)(struct __res_state
*state
);
1312 typedef void (*__libc___res_nclose
)(struct __res_state
*state
);
1313 typedef int (*__libc_res_nquery
)(struct __res_state
*state
,
1317 unsigned char *answer
,
1319 typedef int (*__libc___res_nquery
)(struct __res_state
*state
,
1323 unsigned char *answer
,
1325 typedef int (*__libc_res_nsearch
)(struct __res_state
*state
,
1329 unsigned char *answer
,
1331 typedef int (*__libc___res_nsearch
)(struct __res_state
*state
,
1335 unsigned char *answer
,
1338 #define RWRAP_SYMBOL_ENTRY(i) \
1344 struct rwrap_libc_symbols
{
1345 RWRAP_SYMBOL_ENTRY(res_ninit
);
1346 RWRAP_SYMBOL_ENTRY(__res_ninit
);
1347 RWRAP_SYMBOL_ENTRY(res_nclose
);
1348 RWRAP_SYMBOL_ENTRY(__res_nclose
);
1349 RWRAP_SYMBOL_ENTRY(res_nquery
);
1350 RWRAP_SYMBOL_ENTRY(__res_nquery
);
1351 RWRAP_SYMBOL_ENTRY(res_nsearch
);
1352 RWRAP_SYMBOL_ENTRY(__res_nsearch
);
1354 #undef RWRAP_SYMBOL_ENTRY
1359 struct rwrap_libc_symbols symbols
;
1364 struct rwrap_libc_symbols symbols
;
1373 static struct rwrap rwrap
;
1380 static const char *rwrap_str_lib(enum rwrap_lib lib
)
1385 case RWRAP_LIBRESOLV
:
1389 /* Compiler would warn us about unhandled enum value if we get here */
1393 static void *rwrap_load_lib_handle(enum rwrap_lib lib
)
1395 int flags
= RTLD_LAZY
;
1396 void *handle
= NULL
;
1399 #ifdef RTLD_DEEPBIND
1400 const char *env_preload
= getenv("LD_PRELOAD");
1401 const char *env_deepbind
= getenv("RESOLV_WRAPPER_DISABLE_DEEPBIND");
1402 bool enable_deepbind
= true;
1404 /* Don't do a deepbind if we run with libasan */
1405 if (env_preload
!= NULL
&& strlen(env_preload
) < 1024) {
1406 const char *p
= strstr(env_preload
, "libasan.so");
1408 enable_deepbind
= false;
1412 if (env_deepbind
!= NULL
&& strlen(env_deepbind
) >= 1) {
1413 enable_deepbind
= false;
1416 if (enable_deepbind
) {
1417 flags
|= RTLD_DEEPBIND
;
1422 case RWRAP_LIBRESOLV
:
1423 #ifdef HAVE_LIBRESOLV
1424 handle
= rwrap
.libresolv
.handle
;
1425 if (handle
== NULL
) {
1426 for (i
= 10; i
>= 0; i
--) {
1427 char soname
[256] = {0};
1429 snprintf(soname
, sizeof(soname
), "libresolv.so.%d", i
);
1430 handle
= dlopen(soname
, flags
);
1431 if (handle
!= NULL
) {
1436 rwrap
.libresolv
.handle
= handle
;
1442 handle
= rwrap
.libc
.handle
;
1444 if (handle
== NULL
) {
1445 handle
= dlopen(LIBC_SO
, flags
);
1447 rwrap
.libc
.handle
= handle
;
1450 if (handle
== NULL
) {
1451 for (i
= 10; i
>= 0; i
--) {
1452 char soname
[256] = {0};
1454 snprintf(soname
, sizeof(soname
), "libc.so.%d", i
);
1455 handle
= dlopen(soname
, flags
);
1456 if (handle
!= NULL
) {
1461 rwrap
.libc
.handle
= handle
;
1466 if (handle
== NULL
) {
1468 handle
= rwrap
.libc
.handle
= rwrap
.libresolv
.handle
= RTLD_NEXT
;
1470 RWRAP_LOG(RWRAP_LOG_ERROR
,
1471 "Failed to dlopen library: %s\n",
1480 static void *_rwrap_bind_symbol(enum rwrap_lib lib
, const char *fn_name
)
1485 handle
= rwrap_load_lib_handle(lib
);
1487 func
= dlsym(handle
, fn_name
);
1489 RWRAP_LOG(RWRAP_LOG_ERROR
,
1490 "Failed to find %s: %s\n",
1491 fn_name
, dlerror());
1495 RWRAP_LOG(RWRAP_LOG_TRACE
,
1496 "Loaded %s from %s",
1497 fn_name
, rwrap_str_lib(lib
));
1501 #define rwrap_bind_symbol_libc(sym_name) \
1502 if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
1503 rwrap.libc.symbols._libc_##sym_name.obj = \
1504 _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
1507 #define rwrap_bind_symbol_libresolv(sym_name) \
1508 if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
1509 rwrap.libresolv.symbols._libc_##sym_name.obj = \
1510 _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
1516 * Functions especially from libc need to be loaded individually, you can't load
1517 * all at once or gdb will segfault at startup. The same applies to valgrind and
1518 * has probably something todo with with the linker.
1519 * So we need load each function at the point it is called the first time.
1522 static int libc_res_ninit(struct __res_state
*state
)
1524 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1525 rwrap_bind_symbol_libresolv(res_ninit
);
1527 return rwrap
.libresolv
.symbols
._libc_res_ninit
.f(state
);
1528 #elif defined(HAVE___RES_NINIT)
1529 rwrap_bind_symbol_libresolv(__res_ninit
);
1531 return rwrap
.libresolv
.symbols
._libc___res_ninit
.f(state
);
1533 #error "No res_ninit function"
1537 static void libc_res_nclose(struct __res_state
*state
)
1539 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1540 rwrap_bind_symbol_libresolv(res_nclose
);
1542 rwrap
.libresolv
.symbols
._libc_res_nclose
.f(state
);
1544 #elif defined(HAVE___RES_NCLOSE)
1545 rwrap_bind_symbol_libresolv(__res_nclose
);
1547 rwrap
.libresolv
.symbols
._libc___res_nclose
.f(state
);
1549 #error "No res_nclose function"
1553 static int libc_res_nquery(struct __res_state
*state
,
1557 unsigned char *answer
,
1560 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1561 rwrap_bind_symbol_libresolv(res_nquery
);
1563 return rwrap
.libresolv
.symbols
._libc_res_nquery
.f(state
,
1569 #elif defined(HAVE___RES_NQUERY)
1570 rwrap_bind_symbol_libresolv(__res_nquery
);
1572 return rwrap
.libresolv
.symbols
._libc___res_nquery
.f(state
,
1579 #error "No res_nquery function"
1583 static int libc_res_nsearch(struct __res_state
*state
,
1587 unsigned char *answer
,
1590 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1591 rwrap_bind_symbol_libresolv(res_nsearch
);
1593 return rwrap
.libresolv
.symbols
._libc_res_nsearch
.f(state
,
1599 #elif defined(HAVE___RES_NSEARCH)
1600 rwrap_bind_symbol_libresolv(__res_nsearch
);
1602 return rwrap
.libresolv
.symbols
._libc___res_nsearch
.f(state
,
1609 #error "No res_nsearch function"
1613 /****************************************************************************
1615 ***************************************************************************/
1617 static size_t rwrap_get_nameservers(struct __res_state
*state
,
1619 union rwrap_sockaddr
*nsaddrs
)
1621 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1622 union res_sockaddr_union set
[MAXNS
];
1626 memset(set
, 0, sizeof(set
));
1627 memset(nsaddrs
, 0, sizeof(*nsaddrs
) * nserv
);
1629 if (nserv
> MAXNS
) {
1633 rc
= res_getservers(state
, set
, nserv
);
1641 for (i
= 0; i
< nserv
; i
++) {
1642 switch (set
[i
].sin
.sin_family
) {
1644 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1648 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1650 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1659 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1662 memset(nsaddrs
, 0, sizeof(*nsaddrs
) * nserv
);
1664 if (nserv
> (size_t)state
->nscount
) {
1665 nserv
= (size_t)state
->nscount
;
1668 for (i
= 0; i
< nserv
; i
++) {
1669 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1670 if (state
->_u
._ext
.nsaddrs
[i
] != NULL
) {
1671 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1672 .in6
= *state
->_u
._ext
.nsaddrs
[i
],
1675 #endif /* HAVE_RES_STATE_U_EXT_NSADDRS */
1677 nsaddrs
[i
] = (union rwrap_sockaddr
) {
1678 .in
= state
->nsaddr_list
[i
],
1684 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1687 static void rwrap_log_nameservers(enum rwrap_dbglvl_e dbglvl
,
1689 struct __res_state
*state
)
1691 union rwrap_sockaddr nsaddrs
[MAXNS
];
1692 size_t nserv
= MAXNS
;
1695 memset(nsaddrs
, 0, sizeof(nsaddrs
));
1696 nserv
= rwrap_get_nameservers(state
, nserv
, nsaddrs
);
1697 for (i
= 0; i
< nserv
; i
++) {
1698 char ip
[INET6_ADDRSTRLEN
];
1700 switch (nsaddrs
[i
].sa
.sa_family
) {
1702 inet_ntop(AF_INET
, &(nsaddrs
[i
].in
.sin_addr
),
1706 inet_ntop(AF_INET6
, &(nsaddrs
[i
].in6
.sin6_addr
),
1710 snprintf(ip
, sizeof(ip
), "<unknown sa_family=%d",
1711 nsaddrs
[i
].sa
.sa_family
);
1715 rwrap_log(dbglvl
, func
,
1721 static void rwrap_reset_nameservers(struct __res_state
*state
)
1723 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1724 res_setservers(state
, NULL
, 0);
1725 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1726 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1729 for (i
= 0; i
< (size_t)state
->nscount
; i
++) {
1730 if (state
->_u
._ext
.nssocks
[i
] != -1) {
1731 close(state
->_u
._ext
.nssocks
[i
]);
1732 state
->_u
._ext
.nssocks
[i
] = -1;
1734 SAFE_FREE(state
->_u
._ext
.nsaddrs
[i
]);
1736 memset(&state
->_u
._ext
, 0, sizeof(state
->_u
._ext
));
1737 for (i
= 0; i
< MAXNS
; i
++) {
1738 state
->_u
._ext
.nssocks
[i
] = -1;
1739 state
->_u
._ext
.nsmap
[i
] = MAXNS
+ 1;
1741 state
->ipv6_unavail
= false;
1743 memset(state
->nsaddr_list
, 0, sizeof(state
->nsaddr_list
));
1745 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1748 static int rwrap_set_nameservers(struct __res_state
*state
,
1750 const union rwrap_sockaddr
*nsaddrs
)
1752 #ifdef HAVE_RES_SOCKADDR_UNION_SIN
1753 union res_sockaddr_union set
[MAXNS
];
1756 memset(set
, 0, sizeof(set
));
1758 if (nserv
> MAXNS
) {
1762 rwrap_reset_nameservers(state
);
1764 for (i
= 0; i
< nserv
; i
++) {
1765 switch (nsaddrs
[i
].sa
.sa_family
) {
1767 set
[i
] = (union res_sockaddr_union
) {
1768 .sin
= nsaddrs
[i
].in
,
1771 #ifdef HAVE_RES_SOCKADDR_UNION_SIN6
1773 set
[i
] = (union res_sockaddr_union
) {
1774 .sin6
= nsaddrs
[i
].in6
,
1779 RWRAP_LOG(RWRAP_LOG_ERROR
,
1780 "Internal error unhandled sa_family=%d",
1781 nsaddrs
[i
].sa
.sa_family
);
1787 res_setservers(state
, set
, nserv
);
1789 #else /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1792 if (nserv
> MAXNS
) {
1795 rwrap_reset_nameservers(state
);
1797 for (i
= 0; i
< nserv
; i
++) {
1798 switch (nsaddrs
[i
].sa
.sa_family
) {
1800 state
->nsaddr_list
[i
] = nsaddrs
[i
].in
;
1802 #ifdef HAVE_RES_STATE_U_EXT_NSADDRS
1804 state
->_u
._ext
.nsaddrs
[i
] = malloc(sizeof(nsaddrs
[i
].in6
));
1805 if (state
->_u
._ext
.nsaddrs
[i
] == NULL
) {
1806 rwrap_reset_nameservers(state
);
1810 *state
->_u
._ext
.nsaddrs
[i
] = nsaddrs
[i
].in6
;
1811 state
->_u
._ext
.nssocks
[i
] = -1;
1812 state
->_u
._ext
.nsmap
[i
] = MAXNS
+ 1;
1813 state
->_u
._ext
.nscount6
++;
1817 RWRAP_LOG(RWRAP_LOG_ERROR
,
1818 "Internal error unhandled sa_family=%d",
1819 nsaddrs
[i
].sa
.sa_family
);
1820 rwrap_reset_nameservers(state
);
1827 * note that state->_u._ext.nscount is left as 0,
1828 * this matches glibc and allows resolv wrapper
1829 * to work with most (maybe all) glibc versions.
1834 #endif /* ! HAVE_RES_SOCKADDR_UNION_SIN */
1837 static int rwrap_parse_resolv_conf(struct __res_state
*state
,
1838 const char *resolv_conf
)
1843 union rwrap_sockaddr nsaddrs
[MAXNS
];
1845 memset(nsaddrs
, 0, sizeof(nsaddrs
));
1847 fp
= fopen(resolv_conf
, "r");
1849 RWRAP_LOG(RWRAP_LOG_WARN
,
1850 "Opening %s failed: %s",
1851 resolv_conf
, strerror(errno
));
1855 while(fgets(buf
, sizeof(buf
), fp
) != NULL
) {
1858 /* Ignore comments */
1859 if (buf
[0] == '#' || buf
[0] == ';') {
1863 if (RESOLV_MATCH(buf
, "nameserver") && nserv
< MAXNS
) {
1869 p
= buf
+ strlen("nameserver");
1871 /* Skip spaces and tabs */
1872 while(isblank((int)p
[0])) {
1877 while(q
[0] != '\n' && q
[0] != '\0') {
1882 ok
= inet_pton(AF_INET
, p
, &a
);
1884 nsaddrs
[nserv
] = (union rwrap_sockaddr
) {
1886 .sin_family
= AF_INET
,
1888 .sin_port
= htons(53),
1897 ok
= inet_pton(AF_INET6
, p
, &a6
);
1899 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1900 nsaddrs
[nserv
] = (union rwrap_sockaddr
) {
1903 .sin6_family
= AF_INET6
,
1904 .sin6_port
= htons(53),
1911 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1912 RWRAP_LOG(RWRAP_LOG_WARN
,
1913 "resolve_wrapper does not support "
1914 "IPv6 on this platform");
1919 RWRAP_LOG(RWRAP_LOG_ERROR
, "Malformed DNS server[%s]", p
);
1921 } /* TODO: match other keywords */
1925 RWRAP_LOG(RWRAP_LOG_ERROR
,
1926 "Reading from %s failed",
1935 RWRAP_LOG(RWRAP_LOG_WARN
,
1936 "No usable nameservers found in %s",
1942 return rwrap_set_nameservers(state
, nserv
, nsaddrs
);
1945 /****************************************************************************
1947 ***************************************************************************/
1949 static int rwrap_res_ninit(struct __res_state
*state
)
1953 rc
= libc_res_ninit(state
);
1955 const char *resolv_conf
= getenv("RESOLV_WRAPPER_CONF");
1957 if (resolv_conf
!= NULL
) {
1958 rc
= rwrap_parse_resolv_conf(state
, resolv_conf
);
1965 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1966 int res_ninit(struct __res_state
*state
)
1967 #elif defined(HAVE___RES_NINIT)
1968 int __res_ninit(struct __res_state
*state
)
1971 return rwrap_res_ninit(state
);
1974 /****************************************************************************
1976 ***************************************************************************/
1978 static struct __res_state rwrap_res_state
;
1980 static int rwrap_res_init(void)
1984 rc
= rwrap_res_ninit(&rwrap_res_state
);
1989 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1991 #elif defined(HAVE___RES_INIT)
1992 int __res_init(void)
1995 return rwrap_res_init();
1998 /****************************************************************************
2000 ***************************************************************************/
2002 static void rwrap_res_nclose(struct __res_state
*state
)
2004 rwrap_reset_nameservers(state
);
2005 libc_res_nclose(state
);
2008 #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
2009 void res_nclose(struct __res_state
*state
)
2010 #elif defined(HAVE___RES_NCLOSE)
2011 void __res_nclose(struct __res_state
*state
)
2014 rwrap_res_nclose(state
);
2017 /****************************************************************************
2019 ***************************************************************************/
2021 static void rwrap_res_close(void)
2023 rwrap_res_nclose(&rwrap_res_state
);
2026 #if defined(HAVE_RES_CLOSE)
2027 void res_close(void)
2028 #elif defined(HAVE___RES_CLOSE)
2029 void __res_close(void)
2035 /****************************************************************************
2037 ***************************************************************************/
2039 static int rwrap_res_nquery(struct __res_state
*state
,
2043 unsigned char *answer
,
2047 const char *fake_hosts
;
2049 RWRAP_LOG(RWRAP_LOG_TRACE
,
2050 "Resolve the domain name [%s] - class=%d, type=%d",
2051 dname
, class, type
);
2052 rwrap_log_nameservers(RWRAP_LOG_TRACE
, __func__
, state
);
2054 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
2055 if (fake_hosts
!= NULL
) {
2056 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
2058 rc
= libc_res_nquery(state
, dname
, class, type
, answer
, anslen
);
2062 RWRAP_LOG(RWRAP_LOG_TRACE
,
2063 "The returned response length is: %d",
2069 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
2070 int res_nquery(struct __res_state
*state
,
2074 unsigned char *answer
,
2076 #elif defined(HAVE___RES_NQUERY)
2077 int __res_nquery(struct __res_state
*state
,
2081 unsigned char *answer
,
2085 return rwrap_res_nquery(state
, dname
, class, type
, answer
, anslen
);
2088 /****************************************************************************
2090 ***************************************************************************/
2092 static int rwrap_res_query(const char *dname
,
2095 unsigned char *answer
,
2100 rc
= rwrap_res_ninit(&rwrap_res_state
);
2105 rc
= rwrap_res_nquery(&rwrap_res_state
,
2115 #if !defined(res_query) && defined(HAVE_RES_QUERY)
2116 int res_query(const char *dname
,
2119 unsigned char *answer
,
2121 #elif defined(HAVE___RES_QUERY)
2122 int __res_query(const char *dname
,
2125 unsigned char *answer
,
2129 return rwrap_res_query(dname
, class, type
, answer
, anslen
);
2132 /****************************************************************************
2134 ***************************************************************************/
2136 static int rwrap_res_nsearch(struct __res_state
*state
,
2140 unsigned char *answer
,
2144 const char *fake_hosts
;
2146 RWRAP_LOG(RWRAP_LOG_TRACE
,
2147 "Resolve the domain name [%s] - class=%d, type=%d",
2148 dname
, class, type
);
2149 rwrap_log_nameservers(RWRAP_LOG_TRACE
, __func__
, state
);
2151 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
2152 if (fake_hosts
!= NULL
) {
2153 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
2155 rc
= libc_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
2158 RWRAP_LOG(RWRAP_LOG_TRACE
,
2159 "The returned response length is: %d",
2165 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
2166 int res_nsearch(struct __res_state
*state
,
2170 unsigned char *answer
,
2172 #elif defined(HAVE___RES_NSEARCH)
2173 int __res_nsearch(struct __res_state
*state
,
2177 unsigned char *answer
,
2181 return rwrap_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
2184 /****************************************************************************
2186 ***************************************************************************/
2188 static int rwrap_res_search(const char *dname
,
2191 unsigned char *answer
,
2196 rc
= rwrap_res_ninit(&rwrap_res_state
);
2201 rc
= rwrap_res_nsearch(&rwrap_res_state
,
2211 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
2212 int res_search(const char *dname
,
2215 unsigned char *answer
,
2217 #elif defined(HAVE___RES_SEARCH)
2218 int __res_search(const char *dname
,
2221 unsigned char *answer
,
2225 return rwrap_res_search(dname
, class, type
, answer
, anslen
);