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