1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 /*! \file */
13 
14 /**
15  *    These functions perform thread safe, protocol independent
16  *    nodename-to-address and address-to-nodename translation as defined in
17  *    RFC2553.  This use a struct hostent which is defined in namedb.h:
18  *
19  * \code
20  * struct  hostent {
21  *         char    *h_name;        // official name of host
22  *         char    **h_aliases;    // alias list
23  *         int     h_addrtype;     // host address type
24  *         int     h_length;       // length of address
25  *         char    **h_addr_list;  // list of addresses from name server
26  * };
27  * #define h_addr  h_addr_list[0]  // address, for backward compatibility
28  * \endcode
29  *
30  *    The members of this structure are:
31  *
32  * \li   h_name:
33  *           The official (canonical) name of the host.
34  *
35  * \li   h_aliases:
36  *           A NULL-terminated array of alternate names (nicknames) for the
37  *           host.
38  *
39  * \li   h_addrtype:
40  *           The type of address being returned - usually PF_INET or
41  *           PF_INET6.
42  *
43  * \li   h_length:
44  *           The length of the address in bytes.
45  *
46  * \li   h_addr_list:
47  *           A NULL terminated array of network addresses for the host. Host
48  *           addresses are returned in network byte order.
49  *
50  *    lwres_getipnodebyname() looks up addresses of protocol family af for
51  *    the hostname name. The flags parameter contains ORed flag bits to
52  *    specify the types of addresses that are searched for, and the types of
53  *    addresses that are returned. The flag bits are:
54  *
55  * \li   #AI_V4MAPPED:
56  *           This is used with an af of #AF_INET6, and causes IPv4 addresses
57  *           to be returned as IPv4-mapped IPv6 addresses.
58  *
59  * \li   #AI_ALL:
60  *           This is used with an af of #AF_INET6, and causes all known
61  *           addresses (IPv6 and IPv4) to be returned. If #AI_V4MAPPED is
62  *           also set, the IPv4 addresses are return as mapped IPv6
63  *           addresses.
64  *
65  * \li   #AI_ADDRCONFIG:
66  *           Only return an IPv6 or IPv4 address if here is an active
67  *           network interface of that type. This is not currently
68  *           implemented in the BIND 9 lightweight resolver, and the flag is
69  *           ignored.
70  *
71  * \li   #AI_DEFAULT:
72  *           This default sets the #AI_V4MAPPED and #AI_ADDRCONFIG flag bits.
73  *
74  *    lwres_getipnodebyaddr() performs a reverse lookup of address src which
75  *    is len bytes long. af denotes the protocol family, typically PF_INET
76  *    or PF_INET6.
77  *
78  *    lwres_freehostent() releases all the memory associated with the struct
79  *    hostent pointer. Any memory allocated for the h_name, h_addr_list
80  *    and h_aliases is freed, as is the memory for the hostent structure
81  *    itself.
82  *
83  * \section getipnode_return Return Values
84  *
85  *    If an error occurs, lwres_getipnodebyname() and
86  *    lwres_getipnodebyaddr() set *error_num to an appropriate error code
87  *    and the function returns a NULL pointer. The error codes and their
88  *    meanings are defined in \link netdb.h <lwres/netdb.h>\endlink:
89  *
90  * \li   #HOST_NOT_FOUND:
91  *           No such host is known.
92  *
93  * \li   #NO_ADDRESS:
94  *           The server recognised the request and the name but no address
95  *           is available. Another type of request to the name server for
96  *           the domain might return an answer.
97  *
98  * \li   #TRY_AGAIN:
99  *           A temporary and possibly transient error occurred, such as a
100  *           failure of a server to respond. The request may succeed if
101  *           retried.
102  *
103  * \li   #NO_RECOVERY:
104  *           An unexpected failure occurred, and retrying the request is
105  *           pointless.
106  *
107  *    lwres_hstrerror() translates these error codes to suitable error
108  *    messages.
109  *
110  * \section getipnode_see See Also
111  *
112  * getaddrinfo.c, gethost.c, getnameinfo.c, herror.c, RFC2553
113  */
114 
115 #include <config.h>
116 
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <errno.h>
121 
122 #include <lwres/lwres.h>
123 #include <lwres/net.h>
124 #include <lwres/netdb.h>	/* XXX #include <netdb.h> */
125 
126 #include "assert_p.h"
127 #include "unreachable_p.h"
128 
129 #ifndef INADDRSZ
130 #define INADDRSZ 4
131 #endif
132 #ifndef IN6ADDRSZ
133 #define IN6ADDRSZ 16
134 #endif
135 
136 #ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
137 LIBLWRES_EXTERNAL_DATA const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
138 #endif
139 
140 #ifndef IN6_IS_ADDR_V4COMPAT
141 static const unsigned char in6addr_compat[12] = {
142 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
143 };
144 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
145 				 ((x)->s6_addr[12] != 0 || \
146 				  (x)->s6_addr[13] != 0 || \
147 				  (x)->s6_addr[14] != 0 || \
148 				   ((x)->s6_addr[15] != 0 && \
149 				    (x)->s6_addr[15] != 1)))
150 #endif
151 #ifndef IN6_IS_ADDR_V4MAPPED
152 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
153 #endif
154 
155 static const unsigned char in6addr_mapped[12] = {
156 	0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0xff, 0xff
157 };
158 
159 /***
160  ***	Forward declarations.
161  ***/
162 
163 static int
164 scan_interfaces(int *, int *);
165 
166 static struct hostent *
167 copyandmerge(struct hostent *, struct hostent *, int, int *);
168 
169 static struct hostent *
170 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src);
171 
172 static struct hostent *
173 hostfromname(lwres_gabnresponse_t *name, int af);
174 
175 /***
176  ***	Public functions.
177  ***/
178 
179 /*!
180  *	AI_V4MAPPED + AF_INET6
181  *	If no IPv6 address then a query for IPv4 and map returned values.
182  *
183  *	AI_ALL + AI_V4MAPPED + AF_INET6
184  *	Return IPv6 and IPv4 mapped.
185  *
186  *	AI_ADDRCONFIG
187  *	Only return IPv6 / IPv4 address if there is an interface of that
188  *	type active.
189  */
190 
191 struct hostent *
lwres_getipnodebyname(const char * name,int af,int flags,int * error_num)192 lwres_getipnodebyname(const char *name, int af, int flags, int *error_num) {
193 	int have_v4 = 1, have_v6 = 1;
194 	struct in_addr in4;
195 	struct in6_addr in6;
196 	struct hostent he, *he1 = NULL, *he2 = NULL, *he3 = NULL;
197 	int v4 = 0, v6 = 0;
198 	int tmp_err = 0;
199 	lwres_context_t *lwrctx = NULL;
200 	lwres_gabnresponse_t *by = NULL;
201 	int n;
202 
203 	/*
204 	 * If we care about active interfaces then check.
205 	 */
206 	if ((flags & AI_ADDRCONFIG) != 0)
207 		if (scan_interfaces(&have_v4, &have_v6) == -1) {
208 			*error_num = NO_RECOVERY;
209 			return (NULL);
210 		}
211 
212 	/* Check for literal address. */
213 	if ((v4 = lwres_net_pton(AF_INET, name, &in4)) != 1)
214 		v6 = lwres_net_pton(AF_INET6, name, &in6);
215 
216 	/*
217 	 * Impossible combination?
218 	 */
219 	if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
220 	    (af == AF_INET && v6 == 1) ||
221 	    (have_v4 == 0 && v4 == 1) ||
222 	    (have_v6 == 0 && v6 == 1) ||
223 	    (have_v4 == 0 && af == AF_INET) ||
224 	    (have_v6 == 0 && af == AF_INET6 &&
225 	     (((flags & AI_V4MAPPED) != 0 && have_v4) ||
226 	      (flags & AI_V4MAPPED) == 0))) {
227 		*error_num = HOST_NOT_FOUND;
228 		return (NULL);
229 	}
230 
231 	/*
232 	 * Literal address?
233 	 */
234 	if (v4 == 1 || v6 == 1) {
235 		char *addr_list[2];
236 		char *aliases[1];
237 		char mappedname[sizeof("::ffff:123.123.123.123")];
238 		union {
239 			const char *const_name;
240 			char *deconst_name;
241 		} u;
242 
243 		/* cppcheck-suppress unreadVariable */
244 		u.const_name = name;
245 		if (v4 == 1 && af == AF_INET6) {
246 			strcpy(mappedname, "::ffff:");
247 			lwres_net_ntop(AF_INET, (char *)&in4,
248 				       mappedname + sizeof("::ffff:") - 1,
249 				       sizeof(mappedname) - sizeof("::ffff:")
250 				       + 1);
251 			he.h_name = mappedname;
252 		} else
253 			he.h_name = u.deconst_name;
254 		he.h_addr_list = addr_list;
255 		he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
256 		he.h_addr_list[1] = NULL;
257 		he.h_aliases = aliases;
258 		he.h_aliases[0] = NULL;
259 		he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
260 		he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
261 		return (copyandmerge(&he, NULL, af, error_num));
262 	}
263 
264 	n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
265 	if (n != 0) {
266 		*error_num = NO_RECOVERY;
267 		goto cleanup;
268 	}
269 	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
270 	tmp_err = NO_RECOVERY;
271 	if (have_v6 && af == AF_INET6) {
272 		n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V6, &by);
273 		if (n == 0) {
274 			he1 = hostfromname(by, AF_INET6);
275 			lwres_gabnresponse_free(lwrctx, &by);
276 			if (he1 == NULL) {
277 				*error_num = NO_RECOVERY;
278 				goto cleanup;
279 			}
280 		} else {
281 			if (n == LWRES_R_NOTFOUND)
282 				tmp_err = HOST_NOT_FOUND;
283 			else {
284 				*error_num = NO_RECOVERY;
285 				goto cleanup;
286 			}
287 		}
288 	}
289 
290 	if (have_v4 &&
291 	    ((af == AF_INET) ||
292 	     (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
293 	      (he1 == NULL || (flags & AI_ALL) != 0)))) {
294 		n = lwres_getaddrsbyname(lwrctx, name, LWRES_ADDRTYPE_V4, &by);
295 		if (n == 0) {
296 			he2 = hostfromname(by, AF_INET);
297 			lwres_gabnresponse_free(lwrctx, &by);
298 			if (he2 == NULL) {
299 				*error_num = NO_RECOVERY;
300 				goto cleanup;
301 			}
302 		} else if (he1 == NULL) {
303 			if (n == LWRES_R_NOTFOUND)
304 				*error_num = HOST_NOT_FOUND;
305 			else
306 				*error_num = NO_RECOVERY;
307 			goto cleanup;
308 		}
309 	} else
310 		*error_num = tmp_err;
311 
312 	he3 = copyandmerge(he1, he2, af, error_num);
313 
314  cleanup:
315 	if (he1 != NULL)
316 		lwres_freehostent(he1);
317 	if (he2 != NULL)
318 		lwres_freehostent(he2);
319 	if (lwrctx != NULL) {
320 		lwres_conf_clear(lwrctx);
321 		lwres_context_destroy(&lwrctx);
322 	}
323 	return (he3);
324 }
325 
326 /*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
327 struct hostent *
lwres_getipnodebyaddr(const void * src,size_t len,int af,int * error_num)328 lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
329 	struct hostent *he1, *he2;
330 	lwres_context_t *lwrctx = NULL;
331 	lwres_gnbaresponse_t *by = NULL;
332 	lwres_result_t n;
333 	union {
334 		const void *konst;
335 		struct in6_addr *in6;
336 	} u;
337 
338 	/*
339 	 * Sanity checks.
340 	 */
341 	if (src == NULL) {
342 		*error_num = NO_RECOVERY;
343 		return (NULL);
344 	}
345 
346 	switch (af) {
347 	case AF_INET:
348 		if (len != (unsigned int)INADDRSZ) {
349 			*error_num = NO_RECOVERY;
350 			return (NULL);
351 		}
352 		break;
353 	case AF_INET6:
354 		if (len != (unsigned int)IN6ADDRSZ) {
355 			*error_num = NO_RECOVERY;
356 			return (NULL);
357 		}
358 		break;
359 	default:
360 		*error_num = NO_RECOVERY;
361 		return (NULL);
362 	}
363 
364 	/*
365 	 * The de-"const"-ing game is done because at least one
366 	 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
367 	 * macros in such a way that they discard the const with
368 	 * internal casting, and gcc ends up complaining.  Rather
369 	 * than replacing their own (possibly optimized) definitions
370 	 * with our own, cleanly discarding the const is the easiest
371 	 * thing to do.
372 	 */
373 	/* cppcheck-suppress unreadVariable */
374 	u.konst = src;
375 
376 	/*
377 	 * Look up IPv4 and IPv4 mapped/compatible addresses.
378 	 */
379 	if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
380 	    (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
381 	    (af == AF_INET)) {
382 		const unsigned char *cp = src;
383 
384 		if (af == AF_INET6)
385 			cp += 12;
386 		n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
387 		if (n == LWRES_R_SUCCESS) {
388 			(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
389 
390 			n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
391 						INADDRSZ, cp, &by);
392 		}
393 		if (n != LWRES_R_SUCCESS) {
394 			lwres_conf_clear(lwrctx);
395 			lwres_context_destroy(&lwrctx);
396 			if (n == LWRES_R_NOTFOUND)
397 				*error_num = HOST_NOT_FOUND;
398 			else
399 				*error_num = NO_RECOVERY;
400 			return (NULL);
401 		}
402 		he1 = hostfromaddr(by, AF_INET, cp);
403 		lwres_gnbaresponse_free(lwrctx, &by);
404 		lwres_conf_clear(lwrctx);
405 		lwres_context_destroy(&lwrctx);
406 		if (af != AF_INET6)
407 			return (he1);
408 
409 		/*
410 		 * Convert from AF_INET to AF_INET6.
411 		 */
412 		he2 = copyandmerge(he1, NULL, af, error_num);
413 		lwres_freehostent(he1);
414 		if (he2 == NULL)
415 			return (NULL);
416 		/*
417 		 * Restore original address.
418 		 */
419 		memmove(he2->h_addr, src, len);
420 		return (he2);
421 	}
422 
423 	/*
424 	 * Lookup IPv6 address.
425 	 */
426 	if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
427 		*error_num = HOST_NOT_FOUND;
428 		return (NULL);
429 	}
430 
431 	n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
432 	if (n == LWRES_R_SUCCESS) {
433 		(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
434 		n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
435 					src, &by);
436 	}
437 	if (n != 0) {
438 		lwres_conf_clear(lwrctx);
439 		lwres_context_destroy(&lwrctx);
440 
441 		if (n == LWRES_R_NOTFOUND)
442 		       *error_num = HOST_NOT_FOUND;
443 		else
444 		       *error_num = NO_RECOVERY;
445 
446 		return (NULL);
447 	}
448 
449 	he1 = hostfromaddr(by, AF_INET6, src);
450 	lwres_gnbaresponse_free(lwrctx, &by);
451 	if (he1 == NULL)
452 		*error_num = NO_RECOVERY;
453 	lwres_conf_clear(lwrctx);
454 	lwres_context_destroy(&lwrctx);
455 	return (he1);
456 }
457 
458 /*% releases all the memory associated with the struct hostent pointer */
459 void
lwres_freehostent(struct hostent * he)460 lwres_freehostent(struct hostent *he) {
461 	char **cpp;
462 	int names = 1;
463 	int addresses = 1;
464 
465 	if (he == NULL)
466 		return;
467 
468 	free(he->h_name);
469 
470 	cpp = he->h_addr_list;
471 	while (*cpp != NULL) {
472 		free(*cpp);
473 		*cpp = NULL;
474 		cpp++;
475 		addresses++;
476 	}
477 
478 	cpp = he->h_aliases;
479 	while (*cpp != NULL) {
480 		free(*cpp);
481 		cpp++;
482 		names++;
483 	}
484 
485 	free(he->h_aliases);
486 	free(he->h_addr_list);
487 	free(he);
488 }
489 
490 /*
491  * Private
492  */
493 
494 /*
495  * Scan the interface table and set have_v4 and have_v6 depending
496  * upon whether there are IPv4 and IPv6 interface addresses.
497  *
498  * Returns:
499  *	0 on success
500  *	-1 on failure.
501  */
502 
503 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
504     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
505 
506 #ifdef __hpux
507 #define lifc_len iflc_len
508 #define lifc_buf iflc_buf
509 #define lifc_req iflc_req
510 #define LIFCONF if_laddrconf
511 #else
512 #define ISC_HAVE_LIFC_FAMILY 1
513 #define ISC_HAVE_LIFC_FLAGS 1
514 #define LIFCONF lifconf
515 #endif
516 
517 #ifdef __hpux
518 #define lifr_addr iflr_addr
519 #define lifr_name iflr_name
520 #define lifr_dstaddr iflr_dstaddr
521 #define lifr_flags iflr_flags
522 #define ss_family sa_family
523 #define LIFREQ if_laddrreq
524 #else
525 #define LIFREQ lifreq
526 #endif
527 
528 static int
scan_interfaces6(int * have_v4,int * have_v6)529 scan_interfaces6(int *have_v4, int *have_v6) {
530 	struct LIFCONF lifc;
531 	struct LIFREQ lifreq;
532 	struct in_addr in4;
533 	struct in6_addr in6;
534 	char *buf = NULL, *cp, *cplim;
535 	static unsigned int bufsiz = 4095;
536 	int s, cpsize, n;
537 
538 	/*
539 	 * Set to zero.  Used as loop terminators below.
540 	 */
541 	*have_v4 = *have_v6 = 0;
542 
543 	/*
544 	 * Get interface list from system.
545 	 */
546 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
547 		goto err_ret;
548 
549 	/*
550 	 * Grow buffer until large enough to contain all interface
551 	 * descriptions.
552 	 */
553 	for (;;) {
554 		buf = malloc(bufsiz);
555 		if (buf == NULL)
556 			goto err_ret;
557 #ifdef ISC_HAVE_LIFC_FAMILY
558 		lifc.lifc_family = AF_UNSPEC;	/* request all families */
559 #endif
560 #ifdef ISC_HAVE_LIFC_FLAGS
561 		lifc.lifc_flags = 0;
562 #endif
563 		lifc.lifc_len = bufsiz;
564 		lifc.lifc_buf = buf;
565 		if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
566 			/*
567 			 * Some OS's just return what will fit rather
568 			 * than set EINVAL if the buffer is too small
569 			 * to fit all the interfaces in.  If
570 			 * lifc.lifc_len is too near to the end of the
571 			 * buffer we will grow it just in case and
572 			 * retry.
573 			 */
574 			if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
575 				break;
576 		}
577 		if ((n == -1) && errno != EINVAL)
578 			goto err_ret;
579 
580 		if (bufsiz > 1000000)
581 			goto err_ret;
582 
583 		free(buf);
584 		bufsiz += 4096;
585 	}
586 
587 	/*
588 	 * Parse system's interface list.
589 	 */
590 	cplim = buf + lifc.lifc_len;    /* skip over if's with big ifr_addr's */
591 	for (cp = buf;
592 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
593 	     cp += cpsize) {
594 		memmove(&lifreq, cp, sizeof(lifreq));
595 #ifdef LWRES_PLATFORM_HAVESALEN
596 #ifdef FIX_ZERO_SA_LEN
597 		if (lifreq.lifr_addr.sa_len == 0)
598 			lifreq.lifr_addr.sa_len = 16;
599 #endif
600 #ifdef HAVE_MINIMUM_IFREQ
601 		cpsize = sizeof(lifreq);
602 		if (lifreq.lifr_addr.sa_len > sizeof(struct sockaddr))
603 			cpsize += (int)lifreq.lifr_addr.sa_len -
604 				(int)(sizeof(struct sockaddr));
605 #else
606 		cpsize = sizeof(lifreq.lifr_name) + lifreq.lifr_addr.sa_len;
607 #endif /* HAVE_MINIMUM_IFREQ */
608 #elif defined SIOCGIFCONF_ADDR
609 		cpsize = sizeof(lifreq);
610 #else
611 		cpsize = sizeof(lifreq.lifr_name);
612 		/* XXX maybe this should be a hard error? */
613 		if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
614 			continue;
615 #endif
616 		switch (lifreq.lifr_addr.ss_family) {
617 		case AF_INET:
618 			if (*have_v4 == 0) {
619 				memmove(&in4,
620 					&((struct sockaddr_in *)
621 					  &lifreq.lifr_addr)->sin_addr,
622 					sizeof(in4));
623 				if (in4.s_addr == INADDR_ANY)
624 					break;
625 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
626 				if (n < 0)
627 					break;
628 				if ((lifreq.lifr_flags & IFF_UP) == 0)
629 					break;
630 				*have_v4 = 1;
631 			}
632 			break;
633 		case AF_INET6:
634 			if (*have_v6 == 0) {
635 				memmove(&in6,
636 					&((struct sockaddr_in6 *)
637 					  &lifreq.lifr_addr)->sin6_addr,
638 					sizeof(in6));
639 				if (memcmp(&in6, &in6addr_any,
640 					   sizeof(in6)) == 0)
641 					break;
642 				n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
643 				if (n < 0)
644 					break;
645 				if ((lifreq.lifr_flags & IFF_UP) == 0)
646 					break;
647 				*have_v6 = 1;
648 			}
649 			break;
650 		}
651 	}
652 	if (buf != NULL)
653 		free(buf);
654 	close(s);
655 	return (0);
656  err_ret:
657 	if (buf != NULL)
658 		free(buf);
659 	if (s != -1)
660 		close(s);
661 	return (-1);
662 }
663 #endif
664 
665 static int
scan_interfaces(int * have_v4,int * have_v6)666 scan_interfaces(int *have_v4, int *have_v6) {
667 #if !defined(SIOCGIFCONF) || !defined(SIOCGIFADDR)
668 	*have_v4 = *have_v6 = 1;
669 	return (0);
670 #else
671 	struct ifconf ifc;
672 	union {
673 		char _pad[256];		/* leave space for IPv6 addresses */
674 		struct ifreq ifreq;
675 	} u;
676 	struct in_addr in4;
677 	struct in6_addr in6;
678 	char *buf = NULL, *cp, *cplim;
679 	static unsigned int bufsiz = 4095;
680 	int s, n;
681 	size_t cpsize;
682 
683 #ifdef WIN32
684 	InitSockets();
685 #endif
686 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
687     !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
688 	/*
689 	 * Try to scan the interfaces using IPv6 ioctls().
690 	 */
691 	if (!scan_interfaces6(have_v4, have_v6)) {
692 #ifdef WIN32
693 		DestroySockets();
694 #endif
695 		return (0);
696 	}
697 #endif
698 
699 	/*
700 	 * Set to zero.  Used as loop terminators below.
701 	 */
702 	*have_v4 = *have_v6 = 0;
703 
704 	/*
705 	 * Get interface list from system.
706 	 */
707 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
708 		goto err_ret;
709 
710 	/*
711 	 * Grow buffer until large enough to contain all interface
712 	 * descriptions.
713 	 */
714 	for (;;) {
715 		buf = malloc(bufsiz);
716 		if (buf == NULL)
717 			goto err_ret;
718 		ifc.ifc_len = bufsiz;
719 		ifc.ifc_buf = buf;
720 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
721 		/*
722 		 * This is a fix for IRIX OS in which the call to ioctl with
723 		 * the flag SIOCGIFCONF may not return an entry for all the
724 		 * interfaces like most flavors of Unix.
725 		 */
726 		if (emul_ioctl(&ifc) >= 0)
727 			break;
728 #else
729 		if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
730 			/*
731 			 * Some OS's just return what will fit rather
732 			 * than set EINVAL if the buffer is too small
733 			 * to fit all the interfaces in.  If
734 			 * ifc.ifc_len is too near to the end of the
735 			 * buffer we will grow it just in case and
736 			 * retry.
737 			 */
738 			if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
739 				break;
740 		}
741 #endif
742 		if ((n == -1) && errno != EINVAL)
743 			goto err_ret;
744 
745 		if (bufsiz > 1000000)
746 			goto err_ret;
747 
748 		free(buf);
749 		bufsiz += 4096;
750 	}
751 
752 	/*
753 	 * Parse system's interface list.
754 	 */
755 	cplim = buf + ifc.ifc_len;    /* skip over if's with big ifr_addr's */
756 	for (cp = buf;
757 	     (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
758 	     cp += cpsize) {
759 		memmove(&u.ifreq, cp, sizeof(u.ifreq));
760 #ifdef LWRES_PLATFORM_HAVESALEN
761 #ifdef FIX_ZERO_SA_LEN
762 		if (u.ifreq.ifr_addr.sa_len == 0)
763 			u.ifreq.ifr_addr.sa_len = 16;
764 #endif
765 #ifdef HAVE_MINIMUM_IFREQ
766 		cpsize = sizeof(u.ifreq);
767 		if (u.ifreq.ifr_addr.sa_len > sizeof(struct sockaddr))
768 			cpsize += (int)u.ifreq.ifr_addr.sa_len -
769 				(int)(sizeof(struct sockaddr));
770 #else
771 		cpsize = sizeof(u.ifreq.ifr_name) + u.ifreq.ifr_addr.sa_len;
772 #endif /* HAVE_MINIMUM_IFREQ */
773 		if (cpsize > sizeof(u.ifreq) && cpsize <= sizeof(u))
774 			memmove(&u.ifreq, cp, cpsize);
775 #elif defined SIOCGIFCONF_ADDR
776 		cpsize = sizeof(u.ifreq);
777 #else
778 		cpsize = sizeof(u.ifreq.ifr_name);
779 		/* XXX maybe this should be a hard error? */
780 		if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
781 			continue;
782 #endif
783 		switch (u.ifreq.ifr_addr.sa_family) {
784 		case AF_INET:
785 			if (*have_v4 == 0) {
786 				memmove(&in4,
787 					&((struct sockaddr_in *)
788 					  &u.ifreq.ifr_addr)->sin_addr,
789 					sizeof(in4));
790 				if (in4.s_addr == INADDR_ANY)
791 					break;
792 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
793 				if (n < 0)
794 					break;
795 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
796 					break;
797 				*have_v4 = 1;
798 			}
799 			break;
800 		case AF_INET6:
801 			if (*have_v6 == 0) {
802 				memmove(&in6,
803 					&((struct sockaddr_in6 *)
804 					  &u.ifreq.ifr_addr)->sin6_addr,
805 					sizeof(in6));
806 				if (memcmp(&in6, &in6addr_any,
807 					   sizeof(in6)) == 0)
808 					break;
809 				n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
810 				if (n < 0)
811 					break;
812 				if ((u.ifreq.ifr_flags & IFF_UP) == 0)
813 					break;
814 				*have_v6 = 1;
815 			}
816 			break;
817 		}
818 	}
819 	if (buf != NULL)
820 		free(buf);
821 #ifdef WIN32
822 	DestroySockets();
823 #endif
824 	close(s);
825 	return (0);
826 
827  err_ret:
828 	if (buf != NULL)
829 		free(buf);
830 	if (s != -1)
831 		close(s);
832 #ifdef WIN32
833 	DestroySockets();
834 #endif
835 	return (-1);
836 #endif
837 }
838 
839 static struct hostent *
copyandmerge(struct hostent * he1,struct hostent * he2,int af,int * error_num)840 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num)
841 {
842 	struct hostent *he = NULL;
843 	int addresses = 1;	/* NULL terminator */
844 	int names = 1;		/* NULL terminator */
845 	char *cp_name;
846 	char **cpp, **npp;
847 
848 	/*
849 	 * Work out array sizes.
850 	 */
851 	if (he1 != NULL) {
852 		cpp = he1->h_addr_list;
853 		while (*cpp != NULL) {
854 			addresses++;
855 			cpp++;
856 		}
857 		cpp = he1->h_aliases;
858 		while (*cpp != NULL) {
859 			names++;
860 			cpp++;
861 		}
862 	}
863 
864 	if (he2 != NULL) {
865 		cpp = he2->h_addr_list;
866 		while (*cpp != NULL) {
867 			addresses++;
868 			cpp++;
869 		}
870 		if (he1 == NULL) {
871 			cpp = he2->h_aliases;
872 			while (*cpp != NULL) {
873 				names++;
874 				cpp++;
875 			}
876 		}
877 	}
878 
879 	if (addresses == 1) {
880 		*error_num = NO_ADDRESS;
881 		return (NULL);
882 	}
883 
884 	he = malloc(sizeof(*he));
885 	if (he == NULL)
886 		goto no_recovery;
887 
888 	he->h_addr_list = malloc(sizeof(char *) * (addresses));
889 	if (he->h_addr_list == NULL)
890 		goto cleanup0;
891 	memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
892 
893 	/*
894 	 * Copy addresses.
895 	 */
896 	npp = he->h_addr_list;
897 	if (he1 != NULL) {
898 		cpp = he1->h_addr_list;
899 		while (*cpp != NULL) {
900 			*npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
901 			if (*npp == NULL)
902 				goto cleanup1;
903 			/*
904 			 * Convert to mapped if required.
905 			 */
906 			if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
907 				memmove(*npp, in6addr_mapped,
908 					sizeof(in6addr_mapped));
909 				memmove(*npp + sizeof(in6addr_mapped), *cpp,
910 					INADDRSZ);
911 			} else {
912 				memmove(*npp, *cpp,
913 					(af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
914 			}
915 			cpp++;
916 			npp++;
917 		}
918 	}
919 
920 	if (he2 != NULL) {
921 		cpp = he2->h_addr_list;
922 		while (*cpp != NULL) {
923 			*npp = malloc((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
924 			if (*npp == NULL)
925 				goto cleanup1;
926 			/*
927 			 * Convert to mapped if required.
928 			 */
929 			if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
930 				memmove(*npp, in6addr_mapped,
931 					sizeof(in6addr_mapped));
932 				memmove(*npp + sizeof(in6addr_mapped), *cpp,
933 					INADDRSZ);
934 			} else {
935 				memmove(*npp, *cpp,
936 					(af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
937 			}
938 			cpp++;
939 			npp++;
940 		}
941 	}
942 
943 	he->h_aliases = malloc(sizeof(char *) * (names));
944 	if (he->h_aliases == NULL)
945 		goto cleanup1;
946 	memset(he->h_aliases, 0, sizeof(char *) * (names));
947 
948 	/*
949 	 * Copy aliases.
950 	 */
951 	npp = he->h_aliases;
952 	if (he1 != NULL) {
953 		cpp = he1->h_aliases;
954 	} else if (he2 != NULL) {
955 		cpp = he2->h_aliases;
956 	} else {
957 		cpp = NULL;
958 	}
959 	while (cpp != NULL && *cpp != NULL) {
960 		*npp = strdup(*cpp);
961 		if (*npp == NULL)
962 			goto cleanup2;
963 		npp++;
964 		cpp++;
965 	}
966 
967 	/*
968 	 * Copy hostname.
969 	 */
970 	if (he1 != NULL) {
971 		cp_name = he1->h_name;
972 	} else if (he2 != NULL) {
973 		cp_name = he2->h_name;
974 	} else {
975 		goto cleanup2;
976 	}
977 	he->h_name = strdup(cp_name);
978 	if (he->h_name == NULL) {
979 		goto cleanup2;
980 	}
981 
982 	/*
983 	 * Set address type and length.
984 	 */
985 	he->h_addrtype = af;
986 	he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
987 	/* cppcheck-suppress memleak */
988 	return (he);
989 
990  cleanup2:
991 	cpp = he->h_aliases;
992 	while (*cpp != NULL) {
993 		free(*cpp);
994 		cpp++;
995 	}
996 	free(he->h_aliases);
997 
998  cleanup1:
999 	cpp = he->h_addr_list;
1000 	while (*cpp != NULL) {
1001 		free(*cpp);
1002 		*cpp = NULL;
1003 		cpp++;
1004 	}
1005 	free(he->h_addr_list);
1006 
1007  cleanup0:
1008 	free(he);
1009 
1010  no_recovery:
1011 	*error_num = NO_RECOVERY;
1012 	return (NULL);
1013 }
1014 
1015 static struct hostent *
hostfromaddr(lwres_gnbaresponse_t * addr,int af,const void * src)1016 hostfromaddr(lwres_gnbaresponse_t *addr, int af, const void *src) {
1017 	struct hostent *he;
1018 	int i;
1019 
1020 	he = malloc(sizeof(*he));
1021 	if (he == NULL)
1022 		goto cleanup;
1023 	memset(he, 0, sizeof(*he));
1024 
1025 	/*
1026 	 * Set family and length.
1027 	 */
1028 	he->h_addrtype = af;
1029 	switch (af) {
1030 	case AF_INET:
1031 		he->h_length = INADDRSZ;
1032 		break;
1033 	case AF_INET6:
1034 		he->h_length = IN6ADDRSZ;
1035 		break;
1036 	default:
1037 		INSIST(0);
1038 		ISC_UNREACHABLE();
1039 	}
1040 
1041 	/*
1042 	 * Copy name.
1043 	 */
1044 	he->h_name = strdup(addr->realname);
1045 	if (he->h_name == NULL)
1046 		goto cleanup;
1047 
1048 	/*
1049 	 * Copy aliases.
1050 	 */
1051 	he->h_aliases = malloc(sizeof(char *) * (addr->naliases + 1));
1052 	if (he->h_aliases == NULL)
1053 		goto cleanup;
1054 	for (i = 0; i < addr->naliases; i++) {
1055 		he->h_aliases[i] = strdup(addr->aliases[i]);
1056 		if (he->h_aliases[i] == NULL)
1057 			goto cleanup;
1058 	}
1059 	he->h_aliases[i] = NULL;
1060 
1061 	/*
1062 	 * Copy address.
1063 	 */
1064 	he->h_addr_list = malloc(sizeof(char *) * 2);
1065 	if (he->h_addr_list == NULL)
1066 		goto cleanup;
1067 	he->h_addr_list[0] = malloc(he->h_length);
1068 	if (he->h_addr_list[0] == NULL)
1069 		goto cleanup;
1070 	memmove(he->h_addr_list[0], src, he->h_length);
1071 	he->h_addr_list[1] = NULL;
1072 	return (he);
1073 
1074  cleanup:
1075 	if (he != NULL && he->h_addr_list != NULL) {
1076 		for (i = 0; he->h_addr_list[i] != NULL; i++)
1077 			free(he->h_addr_list[i]);
1078 		free(he->h_addr_list);
1079 	}
1080 	if (he != NULL && he->h_aliases != NULL) {
1081 		for (i = 0; he->h_aliases[i] != NULL; i++)
1082 			free(he->h_aliases[i]);
1083 		free(he->h_aliases);
1084 	}
1085 	if (he != NULL && he->h_name != NULL)
1086 		free(he->h_name);
1087 	if (he != NULL)
1088 		free(he);
1089 	return (NULL);
1090 }
1091 
1092 static struct hostent *
hostfromname(lwres_gabnresponse_t * name,int af)1093 hostfromname(lwres_gabnresponse_t *name, int af) {
1094 	struct hostent *he;
1095 	int i;
1096 	lwres_addr_t *addr;
1097 
1098 	he = malloc(sizeof(*he));
1099 	if (he == NULL)
1100 		goto cleanup;
1101 	memset(he, 0, sizeof(*he));
1102 
1103 	/*
1104 	 * Set family and length.
1105 	 */
1106 	he->h_addrtype = af;
1107 	switch (af) {
1108 	case AF_INET:
1109 		he->h_length = INADDRSZ;
1110 		break;
1111 	case AF_INET6:
1112 		he->h_length = IN6ADDRSZ;
1113 		break;
1114 	default:
1115 		INSIST(0);
1116 		ISC_UNREACHABLE();
1117 	}
1118 
1119 	/*
1120 	 * Copy name.
1121 	 */
1122 	he->h_name = strdup(name->realname);
1123 	if (he->h_name == NULL)
1124 		goto cleanup;
1125 
1126 	/*
1127 	 * Copy aliases.
1128 	 */
1129 	he->h_aliases = malloc(sizeof(char *) * (name->naliases + 1));
1130 	if (he->h_aliases == NULL)
1131 		goto cleanup;
1132 	for (i = 0; i < name->naliases; i++) {
1133 		he->h_aliases[i] = strdup(name->aliases[i]);
1134 		if (he->h_aliases[i] == NULL)
1135 			goto cleanup;
1136 	}
1137 	he->h_aliases[i] = NULL;
1138 
1139 	/*
1140 	 * Copy addresses.
1141 	 */
1142 	he->h_addr_list = malloc(sizeof(char *) * (name->naddrs + 1));
1143 	if (he->h_addr_list == NULL)
1144 		goto cleanup;
1145 	addr = LWRES_LIST_HEAD(name->addrs);
1146 	i = 0;
1147 	while (addr != NULL) {
1148 		he->h_addr_list[i] = malloc(he->h_length);
1149 		if (he->h_addr_list[i] == NULL)
1150 			goto cleanup;
1151 		memmove(he->h_addr_list[i], addr->address, he->h_length);
1152 		addr = LWRES_LIST_NEXT(addr, link);
1153 		i++;
1154 	}
1155 	he->h_addr_list[i] = NULL;
1156 	return (he);
1157 
1158  cleanup:
1159 	if (he != NULL && he->h_addr_list != NULL) {
1160 		for (i = 0; he->h_addr_list[i] != NULL; i++)
1161 			free(he->h_addr_list[i]);
1162 		free(he->h_addr_list);
1163 	}
1164 	if (he != NULL && he->h_aliases != NULL) {
1165 		for (i = 0; he->h_aliases[i] != NULL; i++)
1166 			free(he->h_aliases[i]);
1167 		free(he->h_aliases);
1168 	}
1169 	if (he != NULL && he->h_name != NULL)
1170 		free(he->h_name);
1171 	if (he != NULL)
1172 		free(he);
1173 	return (NULL);
1174 }
1175