Commit | Line | Data |
---|---|---|
42562d13 FF |
1 | /* |
2 | * Copyright (c) 1995, 1999 | |
3 | * Berkeley Software Design, Inc. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * | |
11 | * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND | |
12 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
13 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
14 | * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE | |
15 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
16 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
17 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
18 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
19 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
20 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
21 | * SUCH DAMAGE. | |
22 | * | |
23 | * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp | |
24 | */ | |
25 | /* | |
26 | Copyright (c) 2013, Kenneth MacKay | |
27 | All rights reserved. | |
28 | ||
29 | Redistribution and use in source and binary forms, with or without modification, | |
30 | are permitted provided that the following conditions are met: | |
31 | * Redistributions of source code must retain the above copyright notice, this | |
32 | list of conditions and the following disclaimer. | |
33 | * Redistributions in binary form must reproduce the above copyright notice, | |
34 | this list of conditions and the following disclaimer in the documentation | |
35 | and/or other materials provided with the distribution. | |
36 | ||
37 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
38 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
39 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
40 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
41 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
42 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
43 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
44 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
45 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
46 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
47 | */ | |
48 | ||
49 | #ifndef _IFADDRS_H_ | |
50 | #define _IFADDRS_H_ | |
51 | ||
52 | struct ifaddrs { | |
53 | struct ifaddrs *ifa_next; | |
54 | char *ifa_name; | |
55 | unsigned int ifa_flags; | |
56 | struct sockaddr *ifa_addr; | |
57 | struct sockaddr *ifa_netmask; | |
58 | struct sockaddr *ifa_dstaddr; | |
59 | void *ifa_data; | |
60 | }; | |
61 | ||
62 | /* | |
63 | * This may have been defined in <net/if.h>. Note that if <net/if.h> is | |
64 | * to be included it must be included before this header file. | |
65 | */ | |
66 | #ifndef ifa_broadaddr | |
67 | #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ | |
68 | #endif | |
69 | ||
70 | #include <sys/cdefs.h> | |
71 | ||
72 | __BEGIN_DECLS | |
1197c15b FF |
73 | static int getifaddrs(struct ifaddrs **ifap); |
74 | static void freeifaddrs(struct ifaddrs *ifa); | |
42562d13 FF |
75 | __END_DECLS |
76 | ||
77 | #endif | |
78 | ||
79 | ||
80 | #include <string.h> | |
81 | #include <stdlib.h> | |
82 | #include <stddef.h> | |
83 | #include <errno.h> | |
84 | #include <unistd.h> | |
85 | #include <sys/socket.h> | |
86 | #include <netpacket/packet.h> | |
87 | #include <net/if_arp.h> | |
88 | #include <netinet/in.h> | |
89 | #include <linux/netlink.h> | |
90 | #include <linux/rtnetlink.h> | |
91 | ||
92 | typedef struct NetlinkList { | |
93 | struct NetlinkList *m_next; | |
94 | struct nlmsghdr *m_data; | |
95 | unsigned int m_size; | |
96 | } NetlinkList; | |
97 | ||
98 | static int netlink_socket(void) | |
99 | { | |
100 | int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
101 | if (l_socket < 0) return -1; | |
102 | ||
103 | struct sockaddr_nl l_addr; | |
104 | memset(&l_addr, 0, sizeof(l_addr)); | |
105 | l_addr.nl_family = AF_NETLINK; | |
106 | if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) { | |
107 | close(l_socket); | |
108 | return -1; | |
109 | } | |
110 | ||
111 | return l_socket; | |
112 | } | |
113 | ||
114 | static int netlink_send(int p_socket, int p_request) | |
115 | { | |
116 | struct { | |
117 | struct nlmsghdr m_hdr; | |
118 | struct rtgenmsg m_msg; | |
119 | } l_data; | |
120 | ||
121 | memset(&l_data, 0, sizeof(l_data)); | |
122 | ||
123 | l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); | |
124 | l_data.m_hdr.nlmsg_type = p_request; | |
125 | l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; | |
126 | l_data.m_hdr.nlmsg_pid = 0; | |
127 | l_data.m_hdr.nlmsg_seq = p_socket; | |
128 | l_data.m_msg.rtgen_family = AF_UNSPEC; | |
129 | ||
130 | struct sockaddr_nl l_addr; | |
131 | memset(&l_addr, 0, sizeof(l_addr)); | |
132 | l_addr.nl_family = AF_NETLINK; | |
133 | return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); | |
134 | } | |
135 | ||
136 | static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) | |
137 | { | |
138 | struct msghdr l_msg; | |
139 | struct iovec l_iov = { p_buffer, p_len }; | |
140 | struct sockaddr_nl l_addr; | |
141 | ||
142 | for (;;) { | |
143 | l_msg.msg_name = (void *)&l_addr; | |
144 | l_msg.msg_namelen = sizeof(l_addr); | |
145 | l_msg.msg_iov = &l_iov; | |
146 | l_msg.msg_iovlen = 1; | |
147 | l_msg.msg_control = NULL; | |
148 | l_msg.msg_controllen = 0; | |
149 | l_msg.msg_flags = 0; | |
150 | int l_result = recvmsg(p_socket, &l_msg, 0); | |
151 | ||
152 | if (l_result < 0) { | |
153 | if (errno == EINTR) { | |
154 | continue; | |
155 | } | |
156 | return -2; | |
157 | } | |
158 | ||
159 | if (l_msg.msg_flags & MSG_TRUNC) { | |
160 | /* Buffer was too small. */ | |
161 | return -1; | |
162 | } | |
163 | return l_result; | |
164 | } | |
165 | } | |
166 | ||
167 | static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) | |
168 | { | |
169 | size_t l_size = 4096; | |
170 | void *l_buffer = NULL; | |
171 | ||
172 | for(;;) { | |
173 | free(l_buffer); | |
174 | l_buffer = malloc(l_size); | |
175 | if (l_buffer == NULL) return NULL; | |
176 | ||
177 | int l_read = netlink_recv(p_socket, l_buffer, l_size); | |
178 | *p_size = l_read; | |
179 | if (l_read == -2) { | |
180 | free(l_buffer); | |
181 | return NULL; | |
182 | } | |
183 | if (l_read >= 0) { | |
184 | pid_t l_pid = getpid(); | |
185 | struct nlmsghdr *l_hdr; | |
186 | for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) { | |
187 | if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue; | |
188 | ||
189 | if(l_hdr->nlmsg_type == NLMSG_DONE) { | |
190 | *p_done = 1; | |
191 | break; | |
192 | } | |
193 | ||
194 | if(l_hdr->nlmsg_type == NLMSG_ERROR) { | |
195 | free(l_buffer); | |
196 | return NULL; | |
197 | } | |
198 | } | |
199 | return (struct nlmsghdr*)l_buffer; | |
200 | } | |
201 | ||
202 | l_size *= 2; | |
203 | } | |
204 | } | |
205 | ||
206 | static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) | |
207 | { | |
208 | NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList)); | |
209 | if (l_item == NULL) return NULL; | |
210 | ||
211 | l_item->m_next = NULL; | |
212 | l_item->m_data = p_data; | |
213 | l_item->m_size = p_size; | |
214 | return l_item; | |
215 | } | |
216 | ||
217 | static void freeResultList(NetlinkList *p_list) | |
218 | { | |
219 | NetlinkList *l_cur; | |
220 | while (p_list) { | |
221 | l_cur = p_list; | |
222 | p_list = p_list->m_next; | |
223 | free(l_cur->m_data); | |
224 | free(l_cur); | |
225 | } | |
226 | } | |
227 | ||
228 | static NetlinkList *getResultList(int p_socket, int p_request) | |
229 | { | |
230 | if (netlink_send(p_socket, p_request) < 0) return NULL; | |
231 | ||
232 | NetlinkList *l_list = NULL; | |
233 | NetlinkList *l_end = NULL; | |
234 | int l_size; | |
235 | int l_done = 0; | |
236 | while (!l_done) { | |
237 | struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); | |
238 | if (!l_hdr) { | |
239 | freeResultList(l_list); | |
240 | return NULL; | |
241 | } | |
242 | ||
243 | NetlinkList *l_item = newListItem(l_hdr, l_size); | |
244 | if (!l_item) { | |
245 | freeResultList(l_list); | |
246 | return NULL; | |
247 | } | |
248 | if (!l_list) { | |
249 | l_list = l_item; | |
250 | } else { | |
251 | l_end->m_next = l_item; | |
252 | } | |
253 | l_end = l_item; | |
254 | } | |
255 | return l_list; | |
256 | } | |
257 | ||
258 | static size_t maxSize(size_t a, size_t b) | |
259 | { | |
260 | return (a > b ? a : b); | |
261 | } | |
262 | ||
263 | static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) | |
264 | { | |
265 | switch (p_family) { | |
266 | case AF_INET: | |
267 | return sizeof(struct sockaddr_in); | |
268 | case AF_INET6: | |
269 | return sizeof(struct sockaddr_in6); | |
270 | case AF_PACKET: | |
271 | return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); | |
272 | default: | |
273 | return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); | |
274 | } | |
275 | } | |
276 | ||
277 | static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) | |
278 | { | |
279 | switch (p_family) { | |
280 | case AF_INET: | |
281 | memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); | |
282 | break; | |
283 | case AF_INET6: | |
284 | memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); | |
285 | break; | |
286 | case AF_PACKET: | |
287 | memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); | |
288 | ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; | |
289 | break; | |
290 | default: | |
291 | memcpy(p_dest->sa_data, p_data, p_size); | |
292 | break; | |
293 | } | |
294 | p_dest->sa_family = p_family; | |
295 | } | |
296 | ||
297 | static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) | |
298 | { | |
299 | if (!*p_resultList) { | |
300 | *p_resultList = p_entry; | |
301 | } else { | |
302 | struct ifaddrs *l_cur = *p_resultList; | |
303 | while(l_cur->ifa_next) { | |
304 | l_cur = l_cur->ifa_next; | |
305 | } | |
306 | l_cur->ifa_next = p_entry; | |
307 | } | |
308 | } | |
309 | ||
310 | static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList) | |
311 | { | |
312 | struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); | |
313 | ||
314 | size_t l_nameSize = 0; | |
315 | size_t l_addrSize = 0; | |
316 | size_t l_dataSize = 0; | |
317 | ||
318 | size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); | |
319 | struct rtattr *l_rta; | |
320 | for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { | |
321 | void *l_rtaData = RTA_DATA(l_rta); | |
322 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); | |
323 | switch (l_rta->rta_type) { | |
324 | case IFLA_ADDRESS: | |
325 | case IFLA_BROADCAST: | |
326 | l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); | |
327 | break; | |
328 | case IFLA_IFNAME: | |
329 | l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); | |
330 | break; | |
331 | case IFLA_STATS: | |
332 | l_dataSize += NLMSG_ALIGN(l_rtaSize); | |
333 | break; | |
334 | default: | |
335 | break; | |
336 | } | |
337 | } | |
338 | ||
339 | struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize); | |
340 | if (l_entry == NULL) return -1; | |
341 | memset(l_entry, 0, sizeof(struct ifaddrs)); | |
342 | l_entry->ifa_name = (char*)""; | |
343 | ||
344 | char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs); | |
345 | char *l_name = l_index + sizeof(int); | |
346 | char *l_addr = l_name + l_nameSize; | |
347 | char *l_data = l_addr + l_addrSize; | |
348 | ||
349 | /* Save the interface index so we can look it up when handling the addresses. */ | |
350 | memcpy(l_index, &l_info->ifi_index, sizeof(int)); | |
351 | ||
352 | l_entry->ifa_flags = l_info->ifi_flags; | |
353 | ||
354 | l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); | |
355 | for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { | |
356 | void *l_rtaData = RTA_DATA(l_rta); | |
357 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); | |
358 | switch (l_rta->rta_type) { | |
359 | case IFLA_ADDRESS: | |
360 | case IFLA_BROADCAST: | |
361 | { | |
362 | size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); | |
363 | makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); | |
364 | ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; | |
365 | ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; | |
366 | if (l_rta->rta_type == IFLA_ADDRESS) { | |
367 | l_entry->ifa_addr = (struct sockaddr *)l_addr; | |
368 | } else { | |
369 | l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; | |
370 | } | |
371 | l_addr += NLMSG_ALIGN(l_addrLen); | |
372 | break; | |
373 | } | |
374 | case IFLA_IFNAME: | |
375 | strncpy(l_name, (char*)l_rtaData, l_rtaDataSize); | |
376 | l_name[l_rtaDataSize] = '\0'; | |
377 | l_entry->ifa_name = l_name; | |
378 | break; | |
379 | case IFLA_STATS: | |
380 | memcpy(l_data, l_rtaData, l_rtaDataSize); | |
381 | l_entry->ifa_data = l_data; | |
382 | break; | |
383 | default: | |
384 | break; | |
385 | } | |
386 | } | |
387 | ||
388 | addToEnd(p_resultList, l_entry); | |
389 | return 0; | |
390 | } | |
391 | ||
392 | static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks) | |
393 | { | |
394 | int l_num = 0; | |
395 | struct ifaddrs *l_cur = *p_links; | |
396 | while (l_cur && l_num < p_numLinks) { | |
397 | char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); | |
398 | int l_index; | |
399 | memcpy(&l_index, l_indexPtr, sizeof(int)); | |
400 | if(l_index == p_index) return l_cur; | |
401 | ||
402 | l_cur = l_cur->ifa_next; | |
403 | ++l_num; | |
404 | } | |
405 | return NULL; | |
406 | } | |
407 | ||
408 | static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) | |
409 | { | |
410 | struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); | |
411 | struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks); | |
412 | ||
413 | if (l_info->ifa_family == AF_PACKET) return 0; | |
414 | ||
415 | size_t l_nameSize = 0; | |
416 | size_t l_addrSize = 0; | |
417 | int l_addedNetmask = 0; | |
418 | ||
419 | size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); | |
420 | struct rtattr *l_rta; | |
421 | for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { | |
422 | void *l_rtaData = RTA_DATA(l_rta); | |
423 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); | |
424 | ||
425 | switch (l_rta->rta_type) { | |
426 | case IFA_ADDRESS: | |
427 | case IFA_LOCAL: | |
428 | if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) { | |
429 | /* Make room for netmask. */ | |
430 | l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); | |
431 | l_addedNetmask = 1; | |
432 | } | |
433 | case IFA_BROADCAST: | |
434 | l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); | |
435 | break; | |
436 | case IFA_LABEL: | |
437 | l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); | |
438 | break; | |
439 | default: | |
440 | break; | |
441 | } | |
442 | } | |
443 | ||
444 | struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); | |
445 | if (l_entry == NULL) return -1; | |
446 | memset(l_entry, 0, sizeof(struct ifaddrs)); | |
447 | l_entry->ifa_name = (l_interface ? l_interface->ifa_name : (char*)""); | |
448 | ||
449 | char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); | |
450 | char *l_addr = l_name + l_nameSize; | |
451 | ||
452 | l_entry->ifa_flags = l_info->ifa_flags; | |
453 | if (l_interface) { | |
454 | l_entry->ifa_flags |= l_interface->ifa_flags; | |
455 | } | |
456 | ||
457 | l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); | |
458 | for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) { | |
459 | void *l_rtaData = RTA_DATA(l_rta); | |
460 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); | |
461 | switch (l_rta->rta_type) { | |
462 | case IFA_ADDRESS: | |
463 | case IFA_BROADCAST: | |
464 | case IFA_LOCAL: | |
465 | { | |
466 | size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); | |
467 | makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); | |
468 | if (l_info->ifa_family == AF_INET6) { | |
469 | if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) { | |
470 | ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; | |
471 | } | |
472 | } | |
473 | ||
474 | if (l_rta->rta_type == IFA_ADDRESS) { | |
475 | /* Apparently in a point-to-point network IFA_ADDRESS contains | |
476 | the dest address and IFA_LOCAL contains the local address. */ | |
477 | if(l_entry->ifa_addr) { | |
478 | l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; | |
479 | } else { | |
480 | l_entry->ifa_addr = (struct sockaddr *)l_addr; | |
481 | } | |
482 | } else if (l_rta->rta_type == IFA_LOCAL) { | |
483 | if(l_entry->ifa_addr) { | |
484 | l_entry->ifa_dstaddr = l_entry->ifa_addr; | |
485 | } | |
486 | l_entry->ifa_addr = (struct sockaddr *)l_addr; | |
487 | } else { | |
488 | l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; | |
489 | } | |
490 | l_addr += NLMSG_ALIGN(l_addrLen); | |
491 | break; | |
492 | } | |
493 | case IFA_LABEL: | |
494 | strncpy(l_name, (char*)l_rtaData, l_rtaDataSize); | |
495 | l_name[l_rtaDataSize] = '\0'; | |
496 | l_entry->ifa_name = l_name; | |
497 | break; | |
498 | default: | |
499 | break; | |
500 | } | |
501 | } | |
502 | ||
503 | if (l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) { | |
504 | unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); | |
505 | unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); | |
506 | char l_mask[16] = {0}; | |
507 | unsigned i; | |
508 | for (i=0; i<(l_prefix/8); ++i) { | |
509 | l_mask[i] = 0xff; | |
510 | } | |
511 | if (l_prefix % 8) { | |
512 | l_mask[i] = 0xff << (8 - (l_prefix % 8)); | |
513 | } | |
514 | ||
515 | makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); | |
516 | l_entry->ifa_netmask = (struct sockaddr *)l_addr; | |
517 | } | |
518 | ||
519 | addToEnd(p_resultList, l_entry); | |
520 | return 0; | |
521 | } | |
522 | ||
523 | static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList) | |
524 | { | |
525 | int l_numLinks = 0; | |
526 | pid_t l_pid = getpid(); | |
527 | for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { | |
528 | unsigned int l_nlsize = p_netlinkList->m_size; | |
529 | struct nlmsghdr *l_hdr; | |
530 | for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) | |
531 | { | |
532 | if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue; | |
533 | ||
534 | if (l_hdr->nlmsg_type == NLMSG_DONE) break; | |
535 | ||
536 | if (l_hdr->nlmsg_type == RTM_NEWLINK) { | |
537 | if(interpretLink(l_hdr, p_resultList) == -1) return -1; | |
538 | ++l_numLinks; | |
539 | } | |
540 | } | |
541 | } | |
542 | return l_numLinks; | |
543 | } | |
544 | ||
545 | static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks) | |
546 | { | |
547 | pid_t l_pid = getpid(); | |
548 | for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next) { | |
549 | unsigned int l_nlsize = p_netlinkList->m_size; | |
550 | struct nlmsghdr *l_hdr; | |
551 | for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) { | |
552 | if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue; | |
553 | ||
554 | if (l_hdr->nlmsg_type == NLMSG_DONE) break; | |
555 | ||
556 | if (l_hdr->nlmsg_type == RTM_NEWADDR) { | |
557 | if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) return -1; | |
558 | } | |
559 | } | |
560 | } | |
561 | return 0; | |
562 | } | |
563 | ||
59a1174c | 564 | static int getifaddrs(struct ifaddrs **ifap) |
42562d13 FF |
565 | { |
566 | if (!ifap) return -1; | |
567 | *ifap = NULL; | |
568 | ||
569 | int l_socket = netlink_socket(); | |
570 | if (l_socket < 0) { | |
571 | return -1; | |
572 | } | |
573 | ||
574 | NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); | |
575 | if (!l_linkResults) { | |
576 | close(l_socket); | |
577 | return -1; | |
578 | } | |
579 | ||
580 | NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); | |
581 | if (!l_addrResults) { | |
582 | close(l_socket); | |
583 | freeResultList(l_linkResults); | |
584 | return -1; | |
585 | } | |
586 | ||
587 | int l_result = 0; | |
588 | int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap); | |
589 | if (l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) { | |
590 | l_result = -1; | |
591 | } | |
592 | ||
593 | freeResultList(l_linkResults); | |
594 | freeResultList(l_addrResults); | |
595 | close(l_socket); | |
596 | return l_result; | |
597 | } | |
598 | ||
59a1174c | 599 | static void freeifaddrs(struct ifaddrs *ifa) |
42562d13 FF |
600 | { |
601 | struct ifaddrs *l_cur; | |
602 | while (ifa) { | |
603 | l_cur = ifa; | |
604 | ifa = ifa->ifa_next; | |
605 | free(l_cur); | |
606 | } | |
607 | } |