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 */ 41struct rtentry; 42struct 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/* ====================================================================== */ 141struct nlmsg_list{ 142 struct nlmsg_list *nlm_next; 143 struct nlmsghdr *nlh; 144 int size; 145 time_t seq; 146}; 147 148struct 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/* ====================================================================== */ 170static size_t 171ifa_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 195static void 196ifa_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 228static struct sockaddr * 229ifa_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/* ====================================================================== */ 276static int 277nl_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 302static int 303nl_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 329static int 330nl_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 387static int 388nl_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/* ---------------------------------------------------------------------- */ 449static void 450free_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 466static void 467free_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/* ---------------------------------------------------------------------- */ 476static void 477nl_close(int sd) 478{ 479 int saved_errno = errno; 480 if (sd >= 0) __close(sd); 481 __set_errno(saved_errno); 482} 483 484/* ---------------------------------------------------------------------- */ 485static int 486nl_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/* ====================================================================== */ 503ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 504rk_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 858void ROKEN_LIB_FUNCTION 859rk_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 871static int 872getifaddrs2(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) 1013static int 1014getlifaddrs2(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 */ 1164static struct ifaddrs * 1165append_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 1180ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 1181rk_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 1242ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 1243rk_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 1267void 1268print_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 1282void 1283print_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 1300int 1301main() 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