1258945Sroberto/*
2280849Scy * Copyright (C) 2004, 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <sys/types.h>
25258945Sroberto#include <sys/ioctl.h>
26258945Sroberto#ifdef HAVE_SYS_SOCKIO_H
27258945Sroberto#include <sys/sockio.h>		/* Required for ifiter_ioctl.c. */
28258945Sroberto#endif
29258945Sroberto
30258945Sroberto#include <stdio.h>
31258945Sroberto#include <stdlib.h>
32258945Sroberto#include <unistd.h>
33258945Sroberto#include <errno.h>
34258945Sroberto
35258945Sroberto#include <isc/interfaceiter.h>
36258945Sroberto#include <isc/log.h>
37258945Sroberto#include <isc/magic.h>
38258945Sroberto#include <isc/mem.h>
39258945Sroberto#include <isc/msgs.h>
40258945Sroberto#include <isc/net.h>
41258945Sroberto#include <isc/print.h>
42258945Sroberto#include <isc/result.h>
43258945Sroberto#include <isc/strerror.h>
44258945Sroberto#include <isc/string.h>
45258945Sroberto#include <isc/types.h>
46258945Sroberto#include <isc/util.h>
47258945Sroberto
48258945Sroberto/* Must follow <isc/net.h>. */
49258945Sroberto#ifdef HAVE_NET_IF6_H
50258945Sroberto#include <net/if6.h>
51258945Sroberto#endif
52258945Sroberto#include <net/if.h>
53258945Sroberto
54258945Sroberto#ifdef HAVE_LINUX_IF_ADDR_H
55258945Sroberto# include <linux/if_addr.h>
56258945Sroberto#endif
57258945Sroberto
58258945Sroberto/* Common utility functions */
59258945Sroberto
60258945Sroberto/*%
61258945Sroberto * Extract the network address part from a "struct sockaddr".
62258945Sroberto * \brief
63258945Sroberto * The address family is given explicitly
64258945Sroberto * instead of using src->sa_family, because the latter does not work
65258945Sroberto * for copying a network mask obtained by SIOCGIFNETMASK (it does
66258945Sroberto * not have a valid address family).
67258945Sroberto */
68258945Sroberto
69258945Srobertostatic void
70258945Srobertoget_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
71258945Sroberto	 char *ifname)
72258945Sroberto{
73258945Sroberto	struct sockaddr_in6 *sa6;
74258945Sroberto
75258945Sroberto#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
76258945Sroberto    !defined(ISC_PLATFORM_HAVESCOPEID)
77258945Sroberto	UNUSED(ifname);
78258945Sroberto#endif
79258945Sroberto
80258945Sroberto	/* clear any remaining value for safety */
81258945Sroberto	memset(dst, 0, sizeof(*dst));
82258945Sroberto
83258945Sroberto	dst->family = family;
84258945Sroberto	switch (family) {
85258945Sroberto	case AF_INET:
86258945Sroberto		memcpy(&dst->type.in,
87258945Sroberto		       &((struct sockaddr_in *)(void *)src)->sin_addr,
88258945Sroberto		       sizeof(struct in_addr));
89258945Sroberto		break;
90258945Sroberto	case AF_INET6:
91258945Sroberto		sa6 = (struct sockaddr_in6 *)(void *)src;
92258945Sroberto		memcpy(&dst->type.in6, &sa6->sin6_addr,
93258945Sroberto		       sizeof(struct in6_addr));
94258945Sroberto#ifdef ISC_PLATFORM_HAVESCOPEID
95258945Sroberto		if (sa6->sin6_scope_id != 0)
96258945Sroberto			isc_netaddr_setzone(dst, sa6->sin6_scope_id);
97258945Sroberto		else {
98258945Sroberto			/*
99258945Sroberto			 * BSD variants embed scope zone IDs in the 128bit
100258945Sroberto			 * address as a kernel internal form.  Unfortunately,
101258945Sroberto			 * the embedded IDs are not hidden from applications
102258945Sroberto			 * when getting access to them by sysctl or ioctl.
103258945Sroberto			 * We convert the internal format to the pure address
104258945Sroberto			 * part and the zone ID part.
105258945Sroberto			 * Since multicast addresses should not appear here
106258945Sroberto			 * and they cannot be distinguished from netmasks,
107258945Sroberto			 * we only consider unicast link-local addresses.
108258945Sroberto			 */
109258945Sroberto			if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
110258945Sroberto				isc_uint16_t zone16;
111258945Sroberto
112258945Sroberto				memcpy(&zone16, &sa6->sin6_addr.s6_addr[2],
113258945Sroberto				       sizeof(zone16));
114258945Sroberto				zone16 = ntohs(zone16);
115258945Sroberto				if (zone16 != 0) {
116258945Sroberto					/* the zone ID is embedded */
117258945Sroberto					isc_netaddr_setzone(dst,
118258945Sroberto							    (isc_uint32_t)zone16);
119258945Sroberto					dst->type.in6.s6_addr[2] = 0;
120258945Sroberto					dst->type.in6.s6_addr[3] = 0;
121258945Sroberto#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
122258945Sroberto				} else if (ifname != NULL) {
123258945Sroberto					unsigned int zone;
124258945Sroberto
125258945Sroberto					/*
126258945Sroberto					 * sin6_scope_id is still not provided,
127258945Sroberto					 * but the corresponding interface name
128258945Sroberto					 * is know.  Use the interface ID as
129258945Sroberto					 * the link ID.
130258945Sroberto					 */
131258945Sroberto					zone = if_nametoindex(ifname);
132258945Sroberto					if (zone != 0) {
133258945Sroberto						isc_netaddr_setzone(dst,
134258945Sroberto								    (isc_uint32_t)zone);
135258945Sroberto					}
136258945Sroberto#endif
137258945Sroberto				}
138258945Sroberto			}
139258945Sroberto		}
140258945Sroberto#endif
141258945Sroberto		break;
142258945Sroberto	default:
143258945Sroberto		INSIST(0);
144258945Sroberto		break;
145258945Sroberto	}
146258945Sroberto}
147258945Sroberto
148258945Sroberto/*
149258945Sroberto * Include system-dependent code.
150258945Sroberto */
151258945Sroberto
152258945Sroberto#ifdef __linux
153258945Sroberto#define ISC_IF_INET6_SZ \
154258945Sroberto    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
155258945Srobertostatic isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
156258945Srobertostatic isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
157258945Srobertostatic void linux_if_inet6_first(isc_interfaceiter_t *iter);
158258945Sroberto#endif
159258945Sroberto
160258945Sroberto#if HAVE_GETIFADDRS
161258945Sroberto#include "ifiter_getifaddrs.c"
162258945Sroberto#elif HAVE_IFLIST_SYSCTL
163258945Sroberto#include "ifiter_sysctl.c"
164258945Sroberto#else
165258945Sroberto#include "ifiter_ioctl.c"
166258945Sroberto#endif
167258945Sroberto
168258945Sroberto#ifdef __linux
169258945Srobertostatic void
170258945Srobertolinux_if_inet6_first(isc_interfaceiter_t *iter) {
171258945Sroberto	if (iter->proc != NULL) {
172258945Sroberto		rewind(iter->proc);
173258945Sroberto		(void)linux_if_inet6_next(iter);
174258945Sroberto	} else
175258945Sroberto		iter->valid = ISC_R_NOMORE;
176258945Sroberto}
177258945Sroberto
178258945Srobertostatic isc_result_t
179258945Srobertolinux_if_inet6_next(isc_interfaceiter_t *iter) {
180258945Sroberto	if (iter->proc != NULL &&
181258945Sroberto	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
182258945Sroberto		iter->valid = ISC_R_SUCCESS;
183258945Sroberto	else
184258945Sroberto		iter->valid = ISC_R_NOMORE;
185258945Sroberto	return (iter->valid);
186258945Sroberto}
187258945Sroberto
188258945Srobertostatic isc_result_t
189258945Srobertolinux_if_inet6_current(isc_interfaceiter_t *iter) {
190258945Sroberto	char address[33];
191258945Sroberto	char name[IF_NAMESIZE+1];
192258945Sroberto	struct in6_addr addr6;
193258945Sroberto	unsigned int ifindex;
194258945Sroberto	int prefix, scope, flags;
195258945Sroberto	int res;
196258945Sroberto	unsigned int i;
197258945Sroberto
198258945Sroberto	if (iter->valid != ISC_R_SUCCESS)
199258945Sroberto		return (iter->valid);
200258945Sroberto	if (iter->proc == NULL) {
201258945Sroberto		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
202258945Sroberto			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
203258945Sroberto			      "/proc/net/if_inet6:iter->proc == NULL");
204258945Sroberto		return (ISC_R_FAILURE);
205258945Sroberto	}
206258945Sroberto
207258945Sroberto	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
208258945Sroberto		     address, &ifindex, &prefix, &scope, &flags, name);
209258945Sroberto	if (res != 6) {
210258945Sroberto		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
211258945Sroberto			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
212258945Sroberto			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
213258945Sroberto			      res);
214258945Sroberto		return (ISC_R_FAILURE);
215258945Sroberto	}
216258945Sroberto	if (strlen(address) != 32) {
217258945Sroberto		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
218258945Sroberto			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
219258945Sroberto			      "/proc/net/if_inet6:strlen(%s) != 32", address);
220258945Sroberto		return (ISC_R_FAILURE);
221258945Sroberto	}
222258945Sroberto	/*
223258945Sroberto	** Ignore DAD addresses --
224258945Sroberto	** we can't bind to them until they are resolved
225258945Sroberto	*/
226258945Sroberto#ifdef IFA_F_TENTATIVE
227258945Sroberto	if (flags & IFA_F_TENTATIVE)
228258945Sroberto		return (ISC_R_IGNORE);
229258945Sroberto#endif
230258945Sroberto
231258945Sroberto	for (i = 0; i < 16; i++) {
232258945Sroberto		unsigned char byte;
233258945Sroberto		static const char hex[] = "0123456789abcdef";
234258945Sroberto		byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
235258945Sroberto		       (strchr(hex, address[i * 2 + 1]) - hex);
236258945Sroberto		addr6.s6_addr[i] = byte;
237258945Sroberto	}
238258945Sroberto	iter->current.af = AF_INET6;
239280849Scy	iter->current.flags = INTERFACE_F_UP;
240258945Sroberto	isc_netaddr_fromin6(&iter->current.address, &addr6);
241258945Sroberto	iter->current.ifindex = ifindex;
242258945Sroberto	if (isc_netaddr_islinklocal(&iter->current.address)) {
243258945Sroberto		isc_netaddr_setzone(&iter->current.address,
244258945Sroberto				    (isc_uint32_t)ifindex);
245258945Sroberto	}
246258945Sroberto	for (i = 0; i < 16; i++) {
247258945Sroberto		if (prefix > 8) {
248258945Sroberto			addr6.s6_addr[i] = 0xff;
249258945Sroberto			prefix -= 8;
250258945Sroberto		} else {
251258945Sroberto			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
252258945Sroberto			prefix = 0;
253258945Sroberto		}
254258945Sroberto	}
255258945Sroberto	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
256258945Sroberto	strncpy(iter->current.name, name, sizeof(iter->current.name));
257258945Sroberto	return (ISC_R_SUCCESS);
258258945Sroberto}
259258945Sroberto#endif
260258945Sroberto
261258945Sroberto/*
262258945Sroberto * The remaining code is common to the sysctl and ioctl case.
263258945Sroberto */
264258945Sroberto
265258945Srobertoisc_result_t
266258945Srobertoisc_interfaceiter_current(isc_interfaceiter_t *iter,
267258945Sroberto			  isc_interface_t *ifdata)
268258945Sroberto{
269258945Sroberto	REQUIRE(iter->result == ISC_R_SUCCESS);
270258945Sroberto	memcpy(ifdata, &iter->current, sizeof(*ifdata));
271258945Sroberto	return (ISC_R_SUCCESS);
272258945Sroberto}
273258945Sroberto
274258945Srobertoisc_result_t
275258945Srobertoisc_interfaceiter_first(isc_interfaceiter_t *iter) {
276258945Sroberto	isc_result_t result;
277258945Sroberto
278258945Sroberto	REQUIRE(VALID_IFITER(iter));
279258945Sroberto
280258945Sroberto	internal_first(iter);
281258945Sroberto	for (;;) {
282258945Sroberto		result = internal_current(iter);
283258945Sroberto		if (result != ISC_R_IGNORE)
284258945Sroberto			break;
285258945Sroberto		result = internal_next(iter);
286258945Sroberto		if (result != ISC_R_SUCCESS)
287258945Sroberto			break;
288258945Sroberto	}
289258945Sroberto	iter->result = result;
290258945Sroberto	return (result);
291258945Sroberto}
292258945Sroberto
293258945Srobertoisc_result_t
294258945Srobertoisc_interfaceiter_next(isc_interfaceiter_t *iter) {
295258945Sroberto	isc_result_t result;
296258945Sroberto
297258945Sroberto	REQUIRE(VALID_IFITER(iter));
298258945Sroberto	REQUIRE(iter->result == ISC_R_SUCCESS);
299258945Sroberto
300258945Sroberto	for (;;) {
301258945Sroberto		result = internal_next(iter);
302258945Sroberto		if (result != ISC_R_SUCCESS)
303258945Sroberto			break;
304258945Sroberto		result = internal_current(iter);
305258945Sroberto		if (result != ISC_R_IGNORE)
306258945Sroberto			break;
307258945Sroberto	}
308258945Sroberto	iter->result = result;
309258945Sroberto	return (result);
310258945Sroberto}
311258945Sroberto
312258945Srobertovoid
313258945Srobertoisc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
314258945Sroberto{
315258945Sroberto	isc_interfaceiter_t *iter;
316258945Sroberto	REQUIRE(iterp != NULL);
317258945Sroberto	iter = *iterp;
318258945Sroberto	REQUIRE(VALID_IFITER(iter));
319258945Sroberto
320258945Sroberto	internal_destroy(iter);
321258945Sroberto	if (iter->buf != NULL)
322258945Sroberto		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
323258945Sroberto
324258945Sroberto	iter->magic = 0;
325258945Sroberto	isc_mem_put(iter->mctx, iter, sizeof(*iter));
326258945Sroberto	*iterp = NULL;
327258945Sroberto}
328