interfaceiter.c 13.6 KB
Newer Older
Danny Mayer's avatar
Danny Mayer committed
1
/*
2
 * Copyright (C) 1999-2001, 2004, 2007-2009, 2013-2016  Internet Systems Consortium, Inc. ("ISC")
Danny Mayer's avatar
Danny Mayer committed
3
 *
4
5
6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Danny Mayer's avatar
Danny Mayer committed
7
8
 */

Automatic Updater's avatar
Automatic Updater committed
9
/* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */
Danny Mayer's avatar
Danny Mayer committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

/*
 * Note that this code will need to be revisited to support IPv6 Interfaces.
 * For now we just iterate through IPv4 interfaces.
 */

#include <config.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <sys/types.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <isc/interfaceiter.h>
#include <isc/mem.h>
27
#include <isc/print.h>
Danny Mayer's avatar
Danny Mayer committed
28
29
#include <isc/result.h>
#include <isc/string.h>
30
#include <isc/strerror.h>
Danny Mayer's avatar
Danny Mayer committed
31
32
33
#include <isc/types.h>
#include <isc/util.h>

34
35
void InitSockets(void);

Danny Mayer's avatar
Danny Mayer committed
36
37
38
39
40
/* Common utility functions */

/*
 * Extract the network address part from a "struct sockaddr".
 *
Francis Dupont's avatar
Francis Dupont committed
41
 * The address family is given explicitly
Danny Mayer's avatar
Danny Mayer committed
42
43
44
45
46
47
48
49
50
51
52
 * instead of using src->sa_family, because the latter does not work
 * for copying a network mask obtained by SIOCGIFNETMASK (it does
 * not have a valid address family).
 */


#define IFITER_MAGIC		0x49464954U	/* IFIT. */
#define VALID_IFITER(t)		((t) != NULL && (t)->magic == IFITER_MAGIC)

struct isc_interfaceiter {
	unsigned int		magic;		/* Magic number. */
Danny Mayer's avatar
Danny Mayer committed
53
	isc_mem_t		*mctx;
54
	SOCKET			socket;
55
56
	INTERFACE_INFO		IFData;		/* Current Interface Info. */
	int			numIF;		/* Current Interface count. */
57
58
59
60
	int			v4IF;		/* Number of IPv4 Interfaces */
	INTERFACE_INFO		*buf4;		/* Buffer for WSAIoctl data. */
	unsigned int		buf4size;	/* Bytes allocated. */
	INTERFACE_INFO		*pos4;		/* Current offset in IF List */
61
	SOCKET_ADDRESS_LIST	*buf6;		/* Buffer for WSAIoctl data. */
62
	unsigned int		buf6size;	/* Bytes allocated. */
63
64
65
	unsigned int		pos6;		/* Which entry to process. */
	isc_boolean_t		v6loop;		/* See IPv6 loop address. */
	isc_boolean_t		pos6zero;	/* Done pos6 == 0. */
Danny Mayer's avatar
Danny Mayer committed
66
67
68
69
70
71
72
73
74
75
	isc_interface_t		current;	/* Current interface data. */
	isc_result_t		result;		/* Last result code. */
};


/*
 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
 * We assume no sane system will have more than than 1K of IP addresses on
 * all of its adapters.
 */
Danny Mayer's avatar
Danny Mayer committed
76
77
78
#define IFCONF_SIZE_INITIAL	  16
#define IFCONF_SIZE_INCREMENT	  64
#define IFCONF_SIZE_MAX		1040
Danny Mayer's avatar
Danny Mayer committed
79
80
81
82
83
84

static void
get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
	dst->family = family;
	switch (family) {
	case AF_INET:
85
86
87
		memmove(&dst->type.in,
			&((struct sockaddr_in *) src)->sin_addr,
			sizeof(struct in_addr));
Danny Mayer's avatar
Danny Mayer committed
88
89
		break;
	case	AF_INET6:
90
91
92
		memmove(&dst->type.in6,
			&((struct sockaddr_in6 *) src)->sin6_addr,
			sizeof(struct in6_addr));
93
		dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
Danny Mayer's avatar
Danny Mayer committed
94
95
96
97
98
99
100
101
102
		break;
	default:
		INSIST(0);
		break;
	}
}

isc_result_t
isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
Automatic Updater's avatar
Automatic Updater committed
103
	char strbuf[ISC_STRERRORSIZE];
Danny Mayer's avatar
Danny Mayer committed
104
105
106
107
108
109
110
111
112
113
114
115
116
	isc_interfaceiter_t *iter;
	isc_result_t result;
	int error;
	unsigned long bytesReturned = 0;

	REQUIRE(mctx != NULL);
	REQUIRE(iterp != NULL);
	REQUIRE(*iterp == NULL);

	iter = isc_mem_get(mctx, sizeof(*iter));
	if (iter == NULL)
		return (ISC_R_NOMEMORY);

117
118
	InitSockets();

Danny Mayer's avatar
Danny Mayer committed
119
	iter->mctx = mctx;
120
121
122
123
	iter->buf4 = NULL;
	iter->buf6 = NULL;
	iter->pos4 = NULL;
	iter->pos6 = 0;
124
125
	iter->v6loop = ISC_TRUE;
	iter->pos6zero = ISC_TRUE;
126
127
128
129
130
	iter->buf6size = 0;
	iter->buf4size = 0;
	iter->result = ISC_R_FAILURE;
	iter->numIF = 0;
	iter->v4IF = 0;
Danny Mayer's avatar
Danny Mayer committed
131
132

	/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
133
134
	 * Create an unbound datagram socket to do the
	 * SIO_GET_INTERFACE_LIST WSAIoctl on.
Danny Mayer's avatar
Danny Mayer committed
135
	 */
136
137
	iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
	if (iter->socket == INVALID_SOCKET) {
138
		error = WSAGetLastError();
139
140
		if (error == WSAEAFNOSUPPORT)
			goto inet6_only;
141
		isc__strerror(error, strbuf, sizeof(strbuf));
Danny Mayer's avatar
Danny Mayer committed
142
		UNEXPECTED_ERROR(__FILE__, __LINE__,
143
				"making interface scan socket: %s",
144
				strbuf);
Danny Mayer's avatar
Danny Mayer committed
145
146
147
148
149
150
151
152
		result = ISC_R_UNEXPECTED;
		goto socket_failure;
	}

	/*
	 * Get the interface configuration, allocating more memory if
	 * necessary.
	 */
153
	iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
Danny Mayer's avatar
Danny Mayer committed
154
155

	for (;;) {
156
157
		iter->buf4 = isc_mem_get(mctx, iter->buf4size);
		if (iter->buf4 == NULL) {
Danny Mayer's avatar
Danny Mayer committed
158
159
160
161
			result = ISC_R_NOMEMORY;
			goto alloc_failure;
		}

Andreas Gustafsson's avatar
Andreas Gustafsson committed
162
		if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
163
			     0, 0, iter->buf4, iter->buf4size,
164
			     &bytesReturned, 0, 0) == SOCKET_ERROR)
Andreas Gustafsson's avatar
Andreas Gustafsson committed
165
		{
Danny Mayer's avatar
Danny Mayer committed
166
167
168
			error = WSAGetLastError();
			if (error != WSAEFAULT && error != WSAENOBUFS) {
				errno = error;
169
				isc__strerror(error, strbuf, sizeof(strbuf));
Danny Mayer's avatar
Danny Mayer committed
170
				UNEXPECTED_ERROR(__FILE__, __LINE__,
171
						"get interface configuration: %s",
172
						strbuf);
Danny Mayer's avatar
Danny Mayer committed
173
174
175
176
177
178
179
180
181
				result = ISC_R_UNEXPECTED;
				goto ioctl_failure;
			}
			/*
			 * EINVAL.  Retry with a bigger buffer.
			 */
		} else {
			/*
			 * The WSAIoctl succeeded.
Andreas Gustafsson's avatar
Andreas Gustafsson committed
182
183
184
			 * If the number of the returned bytes is the same
			 * as the buffer size, we will grow it just in
			 * case and retry.
Danny Mayer's avatar
Danny Mayer committed
185
			 */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
186
			if (bytesReturned > 0 &&
187
			    (bytesReturned < iter->buf4size))
Danny Mayer's avatar
Danny Mayer committed
188
189
				break;
		}
190
		if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
Danny Mayer's avatar
Danny Mayer committed
191
192
193
194
195
196
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "get interface configuration: "
					 "maximum buffer size exceeded");
			result = ISC_R_UNEXPECTED;
			goto ioctl_failure;
		}
197
		isc_mem_put(mctx, iter->buf4, iter->buf4size);
Danny Mayer's avatar
Danny Mayer committed
198

199
		iter->buf4size += IFCONF_SIZE_INCREMENT *
Andreas Gustafsson's avatar
Andreas Gustafsson committed
200
			sizeof(INTERFACE_INFO);
Danny Mayer's avatar
Danny Mayer committed
201
202
203
204
205
206
	}

	/*
	 * A newly created iterator has an undefined position
	 * until isc_interfaceiter_first() is called.
	 */
207
208
209
210
211
212
213
214
215
216
	iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);

	/* We don't need the socket any more, so close it */
	closesocket(iter->socket);

 inet6_only:
	/*
	 * Create an unbound datagram socket to do the
	 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
	 */
217
218
	iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
	if (iter->socket == INVALID_SOCKET) {
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
		error = WSAGetLastError();
		if (error == WSAEAFNOSUPPORT)
			goto inet_only;
		isc__strerror(error, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				"making interface scan socket: %s",
				strbuf);
		result = ISC_R_UNEXPECTED;
		goto ioctl_failure;
	}

	/*
	 * Get the interface configuration, allocating more memory if
	 * necessary.
	 */
	iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
			 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);

	for (;;) {
		iter->buf6 = isc_mem_get(mctx, iter->buf6size);
		if (iter->buf6 == NULL) {
			result = ISC_R_NOMEMORY;
			goto ioctl_failure;
		}

		if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
			     0, 0, iter->buf6, iter->buf6size,
			     &bytesReturned, 0, 0) == SOCKET_ERROR)
		{
			error = WSAGetLastError();
			if (error != WSAEFAULT && error != WSAENOBUFS) {
				errno = error;
				isc__strerror(error, strbuf, sizeof(strbuf));
				UNEXPECTED_ERROR(__FILE__, __LINE__,
						 "sio address list query: %s",
						 strbuf);
				result = ISC_R_UNEXPECTED;
				goto ioctl6_failure;
			}
			/*
			 * EINVAL.  Retry with a bigger buffer.
			 */
		} else
			break;
Danny Mayer's avatar
Danny Mayer committed
263

264
265
266
267
268
269
270
271
		if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "get interface configuration: "
					 "maximum buffer size exceeded");
			result = ISC_R_UNEXPECTED;
			goto ioctl6_failure;
		}
		isc_mem_put(mctx, iter->buf6, iter->buf6size);
Danny Mayer's avatar
Danny Mayer committed
272

273
274
275
276
277
278
279
		iter->buf6size += IFCONF_SIZE_INCREMENT *
			sizeof(SOCKET_ADDRESS);
	}

	closesocket(iter->socket);

 inet_only:
Danny Mayer's avatar
Danny Mayer committed
280
281
282
283
	iter->magic = IFITER_MAGIC;
	*iterp = iter;
	return (ISC_R_SUCCESS);

284
285
286
 ioctl6_failure:
	isc_mem_put(mctx, iter->buf6, iter->buf6size);

Danny Mayer's avatar
Danny Mayer committed
287
 ioctl_failure:
288
289
	if (iter->buf4 != NULL)
		isc_mem_put(mctx, iter->buf4, iter->buf4size);
Danny Mayer's avatar
Danny Mayer committed
290
291

 alloc_failure:
292
	if (iter->socket != INVALID_SOCKET)
293
		(void) closesocket(iter->socket);
Danny Mayer's avatar
Danny Mayer committed
294
295

 socket_failure:
Andreas Gustafsson's avatar
Andreas Gustafsson committed
296
	isc_mem_put(mctx, iter, sizeof(*iter));
Danny Mayer's avatar
Danny Mayer committed
297
298
299
300
301
302
303
304
305
306
307
308
	return (result);
}

/*
 * Get information about the current interface to iter->current.
 * If successful, return ISC_R_SUCCESS.
 * If the interface has an unsupported address family, or if
 * some operation on it fails, return ISC_R_IGNORE to make
 * the higher-level iterator code ignore it.
 */

static isc_result_t
309
internal_current(isc_interfaceiter_t *iter) {
Danny Mayer's avatar
Danny Mayer committed
310
311
	BOOL ifNamed = FALSE;
	unsigned long flags;
Andreas Gustafsson's avatar
Andreas Gustafsson committed
312

Danny Mayer's avatar
Danny Mayer committed
313
314
315
316
	REQUIRE(VALID_IFITER(iter));
	REQUIRE(iter->numIF >= 0);

	memset(&iter->current, 0, sizeof(iter->current));
317
	iter->current.af = AF_INET;
Danny Mayer's avatar
Danny Mayer committed
318

319
	get_addr(AF_INET, &iter->current.address,
Danny Mayer's avatar
Danny Mayer committed
320
321
322
323
324
325
326
327
328
329
330
331
		 (struct sockaddr *)&(iter->IFData.iiAddress));

	/*
	 * Get interface flags.
	 */

	iter->current.flags = 0;
	flags = iter->IFData.iiFlags;

	if ((flags & IFF_UP) != 0)
		iter->current.flags |= INTERFACE_F_UP;

Andreas Gustafsson's avatar
Andreas Gustafsson committed
332
	if ((flags & IFF_POINTTOPOINT) != 0) {
Danny Mayer's avatar
Danny Mayer committed
333
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
334
335
		snprintf(iter->current.name, sizeof(iter->current.name),
			 "PPP Interface %d", iter->numIF);
Danny Mayer's avatar
Danny Mayer committed
336
337
338
		ifNamed = TRUE;
	}

Andreas Gustafsson's avatar
Andreas Gustafsson committed
339
	if ((flags & IFF_LOOPBACK) != 0) {
Danny Mayer's avatar
Danny Mayer committed
340
		iter->current.flags |= INTERFACE_F_LOOPBACK;
341
342
		snprintf(iter->current.name, sizeof(iter->current.name),
			 "Loopback Interface %d", iter->numIF);
Danny Mayer's avatar
Danny Mayer committed
343
344
345
346
347
348
349
		ifNamed = TRUE;
	}

	/*
	 * If the interface is point-to-point, get the destination address.
	 */
	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
350
		get_addr(AF_INET, &iter->current.dstaddress,
Danny Mayer's avatar
Danny Mayer committed
351
		(struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
Danny Mayer's avatar
Danny Mayer committed
352
353
	}

Danny Mayer's avatar
Danny Mayer committed
354
	if (ifNamed == FALSE)
355
		snprintf(iter->current.name, sizeof(iter->current.name),
Andreas Gustafsson's avatar
Andreas Gustafsson committed
356
357
			"TCP/IP Interface %d", iter->numIF);

Danny Mayer's avatar
Danny Mayer committed
358
359
360
	/*
	 * Get the network mask.
	 */
361
362
	get_addr(AF_INET, &iter->current.netmask,
		 (struct sockaddr *)&(iter->IFData.iiNetmask));
Danny Mayer's avatar
Danny Mayer committed
363
364
365
366

	return (ISC_R_SUCCESS);
}

367
368
static isc_result_t
internal_current6(isc_interfaceiter_t *iter) {
369
	SOCKET fd;
370
371
372
	int i;

	REQUIRE(VALID_IFITER(iter));
373
	REQUIRE(iter->buf6 != NULL);
374
375
376
377

	memset(&iter->current, 0, sizeof(iter->current));
	iter->current.af = AF_INET6;

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
	if (iter->pos6 != 0U || !iter->pos6zero) {
		if (iter->pos6 == 0U)
			iter->pos6zero = ISC_TRUE;
		get_addr(AF_INET6, &iter->current.address,
			 iter->buf6->Address[iter->pos6].lpSockaddr);

		/*
		 * Set interface flags.
		 */

		iter->current.flags = INTERFACE_F_UP;

		snprintf(iter->current.name, sizeof(iter->current.name),
			 "TCP/IPv6 Interface %d", iter->pos6 + 1);

		for (i = 0; i < 16; i++)
			iter->current.netmask.type.in6.s6_addr[i] = 0xff;
		iter->current.netmask.family = AF_INET6;
		if (IN6_IS_ADDR_LOOPBACK(&iter->current.address.type.in6))
			   iter->v6loop = ISC_TRUE;
	} else {
		/*
		 * See if we can bind to the ::1 and if so return ::1.
		 */
		struct sockaddr_in6 sin6;

		iter->v6loop = ISC_TRUE;	/* So we don't loop forever. */

		fd = socket(AF_INET6, SOCK_DGRAM, 0);
		if (fd == INVALID_SOCKET)
			return (ISC_R_IGNORE);
		memset(&sin6, 0, sizeof(sin6));
		sin6.sin6_family = AF_INET6;
		sin6.sin6_addr.s6_addr[15] = 1;
		if (bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
			closesocket(fd);
			return (ISC_R_IGNORE);
		}
		closesocket(fd);

		iter->current.flags = INTERFACE_F_UP | INTERFACE_F_LOOPBACK;
		snprintf(iter->current.name, sizeof(iter->current.name),
			"TCP/IPv6 Loopback Interface");
		for (i = 0; i < 16; i++) {
			if (i != 15)
				iter->current.address.type.in6.s6_addr[i] = 0;
			else
				iter->current.address.type.in6.s6_addr[i] = 1;
			iter->current.netmask.type.in6.s6_addr[i] = 0xff;
		}
		iter->current.address.family = AF_INET6;
		iter->current.netmask.family = AF_INET6;
	}
431
432
433
	return (ISC_R_SUCCESS);
}

Danny Mayer's avatar
Danny Mayer committed
434
435
436
437
438
439
440
441
442
/*
 * Step the iterator to the next interface.  Unlike
 * isc_interfaceiter_next(), this may leave the iterator
 * positioned on an interface that will ultimately
 * be ignored.  Return ISC_R_NOMORE if there are no more
 * interfaces, otherwise ISC_R_SUCCESS.
 */
static isc_result_t
internal_next(isc_interfaceiter_t *iter) {
443
	if (iter->numIF >= iter->v4IF)
Danny Mayer's avatar
Danny Mayer committed
444
445
446
447
448
449
450
451
		return (ISC_R_NOMORE);

	/*
	 * The first one needs to be set up to point to the last
	 * Element of the array.  Go to the end and back up
	 * Microsoft's implementation is peculiar for returning
	 * the list in reverse order
	 */
Automatic Updater's avatar
Automatic Updater committed
452

Danny Mayer's avatar
Danny Mayer committed
453
	if (iter->numIF == 0)
454
		iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
Andreas Gustafsson's avatar
Andreas Gustafsson committed
455

456
457
	iter->pos4--;
	if (&(iter->pos4) < &(iter->buf4))
Danny Mayer's avatar
Danny Mayer committed
458
459
460
		return (ISC_R_NOMORE);

	memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
461
	memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
Danny Mayer's avatar
Danny Mayer committed
462
463
464
465
466
	iter->numIF++;

	return (ISC_R_SUCCESS);
}

467
static isc_result_t
468
internal_next6(isc_interfaceiter_t *iter) {
469
	if (iter->pos6 == 0 && iter->v6loop)
470
		return (ISC_R_NOMORE);
471
472
	if (iter->pos6 != 0)
		iter->pos6--;
473
474
475
	return (ISC_R_SUCCESS);
}

Danny Mayer's avatar
Danny Mayer committed
476
477
isc_result_t
isc_interfaceiter_current(isc_interfaceiter_t *iter,
Danny Mayer's avatar
Danny Mayer committed
478
			  isc_interface_t *ifdata) {
Danny Mayer's avatar
Danny Mayer committed
479
	REQUIRE(iter->result == ISC_R_SUCCESS);
480
	memmove(ifdata, &iter->current, sizeof(*ifdata));
Danny Mayer's avatar
Danny Mayer committed
481
482
483
484
485
486
487
488
	return (ISC_R_SUCCESS);
}

isc_result_t
isc_interfaceiter_first(isc_interfaceiter_t *iter) {

	REQUIRE(VALID_IFITER(iter));

489
	if (iter->buf6 != NULL) {
490
		iter->pos6 = iter->buf6->iAddressCount;
491
492
493
		iter->v6loop = ISC_FALSE;
		iter->pos6zero = ISC_FALSE;
	}
494
495
	iter->result = ISC_R_SUCCESS;
	return (isc_interfaceiter_next(iter));
Danny Mayer's avatar
Danny Mayer committed
496
497
498
499
500
501
502
503
504
505
506
}

isc_result_t
isc_interfaceiter_next(isc_interfaceiter_t *iter) {
	isc_result_t result;

	REQUIRE(VALID_IFITER(iter));
	REQUIRE(iter->result == ISC_R_SUCCESS);

	for (;;) {
		result = internal_next(iter);
507
508
509
510
511
		if (result == ISC_R_NOMORE) {
			result = internal_next6(iter);
			if (result != ISC_R_SUCCESS)
				break;
			result = internal_current6(iter);
512
513
514
			if (result == ISC_R_IGNORE)
				continue;
			break;
515
		} else if (result != ISC_R_SUCCESS)
Danny Mayer's avatar
Danny Mayer committed
516
			break;
517
		result = internal_current(iter);
Danny Mayer's avatar
Danny Mayer committed
518
519
520
521
522
523
524
525
		if (result != ISC_R_IGNORE)
			break;
	}
	iter->result = result;
	return (result);
}

void
Andreas Gustafsson's avatar
Andreas Gustafsson committed
526
isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
Danny Mayer's avatar
Danny Mayer committed
527
528
529
530
531
	isc_interfaceiter_t *iter;
	REQUIRE(iterp != NULL);
	iter = *iterp;
	REQUIRE(VALID_IFITER(iter));

532
533
534
535
	if (iter->buf4 != NULL)
		isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
	if (iter->buf6 != NULL)
		isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
Danny Mayer's avatar
Danny Mayer committed
536
537

	iter->magic = 0;
Andreas Gustafsson's avatar
Andreas Gustafsson committed
538
	isc_mem_put(iter->mctx, iter, sizeof(*iter));
Danny Mayer's avatar
Danny Mayer committed
539
540
	*iterp = NULL;
}