]>
Commit | Line | Data |
---|---|---|
444c1184 MT |
1 | diff -up dhcp-4.2.4rc2/common/discover.c.getifaddrs dhcp-4.2.4rc2/common/discover.c |
2 | --- dhcp-4.2.4rc2/common/discover.c.getifaddrs 2012-05-25 18:05:29.592024035 +0200 | |
3 | +++ dhcp-4.2.4rc2/common/discover.c 2012-05-25 18:12:05.254266023 +0200 | |
4 | @@ -379,394 +379,13 @@ end_iface_scan(struct iface_conf_list *i | |
5 | ifaces->sock = -1; | |
6 | } | |
7 | ||
8 | -#elif __linux /* !HAVE_SIOCGLIFCONF */ | |
9 | -/* | |
10 | - * Linux support | |
11 | - * ------------- | |
12 | - * | |
13 | - * In Linux, we use the /proc pseudo-filesystem to get information | |
14 | - * about interfaces, along with selected ioctl() calls. | |
15 | - * | |
16 | - * Linux low level access is documented in the netdevice man page. | |
17 | - */ | |
18 | - | |
19 | -/* | |
20 | - * Structure holding state about the scan. | |
21 | - */ | |
22 | -struct iface_conf_list { | |
23 | - int sock; /* file descriptor used to get information */ | |
24 | - FILE *fp; /* input from /proc/net/dev */ | |
25 | -#ifdef DHCPv6 | |
26 | - FILE *fp6; /* input from /proc/net/if_inet6 */ | |
27 | -#endif | |
28 | -}; | |
29 | - | |
30 | -/* | |
31 | - * Structure used to return information about a specific interface. | |
32 | - */ | |
33 | -struct iface_info { | |
34 | - char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */ | |
35 | - struct sockaddr_storage addr; /* address information */ | |
36 | - isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ | |
37 | -}; | |
38 | - | |
39 | -/* | |
40 | - * Start a scan of interfaces. | |
41 | - * | |
42 | - * The iface_conf_list structure maintains state for this process. | |
43 | - */ | |
44 | -int | |
45 | -begin_iface_scan(struct iface_conf_list *ifaces) { | |
46 | - char buf[256]; | |
47 | - int len; | |
48 | - int i; | |
49 | - | |
50 | - ifaces->fp = fopen("/proc/net/dev", "re"); | |
51 | - if (ifaces->fp == NULL) { | |
52 | - log_error("Error opening '/proc/net/dev' to list interfaces"); | |
53 | - return 0; | |
54 | - } | |
55 | - | |
56 | - /* | |
57 | - * The first 2 lines are header information, so read and ignore them. | |
58 | - */ | |
59 | - for (i=0; i<2; i++) { | |
60 | - if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { | |
61 | - log_error("Error reading headers from '/proc/net/dev'"); | |
62 | - fclose(ifaces->fp); | |
63 | - ifaces->fp = NULL; | |
64 | - return 0; | |
65 | - } | |
66 | - len = strlen(buf); | |
67 | - if ((len <= 0) || (buf[len-1] != '\n')) { | |
68 | - log_error("Bad header line in '/proc/net/dev'"); | |
69 | - fclose(ifaces->fp); | |
70 | - ifaces->fp = NULL; | |
71 | - return 0; | |
72 | - } | |
73 | - } | |
74 | - | |
75 | - ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
76 | - if (ifaces->sock < 0) { | |
77 | - log_error("Error creating socket to list interfaces; %m"); | |
78 | - fclose(ifaces->fp); | |
79 | - ifaces->fp = NULL; | |
80 | - return 0; | |
81 | - } | |
82 | - | |
83 | -#ifdef DHCPv6 | |
84 | - if ((local_family == AF_INET6) && !access("/proc/net/if_inet6", R_OK)) { | |
85 | - ifaces->fp6 = fopen("/proc/net/if_inet6", "re"); | |
86 | - if (ifaces->fp6 == NULL) { | |
87 | - log_error("Error opening '/proc/net/if_inet6' to " | |
88 | - "list IPv6 interfaces; %m"); | |
89 | - close(ifaces->sock); | |
90 | - ifaces->sock = -1; | |
91 | - fclose(ifaces->fp); | |
92 | - ifaces->fp = NULL; | |
93 | - return 0; | |
94 | - } | |
95 | - } else { | |
96 | - ifaces->fp6 = NULL; | |
97 | - } | |
98 | -#endif | |
99 | - | |
100 | - return 1; | |
101 | -} | |
102 | - | |
103 | -/* | |
104 | - * Read our IPv4 interfaces from /proc/net/dev. | |
105 | - * | |
106 | - * The file looks something like this: | |
107 | - * | |
108 | - * Inter-| Receive ... | |
109 | - * face |bytes packets errs drop fifo frame ... | |
110 | - * lo: 1580562 4207 0 0 0 0 ... | |
111 | - * eth0: 0 0 0 0 0 0 ... | |
112 | - * eth1:1801552440 37895 0 14 0 ... | |
113 | - * | |
114 | - * We only care about the interface name, which is at the start of | |
115 | - * each line. | |
116 | - * | |
117 | - * We use an ioctl() to get the address and flags for each interface. | |
118 | - */ | |
119 | -static int | |
120 | -next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
121 | - char buf[256]; | |
122 | - int len; | |
123 | - char *p; | |
124 | - char *name; | |
125 | - struct ifreq tmp; | |
126 | - | |
127 | - /* | |
128 | - * Loop exits when we find an interface that has an address, or | |
129 | - * when we run out of interfaces. | |
130 | - */ | |
131 | - for (;;) { | |
132 | - do { | |
133 | - /* | |
134 | - * Read the next line in the file. | |
135 | - */ | |
136 | - if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { | |
137 | - if (ferror(ifaces->fp)) { | |
138 | - *err = 1; | |
139 | - log_error("Error reading interface " | |
140 | - "information"); | |
141 | - } else { | |
142 | - *err = 0; | |
143 | - } | |
144 | - return 0; | |
145 | - } | |
146 | - | |
147 | - /* | |
148 | - * Make sure the line is a nice, | |
149 | - * newline-terminated line. | |
150 | - */ | |
151 | - len = strlen(buf); | |
152 | - if ((len <= 0) || (buf[len-1] != '\n')) { | |
153 | - log_error("Bad line reading interface " | |
154 | - "information"); | |
155 | - *err = 1; | |
156 | - return 0; | |
157 | - } | |
158 | - | |
159 | - /* | |
160 | - * Figure out our name. | |
161 | - */ | |
162 | - p = strrchr(buf, ':'); | |
163 | - if (p == NULL) { | |
164 | - log_error("Bad line reading interface " | |
165 | - "information (no colon)"); | |
166 | - *err = 1; | |
167 | - return 0; | |
168 | - } | |
169 | - *p = '\0'; | |
170 | - name = buf; | |
171 | - while (isspace(*name)) { | |
172 | - name++; | |
173 | - } | |
174 | - | |
175 | - /* | |
176 | - * Copy our name into our interface structure. | |
177 | - */ | |
178 | - len = p - name; | |
179 | - if (len >= sizeof(info->name)) { | |
180 | - *err = 1; | |
181 | - log_error("Interface name '%s' too long", name); | |
182 | - return 0; | |
183 | - } | |
184 | - strcpy(info->name, name); | |
185 | - | |
186 | -#ifdef ALIAS_NAMED_PERMUTED | |
187 | - /* interface aliases look like "eth0:1" or "wlan1:3" */ | |
188 | - s = strchr(info->name, ':'); | |
189 | - if (s != NULL) { | |
190 | - *s = '\0'; | |
191 | - } | |
192 | -#endif | |
193 | - | |
194 | -#ifdef SKIP_DUMMY_INTERFACES | |
195 | - } while (strncmp(info->name, "dummy", 5) == 0); | |
196 | -#else | |
197 | - } while (0); | |
198 | -#endif | |
199 | - | |
200 | - memset(&tmp, 0, sizeof(tmp)); | |
201 | - strcpy(tmp.ifr_name, name); | |
202 | - if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) { | |
203 | - if (errno == EADDRNOTAVAIL) { | |
204 | - continue; | |
205 | - } | |
206 | - log_error("Error getting interface address " | |
207 | - "for '%s'; %m", name); | |
208 | - *err = 1; | |
209 | - return 0; | |
210 | - } | |
211 | - memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr)); | |
212 | - | |
213 | - memset(&tmp, 0, sizeof(tmp)); | |
214 | - strcpy(tmp.ifr_name, name); | |
215 | - if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { | |
216 | - log_error("Error getting interface flags for '%s'; %m", | |
217 | - name); | |
218 | - *err = 1; | |
219 | - return 0; | |
220 | - } | |
221 | - info->flags = tmp.ifr_flags; | |
222 | - | |
223 | - *err = 0; | |
224 | - return 1; | |
225 | - } | |
226 | -} | |
227 | - | |
228 | -#ifdef DHCPv6 | |
229 | -/* | |
230 | - * Read our IPv6 interfaces from /proc/net/if_inet6. | |
231 | - * | |
232 | - * The file looks something like this: | |
233 | - * | |
234 | - * fe80000000000000025056fffec00008 05 40 20 80 vmnet8 | |
235 | - * 00000000000000000000000000000001 01 80 10 80 lo | |
236 | - * fe80000000000000025056fffec00001 06 40 20 80 vmnet1 | |
237 | - * 200108881936000202166ffffe497d9b 03 40 00 00 eth1 | |
238 | - * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1 | |
239 | - * | |
240 | - * We get IPv6 address from the start, the interface name from the end, | |
241 | - * and ioctl() to get flags. | |
242 | - */ | |
243 | -static int | |
244 | -next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
245 | - char buf[256]; | |
246 | - int len; | |
247 | - char *p; | |
248 | - char *name; | |
249 | - int i; | |
250 | - struct sockaddr_in6 addr; | |
251 | - struct ifreq tmp; | |
252 | - | |
253 | - do { | |
254 | - /* | |
255 | - * Read the next line in the file. | |
256 | - */ | |
257 | - if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) { | |
258 | - if (ferror(ifaces->fp6)) { | |
259 | - *err = 1; | |
260 | - log_error("Error reading IPv6 " | |
261 | - "interface information"); | |
262 | - } else { | |
263 | - *err = 0; | |
264 | - } | |
265 | - return 0; | |
266 | - } | |
267 | - | |
268 | - /* | |
269 | - * Make sure the line is a nice, newline-terminated line. | |
270 | - */ | |
271 | - len = strlen(buf); | |
272 | - if ((len <= 0) || (buf[len-1] != '\n')) { | |
273 | - log_error("Bad line reading IPv6 " | |
274 | - "interface information"); | |
275 | - *err = 1; | |
276 | - return 0; | |
277 | - } | |
278 | - | |
279 | - /* | |
280 | - * Figure out our name. | |
281 | - */ | |
282 | - buf[--len] = '\0'; | |
283 | - p = strrchr(buf, ' '); | |
284 | - if (p == NULL) { | |
285 | - log_error("Bad line reading IPv6 interface " | |
286 | - "information (no space)"); | |
287 | - *err = 1; | |
288 | - return 0; | |
289 | - } | |
290 | - name = p+1; | |
291 | - | |
292 | - /* | |
293 | - * Copy our name into our interface structure. | |
294 | - */ | |
295 | - len = strlen(name); | |
296 | - if (len >= sizeof(info->name)) { | |
297 | - *err = 1; | |
298 | - log_error("IPv6 interface name '%s' too long", name); | |
299 | - return 0; | |
300 | - } | |
301 | - strcpy(info->name, name); | |
302 | - | |
303 | -#ifdef SKIP_DUMMY_INTERFACES | |
304 | - } while (strncmp(info->name, "dummy", 5) == 0); | |
305 | -#else | |
306 | - } while (0); | |
307 | -#endif | |
308 | - | |
309 | - /* | |
310 | - * Double-check we start with the IPv6 address. | |
311 | - */ | |
312 | - for (i=0; i<32; i++) { | |
313 | - if (!isxdigit(buf[i]) || isupper(buf[i])) { | |
314 | - *err = 1; | |
315 | - log_error("Bad line reading IPv6 interface address " | |
316 | - "for '%s'", name); | |
317 | - return 0; | |
318 | - } | |
319 | - } | |
320 | - | |
321 | - /* | |
322 | - * Load our socket structure. | |
323 | - */ | |
324 | - memset(&addr, 0, sizeof(addr)); | |
325 | - addr.sin6_family = AF_INET6; | |
326 | - for (i=0; i<16; i++) { | |
327 | - unsigned char byte; | |
328 | - static const char hex[] = "0123456789abcdef"; | |
329 | - byte = ((index(hex, buf[i * 2]) - hex) << 4) | | |
330 | - (index(hex, buf[i * 2 + 1]) - hex); | |
331 | - addr.sin6_addr.s6_addr[i] = byte; | |
332 | - } | |
333 | - memcpy(&info->addr, &addr, sizeof(addr)); | |
334 | - | |
335 | - /* | |
336 | - * Get our flags. | |
337 | - */ | |
338 | - memset(&tmp, 0, sizeof(tmp)); | |
339 | - strcpy(tmp.ifr_name, name); | |
340 | - if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { | |
341 | - log_error("Error getting interface flags for '%s'; %m", name); | |
342 | - *err = 1; | |
343 | - return 0; | |
344 | - } | |
345 | - info->flags = tmp.ifr_flags; | |
346 | - | |
347 | - *err = 0; | |
348 | - return 1; | |
349 | -} | |
350 | -#endif /* DHCPv6 */ | |
351 | - | |
352 | -/* | |
353 | - * Retrieve the next interface. | |
354 | - * | |
355 | - * Returns information in the info structure. | |
356 | - * Sets err to 1 if there is an error, otherwise 0. | |
357 | - */ | |
358 | -int | |
359 | -next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
360 | - if (next_iface4(info, err, ifaces)) { | |
361 | - return 1; | |
362 | - } | |
363 | -#ifdef DHCPv6 | |
364 | - if (!(*err) && ifaces->fp6) { | |
365 | - if (local_family == AF_INET6) | |
366 | - return next_iface6(info, err, ifaces); | |
367 | - } | |
368 | -#endif | |
369 | - return 0; | |
370 | -} | |
371 | - | |
372 | -/* | |
373 | - * End scan of interfaces. | |
374 | - */ | |
375 | -void | |
376 | -end_iface_scan(struct iface_conf_list *ifaces) { | |
377 | - fclose(ifaces->fp); | |
378 | - ifaces->fp = NULL; | |
379 | - close(ifaces->sock); | |
380 | - ifaces->sock = -1; | |
381 | -#ifdef DHCPv6 | |
382 | - if (local_family == AF_INET6) { | |
383 | - if (ifaces->fp6) | |
384 | - fclose(ifaces->fp6); | |
385 | - ifaces->fp6 = NULL; | |
386 | - } | |
387 | -#endif | |
388 | -} | |
389 | #else | |
390 | ||
391 | /* | |
392 | * BSD support | |
393 | * ----------- | |
394 | * | |
395 | - * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs() | |
396 | + * FreeBSD, NetBSD, OpenBSD, OS X and Linux all have the getifaddrs() | |
397 | * function. | |
398 | * | |
399 | * The getifaddrs() man page describes the use. | |
400 | @@ -814,6 +433,8 @@ begin_iface_scan(struct iface_conf_list | |
401 | */ | |
402 | int | |
403 | next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
404 | + size_t sa_len = 0; | |
405 | + | |
406 | if (ifaces->next == NULL) { | |
407 | *err = 0; | |
408 | return 0; | |
409 | @@ -825,8 +446,20 @@ next_iface(struct iface_info *info, int | |
410 | return 0; | |
411 | } | |
412 | strcpy(info->name, ifaces->next->ifa_name); | |
413 | - memcpy(&info->addr, ifaces->next->ifa_addr, | |
414 | - ifaces->next->ifa_addr->sa_len); | |
415 | + | |
416 | + memset(&info->addr, 0 , sizeof(info->addr)); | |
417 | + | |
418 | + if (ifaces->next->ifa_addr != NULL) { | |
419 | +#ifdef HAVE_SA_LEN | |
420 | + sa_len = ifaces->next->ifa_addr->sa_len; | |
421 | +#else | |
422 | + if (ifaces->next->ifa_addr->sa_family == AF_INET) | |
423 | + sa_len = sizeof(struct sockaddr_in); | |
424 | + else if (ifaces->next->ifa_addr->sa_family == AF_INET6) | |
425 | + sa_len = sizeof(struct sockaddr_in6); | |
426 | +#endif | |
427 | + memcpy(&info->addr, ifaces->next->ifa_addr, sa_len); | |
428 | + } | |
429 | info->flags = ifaces->next->ifa_flags; | |
430 | ifaces->next = ifaces->next->ifa_next; | |
431 | *err = 0; |