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