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