Annotation of embedaddon/ntp/lib/isc/unix/ifiter_getifaddrs.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
3: * Copyright (C) 2003 Internet Software Consortium.
4: *
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.
8: *
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.
16: */
17:
18: /* $Id: ifiter_getifaddrs.c,v 1.11 2008/03/20 23:47:00 tbox Exp $ */
19:
20: /*! \file
21: * \brief
22: * Obtain the list of network interfaces using the getifaddrs(3) library.
23: */
24:
25: #include <ifaddrs.h>
26:
27: /*% Iterator Magic */
28: #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
29: /*% Valid Iterator */
30: #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
31:
32: #ifdef __linux
33: static isc_boolean_t seenv6 = ISC_FALSE;
34: #endif
35:
36: /*% Iterator structure */
37: struct isc_interfaceiter {
38: unsigned int magic; /*%< Magic number. */
39: isc_mem_t *mctx;
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. */
46: #ifdef __linux
47: FILE * proc;
48: char entry[ISC_IF_INET6_SZ];
49: isc_result_t valid;
50: #endif
51: };
52:
53: isc_result_t
54: isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
55: isc_interfaceiter_t *iter;
56: isc_result_t result;
57: char strbuf[ISC_STRERRORSIZE];
58:
59: REQUIRE(mctx != NULL);
60: REQUIRE(iterp != NULL);
61: REQUIRE(*iterp == NULL);
62:
63: iter = isc_mem_get(mctx, sizeof(*iter));
64: if (iter == NULL)
65: return (ISC_R_NOMEMORY);
66:
67: iter->mctx = mctx;
68: iter->buf = NULL;
69: iter->bufsize = 0;
70: iter->ifaddrs = NULL;
71: #ifdef __linux
72: /*
73: * Only open "/proc/net/if_inet6" if we have never seen a IPv6
74: * address returned by getifaddrs().
75: */
76: if (!seenv6)
77: iter->proc = fopen("/proc/net/if_inet6", "r");
78: else
79: iter->proc = NULL;
80: iter->valid = ISC_R_FAILURE;
81: #endif
82:
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,
88: ISC_MSG_GETIFADDRS,
89: "getting interface "
90: "addresses: getifaddrs: %s"),
91: strbuf);
92: result = ISC_R_UNEXPECTED;
93: goto failure;
94: }
95:
96: /*
97: * A newly created iterator has an undefined position
98: * until isc_interfaceiter_first() is called.
99: */
100: iter->pos = NULL;
101: iter->result = ISC_R_FAILURE;
102:
103: iter->magic = IFITER_MAGIC;
104: *iterp = iter;
105: return (ISC_R_SUCCESS);
106:
107: failure:
108: #ifdef __linux
109: if (iter->proc != NULL)
110: fclose(iter->proc);
111: #endif
112: if (iter->ifaddrs != NULL) /* just in case */
113: freeifaddrs(iter->ifaddrs);
114: isc_mem_put(mctx, iter, sizeof(*iter));
115: return (result);
116: }
117:
118: /*
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.
123: */
124:
125: static isc_result_t
126: internal_current(isc_interfaceiter_t *iter) {
127: struct ifaddrs *ifa;
128: int family;
129: unsigned int namelen;
130:
131: REQUIRE(VALID_IFITER(iter));
132:
133: ifa = iter->pos;
134:
135: #ifdef __linux
136: if (iter->pos == NULL)
137: return (linux_if_inet6_current(iter));
138: #endif
139:
140: INSIST(ifa != NULL);
141: INSIST(ifa->ifa_name != NULL);
142:
143: if (ifa->ifa_addr == NULL)
144: return (ISC_R_IGNORE);
145:
146: family = ifa->ifa_addr->sa_family;
147: if (family != AF_INET && family != AF_INET6)
148: return (ISC_R_IGNORE);
149:
150: #ifdef __linux
151: if (family == AF_INET6)
152: seenv6 = ISC_TRUE;
153: #endif
154:
155: memset(&iter->current, 0, sizeof(iter->current));
156:
157: namelen = strlen(ifa->ifa_name);
158: if (namelen > sizeof(iter->current.name) - 1)
159: namelen = sizeof(iter->current.name) - 1;
160:
161: memset(iter->current.name, 0, sizeof(iter->current.name));
162: memcpy(iter->current.name, ifa->ifa_name, namelen);
163:
164: iter->current.flags = 0;
165:
166: if ((ifa->ifa_flags & IFF_UP) != 0)
167: iter->current.flags |= INTERFACE_F_UP;
168:
169: if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
170: iter->current.flags |= INTERFACE_F_POINTTOPOINT;
171:
172: if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
173: iter->current.flags |= INTERFACE_F_LOOPBACK;
174:
175: if ((ifa->ifa_flags & IFF_BROADCAST) != 0)
176: iter->current.flags |= INTERFACE_F_BROADCAST;
177:
178: #ifdef IFF_MULTICAST
179: if ((ifa->ifa_flags & IFF_MULTICAST) != 0)
180: iter->current.flags |= INTERFACE_F_MULTICAST;
181: #endif
182:
183: iter->current.af = family;
184:
185: get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
186:
187: if (ifa->ifa_netmask != NULL)
188: get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
189: ifa->ifa_name);
190:
191: if (ifa->ifa_dstaddr != NULL &&
192: (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
193: get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
194: ifa->ifa_name);
195:
196: if (ifa->ifa_broadaddr != NULL &&
197: (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
198: get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr,
199: ifa->ifa_name);
200:
201: return (ISC_R_SUCCESS);
202: }
203:
204: /*
205: * Step the iterator to the next interface. Unlike
206: * isc_interfaceiter_next(), this may leave the iterator
207: * positioned on an interface that will ultimately
208: * be ignored. Return ISC_R_NOMORE if there are no more
209: * interfaces, otherwise ISC_R_SUCCESS.
210: */
211: static isc_result_t
212: internal_next(isc_interfaceiter_t *iter) {
213:
214: if (iter->pos != NULL)
215: iter->pos = iter->pos->ifa_next;
216: if (iter->pos == NULL) {
217: #ifdef __linux
218: if (!seenv6)
219: return (linux_if_inet6_next(iter));
220: #endif
221: return (ISC_R_NOMORE);
222: }
223:
224: return (ISC_R_SUCCESS);
225: }
226:
227: static void
228: internal_destroy(isc_interfaceiter_t *iter) {
229:
230: #ifdef __linux
231: if (iter->proc != NULL)
232: fclose(iter->proc);
233: iter->proc = NULL;
234: #endif
235: if (iter->ifaddrs)
236: freeifaddrs(iter->ifaddrs);
237: iter->ifaddrs = NULL;
238: }
239:
240: static
241: void internal_first(isc_interfaceiter_t *iter) {
242:
243: #ifdef __linux
244: linux_if_inet6_first(iter);
245: #endif
246: iter->pos = iter->ifaddrs;
247: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>