PageRenderTime 59ms CodeModel.GetById 37ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/isc/unix/interfaceiter.c

https://bitbucket.org/freebsd/freebsd-head/
C | 312 lines | 225 code | 34 blank | 53 comment | 46 complexity | 35a5e5c1838957d1f1fc9599f0d84b3c MD5 | raw file
  1/*
  2 * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
  3 * Copyright (C) 1999-2003  Internet Software Consortium.
  4 *
  5 * Permission to use, copy, modify, and/or 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: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */
 19
 20/*! \file */
 21
 22#include <config.h>
 23
 24#include <sys/types.h>
 25#include <sys/ioctl.h>
 26#ifdef HAVE_SYS_SOCKIO_H
 27#include <sys/sockio.h>		/* Required for ifiter_ioctl.c. */
 28#endif
 29
 30#include <stdio.h>
 31#include <stdlib.h>
 32#include <unistd.h>
 33#include <errno.h>
 34
 35#include <isc/interfaceiter.h>
 36#include <isc/log.h>
 37#include <isc/magic.h>
 38#include <isc/mem.h>
 39#include <isc/msgs.h>
 40#include <isc/net.h>
 41#include <isc/print.h>
 42#include <isc/result.h>
 43#include <isc/strerror.h>
 44#include <isc/string.h>
 45#include <isc/types.h>
 46#include <isc/util.h>
 47
 48/* Must follow <isc/net.h>. */
 49#ifdef HAVE_NET_IF6_H
 50#include <net/if6.h>
 51#endif
 52#include <net/if.h>
 53
 54/* Common utility functions */
 55
 56/*%
 57 * Extract the network address part from a "struct sockaddr".
 58 * \brief
 59 * The address family is given explicitly
 60 * instead of using src->sa_family, because the latter does not work
 61 * for copying a network mask obtained by SIOCGIFNETMASK (it does
 62 * not have a valid address family).
 63 */
 64
 65static void
 66get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
 67	 char *ifname)
 68{
 69	struct sockaddr_in6 *sa6;
 70
 71#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
 72    !defined(ISC_PLATFORM_HAVESCOPEID)
 73	UNUSED(ifname);
 74#endif
 75
 76	/* clear any remaining value for safety */
 77	memset(dst, 0, sizeof(*dst));
 78
 79	dst->family = family;
 80	switch (family) {
 81	case AF_INET:
 82		memcpy(&dst->type.in,
 83		       &((struct sockaddr_in *) src)->sin_addr,
 84		       sizeof(struct in_addr));
 85		break;
 86	case AF_INET6:
 87		sa6 = (struct sockaddr_in6 *)src;
 88		memcpy(&dst->type.in6, &sa6->sin6_addr,
 89		       sizeof(struct in6_addr));
 90#ifdef ISC_PLATFORM_HAVESCOPEID
 91		if (sa6->sin6_scope_id != 0)
 92			isc_netaddr_setzone(dst, sa6->sin6_scope_id);
 93		else {
 94			/*
 95			 * BSD variants embed scope zone IDs in the 128bit
 96			 * address as a kernel internal form.  Unfortunately,
 97			 * the embedded IDs are not hidden from applications
 98			 * when getting access to them by sysctl or ioctl.
 99			 * We convert the internal format to the pure address
100			 * part and the zone ID part.
101			 * Since multicast addresses should not appear here
102			 * and they cannot be distinguished from netmasks,
103			 * we only consider unicast link-local addresses.
104			 */
105			if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
106				isc_uint16_t zone16;
107
108				memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
109				       sizeof(zone16));
110				zone16 = ntohs(zone16);
111				if (zone16 != 0) {
112					/* the zone ID is embedded */
113					isc_netaddr_setzone(dst,
114							    (isc_uint32_t)zone16);
115					dst->type.in6.s6_addr[2] = 0;
116					dst->type.in6.s6_addr[3] = 0;
117#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
118				} else if (ifname != NULL) {
119					unsigned int zone;
120
121					/*
122					 * sin6_scope_id is still not provided,
123					 * but the corresponding interface name
124					 * is know.  Use the interface ID as
125					 * the link ID.
126					 */
127					zone = if_nametoindex(ifname);
128					if (zone != 0) {
129						isc_netaddr_setzone(dst,
130								    (isc_uint32_t)zone);
131					}
132#endif
133				}
134			}
135		}
136#endif
137		break;
138	default:
139		INSIST(0);
140		break;
141	}
142}
143
144/*
145 * Include system-dependent code.
146 */
147
148#ifdef __linux
149#define ISC_IF_INET6_SZ \
150    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
151static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
152static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
153static void linux_if_inet6_first(isc_interfaceiter_t *iter);
154#endif
155
156#if HAVE_GETIFADDRS
157#include "ifiter_getifaddrs.c"
158#elif HAVE_IFLIST_SYSCTL
159#include "ifiter_sysctl.c"
160#else
161#include "ifiter_ioctl.c"
162#endif
163
164#ifdef __linux
165static void
166linux_if_inet6_first(isc_interfaceiter_t *iter) {
167	if (iter->proc != NULL) {
168		rewind(iter->proc);
169		(void)linux_if_inet6_next(iter);
170	} else
171		iter->valid = ISC_R_NOMORE;
172}
173
174static isc_result_t
175linux_if_inet6_next(isc_interfaceiter_t *iter) {
176	if (iter->proc != NULL &&
177	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
178		iter->valid = ISC_R_SUCCESS;
179	else
180		iter->valid = ISC_R_NOMORE;
181	return (iter->valid);
182}
183
184static isc_result_t
185linux_if_inet6_current(isc_interfaceiter_t *iter) {
186	char address[33];
187	char name[IF_NAMESIZE+1];
188	struct in6_addr addr6;
189	int ifindex, prefix, flag3, flag4;
190	int res;
191	unsigned int i;
192
193	if (iter->valid != ISC_R_SUCCESS)
194		return (iter->valid);
195	if (iter->proc == NULL) {
196		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
197			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
198			      "/proc/net/if_inet6:iter->proc == NULL");
199		return (ISC_R_FAILURE);
200	}
201
202	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
203		     address, &ifindex, &prefix, &flag3, &flag4, name);
204	if (res != 6) {
205		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
206			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
207			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
208			      res);
209		return (ISC_R_FAILURE);
210	}
211	if (strlen(address) != 32) {
212		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
213			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
214			      "/proc/net/if_inet6:strlen(%s) != 32", address);
215		return (ISC_R_FAILURE);
216	}
217	for (i = 0; i < 16; i++) {
218		unsigned char byte;
219		static const char hex[] = "0123456789abcdef";
220		byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
221		       (strchr(hex, address[i * 2 + 1]) - hex);
222		addr6.s6_addr[i] = byte;
223	}
224	iter->current.af = AF_INET6;
225	iter->current.flags = INTERFACE_F_UP;
226	isc_netaddr_fromin6(&iter->current.address, &addr6);
227	if (isc_netaddr_islinklocal(&iter->current.address)) {
228		isc_netaddr_setzone(&iter->current.address,
229				    (isc_uint32_t)ifindex);
230	}
231	for (i = 0; i < 16; i++) {
232		if (prefix > 8) {
233			addr6.s6_addr[i] = 0xff;
234			prefix -= 8;
235		} else {
236			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
237			prefix = 0;
238		}
239	}
240	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
241	strncpy(iter->current.name, name, sizeof(iter->current.name));
242	return (ISC_R_SUCCESS);
243}
244#endif
245
246/*
247 * The remaining code is common to the sysctl and ioctl case.
248 */
249
250isc_result_t
251isc_interfaceiter_current(isc_interfaceiter_t *iter,
252			  isc_interface_t *ifdata)
253{
254	REQUIRE(iter->result == ISC_R_SUCCESS);
255	memcpy(ifdata, &iter->current, sizeof(*ifdata));
256	return (ISC_R_SUCCESS);
257}
258
259isc_result_t
260isc_interfaceiter_first(isc_interfaceiter_t *iter) {
261	isc_result_t result;
262
263	REQUIRE(VALID_IFITER(iter));
264
265	internal_first(iter);
266	for (;;) {
267		result = internal_current(iter);
268		if (result != ISC_R_IGNORE)
269			break;
270		result = internal_next(iter);
271		if (result != ISC_R_SUCCESS)
272			break;
273	}
274	iter->result = result;
275	return (result);
276}
277
278isc_result_t
279isc_interfaceiter_next(isc_interfaceiter_t *iter) {
280	isc_result_t result;
281
282	REQUIRE(VALID_IFITER(iter));
283	REQUIRE(iter->result == ISC_R_SUCCESS);
284
285	for (;;) {
286		result = internal_next(iter);
287		if (result != ISC_R_SUCCESS)
288			break;
289		result = internal_current(iter);
290		if (result != ISC_R_IGNORE)
291			break;
292	}
293	iter->result = result;
294	return (result);
295}
296
297void
298isc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
299{
300	isc_interfaceiter_t *iter;
301	REQUIRE(iterp != NULL);
302	iter = *iterp;
303	REQUIRE(VALID_IFITER(iter));
304
305	internal_destroy(iter);
306	if (iter->buf != NULL)
307		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
308
309	iter->magic = 0;
310	isc_mem_put(iter->mctx, iter, sizeof(*iter));
311	*iterp = NULL;
312}