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