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