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