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