xref: /minix3/external/bsd/bind/dist/lib/isc/unix/ifiter_getifaddrs.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: ifiter_getifaddrs.c,v 1.5 2014/12/10 04:38:01 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004, 2005, 2007-2009, 2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id: ifiter_getifaddrs.c,v 1.13 2009/09/24 23:48:13 tbox Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file
23*00b67f09SDavid van Moolenbroek  * \brief
24*00b67f09SDavid van Moolenbroek  * Obtain the list of network interfaces using the getifaddrs(3) library.
25*00b67f09SDavid van Moolenbroek  */
26*00b67f09SDavid van Moolenbroek 
27*00b67f09SDavid van Moolenbroek #include <ifaddrs.h>
28*00b67f09SDavid van Moolenbroek 
29*00b67f09SDavid van Moolenbroek /*% Iterator Magic */
30*00b67f09SDavid van Moolenbroek #define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'G')
31*00b67f09SDavid van Moolenbroek /*% Valid Iterator */
32*00b67f09SDavid van Moolenbroek #define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
33*00b67f09SDavid van Moolenbroek 
34*00b67f09SDavid van Moolenbroek #ifdef __linux
35*00b67f09SDavid van Moolenbroek static isc_boolean_t seenv6 = ISC_FALSE;
36*00b67f09SDavid van Moolenbroek #endif
37*00b67f09SDavid van Moolenbroek 
38*00b67f09SDavid van Moolenbroek /*% Iterator structure */
39*00b67f09SDavid van Moolenbroek struct isc_interfaceiter {
40*00b67f09SDavid van Moolenbroek 	unsigned int		magic;		/*%< Magic number. */
41*00b67f09SDavid van Moolenbroek 	isc_mem_t		*mctx;
42*00b67f09SDavid van Moolenbroek 	void			*buf;		/*%< (unused) */
43*00b67f09SDavid van Moolenbroek 	unsigned int		bufsize;	/*%< (always 0) */
44*00b67f09SDavid van Moolenbroek 	struct ifaddrs		*ifaddrs;	/*%< List of ifaddrs */
45*00b67f09SDavid van Moolenbroek 	struct ifaddrs		*pos;		/*%< Ptr to current ifaddr */
46*00b67f09SDavid van Moolenbroek 	isc_interface_t		current;	/*%< Current interface data. */
47*00b67f09SDavid van Moolenbroek 	isc_result_t		result;		/*%< Last result code. */
48*00b67f09SDavid van Moolenbroek #ifdef  __linux
49*00b67f09SDavid van Moolenbroek 	FILE *                  proc;
50*00b67f09SDavid van Moolenbroek 	char                    entry[ISC_IF_INET6_SZ];
51*00b67f09SDavid van Moolenbroek 	isc_result_t            valid;
52*00b67f09SDavid van Moolenbroek #endif
53*00b67f09SDavid van Moolenbroek };
54*00b67f09SDavid van Moolenbroek 
55*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)56*00b67f09SDavid van Moolenbroek isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
57*00b67f09SDavid van Moolenbroek 	isc_interfaceiter_t *iter;
58*00b67f09SDavid van Moolenbroek 	isc_result_t result;
59*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
62*00b67f09SDavid van Moolenbroek 	REQUIRE(iterp != NULL);
63*00b67f09SDavid van Moolenbroek 	REQUIRE(*iterp == NULL);
64*00b67f09SDavid van Moolenbroek 
65*00b67f09SDavid van Moolenbroek 	iter = isc_mem_get(mctx, sizeof(*iter));
66*00b67f09SDavid van Moolenbroek 	if (iter == NULL)
67*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
68*00b67f09SDavid van Moolenbroek 
69*00b67f09SDavid van Moolenbroek 	iter->mctx = mctx;
70*00b67f09SDavid van Moolenbroek 	iter->buf = NULL;
71*00b67f09SDavid van Moolenbroek 	iter->bufsize = 0;
72*00b67f09SDavid van Moolenbroek 	iter->ifaddrs = NULL;
73*00b67f09SDavid van Moolenbroek #ifdef __linux
74*00b67f09SDavid van Moolenbroek 	/*
75*00b67f09SDavid van Moolenbroek 	 * Only open "/proc/net/if_inet6" if we have never seen a IPv6
76*00b67f09SDavid van Moolenbroek 	 * address returned by getifaddrs().
77*00b67f09SDavid van Moolenbroek 	 */
78*00b67f09SDavid van Moolenbroek 	if (!seenv6)
79*00b67f09SDavid van Moolenbroek 		iter->proc = fopen("/proc/net/if_inet6", "r");
80*00b67f09SDavid van Moolenbroek 	else
81*00b67f09SDavid van Moolenbroek 		iter->proc = NULL;
82*00b67f09SDavid van Moolenbroek 	iter->valid = ISC_R_FAILURE;
83*00b67f09SDavid van Moolenbroek #endif
84*00b67f09SDavid van Moolenbroek 
85*00b67f09SDavid van Moolenbroek 	if (getifaddrs(&iter->ifaddrs) < 0) {
86*00b67f09SDavid van Moolenbroek 		isc__strerror(errno, strbuf, sizeof(strbuf));
87*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
88*00b67f09SDavid van Moolenbroek 				 isc_msgcat_get(isc_msgcat,
89*00b67f09SDavid van Moolenbroek 						ISC_MSGSET_IFITERGETIFADDRS,
90*00b67f09SDavid van Moolenbroek 						ISC_MSG_GETIFADDRS,
91*00b67f09SDavid van Moolenbroek 						"getting interface "
92*00b67f09SDavid van Moolenbroek 						"addresses: getifaddrs: %s"),
93*00b67f09SDavid van Moolenbroek 				 strbuf);
94*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
95*00b67f09SDavid van Moolenbroek 		goto failure;
96*00b67f09SDavid van Moolenbroek 	}
97*00b67f09SDavid van Moolenbroek 
98*00b67f09SDavid van Moolenbroek 	/*
99*00b67f09SDavid van Moolenbroek 	 * A newly created iterator has an undefined position
100*00b67f09SDavid van Moolenbroek 	 * until isc_interfaceiter_first() is called.
101*00b67f09SDavid van Moolenbroek 	 */
102*00b67f09SDavid van Moolenbroek 	iter->pos = NULL;
103*00b67f09SDavid van Moolenbroek 	iter->result = ISC_R_FAILURE;
104*00b67f09SDavid van Moolenbroek 
105*00b67f09SDavid van Moolenbroek 	iter->magic = IFITER_MAGIC;
106*00b67f09SDavid van Moolenbroek 	*iterp = iter;
107*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
108*00b67f09SDavid van Moolenbroek 
109*00b67f09SDavid van Moolenbroek  failure:
110*00b67f09SDavid van Moolenbroek #ifdef __linux
111*00b67f09SDavid van Moolenbroek 	if (iter->proc != NULL)
112*00b67f09SDavid van Moolenbroek 		fclose(iter->proc);
113*00b67f09SDavid van Moolenbroek #endif
114*00b67f09SDavid van Moolenbroek 	if (iter->ifaddrs != NULL) /* just in case */
115*00b67f09SDavid van Moolenbroek 		freeifaddrs(iter->ifaddrs);
116*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, iter, sizeof(*iter));
117*00b67f09SDavid van Moolenbroek 	return (result);
118*00b67f09SDavid van Moolenbroek }
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek /*
121*00b67f09SDavid van Moolenbroek  * Get information about the current interface to iter->current.
122*00b67f09SDavid van Moolenbroek  * If successful, return ISC_R_SUCCESS.
123*00b67f09SDavid van Moolenbroek  * If the interface has an unsupported address family,
124*00b67f09SDavid van Moolenbroek  * return ISC_R_IGNORE.
125*00b67f09SDavid van Moolenbroek  */
126*00b67f09SDavid van Moolenbroek 
127*00b67f09SDavid van Moolenbroek static isc_result_t
internal_current(isc_interfaceiter_t * iter)128*00b67f09SDavid van Moolenbroek internal_current(isc_interfaceiter_t *iter) {
129*00b67f09SDavid van Moolenbroek 	struct ifaddrs *ifa;
130*00b67f09SDavid van Moolenbroek 	int family;
131*00b67f09SDavid van Moolenbroek 	unsigned int namelen;
132*00b67f09SDavid van Moolenbroek 
133*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
134*00b67f09SDavid van Moolenbroek 
135*00b67f09SDavid van Moolenbroek 	ifa = iter->pos;
136*00b67f09SDavid van Moolenbroek 
137*00b67f09SDavid van Moolenbroek #ifdef __linux
138*00b67f09SDavid van Moolenbroek 	if (iter->pos == NULL)
139*00b67f09SDavid van Moolenbroek 		return (linux_if_inet6_current(iter));
140*00b67f09SDavid van Moolenbroek #endif
141*00b67f09SDavid van Moolenbroek 
142*00b67f09SDavid van Moolenbroek 	INSIST(ifa != NULL);
143*00b67f09SDavid van Moolenbroek 	INSIST(ifa->ifa_name != NULL);
144*00b67f09SDavid van Moolenbroek 
145*00b67f09SDavid van Moolenbroek 	if (ifa->ifa_addr == NULL)
146*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
147*00b67f09SDavid van Moolenbroek 
148*00b67f09SDavid van Moolenbroek 	family = ifa->ifa_addr->sa_family;
149*00b67f09SDavid van Moolenbroek 	if (family != AF_INET && family != AF_INET6)
150*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
151*00b67f09SDavid van Moolenbroek 
152*00b67f09SDavid van Moolenbroek #ifdef __linux
153*00b67f09SDavid van Moolenbroek 	if (family == AF_INET6)
154*00b67f09SDavid van Moolenbroek 		seenv6 = ISC_TRUE;
155*00b67f09SDavid van Moolenbroek #endif
156*00b67f09SDavid van Moolenbroek 
157*00b67f09SDavid van Moolenbroek 	memset(&iter->current, 0, sizeof(iter->current));
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek 	namelen = strlen(ifa->ifa_name);
160*00b67f09SDavid van Moolenbroek 	if (namelen > sizeof(iter->current.name) - 1)
161*00b67f09SDavid van Moolenbroek 		namelen = sizeof(iter->current.name) - 1;
162*00b67f09SDavid van Moolenbroek 
163*00b67f09SDavid van Moolenbroek 	memset(iter->current.name, 0, sizeof(iter->current.name));
164*00b67f09SDavid van Moolenbroek 	memmove(iter->current.name, ifa->ifa_name, namelen);
165*00b67f09SDavid van Moolenbroek 
166*00b67f09SDavid van Moolenbroek 	iter->current.flags = 0;
167*00b67f09SDavid van Moolenbroek 
168*00b67f09SDavid van Moolenbroek 	if ((ifa->ifa_flags & IFF_UP) != 0)
169*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_UP;
170*00b67f09SDavid van Moolenbroek 
171*00b67f09SDavid van Moolenbroek 	if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
172*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
173*00b67f09SDavid van Moolenbroek 
174*00b67f09SDavid van Moolenbroek 	if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
175*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_LOOPBACK;
176*00b67f09SDavid van Moolenbroek 
177*00b67f09SDavid van Moolenbroek 	iter->current.af = family;
178*00b67f09SDavid van Moolenbroek 
179*00b67f09SDavid van Moolenbroek 	get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek 	if (ifa->ifa_netmask != NULL)
182*00b67f09SDavid van Moolenbroek 		get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
183*00b67f09SDavid van Moolenbroek 			 ifa->ifa_name);
184*00b67f09SDavid van Moolenbroek 
185*00b67f09SDavid van Moolenbroek 	if (ifa->ifa_dstaddr != NULL &&
186*00b67f09SDavid van Moolenbroek 	    (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
187*00b67f09SDavid van Moolenbroek 		get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
188*00b67f09SDavid van Moolenbroek 			 ifa->ifa_name);
189*00b67f09SDavid van Moolenbroek 
190*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
191*00b67f09SDavid van Moolenbroek }
192*00b67f09SDavid van Moolenbroek 
193*00b67f09SDavid van Moolenbroek /*
194*00b67f09SDavid van Moolenbroek  * Step the iterator to the next interface.  Unlike
195*00b67f09SDavid van Moolenbroek  * isc_interfaceiter_next(), this may leave the iterator
196*00b67f09SDavid van Moolenbroek  * positioned on an interface that will ultimately
197*00b67f09SDavid van Moolenbroek  * be ignored.  Return ISC_R_NOMORE if there are no more
198*00b67f09SDavid van Moolenbroek  * interfaces, otherwise ISC_R_SUCCESS.
199*00b67f09SDavid van Moolenbroek  */
200*00b67f09SDavid van Moolenbroek static isc_result_t
internal_next(isc_interfaceiter_t * iter)201*00b67f09SDavid van Moolenbroek internal_next(isc_interfaceiter_t *iter) {
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek 	if (iter->pos != NULL)
204*00b67f09SDavid van Moolenbroek 		iter->pos = iter->pos->ifa_next;
205*00b67f09SDavid van Moolenbroek 	if (iter->pos == NULL) {
206*00b67f09SDavid van Moolenbroek #ifdef __linux
207*00b67f09SDavid van Moolenbroek 		if (!seenv6)
208*00b67f09SDavid van Moolenbroek 			return (linux_if_inet6_next(iter));
209*00b67f09SDavid van Moolenbroek #endif
210*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMORE);
211*00b67f09SDavid van Moolenbroek 	}
212*00b67f09SDavid van Moolenbroek 
213*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
214*00b67f09SDavid van Moolenbroek }
215*00b67f09SDavid van Moolenbroek 
216*00b67f09SDavid van Moolenbroek static void
internal_destroy(isc_interfaceiter_t * iter)217*00b67f09SDavid van Moolenbroek internal_destroy(isc_interfaceiter_t *iter) {
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek #ifdef __linux
220*00b67f09SDavid van Moolenbroek 	if (iter->proc != NULL)
221*00b67f09SDavid van Moolenbroek 		fclose(iter->proc);
222*00b67f09SDavid van Moolenbroek 	iter->proc = NULL;
223*00b67f09SDavid van Moolenbroek #endif
224*00b67f09SDavid van Moolenbroek 	if (iter->ifaddrs)
225*00b67f09SDavid van Moolenbroek 		freeifaddrs(iter->ifaddrs);
226*00b67f09SDavid van Moolenbroek 	iter->ifaddrs = NULL;
227*00b67f09SDavid van Moolenbroek }
228*00b67f09SDavid van Moolenbroek 
229*00b67f09SDavid van Moolenbroek static
internal_first(isc_interfaceiter_t * iter)230*00b67f09SDavid van Moolenbroek void internal_first(isc_interfaceiter_t *iter) {
231*00b67f09SDavid van Moolenbroek 
232*00b67f09SDavid van Moolenbroek #ifdef __linux
233*00b67f09SDavid van Moolenbroek 	linux_if_inet6_first(iter);
234*00b67f09SDavid van Moolenbroek #endif
235*00b67f09SDavid van Moolenbroek 	iter->pos = iter->ifaddrs;
236*00b67f09SDavid van Moolenbroek }
237