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 
13 /*
14  * Note that this code will need to be revisited to support IPv6 Interfaces.
15  * For now we just iterate through IPv4 interfaces.
16  */
17 
18 #include <config.h>
19 #include <winsock2.h>
20 #include <ws2tcpip.h>
21 #include <sys/types.h>
22 
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 
28 #include <isc/interfaceiter.h>
29 #include <isc/mem.h>
30 #include <isc/print.h>
31 #include <isc/result.h>
32 #include <isc/string.h>
33 #include <isc/strerror.h>
34 #include <isc/types.h>
35 #include <isc/util.h>
36 
37 void InitSockets(void);
38 
39 /* Common utility functions */
40 
41 /*
42  * Extract the network address part from a "struct sockaddr".
43  *
44  * The address family is given explicitly
45  * instead of using src->sa_family, because the latter does not work
46  * for copying a network mask obtained by SIOCGIFNETMASK (it does
47  * not have a valid address family).
48  */
49 
50 
51 #define IFITER_MAGIC		0x49464954U	/* IFIT. */
52 #define VALID_IFITER(t)		((t) != NULL && (t)->magic == IFITER_MAGIC)
53 
54 struct isc_interfaceiter {
55 	unsigned int		magic;		/* Magic number. */
56 	isc_mem_t		*mctx;
57 	SOCKET			socket;
58 	INTERFACE_INFO		IFData;		/* Current Interface Info. */
59 	int			numIF;		/* Current Interface count. */
60 	int			v4IF;		/* Number of IPv4 Interfaces */
61 	INTERFACE_INFO		*buf4;		/* Buffer for WSAIoctl data. */
62 	unsigned int		buf4size;	/* Bytes allocated. */
63 	INTERFACE_INFO		*pos4;		/* Current offset in IF List */
64 	SOCKET_ADDRESS_LIST	*buf6;		/* Buffer for WSAIoctl data. */
65 	unsigned int		buf6size;	/* Bytes allocated. */
66 	unsigned int		pos6;		/* Which entry to process. */
67 	bool		v6loop;		/* See IPv6 loop address. */
68 	bool		pos6zero;	/* Done pos6 == 0. */
69 	isc_interface_t		current;	/* Current interface data. */
70 	isc_result_t		result;		/* Last result code. */
71 };
72 
73 
74 /*
75  * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
76  * We assume no sane system will have more than than 1K of IP addresses on
77  * all of its adapters.
78  */
79 #define IFCONF_SIZE_INITIAL	  16
80 #define IFCONF_SIZE_INCREMENT	  64
81 #define IFCONF_SIZE_MAX		1040
82 
83 static void
get_addr(unsigned int family,isc_netaddr_t * dst,struct sockaddr * src)84 get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
85 	dst->family = family;
86 	switch (family) {
87 	case AF_INET:
88 		memmove(&dst->type.in,
89 			&((struct sockaddr_in *) src)->sin_addr,
90 			sizeof(struct in_addr));
91 		break;
92 	case	AF_INET6:
93 		memmove(&dst->type.in6,
94 			&((struct sockaddr_in6 *) src)->sin6_addr,
95 			sizeof(struct in6_addr));
96 		dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
97 		break;
98 	default:
99 		INSIST(0);
100 		ISC_UNREACHABLE();
101 	}
102 }
103 
104 isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)105 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
106 	char strbuf[ISC_STRERRORSIZE];
107 	isc_interfaceiter_t *iter;
108 	isc_result_t result;
109 	int error;
110 	unsigned long bytesReturned = 0;
111 
112 	REQUIRE(mctx != NULL);
113 	REQUIRE(iterp != NULL);
114 	REQUIRE(*iterp == NULL);
115 
116 	iter = isc_mem_get(mctx, sizeof(*iter));
117 	if (iter == NULL)
118 		return (ISC_R_NOMEMORY);
119 
120 	InitSockets();
121 
122 	iter->mctx = mctx;
123 	iter->buf4 = NULL;
124 	iter->buf6 = NULL;
125 	iter->pos4 = NULL;
126 	iter->pos6 = 0;
127 	iter->v6loop = true;
128 	iter->pos6zero = true;
129 	iter->buf6size = 0;
130 	iter->buf4size = 0;
131 	iter->result = ISC_R_FAILURE;
132 	iter->numIF = 0;
133 	iter->v4IF = 0;
134 
135 	/*
136 	 * Create an unbound datagram socket to do the
137 	 * SIO_GET_INTERFACE_LIST WSAIoctl on.
138 	 */
139 	iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
140 	if (iter->socket == INVALID_SOCKET) {
141 		error = WSAGetLastError();
142 		if (error == WSAEAFNOSUPPORT)
143 			goto inet6_only;
144 		isc__strerror(error, strbuf, sizeof(strbuf));
145 		UNEXPECTED_ERROR(__FILE__, __LINE__,
146 				"making interface scan socket: %s",
147 				strbuf);
148 		result = ISC_R_UNEXPECTED;
149 		goto socket_failure;
150 	}
151 
152 	/*
153 	 * Get the interface configuration, allocating more memory if
154 	 * necessary.
155 	 */
156 	iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
157 
158 	for (;;) {
159 		iter->buf4 = isc_mem_get(mctx, iter->buf4size);
160 		if (iter->buf4 == NULL) {
161 			result = ISC_R_NOMEMORY;
162 			goto alloc_failure;
163 		}
164 
165 		if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
166 			     0, 0, iter->buf4, iter->buf4size,
167 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
168 		{
169 			error = WSAGetLastError();
170 			if (error != WSAEFAULT && error != WSAENOBUFS) {
171 				errno = error;
172 				isc__strerror(error, strbuf, sizeof(strbuf));
173 				UNEXPECTED_ERROR(__FILE__, __LINE__,
174 						"get interface configuration: %s",
175 						strbuf);
176 				result = ISC_R_UNEXPECTED;
177 				goto ioctl_failure;
178 			}
179 			/*
180 			 * EINVAL.  Retry with a bigger buffer.
181 			 */
182 		} else {
183 			/*
184 			 * The WSAIoctl succeeded.
185 			 * If the number of the returned bytes is the same
186 			 * as the buffer size, we will grow it just in
187 			 * case and retry.
188 			 */
189 			if (bytesReturned > 0 &&
190 			    (bytesReturned < iter->buf4size))
191 				break;
192 		}
193 		if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
194 			UNEXPECTED_ERROR(__FILE__, __LINE__,
195 					 "get interface configuration: "
196 					 "maximum buffer size exceeded");
197 			result = ISC_R_UNEXPECTED;
198 			goto ioctl_failure;
199 		}
200 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
201 
202 		iter->buf4size += IFCONF_SIZE_INCREMENT *
203 			sizeof(INTERFACE_INFO);
204 	}
205 
206 	/*
207 	 * A newly created iterator has an undefined position
208 	 * until isc_interfaceiter_first() is called.
209 	 */
210 	iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
211 
212 	/* We don't need the socket any more, so close it */
213 	closesocket(iter->socket);
214 
215  inet6_only:
216 	/*
217 	 * Create an unbound datagram socket to do the
218 	 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
219 	 */
220 	iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
221 	if (iter->socket == INVALID_SOCKET) {
222 		error = WSAGetLastError();
223 		if (error == WSAEAFNOSUPPORT)
224 			goto inet_only;
225 		isc__strerror(error, strbuf, sizeof(strbuf));
226 		UNEXPECTED_ERROR(__FILE__, __LINE__,
227 				"making interface scan socket: %s",
228 				strbuf);
229 		result = ISC_R_UNEXPECTED;
230 		goto ioctl_failure;
231 	}
232 
233 	/*
234 	 * Get the interface configuration, allocating more memory if
235 	 * necessary.
236 	 */
237 	iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
238 			 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
239 
240 	for (;;) {
241 		iter->buf6 = isc_mem_get(mctx, iter->buf6size);
242 		if (iter->buf6 == NULL) {
243 			result = ISC_R_NOMEMORY;
244 			goto ioctl_failure;
245 		}
246 
247 		if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
248 			     0, 0, iter->buf6, iter->buf6size,
249 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
250 		{
251 			error = WSAGetLastError();
252 			if (error != WSAEFAULT && error != WSAENOBUFS) {
253 				errno = error;
254 				isc__strerror(error, strbuf, sizeof(strbuf));
255 				UNEXPECTED_ERROR(__FILE__, __LINE__,
256 						 "sio address list query: %s",
257 						 strbuf);
258 				result = ISC_R_UNEXPECTED;
259 				goto ioctl6_failure;
260 			}
261 			/*
262 			 * EINVAL.  Retry with a bigger buffer.
263 			 */
264 		} else
265 			break;
266 
267 		if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
268 			UNEXPECTED_ERROR(__FILE__, __LINE__,
269 					 "get interface configuration: "
270 					 "maximum buffer size exceeded");
271 			result = ISC_R_UNEXPECTED;
272 			goto ioctl6_failure;
273 		}
274 		isc_mem_put(mctx, iter->buf6, iter->buf6size);
275 
276 		iter->buf6size += IFCONF_SIZE_INCREMENT *
277 			sizeof(SOCKET_ADDRESS);
278 	}
279 
280 	closesocket(iter->socket);
281 
282  inet_only:
283 	iter->magic = IFITER_MAGIC;
284 	*iterp = iter;
285 	return (ISC_R_SUCCESS);
286 
287  ioctl6_failure:
288 	isc_mem_put(mctx, iter->buf6, iter->buf6size);
289 
290  ioctl_failure:
291 	if (iter->buf4 != NULL)
292 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
293 
294  alloc_failure:
295 	if (iter->socket != INVALID_SOCKET)
296 		(void) closesocket(iter->socket);
297 
298  socket_failure:
299 	isc_mem_put(mctx, iter, sizeof(*iter));
300 	return (result);
301 }
302 
303 /*
304  * Get information about the current interface to iter->current.
305  * If successful, return ISC_R_SUCCESS.
306  * If the interface has an unsupported address family, or if
307  * some operation on it fails, return ISC_R_IGNORE to make
308  * the higher-level iterator code ignore it.
309  */
310 
311 static isc_result_t
internal_current(isc_interfaceiter_t * iter)312 internal_current(isc_interfaceiter_t *iter) {
313 	BOOL ifNamed = FALSE;
314 	unsigned long flags;
315 
316 	REQUIRE(VALID_IFITER(iter));
317 	REQUIRE(iter->numIF >= 0);
318 
319 	memset(&iter->current, 0, sizeof(iter->current));
320 	iter->current.af = AF_INET;
321 
322 	get_addr(AF_INET, &iter->current.address,
323 		 (struct sockaddr *)&(iter->IFData.iiAddress));
324 
325 	/*
326 	 * Get interface flags.
327 	 */
328 
329 	iter->current.flags = 0;
330 	flags = iter->IFData.iiFlags;
331 
332 	if ((flags & IFF_UP) != 0)
333 		iter->current.flags |= INTERFACE_F_UP;
334 
335 	if ((flags & IFF_POINTTOPOINT) != 0) {
336 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
337 		snprintf(iter->current.name, sizeof(iter->current.name),
338 			 "PPP Interface %d", iter->numIF);
339 		ifNamed = TRUE;
340 	}
341 
342 	if ((flags & IFF_LOOPBACK) != 0) {
343 		iter->current.flags |= INTERFACE_F_LOOPBACK;
344 		snprintf(iter->current.name, sizeof(iter->current.name),
345 			 "Loopback Interface %d", iter->numIF);
346 		ifNamed = TRUE;
347 	}
348 
349 	/*
350 	 * If the interface is point-to-point, get the destination address.
351 	 */
352 	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
353 		get_addr(AF_INET, &iter->current.dstaddress,
354 		(struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
355 	}
356 
357 	if (ifNamed == FALSE)
358 		snprintf(iter->current.name, sizeof(iter->current.name),
359 			"TCP/IP Interface %d", iter->numIF);
360 
361 	/*
362 	 * Get the network mask.
363 	 */
364 	get_addr(AF_INET, &iter->current.netmask,
365 		 (struct sockaddr *)&(iter->IFData.iiNetmask));
366 
367 	return (ISC_R_SUCCESS);
368 }
369 
370 static isc_result_t
internal_current6(isc_interfaceiter_t * iter)371 internal_current6(isc_interfaceiter_t *iter) {
372 	SOCKET fd;
373 	int i;
374 
375 	REQUIRE(VALID_IFITER(iter));
376 	REQUIRE(iter->buf6 != NULL);
377 
378 	memset(&iter->current, 0, sizeof(iter->current));
379 	iter->current.af = AF_INET6;
380 
381 	if (!iter->pos6zero) {
382 		if (iter->pos6 == 0U)
383 			iter->pos6zero = true;
384 		get_addr(AF_INET6, &iter->current.address,
385 			 iter->buf6->Address[iter->pos6].lpSockaddr);
386 
387 		/*
388 		 * Set interface flags.
389 		 */
390 
391 		iter->current.flags = INTERFACE_F_UP;
392 
393 		snprintf(iter->current.name, sizeof(iter->current.name),
394 			 "TCP/IPv6 Interface %u", iter->pos6 + 1);
395 
396 		for (i = 0; i < 16; i++)
397 			iter->current.netmask.type.in6.s6_addr[i] = 0xff;
398 		iter->current.netmask.family = AF_INET6;
399 		if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6))
400 			   iter->v6loop = true;
401 	} else {
402 		/*
403 		 * See if we can bind to the ::1 and if so return ::1.
404 		 */
405 		struct sockaddr_in6 sin6;
406 
407 		iter->v6loop = true;	/* So we don't loop forever. */
408 
409 		fd = socket(AF_INET6, SOCK_DGRAM, 0);
410 		if (fd == INVALID_SOCKET)
411 			return (ISC_R_IGNORE);
412 		memset(&sin6, 0, sizeof(sin6));
413 		sin6.sin6_family = AF_INET6;
414 		sin6.sin6_addr.s6_addr[15] = 1;
415 		if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
416 			closesocket(fd);
417 			return (ISC_R_IGNORE);
418 		}
419 		closesocket(fd);
420 
421 		iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
422 		snprintf(iter->current.name, sizeof(iter->current.name),
423 			"TCP/IPv6 Loopback Interface");
424 		for (i = 0; i < 16; i++) {
425 			if (i != 15)
426 				iter->current.address.type.in6.s6_addr[i] = 0;
427 			else
428 				iter->current.address.type.in6.s6_addr[i] = 1;
429 			iter->current.netmask.type.in6.s6_addr[i] = 0xff;
430 		}
431 		iter->current.address.family = AF_INET6;
432 		iter->current.netmask.family = AF_INET6;
433 	}
434 	return (ISC_R_SUCCESS);
435 }
436 
437 /*
438  * Step the iterator to the next interface.  Unlike
439  * isc_interfaceiter_next(), this may leave the iterator
440  * positioned on an interface that will ultimately
441  * be ignored.  Return ISC_R_NOMORE if there are no more
442  * interfaces, otherwise ISC_R_SUCCESS.
443  */
444 static isc_result_t
internal_next(isc_interfaceiter_t * iter)445 internal_next(isc_interfaceiter_t *iter) {
446 	if (iter->numIF >= iter->v4IF)
447 		return (ISC_R_NOMORE);
448 
449 	/*
450 	 * The first one needs to be set up to point to the last
451 	 * Element of the array.  Go to the end and back up
452 	 * Microsoft's implementation is peculiar for returning
453 	 * the list in reverse order
454 	 */
455 
456 	if (iter->numIF == 0)
457 		iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
458 
459 	iter->pos4--;
460 	if (&(iter->pos4) < &(iter->buf4))
461 		return (ISC_R_NOMORE);
462 
463 	memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
464 	memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
465 	iter->numIF++;
466 
467 	return (ISC_R_SUCCESS);
468 }
469 
470 static isc_result_t
internal_next6(isc_interfaceiter_t * iter)471 internal_next6(isc_interfaceiter_t *iter) {
472 	if (iter->pos6 == 0U && iter->v6loop)
473 		return (ISC_R_NOMORE);
474 	if (iter->pos6 != 0U)
475 		iter->pos6--;
476 	return (ISC_R_SUCCESS);
477 }
478 
479 isc_result_t
isc_interfaceiter_current(isc_interfaceiter_t * iter,isc_interface_t * ifdata)480 isc_interfaceiter_current(isc_interfaceiter_t *iter,
481 			  isc_interface_t *ifdata) {
482 	REQUIRE(iter->result == ISC_R_SUCCESS);
483 	memmove(ifdata, &iter->current, sizeof(*ifdata));
484 	return (ISC_R_SUCCESS);
485 }
486 
487 isc_result_t
isc_interfaceiter_first(isc_interfaceiter_t * iter)488 isc_interfaceiter_first(isc_interfaceiter_t *iter) {
489 
490 	REQUIRE(VALID_IFITER(iter));
491 
492 	if (iter->buf6 != NULL) {
493 		iter->pos6 = iter->buf6->iAddressCount;
494 		iter->v6loop = false;
495 		iter->pos6zero = (iter->pos6 == 0U);
496 	}
497 	iter->result = ISC_R_SUCCESS;
498 	return (isc_interfaceiter_next(iter));
499 }
500 
501 isc_result_t
isc_interfaceiter_next(isc_interfaceiter_t * iter)502 isc_interfaceiter_next(isc_interfaceiter_t *iter) {
503 	isc_result_t result;
504 
505 	REQUIRE(VALID_IFITER(iter));
506 	REQUIRE(iter->result == ISC_R_SUCCESS);
507 
508 	for (;;) {
509 		result = internal_next(iter);
510 		if (result == ISC_R_NOMORE) {
511 			result = internal_next6(iter);
512 			if (result != ISC_R_SUCCESS)
513 				break;
514 			result = internal_current6(iter);
515 			if (result == ISC_R_IGNORE)
516 				continue;
517 			break;
518 		} else if (result != ISC_R_SUCCESS)
519 			break;
520 		result = internal_current(iter);
521 		if (result != ISC_R_IGNORE)
522 			break;
523 	}
524 	iter->result = result;
525 	return (result);
526 }
527 
528 void
isc_interfaceiter_destroy(isc_interfaceiter_t ** iterp)529 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
530 	isc_interfaceiter_t *iter;
531 	REQUIRE(iterp != NULL);
532 	iter = *iterp;
533 	REQUIRE(VALID_IFITER(iter));
534 
535 	if (iter->buf4 != NULL)
536 		isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
537 	if (iter->buf6 != NULL)
538 		isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
539 
540 	iter->magic = 0;
541 	isc_mem_put(iter->mctx, iter, sizeof(*iter));
542 	*iterp = NULL;
543 }
544