1 /*        $NetBSD: getifaddrs.c,v 1.2 2017/01/28 21:31:50 christos Exp $        */
2 
3 /*
4  * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 #include <krb5/roken.h>
38 
39 #ifdef __osf__
40 /* hate */
41 struct rtentry;
42 struct mbuf;
43 #endif
44 #ifdef HAVE_NET_IF_H
45 #include <net/if.h>
46 #endif
47 
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif /* HAVE_SYS_SOCKIO_H */
51 
52 #ifdef HAVE_NETINET_IN6_VAR_H
53 #include <netinet/in6_var.h>
54 #endif /* HAVE_NETINET_IN6_VAR_H */
55 
56 #include <ifaddrs.h>
57 
58 #ifdef __hpux
59 #define lifconf if_laddrconf
60 #define lifc_len iflc_len
61 #define lifc_buf iflc_buf
62 #define lifc_req iflc_req
63 
64 #define lifreq if_laddrreq
65 #define lifr_addr iflr_addr
66 #define lifr_name iflr_name
67 #define lifr_dstaddr iflr_dstaddr
68 #define lifr_broadaddr iflr_broadaddr
69 #define lifr_flags iflr_flags
70 #define lifr_index iflr_index
71 #endif
72 
73 #ifdef AF_NETLINK
74 
75 /*
76  * The linux - AF_NETLINK version of getifaddrs - from Usagi.
77  * Linux does not return v6 addresses from SIOCGIFCONF.
78  */
79 
80 /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
81 
82 /**************************************************************************
83  * ifaddrs.c
84  * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
85  *
86  * Redistribution and use in source and binary forms, with or without
87  * modification, are permitted provided that the following conditions
88  * are met:
89  * 1. Redistributions of source code must retain the above copyright
90  *    notice, this list of conditions and the following disclaimer.
91  * 2. Redistributions in binary form must reproduce the above copyright
92  *    notice, this list of conditions and the following disclaimer in the
93  *    documentation and/or other materials provided with the distribution.
94  * 3. Neither the name of the author nor the names of its contributors
95  *    may be used to endorse or promote products derived from this software
96  *    without specific prior written permission.
97  *
98  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
99  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
100  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
101  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
102  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
103  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
104  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
105  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
106  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
107  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
108  * SUCH DAMAGE.
109  */
110 
111 #include "config.h"
112 
113 #include <string.h>
114 #include <time.h>
115 #include <malloc.h>
116 #include <errno.h>
117 #include <unistd.h>
118 
119 #include <sys/socket.h>
120 #include <asm/types.h>
121 #include <linux/netlink.h>
122 #include <linux/rtnetlink.h>
123 #include <sys/types.h>
124 #include <sys/socket.h>
125 #include <sys/poll.h>
126 #include <netpacket/packet.h>
127 #include <net/ethernet.h>     /* the L2 protocols */
128 #include <sys/uio.h>
129 #include <net/if.h>
130 #include <net/if_arp.h>
131 #include <ifaddrs.h>
132 #include <netinet/in.h>
133 
134 #define __set_errno(e) (errno = (e))
135 #define __close(fd) (close(fd))
136 #undef ifa_broadaddr
137 #define ifa_broadaddr ifa_dstaddr
138 #define IFA_NETMASK
139 
140 /* ====================================================================== */
141 struct nlmsg_list{
142     struct nlmsg_list *nlm_next;
143     struct nlmsghdr *nlh;
144     int size;
145     time_t seq;
146 };
147 
148 struct rtmaddr_ifamap {
149   void *address;
150   void *local;
151 #ifdef IFA_NETMASK
152   void *netmask;
153 #endif
154   void *broadcast;
155 #ifdef HAVE_IFADDRS_IFA_ANYCAST
156   void *anycast;
157 #endif
158   int address_len;
159   int local_len;
160 #ifdef IFA_NETMASK
161   int netmask_len;
162 #endif
163   int broadcast_len;
164 #ifdef HAVE_IFADDRS_IFA_ANYCAST
165   int anycast_len;
166 #endif
167 };
168 
169 /* ====================================================================== */
170 static size_t
ifa_sa_len(sa_family_t family,int len)171 ifa_sa_len(sa_family_t family, int len)
172 {
173   size_t size;
174   switch(family){
175   case AF_INET:
176     size = sizeof(struct sockaddr_in);
177     break;
178   case AF_INET6:
179     size = sizeof(struct sockaddr_in6);
180     break;
181   case AF_PACKET:
182     size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
183     if (size < sizeof(struct sockaddr_ll))
184       size = sizeof(struct sockaddr_ll);
185     break;
186   default:
187     size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
188     if (size < sizeof(struct sockaddr))
189       size = sizeof(struct sockaddr);
190     break;
191   }
192   return size;
193 }
194 
195 static void
ifa_make_sockaddr(sa_family_t family,struct sockaddr * sa,void * p,size_t len,uint32_t scope,uint32_t scopeid)196 ifa_make_sockaddr(sa_family_t family,
197                       struct sockaddr *sa,
198                       void *p, size_t len,
199                       uint32_t scope, uint32_t scopeid)
200 {
201   if (sa == NULL) return;
202   switch(family){
203   case AF_INET:
204     memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
205     break;
206   case AF_INET6:
207     memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
208     if (IN6_IS_ADDR_LINKLOCAL(p) ||
209           IN6_IS_ADDR_MC_LINKLOCAL(p)){
210       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
211     }
212     break;
213   case AF_PACKET:
214     memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
215     ((struct sockaddr_ll*)sa)->sll_halen = len;
216     break;
217   default:
218     memcpy(sa->sa_data, p, len);        /*XXX*/
219     break;
220   }
221   sa->sa_family = family;
222 #ifdef HAVE_SOCKADDR_SA_LEN
223   sa->sa_len = ifa_sa_len(family, len);
224 #endif
225 }
226 
227 #ifndef IFA_NETMASK
228 static struct sockaddr *
ifa_make_sockaddr_mask(sa_family_t family,struct sockaddr * sa,uint32_t prefixlen)229 ifa_make_sockaddr_mask(sa_family_t family,
230                            struct sockaddr *sa,
231                            uint32_t prefixlen)
232 {
233   int i;
234   char *p = NULL, c;
235   uint32_t max_prefixlen = 0;
236 
237   if (sa == NULL) return NULL;
238   switch(family){
239   case AF_INET:
240     memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
241     p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
242     max_prefixlen = 32;
243     break;
244   case AF_INET6:
245     memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
246     p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
247 #if 0     /* XXX: fill scope-id? */
248     if (IN6_IS_ADDR_LINKLOCAL(p) ||
249           IN6_IS_ADDR_MC_LINKLOCAL(p)){
250       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
251     }
252 #endif
253     max_prefixlen = 128;
254     break;
255   default:
256     return NULL;
257   }
258   sa->sa_family = family;
259 #ifdef HAVE_SOCKADDR_SA_LEN
260   sa->sa_len = ifa_sa_len(family, len);
261 #endif
262   if (p){
263     if (prefixlen > max_prefixlen)
264       prefixlen = max_prefixlen;
265     for (i=0; i<(prefixlen / 8); i++)
266       *p++ = 0xff;
267     c = 0xff;
268     c <<= (8 - (prefixlen % 8));
269     *p = c;
270   }
271   return sa;
272 }
273 #endif
274 
275 /* ====================================================================== */
276 static int
nl_sendreq(int sd,int request,int flags,int * seq)277 nl_sendreq(int sd, int request, int flags, int *seq)
278 {
279   char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
280                 NLMSG_ALIGN(sizeof(struct rtgenmsg))];
281   struct sockaddr_nl nladdr;
282   struct nlmsghdr *req_hdr;
283   struct rtgenmsg *req_msg;
284   time_t t = time(NULL);
285 
286   if (seq) *seq = t;
287   memset(&reqbuf, 0, sizeof(reqbuf));
288   req_hdr = (struct nlmsghdr *)reqbuf;
289   req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
290   req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
291   req_hdr->nlmsg_type = request;
292   req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
293   req_hdr->nlmsg_pid = 0;
294   req_hdr->nlmsg_seq = t;
295   req_msg->rtgen_family = AF_UNSPEC;
296   memset(&nladdr, 0, sizeof(nladdr));
297   nladdr.nl_family = AF_NETLINK;
298   return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
299                      (struct sockaddr *)&nladdr, sizeof(nladdr)));
300 }
301 
302 static int
nl_recvmsg(int sd,int request,int seq,void * buf,size_t buflen,int * flags)303 nl_recvmsg(int sd, int request, int seq,
304              void *buf, size_t buflen,
305              int *flags)
306 {
307   struct msghdr msg;
308   struct iovec iov = { buf, buflen };
309   struct sockaddr_nl nladdr;
310   int read_len;
311 
312   for (;;){
313     msg.msg_name = (void *)&nladdr;
314     msg.msg_namelen = sizeof(nladdr);
315     msg.msg_iov = &iov;
316     msg.msg_iovlen = 1;
317     msg.msg_control = NULL;
318     msg.msg_controllen = 0;
319     msg.msg_flags = 0;
320     read_len = recvmsg(sd, &msg, 0);
321     if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
322       continue;
323     if (flags) *flags = msg.msg_flags;
324     break;
325   }
326   return read_len;
327 }
328 
329 static int
nl_getmsg(int sd,int request,int seq,struct nlmsghdr ** nlhp,int * done)330 nl_getmsg(int sd, int request, int seq,
331             struct nlmsghdr **nlhp,
332             int *done)
333 {
334   struct nlmsghdr *nh;
335   size_t bufsize = 65536, lastbufsize = 0;
336   void *buff = NULL;
337   int result = 0, read_size;
338   int msg_flags;
339   pid_t pid = getpid();
340   for (;;){
341     void *newbuff = realloc(buff, bufsize);
342     if (newbuff == NULL || bufsize < lastbufsize) {
343       result = -1;
344       break;
345     }
346     buff = newbuff;
347     result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
348     if (read_size < 0 || (msg_flags & MSG_TRUNC)){
349       lastbufsize = bufsize;
350       bufsize *= 2;
351       continue;
352     }
353     if (read_size == 0) break;
354     nh = (struct nlmsghdr *)buff;
355     for (nh = (struct nlmsghdr *)buff;
356            NLMSG_OK(nh, read_size);
357            nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
358       if (nh->nlmsg_pid != pid ||
359             nh->nlmsg_seq != seq)
360           continue;
361       if (nh->nlmsg_type == NLMSG_DONE){
362           (*done)++;
363           break; /* ok */
364       }
365       if (nh->nlmsg_type == NLMSG_ERROR){
366           struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
367           result = -1;
368           if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
369             __set_errno(EIO);
370           else
371             __set_errno(-nlerr->error);
372           break;
373       }
374     }
375     break;
376   }
377   if (result < 0)
378     if (buff){
379       int saved_errno = errno;
380       free(buff);
381       __set_errno(saved_errno);
382     }
383   *nlhp = (struct nlmsghdr *)buff;
384   return result;
385 }
386 
387 static int
nl_getlist(int sd,int seq,int request,struct nlmsg_list ** nlm_list,struct nlmsg_list ** nlm_end)388 nl_getlist(int sd, int seq,
389              int request,
390              struct nlmsg_list **nlm_list,
391              struct nlmsg_list **nlm_end)
392 {
393   struct nlmsghdr *nlh = NULL;
394   int status;
395   int done = 0;
396   int tries = 3;
397 
398  try_again:
399   status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
400   if (status < 0)
401     return status;
402   if (seq == 0)
403     seq = (int)time(NULL);
404   while(!done){
405     struct pollfd pfd;
406 
407     pfd.fd = sd;
408     pfd.events = POLLIN | POLLPRI;
409     pfd.revents = 0;
410     status = poll(&pfd, 1, 1000);
411     if (status < 0)
412           return status;
413     else if (status == 0) {
414           seq++;
415           if (tries-- > 0)
416               goto try_again;
417           return -1;
418     }
419 
420     status = nl_getmsg(sd, request, seq, &nlh, &done);
421     if (status < 0)
422       return status;
423     if (nlh){
424       struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
425       if (nlm_next == NULL){
426           int saved_errno = errno;
427           free(nlh);
428           __set_errno(saved_errno);
429           status = -1;
430       } else {
431           nlm_next->nlm_next = NULL;
432           nlm_next->nlh = (struct nlmsghdr *)nlh;
433           nlm_next->size = status;
434           nlm_next->seq = seq;
435           if (*nlm_list == NULL){
436             *nlm_list = nlm_next;
437             *nlm_end = nlm_next;
438           } else {
439             (*nlm_end)->nlm_next = nlm_next;
440             *nlm_end = nlm_next;
441           }
442       }
443     }
444   }
445   return status >= 0 ? seq : status;
446 }
447 
448 /* ---------------------------------------------------------------------- */
449 static void
free_nlmsglist(struct nlmsg_list * nlm0)450 free_nlmsglist(struct nlmsg_list *nlm0)
451 {
452   struct nlmsg_list *nlm, *nlm_next;
453   int saved_errno;
454   if (!nlm0)
455     return;
456   saved_errno = errno;
457   for (nlm=nlm0; nlm; nlm=nlm_next){
458     if (nlm->nlh)
459       free(nlm->nlh);
460     nlm_next=nlm->nlm_next;
461     free(nlm);
462   }
463   __set_errno(saved_errno);
464 }
465 
466 static void
free_data(void * data,void * ifdata)467 free_data(void *data, void *ifdata)
468 {
469   int saved_errno = errno;
470   if (data != NULL) free(data);
471   if (ifdata != NULL) free(ifdata);
472   __set_errno(saved_errno);
473 }
474 
475 /* ---------------------------------------------------------------------- */
476 static void
nl_close(int sd)477 nl_close(int sd)
478 {
479   int saved_errno = errno;
480   if (sd >= 0) __close(sd);
481   __set_errno(saved_errno);
482 }
483 
484 /* ---------------------------------------------------------------------- */
485 static int
nl_open(void)486 nl_open(void)
487 {
488   struct sockaddr_nl nladdr;
489   int sd;
490 
491   sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
492   if (sd < 0) return -1;
493   memset(&nladdr, 0, sizeof(nladdr));
494   nladdr.nl_family = AF_NETLINK;
495   if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
496     nl_close(sd);
497     return -1;
498   }
499   return sd;
500 }
501 
502 /* ====================================================================== */
503 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)504 rk_getifaddrs(struct ifaddrs **ifap)
505 {
506   int sd;
507   struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
508   /* - - - - - - - - - - - - - - - */
509   int icnt;
510   size_t dlen, xlen, nlen;
511   uint32_t max_ifindex = 0;
512 
513   pid_t pid = getpid();
514   int seq;
515   int result;
516   int build     ; /* 0 or 1 */
517 
518 /* ---------------------------------- */
519   /* initialize */
520   icnt = dlen = xlen = nlen = 0;
521   nlmsg_list = nlmsg_end = NULL;
522 
523   if (ifap)
524     *ifap = NULL;
525 
526 /* ---------------------------------- */
527   /* open socket and bind */
528   sd = nl_open();
529   if (sd < 0)
530     return -1;
531 
532 /* ---------------------------------- */
533    /* gather info */
534   if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
535                               &nlmsg_list, &nlmsg_end)) < 0){
536     free_nlmsglist(nlmsg_list);
537     nl_close(sd);
538     return -1;
539   }
540   if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
541                               &nlmsg_list, &nlmsg_end)) < 0){
542     free_nlmsglist(nlmsg_list);
543     nl_close(sd);
544     return -1;
545   }
546 
547 /* ---------------------------------- */
548   /* Estimate size of result buffer and fill it */
549   for (build=0; build<=1; build++){
550     struct ifaddrs *ifl = NULL, *ifa = NULL;
551     struct nlmsghdr *nlh, *nlh0;
552     char *data = NULL, *xdata = NULL;
553     void *ifdata = NULL;
554     char *ifname = NULL, **iflist = NULL;
555     uint16_t *ifflist = NULL;
556     struct rtmaddr_ifamap ifamap;
557 
558     if (build){
559       data = calloc(1,
560                         NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
561                         + dlen + xlen + nlen);
562       ifa = (struct ifaddrs *)data;
563       ifdata = calloc(1,
564                           NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
565                           + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
566       if (ifap != NULL)
567           *ifap = (ifdata != NULL) ? ifa : NULL;
568       else{
569           free_data(data, ifdata);
570           result = 0;
571           break;
572       }
573       if (data == NULL || ifdata == NULL){
574           free_data(data, ifdata);
575           result = -1;
576           break;
577       }
578       ifl = NULL;
579       data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
580       xdata = data + dlen;
581       ifname = xdata + xlen;
582       iflist = ifdata;
583       ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])));
584     }
585 
586     for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
587       int nlmlen = nlm->size;
588       if (!(nlh0 = nlm->nlh))
589           continue;
590       for (nlh = nlh0;
591              NLMSG_OK(nlh, nlmlen);
592              nlh=NLMSG_NEXT(nlh,nlmlen)){
593           struct ifinfomsg *ifim = NULL;
594           struct ifaddrmsg *ifam = NULL;
595           struct rtattr *rta;
596 
597           size_t nlm_struct_size = 0;
598           sa_family_t nlm_family = 0;
599           uint32_t nlm_scope = 0, nlm_index = 0;
600           size_t sockaddr_size = 0;
601           uint32_t nlm_prefixlen = 0;
602           size_t rtasize;
603 
604           memset(&ifamap, 0, sizeof(ifamap));
605 
606           /* check if the message is what we want */
607           if (nlh->nlmsg_pid != pid ||
608               nlh->nlmsg_seq != nlm->seq)
609             continue;
610           if (nlh->nlmsg_type == NLMSG_DONE){
611             break; /* ok */
612           }
613           switch (nlh->nlmsg_type){
614           case RTM_NEWLINK:
615             ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
616             nlm_struct_size = sizeof(*ifim);
617             nlm_family = ifim->ifi_family;
618             nlm_scope = 0;
619             nlm_index = ifim->ifi_index;
620             nlm_prefixlen = 0;
621             if (build)
622               ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
623             break;
624           case RTM_NEWADDR:
625             ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
626             nlm_struct_size = sizeof(*ifam);
627             nlm_family = ifam->ifa_family;
628             nlm_scope = ifam->ifa_scope;
629             nlm_index = ifam->ifa_index;
630             nlm_prefixlen = ifam->ifa_prefixlen;
631             if (build)
632               ifa->ifa_flags = ifflist[nlm_index];
633             break;
634           default:
635             continue;
636           }
637 
638           if (!build){
639             if (max_ifindex < nlm_index)
640               max_ifindex = nlm_index;
641           } else {
642             if (ifl != NULL)
643               ifl->ifa_next = ifa;
644           }
645 
646           rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
647           for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
648                RTA_OK(rta, rtasize);
649                rta = RTA_NEXT(rta, rtasize)){
650             struct sockaddr **sap = NULL;
651             void *rtadata = RTA_DATA(rta);
652             size_t rtapayload = RTA_PAYLOAD(rta);
653             socklen_t sa_len;
654 
655             switch(nlh->nlmsg_type){
656             case RTM_NEWLINK:
657               switch(rta->rta_type){
658               case IFLA_ADDRESS:
659               case IFLA_BROADCAST:
660                 if (build){
661                     sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
662                     *sap = (struct sockaddr *)data;
663                 }
664                 sa_len = ifa_sa_len(AF_PACKET, rtapayload);
665                 if (rta->rta_type == IFLA_ADDRESS)
666                     sockaddr_size = NLMSG_ALIGN(sa_len);
667                 if (!build){
668                     dlen += NLMSG_ALIGN(sa_len);
669                 } else {
670                     memset(*sap, 0, sa_len);
671                     ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
672                     ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
673                     ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
674                     data += NLMSG_ALIGN(sa_len);
675                 }
676                 break;
677               case IFLA_IFNAME:/* Name of Interface */
678                 if (!build)
679                     nlen += NLMSG_ALIGN(rtapayload + 1);
680                 else{
681                     ifa->ifa_name = ifname;
682                     if (iflist[nlm_index] == NULL)
683                       iflist[nlm_index] = ifa->ifa_name;
684                     strncpy(ifa->ifa_name, rtadata, rtapayload);
685                     ifa->ifa_name[rtapayload] = '\0';
686                     ifname += NLMSG_ALIGN(rtapayload + 1);
687                 }
688                 break;
689               case IFLA_STATS:/* Statistics of Interface */
690                 if (!build)
691                     xlen += NLMSG_ALIGN(rtapayload);
692                 else{
693                     ifa->ifa_data = xdata;
694                     memcpy(ifa->ifa_data, rtadata, rtapayload);
695                     xdata += NLMSG_ALIGN(rtapayload);
696                 }
697                 break;
698               case IFLA_UNSPEC:
699                 break;
700               case IFLA_MTU:
701                 break;
702               case IFLA_LINK:
703                 break;
704               case IFLA_QDISC:
705                 break;
706               default:
707                 break;
708               }
709               break;
710             case RTM_NEWADDR:
711               if (nlm_family == AF_PACKET) break;
712               switch(rta->rta_type){
713               case IFA_ADDRESS:
714                     ifamap.address = rtadata;
715                     ifamap.address_len = rtapayload;
716                     break;
717               case IFA_LOCAL:
718                     ifamap.local = rtadata;
719                     ifamap.local_len = rtapayload;
720                     break;
721               case IFA_BROADCAST:
722                     ifamap.broadcast = rtadata;
723                     ifamap.broadcast_len = rtapayload;
724                     break;
725 #ifdef HAVE_IFADDRS_IFA_ANYCAST
726               case IFA_ANYCAST:
727                     ifamap.anycast = rtadata;
728                     ifamap.anycast_len = rtapayload;
729                     break;
730 #endif
731               case IFA_LABEL:
732                 if (!build)
733                     nlen += NLMSG_ALIGN(rtapayload + 1);
734                 else{
735                     ifa->ifa_name = ifname;
736                     if (iflist[nlm_index] == NULL)
737                       iflist[nlm_index] = ifname;
738                     strncpy(ifa->ifa_name, rtadata, rtapayload);
739                     ifa->ifa_name[rtapayload] = '\0';
740                     ifname += NLMSG_ALIGN(rtapayload + 1);
741                 }
742                 break;
743               case IFA_UNSPEC:
744                 break;
745               case IFA_CACHEINFO:
746                 break;
747               default:
748                 break;
749               }
750             }
751           }
752           if (nlh->nlmsg_type == RTM_NEWADDR &&
753               nlm_family != AF_PACKET) {
754             if (!ifamap.local) {
755               ifamap.local = ifamap.address;
756               ifamap.local_len = ifamap.address_len;
757             }
758             if (!ifamap.address) {
759               ifamap.address = ifamap.local;
760               ifamap.address_len = ifamap.local_len;
761             }
762             if (ifamap.address_len != ifamap.local_len ||
763                 (ifamap.address != NULL &&
764                  memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
765               /* p2p; address is peer and local is ours */
766               ifamap.broadcast = ifamap.address;
767               ifamap.broadcast_len = ifamap.address_len;
768               ifamap.address = ifamap.local;
769               ifamap.address_len = ifamap.local_len;
770             }
771             if (ifamap.address) {
772 #ifndef IFA_NETMASK
773               sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
774 #endif
775               if (!build)
776                 dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
777               else {
778                 ifa->ifa_addr = (struct sockaddr *)data;
779                 ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
780                                         nlm_scope, nlm_index);
781                 data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
782               }
783             }
784 #ifdef IFA_NETMASK
785             if (ifamap.netmask) {
786               if (!build)
787                 dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
788               else {
789                 ifa->ifa_netmask = (struct sockaddr *)data;
790                 ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
791                                         nlm_scope, nlm_index);
792                 data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
793               }
794             }
795 #endif
796             if (ifamap.broadcast) {
797               if (!build)
798                 dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
799               else {
800                 ifa->ifa_broadaddr = (struct sockaddr *)data;
801                 ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
802                                         nlm_scope, nlm_index);
803                 data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
804               }
805             }
806 #ifdef HAVE_IFADDRS_IFA_ANYCAST
807             if (ifamap.anycast) {
808               if (!build)
809                 dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
810               else {
811                 ifa->ifa_anycast = (struct sockaddr *)data;
812                 ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
813                                         nlm_scope, nlm_index);
814                 data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
815               }
816             }
817 #endif
818           }
819           if (!build){
820 #ifndef IFA_NETMASK
821             dlen += sockaddr_size;
822 #endif
823             icnt++;
824           } else {
825             if (ifa->ifa_name == NULL)
826               ifa->ifa_name = iflist[nlm_index];
827 #ifndef IFA_NETMASK
828             if (ifa->ifa_addr &&
829                 ifa->ifa_addr->sa_family != AF_UNSPEC &&
830                 ifa->ifa_addr->sa_family != AF_PACKET){
831               ifa->ifa_netmask = (struct sockaddr *)data;
832               ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
833             }
834             data += sockaddr_size;
835 #endif
836             ifl = ifa++;
837           }
838       }
839     }
840     if (!build){
841       if (icnt == 0 && (dlen + nlen + xlen == 0)){
842           if (ifap != NULL)
843             *ifap = NULL;
844           break; /* cannot found any addresses */
845       }
846     }
847     else
848       free_data(NULL, ifdata);
849   }
850 
851 /* ---------------------------------- */
852   /* Finalize */
853   free_nlmsglist(nlmsg_list);
854   nl_close(sd);
855   return 0;
856 }
857 
858 void ROKEN_LIB_FUNCTION
rk_freeifaddrs(struct ifaddrs * ifp)859 rk_freeifaddrs(struct ifaddrs *ifp)
860 {
861     /* AF_NETLINK method uses a single allocation for all interfaces */
862     free(ifp);
863 }
864 
865 #else /* !AF_NETLINK */
866 
867 /*
868  * The generic SIOCGIFCONF version.
869  */
870 
871 static int
getifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)872 getifaddrs2(struct ifaddrs **ifap,
873               int af, int siocgifconf, int siocgifflags,
874               size_t ifreq_sz)
875 {
876     int ret;
877     int fd;
878     size_t buf_size;
879     char *buf;
880     struct ifconf ifconf;
881     char *p;
882     size_t sz;
883     struct sockaddr sa_zero;
884     struct ifreq *ifr;
885     struct ifaddrs *start = NULL, **end = &start;
886 
887     buf = NULL;
888 
889     memset (&sa_zero, 0, sizeof(sa_zero));
890     fd = socket(af, SOCK_DGRAM, 0);
891     if (fd < 0)
892           return -1;
893 
894     buf_size = 8192;
895     for (;;) {
896           buf = calloc(1, buf_size);
897           if (buf == NULL) {
898               ret = ENOMEM;
899               goto error_out;
900           }
901           ifconf.ifc_len = buf_size;
902           ifconf.ifc_buf = buf;
903 
904           /*
905            * Solaris returns EINVAL when the buffer is too small.
906            */
907           if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
908               ret = errno;
909               goto error_out;
910           }
911           /*
912            * Can the difference between a full and a overfull buf
913            * be determined?
914            */
915 
916           if (ifconf.ifc_len < buf_size)
917               break;
918           free (buf);
919           buf_size *= 2;
920     }
921 
922     for (p = ifconf.ifc_buf;
923            p < ifconf.ifc_buf + ifconf.ifc_len;
924            p += sz) {
925           struct ifreq ifreq;
926           struct sockaddr *sa;
927           size_t salen;
928 
929           ifr = (struct ifreq *)p;
930           sa  = &ifr->ifr_addr;
931 
932           sz = ifreq_sz;
933           salen = sizeof(struct sockaddr);
934 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
935           salen = sa->sa_len;
936           sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
937 #endif
938 #ifdef SA_LEN
939           salen = SA_LEN(sa);
940           sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
941 #endif
942           memset (&ifreq, 0, sizeof(ifreq));
943           memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
944 
945           if (ioctl(fd, siocgifflags, &ifreq) < 0) {
946               ret = errno;
947               goto error_out;
948           }
949 
950           *end = malloc(sizeof(**end));
951           if (*end == NULL) {
952               ret = ENOMEM;
953               goto error_out;
954           }
955 
956           (*end)->ifa_next = NULL;
957           (*end)->ifa_name = strdup(ifr->ifr_name);
958           if ((*end)->ifa_name == NULL) {
959               ret = ENOMEM;
960               goto error_out;
961           }
962           (*end)->ifa_flags = ifreq.ifr_flags;
963           (*end)->ifa_addr = malloc(salen);
964           if ((*end)->ifa_addr == NULL) {
965               ret = ENOMEM;
966               goto error_out;
967           }
968           memcpy((*end)->ifa_addr, sa, salen);
969           (*end)->ifa_netmask = NULL;
970 
971 #if 0
972           /* fix these when we actually need them */
973           if(ifreq.ifr_flags & IFF_BROADCAST) {
974               (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
975               if ((*end)->ifa_broadaddr == NULL) {
976                     ret = ENOMEM;
977                     goto error_out;
978               }
979               memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
980                        sizeof(ifr->ifr_broadaddr));
981           } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
982               (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
983               if ((*end)->ifa_dstaddr == NULL) {
984                     ret = ENOMEM;
985                     goto error_out;
986               }
987               memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
988                        sizeof(ifr->ifr_dstaddr));
989           } else
990               (*end)->ifa_dstaddr = NULL;
991 #else
992               (*end)->ifa_dstaddr = NULL;
993 #endif
994 
995           (*end)->ifa_data = NULL;
996 
997           end = &(*end)->ifa_next;
998 
999     }
1000     *ifap = start;
1001     close(fd);
1002     free(buf);
1003     return 0;
1004   error_out:
1005     rk_freeifaddrs(start);
1006     close(fd);
1007     free(buf);
1008     errno = ret;
1009     return -1;
1010 }
1011 
1012 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1013 static int
getlifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)1014 getlifaddrs2(struct ifaddrs **ifap,
1015                int af, int siocgifconf, int siocgifflags,
1016                size_t ifreq_sz)
1017 {
1018     int ret;
1019     int fd;
1020     size_t buf_size;
1021     char *buf;
1022     struct lifconf ifconf;
1023     char *p;
1024     size_t sz;
1025     struct sockaddr sa_zero;
1026     struct lifreq *ifr;
1027     struct ifaddrs *start = NULL, **end = &start;
1028 
1029     buf = NULL;
1030 
1031     memset (&sa_zero, 0, sizeof(sa_zero));
1032     fd = socket(af, SOCK_DGRAM, 0);
1033     if (fd < 0)
1034           return -1;
1035 
1036     buf_size = 8192;
1037     for (;;) {
1038           buf = calloc(1, buf_size);
1039           if (buf == NULL) {
1040               ret = ENOMEM;
1041               goto error_out;
1042           }
1043 #ifndef __hpux
1044           ifconf.lifc_family = af;
1045           ifconf.lifc_flags  = 0;
1046 #endif
1047           ifconf.lifc_len    = buf_size;
1048           ifconf.lifc_buf    = buf;
1049 
1050           /*
1051            * Solaris returns EINVAL when the buffer is too small.
1052            */
1053           if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
1054               ret = errno;
1055               goto error_out;
1056           }
1057           /*
1058            * Can the difference between a full and a overfull buf
1059            * be determined?
1060            */
1061 
1062           if (ifconf.lifc_len < buf_size)
1063               break;
1064           free (buf);
1065           buf_size *= 2;
1066     }
1067 
1068     for (p = ifconf.lifc_buf;
1069            p < ifconf.lifc_buf + ifconf.lifc_len;
1070            p += sz) {
1071           struct lifreq ifreq;
1072           struct sockaddr_storage *sa;
1073           size_t salen;
1074 
1075           ifr = (struct lifreq *)p;
1076           sa  = &ifr->lifr_addr;
1077 
1078           sz = ifreq_sz;
1079           salen = sizeof(struct sockaddr_storage);
1080 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1081           salen = sa->sa_len;
1082           sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
1083 #endif
1084 #ifdef SA_LEN
1085           salen = SA_LEN(sa);
1086           sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
1087 #endif
1088           memset (&ifreq, 0, sizeof(ifreq));
1089           memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name));
1090 
1091           if (ioctl(fd, siocgifflags, &ifreq) < 0) {
1092               ret = errno;
1093               goto error_out;
1094           }
1095 
1096           *end = malloc(sizeof(**end));
1097           if (*end == NULL) {
1098               ret = ENOMEM;
1099               goto error_out;
1100           }
1101 
1102           (*end)->ifa_next = NULL;
1103           (*end)->ifa_name = strdup(ifr->lifr_name);
1104           if ((*end)->ifa_name == NULL) {
1105               ret = ENOMEM;
1106               goto error_out;
1107           }
1108           (*end)->ifa_flags = ifreq.lifr_flags;
1109           (*end)->ifa_addr = malloc(salen);
1110           if ((*end)->ifa_addr == NULL) {
1111               ret = ENOMEM;
1112               goto error_out;
1113           }
1114           memcpy((*end)->ifa_addr, sa, salen);
1115           (*end)->ifa_netmask = NULL;
1116 
1117 #if 0
1118           /* fix these when we actually need them */
1119           if(ifreq.ifr_flags & IFF_BROADCAST) {
1120               (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
1121               if ((*end)->ifa_broadaddr == NULL) {
1122                     ret = ENOMEM;
1123                     goto error_out;
1124               }
1125               memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
1126                        sizeof(ifr->ifr_broadaddr));
1127           } else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
1128               (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
1129               if ((*end)->ifa_dstaddr == NULL) {
1130                     ret = ENOMEM;
1131                     goto error_out;
1132               }
1133               memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
1134                        sizeof(ifr->ifr_dstaddr));
1135           } else
1136               (*end)->ifa_dstaddr = NULL;
1137 #else
1138               (*end)->ifa_dstaddr = NULL;
1139 #endif
1140 
1141           (*end)->ifa_data = NULL;
1142 
1143           end = &(*end)->ifa_next;
1144 
1145     }
1146     *ifap = start;
1147     close(fd);
1148     free(buf);
1149     return 0;
1150   error_out:
1151     rk_freeifaddrs(start);
1152     close(fd);
1153     free(buf);
1154     errno = ret;
1155     return -1;
1156 }
1157 #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
1158 
1159 /**
1160  * Join two struct ifaddrs lists by appending supp to base.
1161  * Either may be NULL. The new list head (usually base) will be
1162  * returned.
1163  */
1164 static struct ifaddrs *
append_ifaddrs(struct ifaddrs * base,struct ifaddrs * supp)1165 append_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) {
1166     if (!base)
1167           return supp;
1168 
1169     if (!supp)
1170           return base;
1171 
1172     while (base->ifa_next)
1173           base = base->ifa_next;
1174 
1175     base->ifa_next = supp;
1176 
1177     return base;
1178 }
1179 
1180 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)1181 rk_getifaddrs(struct ifaddrs **ifap)
1182 {
1183     int ret = -1;
1184     errno = ENXIO;
1185 #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
1186     if (ret)
1187           ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
1188                                  sizeof(struct in6_ifreq));
1189 #endif
1190 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1191     /* Do IPv6 and IPv4 queries separately then join the result.
1192      *
1193      * HP-UX only returns IPv6 addresses using SIOCGLIFCONF,
1194      * SIOCGIFCONF has to be used for IPv4 addresses. The result is then
1195      * merged.
1196      *
1197      * Solaris needs particular care, because a SIOCGLIFCONF lookup using
1198      * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just
1199      * do them separately the same as for HP-UX. See
1200      * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73
1201      */
1202     if (ret) {
1203           int v6err, v4err;
1204           struct ifaddrs *v6addrs, *v4addrs;
1205 
1206           v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS,
1207                                   sizeof(struct lifreq));
1208           v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1209                                   sizeof(struct ifreq));
1210           if (v6err)
1211               v6addrs = NULL;
1212           if (v4err)
1213               v4addrs = NULL;
1214 
1215           if (v6addrs) {
1216               if (v4addrs)
1217                     *ifap = append_ifaddrs(v6addrs, v4addrs);
1218               else
1219                     *ifap = v6addrs;
1220           } else if (v4addrs) {
1221               *ifap = v4addrs;
1222           } else {
1223               *ifap = NULL;
1224           }
1225 
1226           ret = (v6err || v4err) ? -1 : 0;
1227     }
1228 #endif
1229 #if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
1230     if (ret)
1231           ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
1232                                  sizeof(struct ifreq));
1233 #endif
1234 #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
1235     if (ret)
1236           ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1237                                  sizeof(struct ifreq));
1238 #endif
1239     return ret;
1240 }
1241 
1242 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_freeifaddrs(struct ifaddrs * ifp)1243 rk_freeifaddrs(struct ifaddrs *ifp)
1244 {
1245     struct ifaddrs *p, *q;
1246 
1247     for(p = ifp; p; ) {
1248           free(p->ifa_name);
1249           if(p->ifa_addr)
1250               free(p->ifa_addr);
1251           if(p->ifa_dstaddr)
1252               free(p->ifa_dstaddr);
1253           if(p->ifa_netmask)
1254               free(p->ifa_netmask);
1255           if(p->ifa_data)
1256               free(p->ifa_data);
1257           q = p;
1258           p = p->ifa_next;
1259           free(q);
1260     }
1261 }
1262 
1263 #endif /* !AF_NETLINK */
1264 
1265 #ifdef TEST
1266 
1267 void
print_addr(const char * s,struct sockaddr * sa)1268 print_addr(const char *s, struct sockaddr *sa)
1269 {
1270     int i;
1271     printf("  %s=%d/", s, sa->sa_family);
1272 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1273     for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
1274           printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1275 #else
1276     for(i = 0; i < sizeof(sa->sa_data); i++)
1277           printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1278 #endif
1279     printf("\n");
1280 }
1281 
1282 void
print_ifaddrs(struct ifaddrs * x)1283 print_ifaddrs(struct ifaddrs *x)
1284 {
1285     struct ifaddrs *p;
1286 
1287     for(p = x; p; p = p->ifa_next) {
1288           printf("%s\n", p->ifa_name);
1289           printf("  flags=%x\n", p->ifa_flags);
1290           if(p->ifa_addr)
1291               print_addr("addr", p->ifa_addr);
1292           if(p->ifa_dstaddr)
1293               print_addr("dstaddr", p->ifa_dstaddr);
1294           if(p->ifa_netmask)
1295               print_addr("netmask", p->ifa_netmask);
1296           printf("  %p\n", p->ifa_data);
1297     }
1298 }
1299 
1300 int
main()1301 main()
1302 {
1303     struct ifaddrs *a = NULL, *b;
1304     getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
1305     print_ifaddrs(a);
1306     printf("---\n");
1307     getifaddrs(&b);
1308     print_ifaddrs(b);
1309     return 0;
1310 }
1311 #endif
1312