/src/ntp-dev/lib/isc/unix/interfaceiter.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") |
3 | | * Copyright (C) 1999-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: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */ |
19 | | |
20 | | /*! \file */ |
21 | | |
22 | | #include <config.h> |
23 | | |
24 | | #include <sys/types.h> |
25 | | #include <sys/ioctl.h> |
26 | | #ifdef HAVE_SYS_SOCKIO_H |
27 | | #include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ |
28 | | #endif |
29 | | |
30 | | #include <stdio.h> |
31 | | #include <stdlib.h> |
32 | | #include <unistd.h> |
33 | | #include <errno.h> |
34 | | |
35 | | #include <isc/interfaceiter.h> |
36 | | #include <isc/log.h> |
37 | | #include <isc/magic.h> |
38 | | #include <isc/mem.h> |
39 | | #include <isc/msgs.h> |
40 | | #include <isc/net.h> |
41 | | #include <isc/print.h> |
42 | | #include <isc/result.h> |
43 | | #include <isc/strerror.h> |
44 | | #include <isc/string.h> |
45 | | #include <isc/types.h> |
46 | | #include <isc/util.h> |
47 | | |
48 | | /* Must follow <isc/net.h>. */ |
49 | | #ifdef HAVE_NET_IF6_H |
50 | | #include <net/if6.h> |
51 | | #endif |
52 | | #include <net/if.h> |
53 | | |
54 | | #ifdef HAVE_LINUX_IF_ADDR_H |
55 | | # include <linux/if_addr.h> |
56 | | #endif |
57 | | |
58 | | /* Common utility functions */ |
59 | | |
60 | | /*% |
61 | | * Extract the network address part from a "struct sockaddr". |
62 | | * \brief |
63 | | * The address family is given explicitly |
64 | | * instead of using src->sa_family, because the latter does not work |
65 | | * for copying a network mask obtained by SIOCGIFNETMASK (it does |
66 | | * not have a valid address family). |
67 | | */ |
68 | | |
69 | | static void |
70 | | get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, |
71 | | char *ifname) |
72 | 5 | { |
73 | 5 | struct sockaddr_in6 *sa6; |
74 | | |
75 | | #if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ |
76 | | !defined(ISC_PLATFORM_HAVESCOPEID) |
77 | | UNUSED(ifname); |
78 | | #endif |
79 | | |
80 | | /* clear any remaining value for safety */ |
81 | 5 | memset(dst, 0, sizeof(*dst)); |
82 | | |
83 | 5 | dst->family = family; |
84 | 5 | switch (family) { |
85 | 5 | case AF_INET: |
86 | 5 | memcpy(&dst->type.in, |
87 | 5 | &((struct sockaddr_in *)(void *)src)->sin_addr, |
88 | 5 | sizeof(struct in_addr)); |
89 | 5 | break; |
90 | 0 | case AF_INET6: |
91 | 0 | sa6 = (struct sockaddr_in6 *)(void *)src; |
92 | 0 | memcpy(&dst->type.in6, &sa6->sin6_addr, |
93 | 0 | sizeof(struct in6_addr)); |
94 | 0 | #ifdef ISC_PLATFORM_HAVESCOPEID |
95 | 0 | if (sa6->sin6_scope_id != 0) |
96 | 0 | isc_netaddr_setzone(dst, sa6->sin6_scope_id); |
97 | 0 | else { |
98 | | /* |
99 | | * BSD variants embed scope zone IDs in the 128bit |
100 | | * address as a kernel internal form. Unfortunately, |
101 | | * the embedded IDs are not hidden from applications |
102 | | * when getting access to them by sysctl or ioctl. |
103 | | * We convert the internal format to the pure address |
104 | | * part and the zone ID part. |
105 | | * Since multicast addresses should not appear here |
106 | | * and they cannot be distinguished from netmasks, |
107 | | * we only consider unicast link-local addresses. |
108 | | */ |
109 | 0 | if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { |
110 | 0 | isc_uint16_t zone16; |
111 | |
|
112 | 0 | memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], |
113 | 0 | sizeof(zone16)); |
114 | 0 | zone16 = ntohs(zone16); |
115 | 0 | if (zone16 != 0) { |
116 | | /* the zone ID is embedded */ |
117 | 0 | isc_netaddr_setzone(dst, |
118 | 0 | (isc_uint32_t)zone16); |
119 | 0 | dst->type.in6.s6_addr[2] = 0; |
120 | 0 | dst->type.in6.s6_addr[3] = 0; |
121 | 0 | #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX |
122 | 0 | } else if (ifname != NULL) { |
123 | 0 | unsigned int zone; |
124 | | |
125 | | /* |
126 | | * sin6_scope_id is still not provided, |
127 | | * but the corresponding interface name |
128 | | * is know. Use the interface ID as |
129 | | * the link ID. |
130 | | */ |
131 | 0 | zone = if_nametoindex(ifname); |
132 | 0 | if (zone != 0) { |
133 | 0 | isc_netaddr_setzone(dst, |
134 | 0 | (isc_uint32_t)zone); |
135 | 0 | } |
136 | 0 | #endif |
137 | 0 | } |
138 | 0 | } |
139 | 0 | } |
140 | 0 | #endif |
141 | 0 | break; |
142 | 0 | default: |
143 | 0 | INSIST(0); |
144 | 0 | break; |
145 | 5 | } |
146 | 5 | } |
147 | | |
148 | | /* |
149 | | * Include system-dependent code. |
150 | | */ |
151 | | |
152 | | #ifdef __linux |
153 | | #define ISC_IF_INET6_SZ \ |
154 | | sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") |
155 | | static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); |
156 | | static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); |
157 | | static void linux_if_inet6_first(isc_interfaceiter_t *iter); |
158 | | #endif |
159 | | |
160 | | #if HAVE_GETIFADDRS |
161 | | #include "ifiter_getifaddrs.c" |
162 | | #elif HAVE_IFLIST_SYSCTL |
163 | | #include "ifiter_sysctl.c" |
164 | | #else |
165 | | #include "ifiter_ioctl.c" |
166 | | #endif |
167 | | |
168 | | #ifdef __linux |
169 | | static void |
170 | 1 | linux_if_inet6_first(isc_interfaceiter_t *iter) { |
171 | 1 | if (iter->proc != NULL) { |
172 | 1 | rewind(iter->proc); |
173 | 1 | (void)linux_if_inet6_next(iter); |
174 | 1 | } else |
175 | 0 | iter->valid = ISC_R_NOMORE; |
176 | 1 | } |
177 | | |
178 | | static isc_result_t |
179 | 2 | linux_if_inet6_next(isc_interfaceiter_t *iter) { |
180 | 2 | if (iter->proc != NULL && |
181 | 2 | fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) |
182 | 0 | iter->valid = ISC_R_SUCCESS; |
183 | 2 | else |
184 | 2 | iter->valid = ISC_R_NOMORE; |
185 | 2 | return (iter->valid); |
186 | 2 | } |
187 | | |
188 | | static isc_result_t |
189 | 0 | linux_if_inet6_current(isc_interfaceiter_t *iter) { |
190 | 0 | char address[33]; |
191 | 0 | char name[IF_NAMESIZE+1]; |
192 | 0 | struct in6_addr addr6; |
193 | 0 | unsigned int ifindex; |
194 | 0 | int prefix, scope, flags; |
195 | 0 | int res; |
196 | 0 | unsigned int i; |
197 | |
|
198 | 0 | if (iter->valid != ISC_R_SUCCESS) |
199 | 0 | return (iter->valid); |
200 | 0 | if (iter->proc == NULL) { |
201 | 0 | isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, |
202 | 0 | ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, |
203 | 0 | "/proc/net/if_inet6:iter->proc == NULL"); |
204 | 0 | return (ISC_R_FAILURE); |
205 | 0 | } |
206 | | |
207 | 0 | res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", |
208 | 0 | address, &ifindex, &prefix, &scope, &flags, name); |
209 | 0 | if (res != 6) { |
210 | 0 | isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, |
211 | 0 | ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, |
212 | 0 | "/proc/net/if_inet6:sscanf() -> %d (expected 6)", |
213 | 0 | res); |
214 | 0 | return (ISC_R_FAILURE); |
215 | 0 | } |
216 | 0 | if (strlen(address) != 32) { |
217 | 0 | isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, |
218 | 0 | ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, |
219 | 0 | "/proc/net/if_inet6:strlen(%s) != 32", address); |
220 | 0 | return (ISC_R_FAILURE); |
221 | 0 | } |
222 | | /* |
223 | | ** Ignore DAD addresses -- |
224 | | ** we can't bind to them until they are resolved |
225 | | */ |
226 | 0 | #ifdef IFA_F_TENTATIVE |
227 | 0 | if (flags & IFA_F_TENTATIVE) |
228 | 0 | return (ISC_R_IGNORE); |
229 | 0 | #endif |
230 | | |
231 | 0 | for (i = 0; i < 16; i++) { |
232 | 0 | unsigned char byte; |
233 | 0 | static const char hex[] = "0123456789abcdef"; |
234 | 0 | byte = ((strchr(hex, address[i * 2]) - hex) << 4) | |
235 | 0 | (strchr(hex, address[i * 2 + 1]) - hex); |
236 | 0 | addr6.s6_addr[i] = byte; |
237 | 0 | } |
238 | 0 | iter->current.af = AF_INET6; |
239 | 0 | iter->current.flags = INTERFACE_F_UP; |
240 | 0 | isc_netaddr_fromin6(&iter->current.address, &addr6); |
241 | 0 | iter->current.ifindex = ifindex; |
242 | 0 | if (isc_netaddr_islinklocal(&iter->current.address)) { |
243 | 0 | isc_netaddr_setzone(&iter->current.address, |
244 | 0 | (isc_uint32_t)ifindex); |
245 | 0 | } |
246 | 0 | for (i = 0; i < 16; i++) { |
247 | 0 | if (prefix > 8) { |
248 | 0 | addr6.s6_addr[i] = 0xff; |
249 | 0 | prefix -= 8; |
250 | 0 | } else { |
251 | 0 | addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; |
252 | 0 | prefix = 0; |
253 | 0 | } |
254 | 0 | } |
255 | 0 | isc_netaddr_fromin6(&iter->current.netmask, &addr6); |
256 | 0 | strncpy(iter->current.name, name, sizeof(iter->current.name)); |
257 | 0 | return (ISC_R_SUCCESS); |
258 | 0 | } |
259 | | #endif |
260 | | |
261 | | /* |
262 | | * The remaining code is common to the sysctl and ioctl case. |
263 | | */ |
264 | | |
265 | | isc_result_t |
266 | | isc_interfaceiter_current(isc_interfaceiter_t *iter, |
267 | | isc_interface_t *ifdata) |
268 | 2 | { |
269 | 2 | REQUIRE(iter->result == ISC_R_SUCCESS); |
270 | 0 | memcpy(ifdata, &iter->current, sizeof(*ifdata)); |
271 | 2 | return (ISC_R_SUCCESS); |
272 | 2 | } |
273 | | |
274 | | isc_result_t |
275 | 1 | isc_interfaceiter_first(isc_interfaceiter_t *iter) { |
276 | 1 | isc_result_t result; |
277 | | |
278 | 1 | REQUIRE(VALID_IFITER(iter)); |
279 | | |
280 | 0 | internal_first(iter); |
281 | 3 | for (;;) { |
282 | 3 | result = internal_current(iter); |
283 | 3 | if (result != ISC_R_IGNORE) |
284 | 1 | break; |
285 | 2 | result = internal_next(iter); |
286 | 2 | if (result != ISC_R_SUCCESS) |
287 | 0 | break; |
288 | 2 | } |
289 | 1 | iter->result = result; |
290 | 1 | return (result); |
291 | 1 | } |
292 | | |
293 | | isc_result_t |
294 | 2 | isc_interfaceiter_next(isc_interfaceiter_t *iter) { |
295 | 2 | isc_result_t result; |
296 | | |
297 | 2 | REQUIRE(VALID_IFITER(iter)); |
298 | 2 | REQUIRE(iter->result == ISC_R_SUCCESS); |
299 | | |
300 | 2 | for (;;) { |
301 | 2 | result = internal_next(iter); |
302 | 2 | if (result != ISC_R_SUCCESS) |
303 | 1 | break; |
304 | 1 | result = internal_current(iter); |
305 | 1 | if (result != ISC_R_IGNORE) |
306 | 1 | break; |
307 | 1 | } |
308 | 2 | iter->result = result; |
309 | 2 | return (result); |
310 | 2 | } |
311 | | |
312 | | void |
313 | | isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) |
314 | 1 | { |
315 | 1 | isc_interfaceiter_t *iter; |
316 | 1 | REQUIRE(iterp != NULL); |
317 | 0 | iter = *iterp; |
318 | 1 | REQUIRE(VALID_IFITER(iter)); |
319 | | |
320 | 0 | internal_destroy(iter); |
321 | 1 | if (iter->buf != NULL) |
322 | 0 | isc_mem_put(iter->mctx, iter->buf, iter->bufsize); |
323 | | |
324 | 1 | iter->magic = 0; |
325 | 1 | isc_mem_put(iter->mctx, iter, sizeof(*iter)); |
326 | 1 | *iterp = NULL; |
327 | 1 | } |