xref: /trueos/contrib/ntp/libisc/ifiter_ioctl.c (revision b3db078f21c6b171ca87f55006f0195783756e42)
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ */
19 
20 /*
21  * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
22  * See netintro(4).
23  */
24 
25 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
26 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
27 #define lifc_len iflc_len
28 #define lifc_buf iflc_buf
29 #define lifc_req iflc_req
30 #define LIFCONF if_laddrconf
31 #else
32 #define ISC_HAVE_LIFC_FAMILY 1
33 #define ISC_HAVE_LIFC_FLAGS 1
34 #define LIFCONF lifconf
35 #endif
36 
37 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
38 #define lifr_addr iflr_addr
39 #define lifr_name iflr_name
40 #define lifr_dstaddr iflr_dstaddr
41 #define lifr_broadaddr iflr_broadaddr
42 #define lifr_flags iflr_flags
43 #define lifr_index iflr_index
44 #define ss_family sa_family
45 #define LIFREQ if_laddrreq
46 #else
47 #define LIFREQ lifreq
48 #endif
49 #endif
50 
51 #define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
52 #define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
53 
54 #define ISC_IF_INET6_SZ \
55     sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
56 
57 struct isc_interfaceiter {
58 	unsigned int		magic;		/* Magic number. */
59 	isc_mem_t		*mctx;
60 	int			mode;
61 	int			socket;
62 	struct ifconf 		ifc;
63 	void			*buf;		/* Buffer for sysctl data. */
64 	unsigned int		bufsize;	/* Bytes allocated. */
65 	unsigned int		pos;		/* Current offset in
66 						   SIOCGIFCONF data */
67 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
68 	int			socket6;
69 	struct LIFCONF 		lifc;
70 	void			*buf6;		/* Buffer for sysctl data. */
71 	unsigned int		bufsize6;	/* Bytes allocated. */
72 	unsigned int		pos6;		/* Current offset in
73 						   SIOCGLIFCONF data */
74 	isc_result_t		result6;	/* Last result code. */
75 	isc_boolean_t		first6;
76 #endif
77 #ifdef HAVE_TRUCLUSTER
78 	int			clua_context;	/* Cluster alias context */
79 	isc_boolean_t		clua_done;
80 	struct sockaddr		clua_sa;
81 #endif
82 #ifdef	__linux
83 	FILE *			proc;
84 	char			entry[ISC_IF_INET6_SZ];
85 	isc_result_t		valid;
86 	isc_boolean_t		first;
87 #endif
88 	isc_interface_t		current;	/* Current interface data. */
89 	isc_result_t		result;		/* Last result code. */
90 };
91 
92 #ifdef HAVE_TRUCLUSTER
93 #include <clua/clua.h>
94 #include <sys/socket.h>
95 #endif
96 
97 
98 /*
99  * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
100  * will have more than a megabyte of interface configuration data.
101  */
102 #define IFCONF_BUFSIZE_INITIAL	4096
103 #define IFCONF_BUFSIZE_MAX	1048576
104 
105 #ifdef __linux
106 #ifndef IF_NAMESIZE
107 # ifdef IFNAMSIZ
108 #  define IF_NAMESIZE  IFNAMSIZ
109 # else
110 #  define IF_NAMESIZE 16
111 # endif
112 #endif
113 #endif
114 
115 static isc_result_t
getbuf4(isc_interfaceiter_t * iter)116 getbuf4(isc_interfaceiter_t *iter) {
117 	char strbuf[ISC_STRERRORSIZE];
118 
119 	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
120 
121 	for (;;) {
122 		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
123 		if (iter->buf == NULL)
124 			return (ISC_R_NOMEMORY);
125 
126 		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
127 		iter->ifc.ifc_len = iter->bufsize;
128 		iter->ifc.ifc_buf = iter->buf;
129 		/*
130 		 * Ignore the HP/UX warning about "integer overflow during
131 		 * conversion".  It comes from its own macro definition,
132 		 * and is really hard to shut up.
133 		 */
134 		if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
135 		    == -1) {
136 			if (errno != EINVAL) {
137 				isc__strerror(errno, strbuf, sizeof(strbuf));
138 				UNEXPECTED_ERROR(__FILE__, __LINE__,
139 						 isc_msgcat_get(isc_msgcat,
140 							ISC_MSGSET_IFITERIOCTL,
141 							ISC_MSG_GETIFCONFIG,
142 							"get interface "
143 							"configuration: %s"),
144 						 strbuf);
145 				goto unexpected;
146 			}
147 			/*
148 			 * EINVAL.  Retry with a bigger buffer.
149 			 */
150 		} else {
151 			/*
152 			 * The ioctl succeeded.
153 			 * Some OS's just return what will fit rather
154 			 * than set EINVAL if the buffer is too small
155 			 * to fit all the interfaces in.  If
156 			 * ifc.lifc_len is too near to the end of the
157 			 * buffer we will grow it just in case and
158 			 * retry.
159 			 */
160 			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
161 			    < iter->bufsize)
162 				break;
163 		}
164 		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
165 			UNEXPECTED_ERROR(__FILE__, __LINE__,
166 					 isc_msgcat_get(isc_msgcat,
167 							ISC_MSGSET_IFITERIOCTL,
168 							ISC_MSG_BUFFERMAX,
169 							"get interface "
170 							"configuration: "
171 							"maximum buffer "
172 							"size exceeded"));
173 			goto unexpected;
174 		}
175 		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
176 
177 		iter->bufsize *= 2;
178 	}
179 	return (ISC_R_SUCCESS);
180 
181  unexpected:
182 	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
183 	iter->buf = NULL;
184 	return (ISC_R_UNEXPECTED);
185 }
186 
187 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
188 static isc_result_t
getbuf6(isc_interfaceiter_t * iter)189 getbuf6(isc_interfaceiter_t *iter) {
190 	char strbuf[ISC_STRERRORSIZE];
191 	isc_result_t result;
192 
193 	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
194 
195 	for (;;) {
196 		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
197 		if (iter->buf6 == NULL)
198 			return (ISC_R_NOMEMORY);
199 
200 		memset(&iter->lifc, 0, sizeof(iter->lifc));
201 #ifdef ISC_HAVE_LIFC_FAMILY
202 		iter->lifc.lifc_family = AF_INET6;
203 #endif
204 #ifdef ISC_HAVE_LIFC_FLAGS
205 		iter->lifc.lifc_flags = 0;
206 #endif
207 		iter->lifc.lifc_len = iter->bufsize6;
208 		iter->lifc.lifc_buf = iter->buf6;
209 		/*
210 		 * Ignore the HP/UX warning about "integer overflow during
211 		 * conversion".  It comes from its own macro definition,
212 		 * and is really hard to shut up.
213 		 */
214 		if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
215 		    == -1) {
216 #ifdef __hpux
217 			/*
218 			 * IPv6 interface scanning is not available on all
219 			 * kernels w/ IPv6 sockets.
220 			 */
221 			if (errno == ENOENT) {
222 				isc__strerror(errno, strbuf, sizeof(strbuf));
223 				UNEXPECTED_ERROR(__FILE__, __LINE__,
224 						 isc_msgcat_get(isc_msgcat,
225 							ISC_MSGSET_IFITERIOCTL,
226 							ISC_MSG_GETIFCONFIG,
227 							"get interface "
228 							"configuration: %s"),
229 						 strbuf);
230 				result = ISC_R_FAILURE;
231 				goto cleanup;
232 			}
233 #endif
234 			if (errno != EINVAL) {
235 				isc__strerror(errno, strbuf, sizeof(strbuf));
236 				UNEXPECTED_ERROR(__FILE__, __LINE__,
237 						 isc_msgcat_get(isc_msgcat,
238 							ISC_MSGSET_IFITERIOCTL,
239 							ISC_MSG_GETIFCONFIG,
240 							"get interface "
241 							"configuration: %s"),
242 						 strbuf);
243 				result = ISC_R_UNEXPECTED;
244 				goto cleanup;
245 			}
246 			/*
247 			 * EINVAL.  Retry with a bigger buffer.
248 			 */
249 		} else {
250 			/*
251 			 * The ioctl succeeded.
252 			 * Some OS's just return what will fit rather
253 			 * than set EINVAL if the buffer is too small
254 			 * to fit all the interfaces in.  If
255 			 * ifc.ifc_len is too near to the end of the
256 			 * buffer we will grow it just in case and
257 			 * retry.
258 			 */
259 			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
260 			    < iter->bufsize6)
261 				break;
262 		}
263 		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
264 			UNEXPECTED_ERROR(__FILE__, __LINE__,
265 					 isc_msgcat_get(isc_msgcat,
266 							ISC_MSGSET_IFITERIOCTL,
267 							ISC_MSG_BUFFERMAX,
268 							"get interface "
269 							"configuration: "
270 							"maximum buffer "
271 							"size exceeded"));
272 			result = ISC_R_UNEXPECTED;
273 			goto cleanup;
274 		}
275 		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
276 
277 		iter->bufsize6 *= 2;
278 	}
279 
280 	if (iter->lifc.lifc_len != 0)
281 		iter->mode = 6;
282 	return (ISC_R_SUCCESS);
283 
284  cleanup:
285 	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
286 	iter->buf6 = NULL;
287 	return (result);
288 }
289 #endif
290 
291 isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)292 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
293 	isc_interfaceiter_t *iter;
294 	isc_result_t result;
295 	char strbuf[ISC_STRERRORSIZE];
296 
297 	REQUIRE(iterp != NULL);
298 	REQUIRE(*iterp == NULL);
299 
300 	iter = isc_mem_get(mctx, sizeof(*iter));
301 	if (iter == NULL)
302 		return (ISC_R_NOMEMORY);
303 
304 	iter->mctx = mctx;
305 	iter->mode = 4;
306 	iter->buf = NULL;
307 	iter->pos = (unsigned int) -1;
308 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
309 	iter->buf6 = NULL;
310 	iter->pos6 = (unsigned int) -1;
311 	iter->result6 = ISC_R_NOMORE;
312 	iter->socket6 = -1;
313 	iter->first6 = ISC_FALSE;
314 #endif
315 
316 	/*
317 	 * Get the interface configuration, allocating more memory if
318 	 * necessary.
319 	 */
320 
321 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
322 	result = isc_net_probeipv6();
323 	if (result == ISC_R_SUCCESS) {
324 		/*
325 		 * Create an unbound datagram socket to do the SIOCGLIFCONF
326 		 * ioctl on.  HP/UX requires an AF_INET6 socket for
327 		 * SIOCGLIFCONF to get IPv6 addresses.
328 		 */
329 		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
330 			isc__strerror(errno, strbuf, sizeof(strbuf));
331 			UNEXPECTED_ERROR(__FILE__, __LINE__,
332 					 isc_msgcat_get(isc_msgcat,
333 							ISC_MSGSET_IFITERIOCTL,
334 							ISC_MSG_MAKESCANSOCKET,
335 							"making interface "
336 							"scan socket: %s"),
337 					 strbuf);
338 			result = ISC_R_UNEXPECTED;
339 			goto socket6_failure;
340 		}
341 		iter->result6 = getbuf6(iter);
342 		if (iter->result6 != ISC_R_NOTIMPLEMENTED &&
343 		    iter->result6 != ISC_R_SUCCESS)
344 			goto ioctl6_failure;
345 	}
346 #endif
347 	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
348 		isc__strerror(errno, strbuf, sizeof(strbuf));
349 		UNEXPECTED_ERROR(__FILE__, __LINE__,
350 				 isc_msgcat_get(isc_msgcat,
351 						ISC_MSGSET_IFITERIOCTL,
352 						ISC_MSG_MAKESCANSOCKET,
353 						"making interface "
354 						"scan socket: %s"),
355 				 strbuf);
356 		result = ISC_R_UNEXPECTED;
357 		goto socket_failure;
358 	}
359 	result = getbuf4(iter);
360 	if (result != ISC_R_SUCCESS)
361 		goto ioctl_failure;
362 
363 	/*
364 	 * A newly created iterator has an undefined position
365 	 * until isc_interfaceiter_first() is called.
366 	 */
367 #ifdef HAVE_TRUCLUSTER
368 	iter->clua_context = -1;
369 	iter->clua_done = ISC_TRUE;
370 #endif
371 #ifdef __linux
372 	iter->proc = fopen("/proc/net/if_inet6", "r");
373 	iter->valid = ISC_R_FAILURE;
374 	iter->first = ISC_FALSE;
375 #endif
376 	iter->result = ISC_R_FAILURE;
377 
378 	iter->magic = IFITER_MAGIC;
379 	*iterp = iter;
380 	return (ISC_R_SUCCESS);
381 
382  ioctl_failure:
383 	if (iter->buf != NULL)
384 		isc_mem_put(mctx, iter->buf, iter->bufsize);
385 	(void) close(iter->socket);
386 
387  socket_failure:
388 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389 	if (iter->buf6 != NULL)
390 		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
391   ioctl6_failure:
392 	if (iter->socket6 != -1)
393 		(void) close(iter->socket6);
394   socket6_failure:
395 #endif
396 
397 	isc_mem_put(mctx, iter, sizeof(*iter));
398 	return (result);
399 }
400 
401 #ifdef HAVE_TRUCLUSTER
402 static void
get_inaddr(isc_netaddr_t * dst,struct in_addr * src)403 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
404 	dst->family = AF_INET;
405 	memcpy(&dst->type.in, src, sizeof(struct in_addr));
406 }
407 
408 static isc_result_t
internal_current_clusteralias(isc_interfaceiter_t * iter)409 internal_current_clusteralias(isc_interfaceiter_t *iter) {
410 	struct clua_info ci;
411 	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
412 		return (ISC_R_IGNORE);
413 	memset(&iter->current, 0, sizeof(iter->current));
414 	iter->current.af = iter->clua_sa.sa_family;
415 	memset(iter->current.name, 0, sizeof(iter->current.name));
416 	sprintf(iter->current.name, "clua%d", ci.aliasid);
417 	iter->current.flags = INTERFACE_F_UP;
418 	get_inaddr(&iter->current.address, &ci.addr);
419 	get_inaddr(&iter->current.netmask, &ci.netmask);
420 	return (ISC_R_SUCCESS);
421 }
422 #endif
423 
424 #ifdef __linux
425 static isc_result_t
linux_if_inet6_next(isc_interfaceiter_t * iter)426 linux_if_inet6_next(isc_interfaceiter_t *iter) {
427 	if (iter->proc != NULL &&
428 	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
429 		iter->valid = ISC_R_SUCCESS;
430 	else
431 		iter->valid = ISC_R_NOMORE;
432 	return (iter->valid);
433 }
434 
435 static void
linux_if_inet6_first(isc_interfaceiter_t * iter)436 linux_if_inet6_first(isc_interfaceiter_t *iter) {
437 	if (iter->proc != NULL) {
438 		rewind(iter->proc);
439 		(void)linux_if_inet6_next(iter);
440 	} else
441 		iter->valid = ISC_R_NOMORE;
442 	iter->first = ISC_FALSE;
443 }
444 
445 static isc_result_t
linux_if_inet6_current(isc_interfaceiter_t * iter)446 linux_if_inet6_current(isc_interfaceiter_t *iter) {
447 	char address[33];
448 	char name[IF_NAMESIZE+1];
449 	char strbuf[ISC_STRERRORSIZE];
450 	struct in6_addr addr6;
451 	struct ifreq ifreq;
452 	int ifindex, prefix, scope, flags;
453 	int res;
454 	unsigned int i;
455 
456 	if (iter->valid != ISC_R_SUCCESS)
457 		return (iter->valid);
458 	if (iter->proc == NULL) {
459 		UNEXPECTED_ERROR(__FILE__, __LINE__,
460 			      "/proc/net/if_inet6:iter->proc == NULL");
461 		return (ISC_R_FAILURE);
462 	}
463 
464 	/*
465 	 * Format for /proc/net/if_inet6:
466 	 * (see iface_proc_info() in net/ipv6/addrconf.c)
467 	 * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
468 	 */
469 	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
470 		     address, &ifindex, &prefix, &scope, &flags, name);
471 	if (res != 6) {
472 		UNEXPECTED_ERROR(__FILE__, __LINE__,
473 			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
474 			      res);
475 		return (ISC_R_FAILURE);
476 	}
477 	if (strlen(address) != 32) {
478 		UNEXPECTED_ERROR(__FILE__, __LINE__,
479 			      "/proc/net/if_inet6:strlen(%s) != 32", address);
480 		return (ISC_R_FAILURE);
481 	}
482 	for (i = 0; i < 16; i++) {
483 		unsigned char byte;
484 		static const char hex[] = "0123456789abcdef";
485 		byte = ((index(hex, address[i * 2]) - hex) << 4) |
486 		       (index(hex, address[i * 2 + 1]) - hex);
487 		addr6.s6_addr[i] = byte;
488 	}
489 	iter->current.af = AF_INET6;
490 	/* iter->current.ifindex = ifindex; */
491 	iter->current.flags = 0;
492 
493 	memset(&ifreq, 0, sizeof(ifreq));
494 	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
495 	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
496 
497 	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
498 		isc__strerror(errno, strbuf, sizeof(strbuf));
499 		UNEXPECTED_ERROR(__FILE__, __LINE__,
500 				 "%s: getting interface flags: %s",
501 				 ifreq.ifr_name, strbuf);
502 		return (ISC_R_IGNORE);
503 	}
504 
505 	if ((ifreq.ifr_flags & IFF_UP) != 0)
506 		iter->current.flags |= INTERFACE_F_UP;
507 #ifdef IFF_POINTOPOINT
508 	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
509 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
510 #endif
511 	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
512 		iter->current.flags |= INTERFACE_F_LOOPBACK;
513 	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
514 		iter->current.flags |= INTERFACE_F_BROADCAST;
515 #ifdef IFF_MULTICAST
516 	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
517 		iter->current.flags |= INTERFACE_F_MULTICAST;
518 #endif
519 
520 	/*
521 	 * enable_multicast_if() requires scopeid for setsockopt,
522 	 * so associate address with their corresponding ifindex.
523 	 */
524 	isc_netaddr_fromin6(&iter->current.address, &addr6);
525 	isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);
526 
527 	for (i = 0; i < 16; i++) {
528 		if (prefix > 8) {
529 			addr6.s6_addr[i] = 0xff;
530 			prefix -= 8;
531 		} else {
532 			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
533 			prefix = 0;
534 		}
535 	}
536 	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
537 	strncpy(iter->current.name, name, sizeof(iter->current.name));
538 	return (ISC_R_SUCCESS);
539 }
540 #endif
541 
542 /*
543  * Get information about the current interface to iter->current.
544  * If successful, return ISC_R_SUCCESS.
545  * If the interface has an unsupported address family, or if
546  * some operation on it fails, return ISC_R_IGNORE to make
547  * the higher-level iterator code ignore it.
548  */
549 
550 static isc_result_t
internal_current4(isc_interfaceiter_t * iter)551 internal_current4(isc_interfaceiter_t *iter) {
552 	struct ifreq *ifrp;
553 	struct ifreq ifreq;
554 	int family;
555 	char strbuf[ISC_STRERRORSIZE];
556 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
557 	struct lifreq lifreq;
558 #else
559 	char sabuf[256];
560 #endif
561 	int i, bits, prefixlen;
562 #ifdef __linux
563 	isc_result_t result;
564 #endif
565 
566 	REQUIRE(VALID_IFITER(iter));
567 	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
568 
569 #ifdef __linux
570 	result = linux_if_inet6_current(iter);
571 	if (result != ISC_R_NOMORE)
572 		return (result);
573 	iter->first = ISC_TRUE;
574 #endif
575 
576 	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
577 
578 	memset(&ifreq, 0, sizeof(ifreq));
579 	memcpy(&ifreq, ifrp, sizeof(ifreq));
580 
581 	family = ifreq.ifr_addr.sa_family;
582 #if defined(ISC_PLATFORM_HAVEIPV6)
583 	if (family != AF_INET && family != AF_INET6)
584 #else
585 	if (family != AF_INET)
586 #endif
587 		return (ISC_R_IGNORE);
588 
589 	memset(&iter->current, 0, sizeof(iter->current));
590 	iter->current.af = family;
591 
592 	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
593 	memset(iter->current.name, 0, sizeof(iter->current.name));
594 	memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
595 
596 	get_addr(family, &iter->current.address,
597 		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
598 
599 	/*
600 	 * If the interface does not have a address ignore it.
601 	 */
602 	switch (family) {
603 	case AF_INET:
604 		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
605 			return (ISC_R_IGNORE);
606 		break;
607 #ifdef ISC_PLATFORM_HAVEIPV6
608 	case AF_INET6:
609 		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
610 			   sizeof(in6addr_any)) == 0)
611 			return (ISC_R_IGNORE);
612 		break;
613 #endif
614 	}
615 
616 	/*
617 	 * Get interface flags.
618 	 */
619 
620 	iter->current.flags = 0;
621 
622 	/*
623 	 * Ignore the HP/UX warning about "integer overflow during
624 	 * conversion.  It comes from its own macro definition,
625 	 * and is really hard to shut up.
626 	 */
627 	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
628 		isc__strerror(errno, strbuf, sizeof(strbuf));
629 		UNEXPECTED_ERROR(__FILE__, __LINE__,
630 				 "%s: getting interface flags: %s",
631 				 ifreq.ifr_name, strbuf);
632 		return (ISC_R_IGNORE);
633 	}
634 
635 	if ((ifreq.ifr_flags & IFF_UP) != 0)
636 		iter->current.flags |= INTERFACE_F_UP;
637 
638 #ifdef IFF_POINTOPOINT
639 	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
640 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
641 #endif
642 
643 	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
644 		iter->current.flags |= INTERFACE_F_LOOPBACK;
645 
646 	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) {
647 		iter->current.flags |= INTERFACE_F_BROADCAST;
648 	}
649 
650 #ifdef IFF_MULTICAST
651 	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
652 		iter->current.flags |= INTERFACE_F_MULTICAST;
653 	}
654 #endif
655 
656 	if (family == AF_INET)
657 		goto inet;
658 
659 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
660 	memset(&lifreq, 0, sizeof(lifreq));
661 	memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
662 	memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
663 	       sizeof(iter->current.address.type.in6));
664 
665 	if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
666 		isc__strerror(errno, strbuf, sizeof(strbuf));
667 		UNEXPECTED_ERROR(__FILE__, __LINE__,
668 				 "%s: getting interface address: %s",
669 				 ifreq.ifr_name, strbuf);
670 		return (ISC_R_IGNORE);
671 	}
672 	prefixlen = lifreq.lifr_addrlen;
673 #else
674 	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
675 	UNEXPECTED_ERROR(__FILE__, __LINE__,
676 		      isc_msgcat_get(isc_msgcat,
677 				     ISC_MSGSET_IFITERIOCTL,
678 				     ISC_MSG_GETIFCONFIG,
679 				     "prefix length for %s is unknown "
680 				     "(assume 128)"), sabuf);
681 	prefixlen = 128;
682 #endif
683 
684 	/*
685 	 * Netmask already zeroed.
686 	 */
687 	iter->current.netmask.family = family;
688 	for (i = 0; i < 16; i++) {
689 		if (prefixlen > 8) {
690 			bits = 0;
691 			prefixlen -= 8;
692 		} else {
693 			bits = 8 - prefixlen;
694 			prefixlen = 0;
695 		}
696 		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
697 	}
698 	return (ISC_R_SUCCESS);
699 
700  inet:
701 	if (family != AF_INET)
702 		return (ISC_R_IGNORE);
703 #ifdef IFF_POINTOPOINT
704 	/*
705 	 * If the interface is point-to-point, get the destination address.
706 	 */
707 	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
708 		/*
709 		 * Ignore the HP/UX warning about "integer overflow during
710 		 * conversion.  It comes from its own macro definition,
711 		 * and is really hard to shut up.
712 		 */
713 		if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
714 		    < 0) {
715 			isc__strerror(errno, strbuf, sizeof(strbuf));
716 			UNEXPECTED_ERROR(__FILE__, __LINE__,
717 				isc_msgcat_get(isc_msgcat,
718 					       ISC_MSGSET_IFITERIOCTL,
719 					       ISC_MSG_GETDESTADDR,
720 					       "%s: getting "
721 					       "destination address: %s"),
722 					 ifreq.ifr_name, strbuf);
723 			return (ISC_R_IGNORE);
724 		}
725 		get_addr(family, &iter->current.dstaddress,
726 			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
727 	}
728 #endif
729 	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
730 		/*
731 		 * Ignore the HP/UX warning about "integer overflow during
732 		 * conversion.  It comes from its own macro definition,
733 		 * and is really hard to shut up.
734 		 */
735 		if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
736 		    < 0) {
737 			isc__strerror(errno, strbuf, sizeof(strbuf));
738 			UNEXPECTED_ERROR(__FILE__, __LINE__,
739 				isc_msgcat_get(isc_msgcat,
740 					       ISC_MSGSET_IFITERIOCTL,
741 					       ISC_MSG_GETDESTADDR,
742 					       "%s: getting "
743 					       "broadcast address: %s"),
744 					 ifreq.ifr_name, strbuf);
745 			return (ISC_R_IGNORE);
746 		}
747 		get_addr(family, &iter->current.broadcast,
748 			 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
749 	}
750 
751 	/*
752 	 * Get the network mask.
753 	 */
754 	memset(&ifreq, 0, sizeof(ifreq));
755 	memcpy(&ifreq, ifrp, sizeof(ifreq));
756 	/*
757 	 * Ignore the HP/UX warning about "integer overflow during
758 	 * conversion.  It comes from its own macro definition,
759 	 * and is really hard to shut up.
760 	 */
761 	if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
762 		isc__strerror(errno, strbuf, sizeof(strbuf));
763 		UNEXPECTED_ERROR(__FILE__, __LINE__,
764 			isc_msgcat_get(isc_msgcat,
765 				       ISC_MSGSET_IFITERIOCTL,
766 				       ISC_MSG_GETNETMASK,
767 				       "%s: getting netmask: %s"),
768 				       ifreq.ifr_name, strbuf);
769 		return (ISC_R_IGNORE);
770 	}
771 	get_addr(family, &iter->current.netmask,
772 		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
773 	return (ISC_R_SUCCESS);
774 }
775 
776 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
777 static isc_result_t
internal_current6(isc_interfaceiter_t * iter)778 internal_current6(isc_interfaceiter_t *iter) {
779 	struct LIFREQ *ifrp;
780 	struct LIFREQ lifreq;
781 	int family;
782 	char strbuf[ISC_STRERRORSIZE];
783 	int fd;
784 
785 	REQUIRE(VALID_IFITER(iter));
786 	if (iter->result6 != ISC_R_SUCCESS)
787 		return (iter->result6);
788 	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
789 
790 	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
791 
792 	memset(&lifreq, 0, sizeof(lifreq));
793 	memcpy(&lifreq, ifrp, sizeof(lifreq));
794 
795 	family = lifreq.lifr_addr.ss_family;
796 #ifdef ISC_PLATFORM_HAVEIPV6
797 	if (family != AF_INET && family != AF_INET6)
798 #else
799 	if (family != AF_INET)
800 #endif
801 		return (ISC_R_IGNORE);
802 
803 	memset(&iter->current, 0, sizeof(iter->current));
804 	iter->current.af = family;
805 
806 	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
807 	memset(iter->current.name, 0, sizeof(iter->current.name));
808 	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
809 
810 	get_addr(family, &iter->current.address,
811 		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
812 
813 	/*
814 	 * If the interface does not have a address ignore it.
815 	 */
816 	switch (family) {
817 	case AF_INET:
818 		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
819 			return (ISC_R_IGNORE);
820 		break;
821 #ifdef ISC_PLATFORM_HAVEIPV6
822 	case AF_INET6:
823 		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
824 			   sizeof(in6addr_any)) == 0)
825 			return (ISC_R_IGNORE);
826 		break;
827 #endif
828 	}
829 
830 	/*
831 	 * Get interface flags.
832 	 */
833 
834 	iter->current.flags = 0;
835 
836 	if (family == AF_INET6)
837 		fd = iter->socket6;
838 	else
839 		fd = iter->socket;
840 
841 	/*
842 	 * Ignore the HP/UX warning about "integer overflow during
843 	 * conversion.  It comes from its own macro definition,
844 	 * and is really hard to shut up.
845 	 */
846 	if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
847 		isc__strerror(errno, strbuf, sizeof(strbuf));
848 		UNEXPECTED_ERROR(__FILE__, __LINE__,
849 				 "%s: getting interface flags: %s",
850 				 lifreq.lifr_name, strbuf);
851 		return (ISC_R_IGNORE);
852 	}
853 
854 	if ((lifreq.lifr_flags & IFF_UP) != 0)
855 		iter->current.flags |= INTERFACE_F_UP;
856 
857 #ifdef IFF_POINTOPOINT
858 	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
859 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
860 #endif
861 
862 	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
863 		iter->current.flags |= INTERFACE_F_LOOPBACK;
864 
865 	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
866 		iter->current.flags |= INTERFACE_F_BROADCAST;
867 	}
868 
869 #ifdef IFF_MULTICAST
870 	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
871 		iter->current.flags |= INTERFACE_F_MULTICAST;
872 	}
873 #endif
874 
875 #ifdef IFF_POINTOPOINT
876 	/*
877 	 * If the interface is point-to-point, get the destination address.
878 	 */
879 	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
880 		/*
881 		 * Ignore the HP/UX warning about "interger overflow during
882 		 * conversion.  It comes from its own macro definition,
883 		 * and is really hard to shut up.
884 		 */
885 		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
886 		    < 0) {
887 			isc__strerror(errno, strbuf, sizeof(strbuf));
888 			UNEXPECTED_ERROR(__FILE__, __LINE__,
889 				isc_msgcat_get(isc_msgcat,
890 					       ISC_MSGSET_IFITERIOCTL,
891 					       ISC_MSG_GETDESTADDR,
892 					       "%s: getting "
893 					       "destination address: %s"),
894 					 lifreq.lifr_name, strbuf);
895 			return (ISC_R_IGNORE);
896 		}
897 		get_addr(family, &iter->current.dstaddress,
898 			 (struct sockaddr *)&lifreq.lifr_dstaddr,
899 			 lifreq.lifr_name);
900 	}
901 #endif
902 
903 #ifdef SIOCGLIFBRDADDR
904 	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
905 		/*
906 		 * Ignore the HP/UX warning about "integer overflow during
907 		 * conversion.  It comes from its own macro definition,
908 		 * and is really hard to shut up.
909 		 */
910 		if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
911 		    < 0) {
912 			isc__strerror(errno, strbuf, sizeof(strbuf));
913 			UNEXPECTED_ERROR(__FILE__, __LINE__,
914 				isc_msgcat_get(isc_msgcat,
915 					       ISC_MSGSET_IFITERIOCTL,
916 					       ISC_MSG_GETDESTADDR,
917 					       "%s: getting "
918 					       "broadcast address: %s"),
919 					 lifreq.lifr_name, strbuf);
920 			return (ISC_R_IGNORE);
921 		}
922 		get_addr(family, &iter->current.broadcast,
923 			 (struct sockaddr *)&lifreq.lifr_broadaddr,
924 			 lifreq.lifr_name);
925 	}
926 #endif	/* SIOCGLIFBRDADDR */
927 
928 	/*
929 	 * Get the network mask.  Netmask already zeroed.
930 	 */
931 	memset(&lifreq, 0, sizeof(lifreq));
932 	memcpy(&lifreq, ifrp, sizeof(lifreq));
933 
934 #ifdef lifr_addrlen
935 	/*
936 	 * Special case: if the system provides lifr_addrlen member, the
937 	 * netmask of an IPv6 address can be derived from the length, since
938 	 * an IPv6 address always has a contiguous mask.
939 	 */
940 	if (family == AF_INET6) {
941 		int i, bits;
942 
943 		iter->current.netmask.family = family;
944 		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
945 			bits = lifreq.lifr_addrlen - i;
946 			bits = (bits < 8) ? (8 - bits) : 0;
947 			iter->current.netmask.type.in6.s6_addr[i / 8] =
948 				(~0 << bits) & 0xff;
949 		}
950 
951 		return (ISC_R_SUCCESS);
952 	}
953 #endif
954 
955 	/*
956 	 * Ignore the HP/UX warning about "integer overflow during
957 	 * conversion.  It comes from its own macro definition,
958 	 * and is really hard to shut up.
959 	 */
960 	if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
961 		isc__strerror(errno, strbuf, sizeof(strbuf));
962 		UNEXPECTED_ERROR(__FILE__, __LINE__,
963 				 isc_msgcat_get(isc_msgcat,
964 						ISC_MSGSET_IFITERIOCTL,
965 						ISC_MSG_GETNETMASK,
966 						"%s: getting netmask: %s"),
967 				 lifreq.lifr_name, strbuf);
968 		return (ISC_R_IGNORE);
969 	}
970 	get_addr(family, &iter->current.netmask,
971 		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
972 
973 	return (ISC_R_SUCCESS);
974 }
975 #endif
976 
977 static isc_result_t
internal_current(isc_interfaceiter_t * iter)978 internal_current(isc_interfaceiter_t *iter) {
979 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
980 	if (iter->mode == 6) {
981 		iter->result6 = internal_current6(iter);
982 		if (iter->result6 != ISC_R_NOMORE)
983 			return (iter->result6);
984 	}
985 #endif
986 #ifdef HAVE_TRUCLUSTER
987 	if (!iter->clua_done)
988 		return(internal_current_clusteralias(iter));
989 #endif
990 	return (internal_current4(iter));
991 }
992 
993 /*
994  * Step the iterator to the next interface.  Unlike
995  * isc_interfaceiter_next(), this may leave the iterator
996  * positioned on an interface that will ultimately
997  * be ignored.  Return ISC_R_NOMORE if there are no more
998  * interfaces, otherwise ISC_R_SUCCESS.
999  */
1000 static isc_result_t
internal_next4(isc_interfaceiter_t * iter)1001 internal_next4(isc_interfaceiter_t *iter) {
1002 	struct ifreq *ifrp;
1003 
1004 	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
1005 
1006 #ifdef __linux
1007 	if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
1008 		return (ISC_R_SUCCESS);
1009 	if (!iter->first)
1010 		return (ISC_R_SUCCESS);
1011 #endif
1012 	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
1013 
1014 #ifdef ISC_PLATFORM_HAVESALEN
1015 	if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
1016 		iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
1017 	else
1018 #endif
1019 		iter->pos += sizeof(*ifrp);
1020 
1021 	if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
1022 		return (ISC_R_NOMORE);
1023 
1024 	return (ISC_R_SUCCESS);
1025 }
1026 
1027 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1028 static isc_result_t
internal_next6(isc_interfaceiter_t * iter)1029 internal_next6(isc_interfaceiter_t *iter) {
1030 	struct LIFREQ *ifrp;
1031 
1032 	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
1033 		return (iter->result6);
1034 
1035 	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
1036 
1037 	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
1038 
1039 #ifdef ISC_PLATFORM_HAVESALEN
1040 	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
1041 		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
1042 	else
1043 #endif
1044 		iter->pos6 += sizeof(*ifrp);
1045 
1046 	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
1047 		return (ISC_R_NOMORE);
1048 
1049 	return (ISC_R_SUCCESS);
1050 }
1051 #endif
1052 
1053 static isc_result_t
internal_next(isc_interfaceiter_t * iter)1054 internal_next(isc_interfaceiter_t *iter) {
1055 #ifdef HAVE_TRUCLUSTER
1056 	int clua_result;
1057 #endif
1058 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1059 	if (iter->mode == 6) {
1060 		iter->result6 = internal_next6(iter);
1061 		if (iter->result6 != ISC_R_NOMORE)
1062 			return (iter->result6);
1063 		if (iter->first6) {
1064 			iter->first6 = ISC_FALSE;
1065 			return (ISC_R_SUCCESS);
1066 		}
1067 	}
1068 #endif
1069 #ifdef HAVE_TRUCLUSTER
1070 	if (!iter->clua_done) {
1071 		clua_result = clua_getaliasaddress(&iter->clua_sa,
1072 						   &iter->clua_context);
1073 		if (clua_result != CLUA_SUCCESS)
1074 			iter->clua_done = ISC_TRUE;
1075 		return (ISC_R_SUCCESS);
1076 	}
1077 #endif
1078 	return (internal_next4(iter));
1079 }
1080 
1081 static void
internal_destroy(isc_interfaceiter_t * iter)1082 internal_destroy(isc_interfaceiter_t *iter) {
1083 	(void) close(iter->socket);
1084 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1085 	if (iter->socket6 != -1)
1086 		(void) close(iter->socket6);
1087 	if (iter->buf6 != NULL) {
1088 		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1089 	}
1090 #endif
1091 #ifdef __linux
1092 	if (iter->proc != NULL)
1093 		fclose(iter->proc);
1094 #endif
1095 }
1096 
1097 static
internal_first(isc_interfaceiter_t * iter)1098 void internal_first(isc_interfaceiter_t *iter) {
1099 #ifdef HAVE_TRUCLUSTER
1100 	int clua_result;
1101 #endif
1102 	iter->pos = 0;
1103 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1104 	iter->pos6 = 0;
1105 	if (iter->result6 == ISC_R_NOMORE)
1106 		iter->result6 = ISC_R_SUCCESS;
1107 	iter->first6 = ISC_TRUE;
1108 #endif
1109 #ifdef HAVE_TRUCLUSTER
1110 	iter->clua_context = 0;
1111 	clua_result = clua_getaliasaddress(&iter->clua_sa,
1112 					   &iter->clua_context);
1113 	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1114 #endif
1115 #ifdef __linux
1116 	linux_if_inet6_first(iter);
1117 #endif
1118 }
1119