2 * Copyright (c) 2014 Andreas Schneider <asn@samba.org>
3 * Copyright (c) 2014 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 /* GCC has printf type attribute check. */
56 #ifdef HAVE_ATTRIBUTE_PRINTF_FORMAT
57 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
59 #define PRINTF_ATTRIBUTE(a,b)
60 #endif /* HAVE_ATTRIBUTE_PRINTF_FORMAT */
62 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
63 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
65 #define DESTRUCTOR_ATTRIBUTE
66 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
68 #ifndef RWRAP_DEFAULT_FAKE_TTL
69 #define RWRAP_DEFAULT_FAKE_TTL 600
70 #endif /* RWRAP_DEFAULT_FAKE_TTL */
72 #ifndef HAVE_NS_NAME_COMPRESS
73 #define ns_name_compress dn_comp
84 # define RWRAP_LOG(...)
87 static void rwrap_log(enum rwrap_dbglvl_e dbglvl
, const char *func
, const char *format
, ...) PRINTF_ATTRIBUTE(3, 4);
88 # define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
90 static void rwrap_log(enum rwrap_dbglvl_e dbglvl
,
92 const char *format
, ...)
100 d
= getenv("RESOLV_WRAPPER_DEBUGLEVEL");
105 va_start(va
, format
);
106 vsnprintf(buffer
, sizeof(buffer
), format
, va
);
111 case RWRAP_LOG_ERROR
:
113 "RWRAP_ERROR(%d) - %s: %s\n",
118 "RWRAP_WARN(%d) - %s: %s\n",
121 case RWRAP_LOG_DEBUG
:
123 "RWRAP_DEBUG(%d) - %s: %s\n",
126 case RWRAP_LOG_TRACE
:
128 "RWRAP_TRACE(%d) - %s: %s\n",
134 #endif /* NDEBUG RWRAP_LOG */
137 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
140 #define NEXT_KEY(buf, key) do { \
141 (key) = (buf) ? strpbrk((buf), " \t") : NULL; \
142 if ((key) != NULL) { \
146 while ((key) != NULL \
147 && (isblank((int)(key)[0]))) { \
152 #define RWRAP_MAX_RECURSION 5
154 /* Priority and weight can be omitted from the hosts file, but need to be part
157 #define DFL_SRV_PRIO 1
158 #define DFL_SRV_WEIGHT 100
160 struct rwrap_srv_rrdata
{
164 char hostname
[MAXDNAME
];
167 struct rwrap_soa_rrdata
{
173 char nameserver
[MAXDNAME
];
174 char mailbox
[MAXDNAME
];
177 struct rwrap_fake_rr
{
179 struct in_addr a_rec
;
180 struct in6_addr aaaa_rec
;
181 struct rwrap_srv_rrdata srv_rec
;
182 struct rwrap_soa_rrdata soa_rec
;
183 char cname_rec
[MAXDNAME
];
187 int type
; /* ns_t_* */
190 static void rwrap_fake_rr_init(struct rwrap_fake_rr
*rr
, size_t len
)
194 for (i
= 0; i
< len
; i
++) {
195 rr
[i
].type
= ns_t_invalid
;
199 static int rwrap_create_fake_a_rr(const char *key
,
201 struct rwrap_fake_rr
*rr
)
205 ok
= inet_pton(AF_INET
, value
, &rr
->rrdata
.a_rec
);
207 RWRAP_LOG(RWRAP_LOG_ERROR
,
208 "Failed to convert [%s] to binary\n", value
);
212 memcpy(rr
->key
, key
, strlen(key
) + 1);
217 static int rwrap_create_fake_aaaa_rr(const char *key
,
219 struct rwrap_fake_rr
*rr
)
223 ok
= inet_pton(AF_INET6
, value
, &rr
->rrdata
.aaaa_rec
);
225 RWRAP_LOG(RWRAP_LOG_ERROR
,
226 "Failed to convert [%s] to binary\n", value
);
230 memcpy(rr
->key
, key
, strlen(key
) + 1);
231 rr
->type
= ns_t_aaaa
;
234 static int rwrap_create_fake_ns_rr(const char *key
,
236 struct rwrap_fake_rr
*rr
)
238 memcpy(rr
->rrdata
.srv_rec
.hostname
, value
, strlen(value
) + 1);
239 memcpy(rr
->key
, key
, strlen(key
) + 1);
244 static int rwrap_create_fake_srv_rr(const char *key
,
246 struct rwrap_fake_rr
*rr
)
251 const char *hostname
;
253 /* parse the value into priority, weight, port and hostname
254 * and check the validity */
256 NEXT_KEY(hostname
, str_port
);
257 NEXT_KEY(str_port
, str_prio
);
258 NEXT_KEY(str_prio
, str_weight
);
259 if (str_port
== NULL
|| hostname
== NULL
) {
260 RWRAP_LOG(RWRAP_LOG_ERROR
,
261 "Malformed SRV entry [%s]\n", value
);
266 rr
->rrdata
.srv_rec
.prio
= atoi(str_prio
);
268 rr
->rrdata
.srv_rec
.prio
= DFL_SRV_PRIO
;
271 rr
->rrdata
.srv_rec
.weight
= atoi(str_weight
);
273 rr
->rrdata
.srv_rec
.weight
= DFL_SRV_WEIGHT
;
275 rr
->rrdata
.srv_rec
.port
= atoi(str_port
);
276 memcpy(rr
->rrdata
.srv_rec
.hostname
, hostname
, strlen(hostname
) + 1);
278 memcpy(rr
->key
, key
, strlen(key
) + 1);
283 static int rwrap_create_fake_soa_rr(const char *key
,
285 struct rwrap_fake_rr
*rr
)
287 const char *nameserver
;
295 /* parse the value into nameserver, mailbox, serial, refresh,
296 * retry, expire, minimum and check the validity
299 NEXT_KEY(nameserver
, mailbox
);
300 NEXT_KEY(mailbox
, str_serial
);
301 NEXT_KEY(str_serial
, str_refresh
);
302 NEXT_KEY(str_refresh
, str_retry
);
303 NEXT_KEY(str_retry
, str_expire
);
304 NEXT_KEY(str_expire
, str_minimum
);
305 if (nameserver
== NULL
|| mailbox
== NULL
|| str_serial
== NULL
||
306 str_refresh
== NULL
|| str_retry
== NULL
|| str_expire
== NULL
||
307 str_minimum
== NULL
) {
308 RWRAP_LOG(RWRAP_LOG_ERROR
,
309 "Malformed SOA entry [%s]\n", value
);
313 memcpy(rr
->rrdata
.soa_rec
.nameserver
, nameserver
, strlen(nameserver
)+1);
314 memcpy(rr
->rrdata
.soa_rec
.mailbox
, mailbox
, strlen(mailbox
)+1);
316 rr
->rrdata
.soa_rec
.serial
= atoi(str_serial
);
317 rr
->rrdata
.soa_rec
.refresh
= atoi(str_refresh
);
318 rr
->rrdata
.soa_rec
.retry
= atoi(str_retry
);
319 rr
->rrdata
.soa_rec
.expire
= atoi(str_expire
);
320 rr
->rrdata
.soa_rec
.minimum
= atoi(str_minimum
);
322 memcpy(rr
->key
, key
, strlen(key
) + 1);
327 static int rwrap_create_fake_cname_rr(const char *key
,
329 struct rwrap_fake_rr
*rr
)
331 memcpy(rr
->rrdata
.cname_rec
, value
, strlen(value
) + 1);
332 memcpy(rr
->key
, key
, strlen(key
) + 1);
333 rr
->type
= ns_t_cname
;
337 /* Prepares a fake header with a single response. Advances header_blob */
338 static ssize_t
rwrap_fake_header(uint8_t **header_blob
, size_t remaining
,
339 size_t ancount
, size_t arcount
)
344 if (remaining
< NS_HFIXEDSZ
) {
345 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
350 memset(hb
, 0, NS_HFIXEDSZ
);
353 h
->id
= res_randomid(); /* random query ID */
354 h
->qr
= 1; /* response flag */
355 h
->rd
= 1; /* recursion desired */
356 h
->ra
= 1; /* recursion available */
358 h
->qdcount
= htons(1); /* no. of questions */
359 h
->ancount
= htons(ancount
); /* no. of answers */
360 h
->arcount
= htons(arcount
); /* no. of add'tl records */
362 hb
+= NS_HFIXEDSZ
; /* move past the header */
368 static ssize_t
rwrap_fake_question(const char *question
,
370 uint8_t **question_ptr
,
373 uint8_t *qb
= *question_ptr
;
376 n
= ns_name_compress(question
, qb
, remaining
, NULL
, NULL
);
378 RWRAP_LOG(RWRAP_LOG_ERROR
,
379 "Failed to compress [%s]\n", question
);
386 if (remaining
< 2 * sizeof(uint16_t)) {
387 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small!\n");
392 NS_PUT16(ns_c_in
, qb
);
395 return n
+ 2 * sizeof(uint16_t);
398 static ssize_t
rwrap_fake_rdata_common(uint16_t type
,
404 uint8_t *rd
= *rdata_ptr
;
407 written
= ns_name_compress(key
, rd
, remaining
, NULL
, NULL
);
409 RWRAP_LOG(RWRAP_LOG_ERROR
,
410 "Failed to compress [%s]\n", key
);
414 remaining
-= written
;
416 if (remaining
< 3 * sizeof(uint16_t) + sizeof(uint32_t)) {
417 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
422 NS_PUT16(ns_c_in
, rd
);
423 NS_PUT32(RWRAP_DEFAULT_FAKE_TTL
, rd
);
424 NS_PUT16(rdata_size
, rd
);
426 if (remaining
< rdata_size
) {
427 RWRAP_LOG(RWRAP_LOG_ERROR
, "Buffer too small\n");
432 return written
+ 3 * sizeof(uint16_t) + sizeof(uint32_t) + rdata_size
;
435 static ssize_t
rwrap_fake_a(struct rwrap_fake_rr
*rr
,
439 uint8_t *a
= answer_ptr
;
442 if (rr
== NULL
|| rr
->type
!= ns_t_a
) {
443 RWRAP_LOG(RWRAP_LOG_ERROR
,
444 "Malformed record, no or wrong value!\n");
447 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding A RR");
449 resp_size
= rwrap_fake_rdata_common(ns_t_a
, sizeof(struct in_addr
), rr
->key
,
455 memcpy(a
, &rr
->rrdata
.a_rec
, sizeof(struct in_addr
));
460 static ssize_t
rwrap_fake_aaaa(struct rwrap_fake_rr
*rr
,
467 if (rr
== NULL
|| rr
->type
!= ns_t_aaaa
) {
468 RWRAP_LOG(RWRAP_LOG_ERROR
,
469 "Malformed record, no or wrong value!\n");
472 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding AAAA RR");
474 resp_size
= rwrap_fake_rdata_common(ns_t_aaaa
, sizeof(struct in6_addr
),
475 rr
->key
, anslen
, &a
);
480 memcpy(a
, &rr
->rrdata
.aaaa_rec
, sizeof(struct in6_addr
));
485 static ssize_t
rwrap_fake_ns(struct rwrap_fake_rr
*rr
,
490 ssize_t resp_size
= 0;
492 unsigned char hostname_compressed
[MAXDNAME
];
493 ssize_t compressed_len
;
495 if (rr
== NULL
|| rr
->type
!= ns_t_ns
) {
496 RWRAP_LOG(RWRAP_LOG_ERROR
,
497 "Malformed record, no or wrong value!\n");
500 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding NS RR");
502 /* Prepare the data to write */
503 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
508 if (compressed_len
< 0) {
512 /* Is this enough? */
513 rdata_size
= compressed_len
;
515 resp_size
= rwrap_fake_rdata_common(ns_t_ns
, rdata_size
,
516 rr
->key
, anslen
, &a
);
521 memcpy(a
, hostname_compressed
, compressed_len
);
526 static ssize_t
rwrap_fake_srv(struct rwrap_fake_rr
*rr
,
533 unsigned char hostname_compressed
[MAXDNAME
];
534 ssize_t compressed_len
;
536 if (rr
== NULL
|| rr
->type
!= ns_t_srv
) {
537 RWRAP_LOG(RWRAP_LOG_ERROR
,
538 "Malformed record, no or wrong value!\n");
541 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SRV RR");
542 rdata_size
= 3 * sizeof(uint16_t);
544 /* Prepare the data to write */
545 compressed_len
= ns_name_compress(rr
->rrdata
.srv_rec
.hostname
,
546 hostname_compressed
, MAXDNAME
,
548 if (compressed_len
< 0) {
551 rdata_size
+= compressed_len
;
553 resp_size
= rwrap_fake_rdata_common(ns_t_srv
, rdata_size
,
554 rr
->key
, anslen
, &a
);
559 NS_PUT16(rr
->rrdata
.srv_rec
.prio
, a
);
560 NS_PUT16(rr
->rrdata
.srv_rec
.weight
, a
);
561 NS_PUT16(rr
->rrdata
.srv_rec
.port
, a
);
562 memcpy(a
, hostname_compressed
, compressed_len
);
567 static ssize_t
rwrap_fake_soa(struct rwrap_fake_rr
*rr
,
574 unsigned char nameser_compressed
[MAXDNAME
];
575 ssize_t compressed_ns_len
;
576 unsigned char mailbox_compressed
[MAXDNAME
];
577 ssize_t compressed_mb_len
;
579 if (rr
== NULL
|| rr
->type
!= ns_t_soa
) {
580 RWRAP_LOG(RWRAP_LOG_ERROR
,
581 "Malformed record, no or wrong value!\n");
584 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding SOA RR");
585 rdata_size
= 5 * sizeof(uint16_t);
587 compressed_ns_len
= ns_name_compress(rr
->rrdata
.soa_rec
.nameserver
,
589 MAXDNAME
, NULL
, NULL
);
590 if (compressed_ns_len
< 0) {
593 rdata_size
+= compressed_ns_len
;
595 compressed_mb_len
= ns_name_compress(rr
->rrdata
.soa_rec
.mailbox
,
597 MAXDNAME
, NULL
, NULL
);
598 if (compressed_mb_len
< 0) {
601 rdata_size
+= compressed_mb_len
;
603 resp_size
= rwrap_fake_rdata_common(ns_t_soa
, rdata_size
,
604 rr
->key
, anslen
, &a
);
609 memcpy(a
, nameser_compressed
, compressed_ns_len
);
610 a
+= compressed_ns_len
;
611 memcpy(a
, mailbox_compressed
, compressed_mb_len
);
612 a
+= compressed_mb_len
;
613 NS_PUT32(rr
->rrdata
.soa_rec
.serial
, a
);
614 NS_PUT32(rr
->rrdata
.soa_rec
.refresh
, a
);
615 NS_PUT32(rr
->rrdata
.soa_rec
.retry
, a
);
616 NS_PUT32(rr
->rrdata
.soa_rec
.expire
, a
);
617 NS_PUT32(rr
->rrdata
.soa_rec
.minimum
, a
);
622 static ssize_t
rwrap_fake_cname(struct rwrap_fake_rr
*rr
,
628 unsigned char hostname_compressed
[MAXDNAME
];
631 if (rr
== NULL
|| rr
->type
!= ns_t_cname
) {
632 RWRAP_LOG(RWRAP_LOG_ERROR
,
633 "Malformed record, no or wrong value!\n");
636 RWRAP_LOG(RWRAP_LOG_TRACE
, "Adding CNAME RR");
638 /* Prepare the data to write */
639 rdata_size
= ns_name_compress(rr
->rrdata
.cname_rec
,
640 hostname_compressed
, MAXDNAME
,
642 if (rdata_size
< 0) {
646 resp_size
= rwrap_fake_rdata_common(ns_t_cname
, rdata_size
,
647 rr
->key
, anslen
, &a
);
652 memcpy(a
, hostname_compressed
, rdata_size
);
657 #define RESOLV_MATCH(line, name) \
658 (strncmp(line, name, sizeof(name) - 1) == 0 && \
659 (line[sizeof(name) - 1] == ' ' || \
660 line[sizeof(name) - 1] == '\t'))
662 #define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
663 ((type) == (ns_type) && \
664 (strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
665 (strcasecmp(key, query)) == 0)
668 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
669 const char *query
, int type
,
670 struct rwrap_fake_rr
*rr
);
672 static int rwrap_srv_recurse(const char *hostfile
, unsigned recursion
,
673 const char *query
, struct rwrap_fake_rr
*rr
)
677 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
678 if (rc
== 0) return 0;
680 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
681 if (rc
== ENOENT
) rc
= 0;
686 static int rwrap_cname_recurse(const char *hostfile
, unsigned recursion
,
687 const char *query
, struct rwrap_fake_rr
*rr
)
691 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_a
, rr
);
692 if (rc
== 0) return 0;
694 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_aaaa
, rr
);
695 if (rc
== 0) return 0;
697 rc
= rwrap_get_record(hostfile
, recursion
, query
, ns_t_cname
, rr
);
698 if (rc
== ENOENT
) rc
= 0;
703 static int rwrap_get_record(const char *hostfile
, unsigned recursion
,
704 const char *query
, int type
,
705 struct rwrap_fake_rr
*rr
)
713 if (recursion
>= RWRAP_MAX_RECURSION
) {
714 RWRAP_LOG(RWRAP_LOG_ERROR
, "Recursed too deep!\n");
718 RWRAP_LOG(RWRAP_LOG_TRACE
,
719 "Searching in fake hosts file %s for %s:%d\n", hostfile
,
722 fp
= fopen(hostfile
, "r");
724 RWRAP_LOG(RWRAP_LOG_ERROR
,
725 "Opening %s failed: %s",
726 hostfile
, strerror(errno
));
730 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
737 NEXT_KEY(rec_type
, key
);
738 NEXT_KEY(key
, value
);
740 if (key
== NULL
|| value
== NULL
) {
741 RWRAP_LOG(RWRAP_LOG_WARN
,
742 "Malformed line: not enough parts, use \"rec_type key data\n"
743 "For example \"A cwrap.org 10.10.10.10\"");
748 while(q
[0] != '\n' && q
[0] != '\0') {
753 if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "A", key
, query
)) {
754 rc
= rwrap_create_fake_a_rr(key
, value
, rr
);
756 } else if (TYPE_MATCH(type
, ns_t_aaaa
,
757 rec_type
, "AAAA", key
, query
)) {
758 rc
= rwrap_create_fake_aaaa_rr(key
, value
, rr
);
760 } else if (TYPE_MATCH(type
, ns_t_ns
,
761 rec_type
, "NS", key
, query
)) {
762 rc
= rwrap_create_fake_ns_rr(key
, value
, rr
);
764 } else if (TYPE_MATCH(type
, ns_t_srv
,
765 rec_type
, "SRV", key
, query
)) {
766 rc
= rwrap_create_fake_srv_rr(key
, value
, rr
);
768 rc
= rwrap_srv_recurse(hostfile
, recursion
+1,
769 rr
->rrdata
.srv_rec
.hostname
,
773 } else if (TYPE_MATCH(type
, ns_t_soa
,
774 rec_type
, "SOA", key
, query
)) {
775 rc
= rwrap_create_fake_soa_rr(key
, value
, rr
);
777 } else if (TYPE_MATCH(type
, ns_t_cname
,
778 rec_type
, "CNAME", key
, query
)) {
779 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
781 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
785 } else if (TYPE_MATCH(type
, ns_t_a
, rec_type
, "CNAME", key
, query
)) {
786 rc
= rwrap_create_fake_cname_rr(key
, value
, rr
);
788 rc
= rwrap_cname_recurse(hostfile
, recursion
+1,
795 if (rc
== ENOENT
&& recursion
== 0 && key
!= NULL
) {
796 RWRAP_LOG(RWRAP_LOG_TRACE
, "Record for [%s] not found\n", query
);
797 memcpy(rr
->key
, key
, strlen(key
) + 1);
804 static ssize_t
rwrap_fake_empty(int type
,
805 const char *question
,
810 size_t remaining
= anslen
;
812 resp_data
= rwrap_fake_header(&answer
, remaining
, 0, 0);
816 remaining
-= resp_data
;
818 resp_data
+= rwrap_fake_question(question
, type
, &answer
, remaining
);
822 remaining
-= resp_data
;
824 resp_data
+= rwrap_fake_rdata_common(type
, 0, question
,
833 static inline bool rwrap_known_type(int type
)
848 static int rwrap_ancount(struct rwrap_fake_rr
*rrs
, int qtype
)
853 /* Include all RRs in the stack until the sought type
854 * in the answer section. This is the case i.e. when looking
855 * up an A record but the name points to a CNAME
857 for (i
= 0; i
< RWRAP_MAX_RECURSION
; i
++) {
860 if (rwrap_known_type(rrs
[i
].type
) &&
861 rrs
[i
].type
== qtype
) {
866 /* Return 0 records if the sought type wasn't in the stack */
867 return i
< RWRAP_MAX_RECURSION
? ancount
: 0;
870 static int rwrap_arcount(struct rwrap_fake_rr
*rrs
, int ancount
)
875 /* start from index ancount */
876 for (i
= ancount
; i
< RWRAP_MAX_RECURSION
; i
++) {
877 if (rwrap_known_type(rrs
[i
].type
)) {
885 static ssize_t
rwrap_add_rr(struct rwrap_fake_rr
*rr
,
893 resp_data
= rwrap_fake_a(rr
, answer
, anslen
);
896 resp_data
= rwrap_fake_aaaa(rr
, answer
, anslen
);
899 resp_data
= rwrap_fake_ns(rr
, answer
, anslen
);
902 resp_data
= rwrap_fake_srv(rr
, answer
, anslen
);
905 resp_data
= rwrap_fake_soa(rr
, answer
, anslen
);
908 resp_data
= rwrap_fake_cname(rr
, answer
, anslen
);
917 static ssize_t
rwrap_fake_answer(struct rwrap_fake_rr
*rrs
,
925 size_t remaining
= anslen
;
930 ancount
= rwrap_ancount(rrs
, type
);
931 arcount
= rwrap_arcount(rrs
, ancount
);
932 RWRAP_LOG(RWRAP_LOG_TRACE
,
933 "Got %d answers and %d additional records\n", ancount
, arcount
);
935 resp_data
= rwrap_fake_header(&answer
, remaining
, ancount
, arcount
);
939 remaining
-= resp_data
;
941 resp_data
+= rwrap_fake_question(rrs
->key
, rrs
->type
, &answer
, remaining
);
945 remaining
-= resp_data
;
948 for (i
= 0; i
< ancount
; i
++) {
949 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
958 /* add authoritative NS here? */
960 /* additional records */
961 for (i
= ancount
; i
< ancount
+ arcount
; i
++) {
962 rrlen
= rwrap_add_rr(&rrs
[i
], answer
, remaining
);
974 /* Reads in a file in the following format:
977 * Malformed entries are silently skipped.
978 * Allocates answer buffer of size anslen that has to be freed after use.
980 static int rwrap_res_fake_hosts(const char *hostfile
,
983 unsigned char *answer
,
987 char *query_name
= NULL
;
988 size_t qlen
= strlen(query
);
989 struct rwrap_fake_rr rrs
[RWRAP_MAX_RECURSION
];
992 RWRAP_LOG(RWRAP_LOG_TRACE
,
993 "Searching in fake hosts file %s\n", hostfile
);
995 if (qlen
> 0 && query
[qlen
-1] == '.') {
999 query_name
= strndup(query
, qlen
);
1000 if (query_name
== NULL
) {
1004 rwrap_fake_rr_init(rrs
, RWRAP_MAX_RECURSION
);
1006 rc
= rwrap_get_record(hostfile
, 0, query_name
, type
, rrs
);
1009 RWRAP_LOG(RWRAP_LOG_TRACE
,
1010 "Found record for [%s]\n", query_name
);
1011 resp_size
= rwrap_fake_answer(rrs
, type
, answer
, anslen
);
1014 RWRAP_LOG(RWRAP_LOG_TRACE
,
1015 "No record for [%s]\n", query_name
);
1016 resp_size
= rwrap_fake_empty(type
, rrs
->key
, answer
, anslen
);
1019 RWRAP_LOG(RWRAP_LOG_ERROR
,
1020 "Error searching for [%s]\n", query_name
);
1025 switch (resp_size
) {
1027 RWRAP_LOG(RWRAP_LOG_ERROR
,
1028 "Error faking answer for [%s]\n", query_name
);
1031 RWRAP_LOG(RWRAP_LOG_TRACE
,
1032 "Successfully faked answer for [%s]\n",
1041 /*********************************************************
1042 * RWRAP LOADING LIBC FUNCTIONS
1043 *********************************************************/
1047 typedef int (*__libc_res_ninit
)(struct __res_state
*state
);
1048 typedef int (*__libc___res_ninit
)(struct __res_state
*state
);
1049 typedef void (*__libc_res_nclose
)(struct __res_state
*state
);
1050 typedef void (*__libc___res_nclose
)(struct __res_state
*state
);
1051 typedef int (*__libc_res_nquery
)(struct __res_state
*state
,
1055 unsigned char *answer
,
1057 typedef int (*__libc___res_nquery
)(struct __res_state
*state
,
1061 unsigned char *answer
,
1063 typedef int (*__libc_res_nsearch
)(struct __res_state
*state
,
1067 unsigned char *answer
,
1069 typedef int (*__libc___res_nsearch
)(struct __res_state
*state
,
1073 unsigned char *answer
,
1076 #define RWRAP_SYMBOL_ENTRY(i) \
1082 struct rwrap_libc_symbols
{
1083 RWRAP_SYMBOL_ENTRY(res_ninit
);
1084 RWRAP_SYMBOL_ENTRY(__res_ninit
);
1085 RWRAP_SYMBOL_ENTRY(res_nclose
);
1086 RWRAP_SYMBOL_ENTRY(__res_nclose
);
1087 RWRAP_SYMBOL_ENTRY(res_nquery
);
1088 RWRAP_SYMBOL_ENTRY(__res_nquery
);
1089 RWRAP_SYMBOL_ENTRY(res_nsearch
);
1090 RWRAP_SYMBOL_ENTRY(__res_nsearch
);
1092 #undef RWRAP_SYMBOL_ENTRY
1097 struct rwrap_libc_symbols symbols
;
1102 struct rwrap_libc_symbols symbols
;
1111 static struct rwrap rwrap
;
1119 static const char *rwrap_str_lib(enum rwrap_lib lib
)
1124 case RWRAP_LIBRESOLV
:
1128 /* Compiler would warn us about unhandled enum value if we get here */
1133 static void *rwrap_load_lib_handle(enum rwrap_lib lib
)
1135 int flags
= RTLD_LAZY
;
1136 void *handle
= NULL
;
1139 #ifdef RTLD_DEEPBIND
1140 flags
|= RTLD_DEEPBIND
;
1144 case RWRAP_LIBRESOLV
:
1145 #ifdef HAVE_LIBRESOLV
1146 handle
= rwrap
.libresolv
.handle
;
1147 if (handle
== NULL
) {
1148 for (i
= 10; i
>= 0; i
--) {
1149 char soname
[256] = {0};
1151 snprintf(soname
, sizeof(soname
), "libresolv.so.%d", i
);
1152 handle
= dlopen(soname
, flags
);
1153 if (handle
!= NULL
) {
1158 rwrap
.libresolv
.handle
= handle
;
1164 handle
= rwrap
.libc
.handle
;
1166 if (handle
== NULL
) {
1167 handle
= dlopen(LIBC_SO
, flags
);
1169 rwrap
.libc
.handle
= handle
;
1172 if (handle
== NULL
) {
1173 for (i
= 10; i
>= 0; i
--) {
1174 char soname
[256] = {0};
1176 snprintf(soname
, sizeof(soname
), "libc.so.%d", i
);
1177 handle
= dlopen(soname
, flags
);
1178 if (handle
!= NULL
) {
1183 rwrap
.libc
.handle
= handle
;
1188 if (handle
== NULL
) {
1190 handle
= rwrap
.libc
.handle
= rwrap
.libresolv
.handle
= RTLD_NEXT
;
1192 RWRAP_LOG(RWRAP_LOG_ERROR
,
1193 "Failed to dlopen library: %s\n",
1202 static void *_rwrap_bind_symbol(enum rwrap_lib lib
, const char *fn_name
)
1207 handle
= rwrap_load_lib_handle(lib
);
1209 func
= dlsym(handle
, fn_name
);
1211 RWRAP_LOG(RWRAP_LOG_ERROR
,
1212 "Failed to find %s: %s\n",
1213 fn_name
, dlerror());
1217 RWRAP_LOG(RWRAP_LOG_TRACE
,
1218 "Loaded %s from %s",
1219 fn_name
, rwrap_str_lib(lib
));
1223 #define rwrap_bind_symbol_libc(sym_name) \
1224 if (rwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
1225 rwrap.libc.symbols._libc_##sym_name.obj = \
1226 _rwrap_bind_symbol(RWRAP_LIBC, #sym_name); \
1229 #define rwrap_bind_symbol_libresolv(sym_name) \
1230 if (rwrap.libresolv.symbols._libc_##sym_name.obj == NULL) { \
1231 rwrap.libresolv.symbols._libc_##sym_name.obj = \
1232 _rwrap_bind_symbol(RWRAP_LIBRESOLV, #sym_name); \
1238 * Functions especially from libc need to be loaded individually, you can't load
1239 * all at once or gdb will segfault at startup. The same applies to valgrind and
1240 * has probably something todo with with the linker.
1241 * So we need load each function at the point it is called the first time.
1244 static int libc_res_ninit(struct __res_state
*state
)
1246 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1248 #if defined(HAVE_RES_NINIT_IN_LIBRESOLV)
1249 rwrap_bind_symbol_libresolv(res_ninit
);
1251 return rwrap
.libresolv
.symbols
._libc_res_ninit
.f(state
);
1252 #else /* HAVE_RES_NINIT_IN_LIBRESOLV */
1253 rwrap_bind_symbol_libc(res_ninit
);
1255 return rwrap
.libc
.symbols
._libc_res_ninit
.f(state
);
1256 #endif /* HAVE_RES_NINIT_IN_LIBRESOLV */
1258 #elif defined(HAVE___RES_NINIT)
1259 rwrap_bind_symbol_libc(__res_ninit
);
1261 return rwrap
.libc
.symbols
._libc___res_ninit
.f(state
);
1263 #error "No res_ninit function"
1267 static void libc_res_nclose(struct __res_state
*state
)
1269 #if !defined(res_close) && defined(HAVE_RES_NCLOSE)
1271 #if defined(HAVE_RES_NCLOSE_IN_LIBRESOLV)
1272 rwrap_bind_symbol_libresolv(res_nclose
);
1274 rwrap
.libresolv
.symbols
._libc_res_nclose
.f(state
);
1276 #else /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1277 rwrap_bind_symbol_libc(res_nclose
);
1279 rwrap
.libc
.symbols
._libc_res_nclose
.f(state
);
1281 #endif /* HAVE_RES_NCLOSE_IN_LIBRESOLV */
1283 #elif defined(HAVE___RES_NCLOSE)
1284 rwrap_bind_symbol_libc(__res_nclose
);
1286 rwrap
.libc
.symbols
._libc___res_nclose
.f(state
);
1288 #error "No res_nclose function"
1292 static int libc_res_nquery(struct __res_state
*state
,
1296 unsigned char *answer
,
1299 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1300 rwrap_bind_symbol_libresolv(res_nquery
);
1302 return rwrap
.libresolv
.symbols
._libc_res_nquery
.f(state
,
1308 #elif defined(HAVE___RES_NQUERY)
1309 rwrap_bind_symbol_libresolv(__res_nquery
);
1311 return rwrap
.libresolv
.symbols
._libc___res_nquery
.f(state
,
1318 #error "No res_nquery function"
1322 static int libc_res_nsearch(struct __res_state
*state
,
1326 unsigned char *answer
,
1329 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1330 rwrap_bind_symbol_libresolv(res_nsearch
);
1332 return rwrap
.libresolv
.symbols
._libc_res_nsearch
.f(state
,
1338 #elif defined(HAVE___RES_NSEARCH)
1339 rwrap_bind_symbol_libresolv(__res_nsearch
);
1341 return rwrap
.libresolv
.symbols
._libc___res_nsearch
.f(state
,
1348 #error "No res_nsearch function"
1352 /****************************************************************************
1354 ***************************************************************************/
1356 static int rwrap_parse_resolv_conf(struct __res_state
*state
,
1357 const char *resolv_conf
)
1363 fp
= fopen(resolv_conf
, "r");
1365 RWRAP_LOG(RWRAP_LOG_ERROR
,
1366 "Opening %s failed: %s",
1367 resolv_conf
, strerror(errno
));
1371 while(fgets(buf
, sizeof(buf
), fp
) != NULL
) {
1374 /* Ignore comments */
1375 if (buf
[0] == '#' || buf
[0] == ';') {
1379 if (RESOLV_MATCH(buf
, "nameserver") && nserv
< MAXNS
) {
1384 p
= buf
+ strlen("nameserver");
1386 /* Skip spaces and tabs */
1387 while(isblank((int)p
[0])) {
1392 while(q
[0] != '\n' && q
[0] != '\0') {
1397 ok
= inet_pton(AF_INET
, p
, &a
);
1399 state
->nsaddr_list
[state
->nscount
] = (struct sockaddr_in
) {
1400 .sin_family
= AF_INET
,
1402 .sin_port
= htons(53),
1409 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1412 ok
= inet_pton(AF_INET6
, p
, &a6
);
1414 struct sockaddr_in6
*sa6
;
1416 sa6
= malloc(sizeof(*sa6
));
1422 sa6
->sin6_family
= AF_INET6
;
1423 sa6
->sin6_port
= htons(53);
1424 sa6
->sin6_flowinfo
= 0;
1425 sa6
->sin6_addr
= a6
;
1427 state
->_u
._ext
.nsaddrs
[state
->_u
._ext
.nscount
] = sa6
;
1428 state
->_u
._ext
.nssocks
[state
->_u
._ext
.nscount
] = -1;
1429 state
->_u
._ext
.nsmap
[state
->_u
._ext
.nscount
] = MAXNS
+ 1;
1431 state
->_u
._ext
.nscount
++;
1434 RWRAP_LOG(RWRAP_LOG_ERROR
,
1435 "Malformed DNS server");
1438 #else /* !HAVE_RESOLV_IPV6_NSADDRS */
1440 * BSD uses an opaque structure to store the
1441 * IPv6 addresses. So we can not simply store
1442 * these addresses the same way as above.
1444 RWRAP_LOG(RWRAP_LOG_WARN
,
1445 "resolve_wrapper does not support "
1446 "IPv6 on this platform");
1451 } /* TODO: match other keywords */
1455 RWRAP_LOG(RWRAP_LOG_ERROR
,
1456 "Reading from %s failed",
1466 /****************************************************************************
1468 ***************************************************************************/
1470 static int rwrap_res_ninit(struct __res_state
*state
)
1474 rc
= libc_res_ninit(state
);
1476 const char *resolv_conf
= getenv("RESOLV_WRAPPER_CONF");
1478 if (resolv_conf
!= NULL
) {
1481 (void)i
; /* maybe unused */
1483 /* Delete name servers */
1485 memset(state
->nsaddr_list
, 0, sizeof(state
->nsaddr_list
));
1487 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1488 state
->_u
._ext
.nscount
= 0;
1489 for (i
= 0; i
< state
->_u
._ext
.nscount
; i
++) {
1490 SAFE_FREE(state
->_u
._ext
.nsaddrs
[i
]);
1494 rc
= rwrap_parse_resolv_conf(state
, resolv_conf
);
1501 #if !defined(res_ninit) && defined(HAVE_RES_NINIT)
1502 int res_ninit(struct __res_state
*state
)
1503 #elif defined(HAVE___RES_NINIT)
1504 int __res_ninit(struct __res_state
*state
)
1507 return rwrap_res_ninit(state
);
1510 /****************************************************************************
1512 ***************************************************************************/
1514 static struct __res_state rwrap_res_state
;
1516 static int rwrap_res_init(void)
1520 rc
= rwrap_res_ninit(&rwrap_res_state
);
1525 #if !defined(res_ninit) && defined(HAVE_RES_INIT)
1527 #elif defined(HAVE___RES_INIT)
1528 int __res_init(void)
1531 return rwrap_res_init();
1534 /****************************************************************************
1536 ***************************************************************************/
1538 static void rwrap_res_nclose(struct __res_state
*state
)
1540 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1544 libc_res_nclose(state
);
1546 #ifdef HAVE_RESOLV_IPV6_NSADDRS
1547 if (state
!= NULL
) {
1548 for (i
= 0; i
< state
->_u
._ext
.nscount
; i
++) {
1549 SAFE_FREE(state
->_u
._ext
.nsaddrs
[i
]);
1555 #if !defined(res_nclose) && defined(HAVE_RES_NCLOSE)
1556 void res_nclose(struct __res_state
*state
)
1557 #elif defined(HAVE___RES_NCLOSE)
1558 void __res_nclose(struct __res_state
*state
)
1561 rwrap_res_nclose(state
);
1564 /****************************************************************************
1566 ***************************************************************************/
1568 static void rwrap_res_close(void)
1570 rwrap_res_nclose(&rwrap_res_state
);
1573 #if defined(HAVE_RES_CLOSE)
1574 void res_close(void)
1575 #elif defined(HAVE___RES_CLOSE)
1576 void __res_close(void)
1582 /****************************************************************************
1584 ***************************************************************************/
1586 static int rwrap_res_nquery(struct __res_state
*state
,
1590 unsigned char *answer
,
1594 const char *fake_hosts
;
1599 RWRAP_LOG(RWRAP_LOG_TRACE
,
1600 "Resolve the domain name [%s] - class=%d, type=%d",
1601 dname
, class, type
);
1603 for (i
= 0; i
< state
->nscount
; i
++) {
1604 char ip
[INET6_ADDRSTRLEN
];
1606 inet_ntop(AF_INET
, &state
->nsaddr_list
[i
].sin_addr
, ip
, sizeof(ip
));
1607 RWRAP_LOG(RWRAP_LOG_TRACE
,
1613 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
1614 if (fake_hosts
!= NULL
) {
1615 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
1617 rc
= libc_res_nquery(state
, dname
, class, type
, answer
, anslen
);
1621 RWRAP_LOG(RWRAP_LOG_TRACE
,
1622 "The returned response length is: %d",
1628 #if !defined(res_nquery) && defined(HAVE_RES_NQUERY)
1629 int res_nquery(struct __res_state
*state
,
1633 unsigned char *answer
,
1635 #elif defined(HAVE___RES_NQUERY)
1636 int __res_nquery(struct __res_state
*state
,
1640 unsigned char *answer
,
1644 return rwrap_res_nquery(state
, dname
, class, type
, answer
, anslen
);
1647 /****************************************************************************
1649 ***************************************************************************/
1651 static int rwrap_res_query(const char *dname
,
1654 unsigned char *answer
,
1659 rc
= rwrap_res_ninit(&rwrap_res_state
);
1664 rc
= rwrap_res_nquery(&rwrap_res_state
,
1674 #if !defined(res_query) && defined(HAVE_RES_QUERY)
1675 int res_query(const char *dname
,
1678 unsigned char *answer
,
1680 #elif defined(HAVE___RES_QUERY)
1681 int __res_query(const char *dname
,
1684 unsigned char *answer
,
1688 return rwrap_res_query(dname
, class, type
, answer
, anslen
);
1691 /****************************************************************************
1693 ***************************************************************************/
1695 static int rwrap_res_nsearch(struct __res_state
*state
,
1699 unsigned char *answer
,
1703 const char *fake_hosts
;
1708 RWRAP_LOG(RWRAP_LOG_TRACE
,
1709 "Resolve the domain name [%s] - class=%d, type=%d",
1710 dname
, class, type
);
1712 for (i
= 0; i
< state
->nscount
; i
++) {
1713 char ip
[INET6_ADDRSTRLEN
];
1715 inet_ntop(AF_INET
, &state
->nsaddr_list
[i
].sin_addr
, ip
, sizeof(ip
));
1716 RWRAP_LOG(RWRAP_LOG_TRACE
,
1722 fake_hosts
= getenv("RESOLV_WRAPPER_HOSTS");
1723 if (fake_hosts
!= NULL
) {
1724 rc
= rwrap_res_fake_hosts(fake_hosts
, dname
, type
, answer
, anslen
);
1726 rc
= libc_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
1729 RWRAP_LOG(RWRAP_LOG_TRACE
,
1730 "The returned response length is: %d",
1736 #if !defined(res_nsearch) && defined(HAVE_RES_NSEARCH)
1737 int res_nsearch(struct __res_state
*state
,
1741 unsigned char *answer
,
1743 #elif defined(HAVE___RES_NSEARCH)
1744 int __res_nsearch(struct __res_state
*state
,
1748 unsigned char *answer
,
1752 return rwrap_res_nsearch(state
, dname
, class, type
, answer
, anslen
);
1755 /****************************************************************************
1757 ***************************************************************************/
1759 static int rwrap_res_search(const char *dname
,
1762 unsigned char *answer
,
1767 rc
= rwrap_res_ninit(&rwrap_res_state
);
1772 rc
= rwrap_res_nsearch(&rwrap_res_state
,
1782 #if !defined(res_search) && defined(HAVE_RES_SEARCH)
1783 int res_search(const char *dname
,
1786 unsigned char *answer
,
1788 #elif defined(HAVE___RES_SEARCH)
1789 int __res_search(const char *dname
,
1792 unsigned char *answer
,
1796 return rwrap_res_search(dname
, class, type
, answer
, anslen
);