1135446Strhodes/*
2262706Serwin * Copyright (C) 2004, 2005, 2007, 2008, 2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <sys/types.h>
25135446Strhodes#include <sys/ioctl.h>
26135446Strhodes#ifdef HAVE_SYS_SOCKIO_H
27135446Strhodes#include <sys/sockio.h>		/* Required for ifiter_ioctl.c. */
28135446Strhodes#endif
29135446Strhodes
30135446Strhodes#include <stdio.h>
31135446Strhodes#include <stdlib.h>
32135446Strhodes#include <unistd.h>
33135446Strhodes#include <errno.h>
34135446Strhodes
35135446Strhodes#include <isc/interfaceiter.h>
36135446Strhodes#include <isc/log.h>
37135446Strhodes#include <isc/magic.h>
38135446Strhodes#include <isc/mem.h>
39135446Strhodes#include <isc/msgs.h>
40135446Strhodes#include <isc/net.h>
41135446Strhodes#include <isc/print.h>
42135446Strhodes#include <isc/result.h>
43135446Strhodes#include <isc/strerror.h>
44135446Strhodes#include <isc/string.h>
45135446Strhodes#include <isc/types.h>
46135446Strhodes#include <isc/util.h>
47135446Strhodes
48135446Strhodes/* Must follow <isc/net.h>. */
49135446Strhodes#ifdef HAVE_NET_IF6_H
50135446Strhodes#include <net/if6.h>
51135446Strhodes#endif
52135446Strhodes#include <net/if.h>
53135446Strhodes
54135446Strhodes/* Common utility functions */
55135446Strhodes
56170222Sdougb/*%
57135446Strhodes * Extract the network address part from a "struct sockaddr".
58170222Sdougb * \brief
59135446Strhodes * The address family is given explicitly
60135446Strhodes * instead of using src->sa_family, because the latter does not work
61135446Strhodes * for copying a network mask obtained by SIOCGIFNETMASK (it does
62135446Strhodes * not have a valid address family).
63135446Strhodes */
64135446Strhodes
65135446Strhodesstatic void
66135446Strhodesget_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src,
67135446Strhodes	 char *ifname)
68135446Strhodes{
69135446Strhodes	struct sockaddr_in6 *sa6;
70135446Strhodes
71135446Strhodes#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \
72135446Strhodes    !defined(ISC_PLATFORM_HAVESCOPEID)
73135446Strhodes	UNUSED(ifname);
74135446Strhodes#endif
75135446Strhodes
76135446Strhodes	/* clear any remaining value for safety */
77135446Strhodes	memset(dst, 0, sizeof(*dst));
78135446Strhodes
79135446Strhodes	dst->family = family;
80135446Strhodes	switch (family) {
81135446Strhodes	case AF_INET:
82262706Serwin		memmove(&dst->type.in,
83262706Serwin			&((struct sockaddr_in *) src)->sin_addr,
84262706Serwin			sizeof(struct in_addr));
85135446Strhodes		break;
86135446Strhodes	case AF_INET6:
87135446Strhodes		sa6 = (struct sockaddr_in6 *)src;
88262706Serwin		memmove(&dst->type.in6, &sa6->sin6_addr,
89262706Serwin			sizeof(struct in6_addr));
90135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID
91135446Strhodes		if (sa6->sin6_scope_id != 0)
92135446Strhodes			isc_netaddr_setzone(dst, sa6->sin6_scope_id);
93135446Strhodes		else {
94135446Strhodes			/*
95135446Strhodes			 * BSD variants embed scope zone IDs in the 128bit
96135446Strhodes			 * address as a kernel internal form.  Unfortunately,
97135446Strhodes			 * the embedded IDs are not hidden from applications
98135446Strhodes			 * when getting access to them by sysctl or ioctl.
99135446Strhodes			 * We convert the internal format to the pure address
100135446Strhodes			 * part and the zone ID part.
101135446Strhodes			 * Since multicast addresses should not appear here
102135446Strhodes			 * and they cannot be distinguished from netmasks,
103135446Strhodes			 * we only consider unicast link-local addresses.
104135446Strhodes			 */
105135446Strhodes			if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
106135446Strhodes				isc_uint16_t zone16;
107135446Strhodes
108262706Serwin				memmove(&zone16, &sa6->sin6_addr.s6_addr[2],
109262706Serwin					sizeof(zone16));
110135446Strhodes				zone16 = ntohs(zone16);
111135446Strhodes				if (zone16 != 0) {
112135446Strhodes					/* the zone ID is embedded */
113135446Strhodes					isc_netaddr_setzone(dst,
114135446Strhodes							    (isc_uint32_t)zone16);
115135446Strhodes					dst->type.in6.s6_addr[2] = 0;
116135446Strhodes					dst->type.in6.s6_addr[3] = 0;
117135446Strhodes#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
118135446Strhodes				} else if (ifname != NULL) {
119135446Strhodes					unsigned int zone;
120135446Strhodes
121135446Strhodes					/*
122135446Strhodes					 * sin6_scope_id is still not provided,
123135446Strhodes					 * but the corresponding interface name
124135446Strhodes					 * is know.  Use the interface ID as
125135446Strhodes					 * the link ID.
126135446Strhodes					 */
127135446Strhodes					zone = if_nametoindex(ifname);
128135446Strhodes					if (zone != 0) {
129135446Strhodes						isc_netaddr_setzone(dst,
130135446Strhodes								    (isc_uint32_t)zone);
131135446Strhodes					}
132135446Strhodes#endif
133135446Strhodes				}
134135446Strhodes			}
135135446Strhodes		}
136135446Strhodes#endif
137135446Strhodes		break;
138135446Strhodes	default:
139135446Strhodes		INSIST(0);
140135446Strhodes		break;
141135446Strhodes	}
142135446Strhodes}
143135446Strhodes
144135446Strhodes/*
145135446Strhodes * Include system-dependent code.
146135446Strhodes */
147135446Strhodes
148193149Sdougb#ifdef __linux
149193149Sdougb#define ISC_IF_INET6_SZ \
150193149Sdougb    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
151193149Sdougbstatic isc_result_t linux_if_inet6_next(isc_interfaceiter_t *);
152193149Sdougbstatic isc_result_t linux_if_inet6_current(isc_interfaceiter_t *);
153193149Sdougbstatic void linux_if_inet6_first(isc_interfaceiter_t *iter);
154193149Sdougb#endif
155193149Sdougb
156135446Strhodes#if HAVE_GETIFADDRS
157135446Strhodes#include "ifiter_getifaddrs.c"
158135446Strhodes#elif HAVE_IFLIST_SYSCTL
159135446Strhodes#include "ifiter_sysctl.c"
160135446Strhodes#else
161135446Strhodes#include "ifiter_ioctl.c"
162135446Strhodes#endif
163135446Strhodes
164193149Sdougb#ifdef __linux
165193149Sdougbstatic void
166193149Sdougblinux_if_inet6_first(isc_interfaceiter_t *iter) {
167193149Sdougb	if (iter->proc != NULL) {
168193149Sdougb		rewind(iter->proc);
169193149Sdougb		(void)linux_if_inet6_next(iter);
170193149Sdougb	} else
171193149Sdougb		iter->valid = ISC_R_NOMORE;
172193149Sdougb}
173193149Sdougb
174193149Sdougbstatic isc_result_t
175193149Sdougblinux_if_inet6_next(isc_interfaceiter_t *iter) {
176193149Sdougb	if (iter->proc != NULL &&
177193149Sdougb	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
178193149Sdougb		iter->valid = ISC_R_SUCCESS;
179193149Sdougb	else
180193149Sdougb		iter->valid = ISC_R_NOMORE;
181193149Sdougb	return (iter->valid);
182193149Sdougb}
183193149Sdougb
184193149Sdougbstatic isc_result_t
185193149Sdougblinux_if_inet6_current(isc_interfaceiter_t *iter) {
186193149Sdougb	char address[33];
187193149Sdougb	char name[IF_NAMESIZE+1];
188193149Sdougb	struct in6_addr addr6;
189193149Sdougb	int ifindex, prefix, flag3, flag4;
190193149Sdougb	int res;
191193149Sdougb	unsigned int i;
192193149Sdougb
193193149Sdougb	if (iter->valid != ISC_R_SUCCESS)
194193149Sdougb		return (iter->valid);
195193149Sdougb	if (iter->proc == NULL) {
196193149Sdougb		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
197193149Sdougb			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
198193149Sdougb			      "/proc/net/if_inet6:iter->proc == NULL");
199193149Sdougb		return (ISC_R_FAILURE);
200193149Sdougb	}
201193149Sdougb
202193149Sdougb	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
203193149Sdougb		     address, &ifindex, &prefix, &flag3, &flag4, name);
204193149Sdougb	if (res != 6) {
205193149Sdougb		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
206193149Sdougb			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
207193149Sdougb			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
208193149Sdougb			      res);
209193149Sdougb		return (ISC_R_FAILURE);
210193149Sdougb	}
211193149Sdougb	if (strlen(address) != 32) {
212193149Sdougb		isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
213193149Sdougb			      ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR,
214193149Sdougb			      "/proc/net/if_inet6:strlen(%s) != 32", address);
215193149Sdougb		return (ISC_R_FAILURE);
216193149Sdougb	}
217193149Sdougb	for (i = 0; i < 16; i++) {
218193149Sdougb		unsigned char byte;
219193149Sdougb		static const char hex[] = "0123456789abcdef";
220193149Sdougb		byte = ((strchr(hex, address[i * 2]) - hex) << 4) |
221193149Sdougb		       (strchr(hex, address[i * 2 + 1]) - hex);
222193149Sdougb		addr6.s6_addr[i] = byte;
223193149Sdougb	}
224193149Sdougb	iter->current.af = AF_INET6;
225193149Sdougb	iter->current.flags = INTERFACE_F_UP;
226193149Sdougb	isc_netaddr_fromin6(&iter->current.address, &addr6);
227193149Sdougb	if (isc_netaddr_islinklocal(&iter->current.address)) {
228193149Sdougb		isc_netaddr_setzone(&iter->current.address,
229193149Sdougb				    (isc_uint32_t)ifindex);
230193149Sdougb	}
231193149Sdougb	for (i = 0; i < 16; i++) {
232193149Sdougb		if (prefix > 8) {
233193149Sdougb			addr6.s6_addr[i] = 0xff;
234193149Sdougb			prefix -= 8;
235193149Sdougb		} else {
236193149Sdougb			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
237193149Sdougb			prefix = 0;
238193149Sdougb		}
239193149Sdougb	}
240193149Sdougb	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
241193149Sdougb	strncpy(iter->current.name, name, sizeof(iter->current.name));
242193149Sdougb	return (ISC_R_SUCCESS);
243193149Sdougb}
244193149Sdougb#endif
245193149Sdougb
246135446Strhodes/*
247135446Strhodes * The remaining code is common to the sysctl and ioctl case.
248135446Strhodes */
249135446Strhodes
250135446Strhodesisc_result_t
251135446Strhodesisc_interfaceiter_current(isc_interfaceiter_t *iter,
252135446Strhodes			  isc_interface_t *ifdata)
253135446Strhodes{
254135446Strhodes	REQUIRE(iter->result == ISC_R_SUCCESS);
255262706Serwin	memmove(ifdata, &iter->current, sizeof(*ifdata));
256135446Strhodes	return (ISC_R_SUCCESS);
257135446Strhodes}
258135446Strhodes
259135446Strhodesisc_result_t
260135446Strhodesisc_interfaceiter_first(isc_interfaceiter_t *iter) {
261135446Strhodes	isc_result_t result;
262135446Strhodes
263135446Strhodes	REQUIRE(VALID_IFITER(iter));
264135446Strhodes
265135446Strhodes	internal_first(iter);
266135446Strhodes	for (;;) {
267135446Strhodes		result = internal_current(iter);
268135446Strhodes		if (result != ISC_R_IGNORE)
269135446Strhodes			break;
270135446Strhodes		result = internal_next(iter);
271135446Strhodes		if (result != ISC_R_SUCCESS)
272135446Strhodes			break;
273135446Strhodes	}
274135446Strhodes	iter->result = result;
275135446Strhodes	return (result);
276135446Strhodes}
277135446Strhodes
278135446Strhodesisc_result_t
279135446Strhodesisc_interfaceiter_next(isc_interfaceiter_t *iter) {
280135446Strhodes	isc_result_t result;
281135446Strhodes
282135446Strhodes	REQUIRE(VALID_IFITER(iter));
283135446Strhodes	REQUIRE(iter->result == ISC_R_SUCCESS);
284135446Strhodes
285135446Strhodes	for (;;) {
286135446Strhodes		result = internal_next(iter);
287135446Strhodes		if (result != ISC_R_SUCCESS)
288135446Strhodes			break;
289135446Strhodes		result = internal_current(iter);
290135446Strhodes		if (result != ISC_R_IGNORE)
291135446Strhodes			break;
292135446Strhodes	}
293135446Strhodes	iter->result = result;
294135446Strhodes	return (result);
295135446Strhodes}
296135446Strhodes
297135446Strhodesvoid
298135446Strhodesisc_interfaceiter_destroy(isc_interfaceiter_t **iterp)
299135446Strhodes{
300135446Strhodes	isc_interfaceiter_t *iter;
301135446Strhodes	REQUIRE(iterp != NULL);
302135446Strhodes	iter = *iterp;
303135446Strhodes	REQUIRE(VALID_IFITER(iter));
304135446Strhodes
305135446Strhodes	internal_destroy(iter);
306135446Strhodes	if (iter->buf != NULL)
307135446Strhodes		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
308135446Strhodes
309135446Strhodes	iter->magic = 0;
310135446Strhodes	isc_mem_put(iter->mctx, iter, sizeof(*iter));
311135446Strhodes	*iterp = NULL;
312135446Strhodes}
313