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