2 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2003 Internet Software Consortium.
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.
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.
18 /* $Id: ifiter_getifaddrs.c,v 1.11.120.2 2009/09/24 23:47:34 tbox Exp $ */
22 * Obtain the list of network interfaces using the getifaddrs(3) library.
28 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
30 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
33 static isc_boolean_t seenv6 = ISC_FALSE;
36 /*% Iterator structure */
37 struct isc_interfaceiter {
38 unsigned int magic; /*%< Magic number. */
40 void *buf; /*%< (unused) */
41 unsigned int bufsize; /*%< (always 0) */
42 struct ifaddrs *ifaddrs; /*%< List of ifaddrs */
43 struct ifaddrs *pos; /*%< Ptr to current ifaddr */
44 isc_interface_t current; /*%< Current interface data. */
45 isc_result_t result; /*%< Last result code. */
48 char entry[ISC_IF_INET6_SZ];
54 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
55 isc_interfaceiter_t *iter;
57 char strbuf[ISC_STRERRORSIZE];
59 REQUIRE(mctx != NULL);
60 REQUIRE(iterp != NULL);
61 REQUIRE(*iterp == NULL);
63 iter = isc_mem_get(mctx, sizeof(*iter));
65 return (ISC_R_NOMEMORY);
73 * Only open "/proc/net/if_inet6" if we have never seen a IPv6
74 * address returned by getifaddrs().
77 iter->proc = fopen("/proc/net/if_inet6", "r");
80 iter->valid = ISC_R_FAILURE;
83 if (getifaddrs(&iter->ifaddrs) < 0) {
84 isc__strerror(errno, strbuf, sizeof(strbuf));
85 UNEXPECTED_ERROR(__FILE__, __LINE__,
86 isc_msgcat_get(isc_msgcat,
87 ISC_MSGSET_IFITERGETIFADDRS,
90 "addresses: getifaddrs: %s"),
92 result = ISC_R_UNEXPECTED;
97 * A newly created iterator has an undefined position
98 * until isc_interfaceiter_first() is called.
101 iter->result = ISC_R_FAILURE;
103 iter->magic = IFITER_MAGIC;
105 return (ISC_R_SUCCESS);
109 if (iter->proc != NULL)
112 if (iter->ifaddrs != NULL) /* just in case */
113 freeifaddrs(iter->ifaddrs);
114 isc_mem_put(mctx, iter, sizeof(*iter));
119 * Get information about the current interface to iter->current.
120 * If successful, return ISC_R_SUCCESS.
121 * If the interface has an unsupported address family,
122 * return ISC_R_IGNORE.
126 internal_current(isc_interfaceiter_t *iter) {
129 unsigned int namelen;
131 REQUIRE(VALID_IFITER(iter));
136 if (iter->pos == NULL)
137 return (linux_if_inet6_current(iter));
141 INSIST(ifa->ifa_name != NULL);
143 if (ifa->ifa_addr == NULL)
144 return (ISC_R_IGNORE);
146 family = ifa->ifa_addr->sa_family;
147 if (family != AF_INET && family != AF_INET6)
148 return (ISC_R_IGNORE);
151 if (family == AF_INET6)
155 memset(&iter->current, 0, sizeof(iter->current));
157 namelen = strlen(ifa->ifa_name);
158 if (namelen > sizeof(iter->current.name) - 1)
159 namelen = sizeof(iter->current.name) - 1;
161 memset(iter->current.name, 0, sizeof(iter->current.name));
162 memcpy(iter->current.name, ifa->ifa_name, namelen);
164 iter->current.flags = 0;
166 if ((ifa->ifa_flags & IFF_UP) != 0)
167 iter->current.flags |= INTERFACE_F_UP;
169 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
170 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
172 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
173 iter->current.flags |= INTERFACE_F_LOOPBACK;
175 iter->current.af = family;
177 get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
179 if (ifa->ifa_netmask != NULL)
180 get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
183 if (ifa->ifa_dstaddr != NULL &&
184 (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
185 get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
188 return (ISC_R_SUCCESS);
192 * Step the iterator to the next interface. Unlike
193 * isc_interfaceiter_next(), this may leave the iterator
194 * positioned on an interface that will ultimately
195 * be ignored. Return ISC_R_NOMORE if there are no more
196 * interfaces, otherwise ISC_R_SUCCESS.
199 internal_next(isc_interfaceiter_t *iter) {
201 if (iter->pos != NULL)
202 iter->pos = iter->pos->ifa_next;
203 if (iter->pos == NULL) {
206 return (linux_if_inet6_next(iter));
208 return (ISC_R_NOMORE);
211 return (ISC_R_SUCCESS);
215 internal_destroy(isc_interfaceiter_t *iter) {
218 if (iter->proc != NULL)
223 freeifaddrs(iter->ifaddrs);
224 iter->ifaddrs = NULL;
228 void internal_first(isc_interfaceiter_t *iter) {
231 linux_if_inet6_first(iter);
233 iter->pos = iter->ifaddrs;