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}
313