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