172445Sassar/* 2233294Sstas * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska H��gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 5233294Sstas * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 9233294Sstas * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 12233294Sstas * 1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1472445Sassar * notice, this list of conditions and the following disclaimer in the 1572445Sassar * documentation and/or other materials provided with the distribution. 16233294Sstas * 1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 20233294Sstas * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include <config.h> 3572445Sassar#include "roken.h" 3672445Sassar 3772445Sassar#ifdef __osf__ 3872445Sassar/* hate */ 3972445Sassarstruct rtentry; 4072445Sassarstruct mbuf; 4172445Sassar#endif 4272445Sassar#ifdef HAVE_NET_IF_H 4372445Sassar#include <net/if.h> 4472445Sassar#endif 4572445Sassar 4672445Sassar#ifdef HAVE_SYS_SOCKIO_H 4772445Sassar#include <sys/sockio.h> 4872445Sassar#endif /* HAVE_SYS_SOCKIO_H */ 4972445Sassar 5072445Sassar#ifdef HAVE_NETINET_IN6_VAR_H 5172445Sassar#include <netinet/in6_var.h> 5272445Sassar#endif /* HAVE_NETINET_IN6_VAR_H */ 5372445Sassar 5472445Sassar#include <ifaddrs.h> 5572445Sassar 56178825Sdfr#ifdef __hpux 57178825Sdfr#define lifconf if_laddrconf 58178825Sdfr#define lifc_len iflc_len 59178825Sdfr#define lifc_buf iflc_buf 60178825Sdfr#define lifc_req iflc_req 61178825Sdfr 62178825Sdfr#define lifreq if_laddrreq 63178825Sdfr#define lifr_addr iflr_addr 64178825Sdfr#define lifr_name iflr_name 65178825Sdfr#define lifr_dstaddr iflr_dstaddr 66178825Sdfr#define lifr_broadaddr iflr_broadaddr 67178825Sdfr#define lifr_flags iflr_flags 68178825Sdfr#define lifr_index iflr_index 69178825Sdfr#endif 70178825Sdfr 71103423Snectar#ifdef AF_NETLINK 72103423Snectar 73103423Snectar/* 74103423Snectar * The linux - AF_NETLINK version of getifaddrs - from Usagi. 75103423Snectar * Linux does not return v6 addresses from SIOCGIFCONF. 76103423Snectar */ 77103423Snectar 78103423Snectar/* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */ 79103423Snectar 80103423Snectar/************************************************************************** 81103423Snectar * ifaddrs.c 82103423Snectar * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved. 83103423Snectar * 84103423Snectar * Redistribution and use in source and binary forms, with or without 85103423Snectar * modification, are permitted provided that the following conditions 86103423Snectar * are met: 87103423Snectar * 1. Redistributions of source code must retain the above copyright 88103423Snectar * notice, this list of conditions and the following disclaimer. 89103423Snectar * 2. Redistributions in binary form must reproduce the above copyright 90103423Snectar * notice, this list of conditions and the following disclaimer in the 91103423Snectar * documentation and/or other materials provided with the distribution. 92103423Snectar * 3. Neither the name of the author nor the names of its contributors 93103423Snectar * may be used to endorse or promote products derived from this software 94103423Snectar * without specific prior written permission. 95233294Sstas * 96103423Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 97103423Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 98103423Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 99103423Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 100103423Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 101103423Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 102103423Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 103103423Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 104103423Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 105103423Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 106103423Snectar * SUCH DAMAGE. 107103423Snectar */ 108103423Snectar 109103423Snectar#include "config.h" 110103423Snectar 111103423Snectar#include <string.h> 112103423Snectar#include <time.h> 113103423Snectar#include <malloc.h> 114103423Snectar#include <errno.h> 115103423Snectar#include <unistd.h> 116103423Snectar 117103423Snectar#include <sys/socket.h> 118103423Snectar#include <asm/types.h> 119103423Snectar#include <linux/netlink.h> 120103423Snectar#include <linux/rtnetlink.h> 121103423Snectar#include <sys/types.h> 122103423Snectar#include <sys/socket.h> 123178825Sdfr#include <sys/poll.h> 124103423Snectar#include <netpacket/packet.h> 125103423Snectar#include <net/ethernet.h> /* the L2 protocols */ 126103423Snectar#include <sys/uio.h> 127103423Snectar#include <net/if.h> 128103423Snectar#include <net/if_arp.h> 129103423Snectar#include <ifaddrs.h> 130103423Snectar#include <netinet/in.h> 131103423Snectar 132103423Snectar#define __set_errno(e) (errno = (e)) 133103423Snectar#define __close(fd) (close(fd)) 134103423Snectar#undef ifa_broadaddr 135103423Snectar#define ifa_broadaddr ifa_dstaddr 136103423Snectar#define IFA_NETMASK 137103423Snectar 138103423Snectar/* ====================================================================== */ 139103423Snectarstruct nlmsg_list{ 140103423Snectar struct nlmsg_list *nlm_next; 141103423Snectar struct nlmsghdr *nlh; 142103423Snectar int size; 143103423Snectar time_t seq; 144103423Snectar}; 145103423Snectar 146103423Snectarstruct rtmaddr_ifamap { 147103423Snectar void *address; 148103423Snectar void *local; 149103423Snectar#ifdef IFA_NETMASK 150103423Snectar void *netmask; 151103423Snectar#endif 152103423Snectar void *broadcast; 153103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 154103423Snectar void *anycast; 155103423Snectar#endif 156103423Snectar int address_len; 157103423Snectar int local_len; 158103423Snectar#ifdef IFA_NETMASK 159103423Snectar int netmask_len; 160103423Snectar#endif 161103423Snectar int broadcast_len; 162103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 163103423Snectar int anycast_len; 164103423Snectar#endif 165103423Snectar}; 166103423Snectar 167103423Snectar/* ====================================================================== */ 168103423Snectarstatic size_t 169103423Snectarifa_sa_len(sa_family_t family, int len) 170103423Snectar{ 171103423Snectar size_t size; 172103423Snectar switch(family){ 173103423Snectar case AF_INET: 174103423Snectar size = sizeof(struct sockaddr_in); 175103423Snectar break; 176103423Snectar case AF_INET6: 177103423Snectar size = sizeof(struct sockaddr_in6); 178103423Snectar break; 179103423Snectar case AF_PACKET: 180103423Snectar size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len; 181103423Snectar if (size < sizeof(struct sockaddr_ll)) 182103423Snectar size = sizeof(struct sockaddr_ll); 183103423Snectar break; 184103423Snectar default: 185103423Snectar size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len; 186103423Snectar if (size < sizeof(struct sockaddr)) 187103423Snectar size = sizeof(struct sockaddr); 188178825Sdfr break; 189103423Snectar } 190103423Snectar return size; 191103423Snectar} 192103423Snectar 193233294Sstasstatic void 194233294Sstasifa_make_sockaddr(sa_family_t family, 195233294Sstas struct sockaddr *sa, 196103423Snectar void *p, size_t len, 197103423Snectar uint32_t scope, uint32_t scopeid) 198103423Snectar{ 199103423Snectar if (sa == NULL) return; 200103423Snectar switch(family){ 201103423Snectar case AF_INET: 202103423Snectar memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len); 203103423Snectar break; 204103423Snectar case AF_INET6: 205103423Snectar memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len); 206103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 207103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 208103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 209103423Snectar } 210103423Snectar break; 211103423Snectar case AF_PACKET: 212103423Snectar memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len); 213103423Snectar ((struct sockaddr_ll*)sa)->sll_halen = len; 214103423Snectar break; 215103423Snectar default: 216103423Snectar memcpy(sa->sa_data, p, len); /*XXX*/ 217103423Snectar break; 218103423Snectar } 219103423Snectar sa->sa_family = family; 220103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 221103423Snectar sa->sa_len = ifa_sa_len(family, len); 222103423Snectar#endif 223103423Snectar} 224103423Snectar 225103423Snectar#ifndef IFA_NETMASK 226103423Snectarstatic struct sockaddr * 227233294Sstasifa_make_sockaddr_mask(sa_family_t family, 228233294Sstas struct sockaddr *sa, 229103423Snectar uint32_t prefixlen) 230103423Snectar{ 231103423Snectar int i; 232103423Snectar char *p = NULL, c; 233103423Snectar uint32_t max_prefixlen = 0; 234103423Snectar 235103423Snectar if (sa == NULL) return NULL; 236103423Snectar switch(family){ 237103423Snectar case AF_INET: 238103423Snectar memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr)); 239103423Snectar p = (char *)&((struct sockaddr_in*)sa)->sin_addr; 240103423Snectar max_prefixlen = 32; 241103423Snectar break; 242103423Snectar case AF_INET6: 243103423Snectar memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr)); 244103423Snectar p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr; 245103423Snectar#if 0 /* XXX: fill scope-id? */ 246103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 247103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 248103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 249103423Snectar } 250103423Snectar#endif 251103423Snectar max_prefixlen = 128; 252103423Snectar break; 253103423Snectar default: 254103423Snectar return NULL; 255103423Snectar } 256103423Snectar sa->sa_family = family; 257103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 258103423Snectar sa->sa_len = ifa_sa_len(family, len); 259103423Snectar#endif 260103423Snectar if (p){ 261103423Snectar if (prefixlen > max_prefixlen) 262103423Snectar prefixlen = max_prefixlen; 263103423Snectar for (i=0; i<(prefixlen / 8); i++) 264103423Snectar *p++ = 0xff; 265103423Snectar c = 0xff; 266103423Snectar c <<= (8 - (prefixlen % 8)); 267103423Snectar *p = c; 268103423Snectar } 269103423Snectar return sa; 270103423Snectar} 271103423Snectar#endif 272103423Snectar 273103423Snectar/* ====================================================================== */ 274233294Sstasstatic int 275103423Snectarnl_sendreq(int sd, int request, int flags, int *seq) 276103423Snectar{ 277103423Snectar char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 278103423Snectar NLMSG_ALIGN(sizeof(struct rtgenmsg))]; 279103423Snectar struct sockaddr_nl nladdr; 280103423Snectar struct nlmsghdr *req_hdr; 281103423Snectar struct rtgenmsg *req_msg; 282103423Snectar time_t t = time(NULL); 283103423Snectar 284103423Snectar if (seq) *seq = t; 285103423Snectar memset(&reqbuf, 0, sizeof(reqbuf)); 286103423Snectar req_hdr = (struct nlmsghdr *)reqbuf; 287103423Snectar req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr); 288103423Snectar req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg)); 289103423Snectar req_hdr->nlmsg_type = request; 290103423Snectar req_hdr->nlmsg_flags = flags | NLM_F_REQUEST; 291103423Snectar req_hdr->nlmsg_pid = 0; 292103423Snectar req_hdr->nlmsg_seq = t; 293103423Snectar req_msg->rtgen_family = AF_UNSPEC; 294103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 295103423Snectar nladdr.nl_family = AF_NETLINK; 296103423Snectar return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0, 297103423Snectar (struct sockaddr *)&nladdr, sizeof(nladdr))); 298103423Snectar} 299103423Snectar 300233294Sstasstatic int 301233294Sstasnl_recvmsg(int sd, int request, int seq, 302233294Sstas void *buf, size_t buflen, 303103423Snectar int *flags) 304103423Snectar{ 305103423Snectar struct msghdr msg; 306103423Snectar struct iovec iov = { buf, buflen }; 307103423Snectar struct sockaddr_nl nladdr; 308103423Snectar int read_len; 309103423Snectar 310103423Snectar for (;;){ 311103423Snectar msg.msg_name = (void *)&nladdr; 312103423Snectar msg.msg_namelen = sizeof(nladdr); 313103423Snectar msg.msg_iov = &iov; 314103423Snectar msg.msg_iovlen = 1; 315103423Snectar msg.msg_control = NULL; 316103423Snectar msg.msg_controllen = 0; 317103423Snectar msg.msg_flags = 0; 318103423Snectar read_len = recvmsg(sd, &msg, 0); 319103423Snectar if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC)) 320103423Snectar continue; 321103423Snectar if (flags) *flags = msg.msg_flags; 322103423Snectar break; 323103423Snectar } 324103423Snectar return read_len; 325103423Snectar} 326103423Snectar 327233294Sstasstatic int 328233294Sstasnl_getmsg(int sd, int request, int seq, 329103423Snectar struct nlmsghdr **nlhp, 330103423Snectar int *done) 331103423Snectar{ 332103423Snectar struct nlmsghdr *nh; 333103423Snectar size_t bufsize = 65536, lastbufsize = 0; 334103423Snectar void *buff = NULL; 335103423Snectar int result = 0, read_size; 336103423Snectar int msg_flags; 337103423Snectar pid_t pid = getpid(); 338103423Snectar for (;;){ 339103423Snectar void *newbuff = realloc(buff, bufsize); 340103423Snectar if (newbuff == NULL || bufsize < lastbufsize) { 341103423Snectar result = -1; 342103423Snectar break; 343103423Snectar } 344103423Snectar buff = newbuff; 345103423Snectar result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags); 346103423Snectar if (read_size < 0 || (msg_flags & MSG_TRUNC)){ 347103423Snectar lastbufsize = bufsize; 348103423Snectar bufsize *= 2; 349103423Snectar continue; 350103423Snectar } 351103423Snectar if (read_size == 0) break; 352103423Snectar nh = (struct nlmsghdr *)buff; 353103423Snectar for (nh = (struct nlmsghdr *)buff; 354103423Snectar NLMSG_OK(nh, read_size); 355103423Snectar nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){ 356103423Snectar if (nh->nlmsg_pid != pid || 357103423Snectar nh->nlmsg_seq != seq) 358103423Snectar continue; 359103423Snectar if (nh->nlmsg_type == NLMSG_DONE){ 360103423Snectar (*done)++; 361103423Snectar break; /* ok */ 362103423Snectar } 363103423Snectar if (nh->nlmsg_type == NLMSG_ERROR){ 364103423Snectar struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh); 365103423Snectar result = -1; 366103423Snectar if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 367103423Snectar __set_errno(EIO); 368103423Snectar else 369103423Snectar __set_errno(-nlerr->error); 370103423Snectar break; 371103423Snectar } 372103423Snectar } 373103423Snectar break; 374103423Snectar } 375103423Snectar if (result < 0) 376103423Snectar if (buff){ 377103423Snectar int saved_errno = errno; 378103423Snectar free(buff); 379103423Snectar __set_errno(saved_errno); 380103423Snectar } 381103423Snectar *nlhp = (struct nlmsghdr *)buff; 382103423Snectar return result; 383103423Snectar} 384103423Snectar 38572445Sassarstatic int 386103423Snectarnl_getlist(int sd, int seq, 387103423Snectar int request, 388103423Snectar struct nlmsg_list **nlm_list, 389103423Snectar struct nlmsg_list **nlm_end) 390103423Snectar{ 391103423Snectar struct nlmsghdr *nlh = NULL; 392103423Snectar int status; 393103423Snectar int done = 0; 394178825Sdfr int tries = 3; 395103423Snectar 396178825Sdfr try_again: 397103423Snectar status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq); 398103423Snectar if (status < 0) 399103423Snectar return status; 400103423Snectar if (seq == 0) 401103423Snectar seq = (int)time(NULL); 402103423Snectar while(!done){ 403178825Sdfr struct pollfd pfd; 404178825Sdfr 405178825Sdfr pfd.fd = sd; 406178825Sdfr pfd.events = POLLIN | POLLPRI; 407178825Sdfr pfd.revents = 0; 408178825Sdfr status = poll(&pfd, 1, 1000); 409178825Sdfr if (status < 0) 410178825Sdfr return status; 411178825Sdfr else if (status == 0) { 412178825Sdfr seq++; 413178825Sdfr if (tries-- > 0) 414178825Sdfr goto try_again; 415178825Sdfr return -1; 416178825Sdfr } 417178825Sdfr 418103423Snectar status = nl_getmsg(sd, request, seq, &nlh, &done); 419103423Snectar if (status < 0) 420103423Snectar return status; 421103423Snectar if (nlh){ 422103423Snectar struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list)); 423103423Snectar if (nlm_next == NULL){ 424103423Snectar int saved_errno = errno; 425103423Snectar free(nlh); 426103423Snectar __set_errno(saved_errno); 427103423Snectar status = -1; 428103423Snectar } else { 429103423Snectar nlm_next->nlm_next = NULL; 430103423Snectar nlm_next->nlh = (struct nlmsghdr *)nlh; 431103423Snectar nlm_next->size = status; 432103423Snectar nlm_next->seq = seq; 433103423Snectar if (*nlm_list == NULL){ 434103423Snectar *nlm_list = nlm_next; 435103423Snectar *nlm_end = nlm_next; 436103423Snectar } else { 437103423Snectar (*nlm_end)->nlm_next = nlm_next; 438103423Snectar *nlm_end = nlm_next; 439103423Snectar } 440103423Snectar } 441103423Snectar } 442103423Snectar } 443103423Snectar return status >= 0 ? seq : status; 444103423Snectar} 445103423Snectar 446103423Snectar/* ---------------------------------------------------------------------- */ 447233294Sstasstatic void 448103423Snectarfree_nlmsglist(struct nlmsg_list *nlm0) 449103423Snectar{ 450178825Sdfr struct nlmsg_list *nlm, *nlm_next; 451103423Snectar int saved_errno; 452103423Snectar if (!nlm0) 453103423Snectar return; 454103423Snectar saved_errno = errno; 455178825Sdfr for (nlm=nlm0; nlm; nlm=nlm_next){ 456103423Snectar if (nlm->nlh) 457103423Snectar free(nlm->nlh); 458178825Sdfr nlm_next=nlm->nlm_next; 459178825Sdfr free(nlm); 460103423Snectar } 461103423Snectar __set_errno(saved_errno); 462103423Snectar} 463103423Snectar 464233294Sstasstatic void 465103423Snectarfree_data(void *data, void *ifdata) 466103423Snectar{ 467103423Snectar int saved_errno = errno; 468103423Snectar if (data != NULL) free(data); 469103423Snectar if (ifdata != NULL) free(ifdata); 470103423Snectar __set_errno(saved_errno); 471103423Snectar} 472103423Snectar 473103423Snectar/* ---------------------------------------------------------------------- */ 474233294Sstasstatic void 475103423Snectarnl_close(int sd) 476103423Snectar{ 477103423Snectar int saved_errno = errno; 478103423Snectar if (sd >= 0) __close(sd); 479103423Snectar __set_errno(saved_errno); 480103423Snectar} 481103423Snectar 482103423Snectar/* ---------------------------------------------------------------------- */ 483233294Sstasstatic int 484103423Snectarnl_open(void) 485103423Snectar{ 486103423Snectar struct sockaddr_nl nladdr; 487103423Snectar int sd; 488103423Snectar 489103423Snectar sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 490103423Snectar if (sd < 0) return -1; 491103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 492103423Snectar nladdr.nl_family = AF_NETLINK; 493103423Snectar if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){ 494103423Snectar nl_close(sd); 495103423Snectar return -1; 496103423Snectar } 497103423Snectar return sd; 498103423Snectar} 499103423Snectar 500103423Snectar/* ====================================================================== */ 501233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 502178825Sdfrrk_getifaddrs(struct ifaddrs **ifap) 503103423Snectar{ 504103423Snectar int sd; 505103423Snectar struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; 506103423Snectar /* - - - - - - - - - - - - - - - */ 507103423Snectar int icnt; 508103423Snectar size_t dlen, xlen, nlen; 509103423Snectar uint32_t max_ifindex = 0; 510103423Snectar 511103423Snectar pid_t pid = getpid(); 512103423Snectar int seq; 513103423Snectar int result; 514103423Snectar int build ; /* 0 or 1 */ 515103423Snectar 516103423Snectar/* ---------------------------------- */ 517103423Snectar /* initialize */ 518103423Snectar icnt = dlen = xlen = nlen = 0; 519103423Snectar nlmsg_list = nlmsg_end = NULL; 520103423Snectar 521103423Snectar if (ifap) 522103423Snectar *ifap = NULL; 523103423Snectar 524103423Snectar/* ---------------------------------- */ 525103423Snectar /* open socket and bind */ 526103423Snectar sd = nl_open(); 527103423Snectar if (sd < 0) 528103423Snectar return -1; 529103423Snectar 530103423Snectar/* ---------------------------------- */ 531103423Snectar /* gather info */ 532103423Snectar if ((seq = nl_getlist(sd, 0, RTM_GETLINK, 533103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 534103423Snectar free_nlmsglist(nlmsg_list); 535103423Snectar nl_close(sd); 536103423Snectar return -1; 537103423Snectar } 538103423Snectar if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, 539103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 540103423Snectar free_nlmsglist(nlmsg_list); 541103423Snectar nl_close(sd); 542103423Snectar return -1; 543103423Snectar } 544103423Snectar 545103423Snectar/* ---------------------------------- */ 546103423Snectar /* Estimate size of result buffer and fill it */ 547103423Snectar for (build=0; build<=1; build++){ 548103423Snectar struct ifaddrs *ifl = NULL, *ifa = NULL; 549103423Snectar struct nlmsghdr *nlh, *nlh0; 550103423Snectar char *data = NULL, *xdata = NULL; 551103423Snectar void *ifdata = NULL; 552103423Snectar char *ifname = NULL, **iflist = NULL; 553103423Snectar uint16_t *ifflist = NULL; 554103423Snectar struct rtmaddr_ifamap ifamap; 555103423Snectar 556103423Snectar if (build){ 557103423Snectar data = calloc(1, 558103423Snectar NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) 559103423Snectar + dlen + xlen + nlen); 560103423Snectar ifa = (struct ifaddrs *)data; 561233294Sstas ifdata = calloc(1, 562103423Snectar NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) 563103423Snectar + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); 564103423Snectar if (ifap != NULL) 565103423Snectar *ifap = (ifdata != NULL) ? ifa : NULL; 566103423Snectar else{ 567103423Snectar free_data(data, ifdata); 568103423Snectar result = 0; 569103423Snectar break; 570103423Snectar } 571103423Snectar if (data == NULL || ifdata == NULL){ 572103423Snectar free_data(data, ifdata); 573103423Snectar result = -1; 574103423Snectar break; 575103423Snectar } 576103423Snectar ifl = NULL; 577103423Snectar data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; 578103423Snectar xdata = data + dlen; 579103423Snectar ifname = xdata + xlen; 580103423Snectar iflist = ifdata; 581103423Snectar ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))); 582103423Snectar } 583103423Snectar 584103423Snectar for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ 585103423Snectar int nlmlen = nlm->size; 586103423Snectar if (!(nlh0 = nlm->nlh)) 587103423Snectar continue; 588233294Sstas for (nlh = nlh0; 589233294Sstas NLMSG_OK(nlh, nlmlen); 590103423Snectar nlh=NLMSG_NEXT(nlh,nlmlen)){ 591103423Snectar struct ifinfomsg *ifim = NULL; 592103423Snectar struct ifaddrmsg *ifam = NULL; 593103423Snectar struct rtattr *rta; 594103423Snectar 595103423Snectar size_t nlm_struct_size = 0; 596103423Snectar sa_family_t nlm_family = 0; 597103423Snectar uint32_t nlm_scope = 0, nlm_index = 0; 598103423Snectar size_t sockaddr_size = 0; 599103423Snectar uint32_t nlm_prefixlen = 0; 600103423Snectar size_t rtasize; 601103423Snectar 602103423Snectar memset(&ifamap, 0, sizeof(ifamap)); 603103423Snectar 604103423Snectar /* check if the message is what we want */ 605103423Snectar if (nlh->nlmsg_pid != pid || 606103423Snectar nlh->nlmsg_seq != nlm->seq) 607103423Snectar continue; 608103423Snectar if (nlh->nlmsg_type == NLMSG_DONE){ 609103423Snectar break; /* ok */ 610103423Snectar } 611103423Snectar switch (nlh->nlmsg_type){ 612103423Snectar case RTM_NEWLINK: 613103423Snectar ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); 614103423Snectar nlm_struct_size = sizeof(*ifim); 615103423Snectar nlm_family = ifim->ifi_family; 616103423Snectar nlm_scope = 0; 617103423Snectar nlm_index = ifim->ifi_index; 618103423Snectar nlm_prefixlen = 0; 619103423Snectar if (build) 620103423Snectar ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; 621103423Snectar break; 622103423Snectar case RTM_NEWADDR: 623103423Snectar ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); 624103423Snectar nlm_struct_size = sizeof(*ifam); 625103423Snectar nlm_family = ifam->ifa_family; 626103423Snectar nlm_scope = ifam->ifa_scope; 627103423Snectar nlm_index = ifam->ifa_index; 628103423Snectar nlm_prefixlen = ifam->ifa_prefixlen; 629103423Snectar if (build) 630103423Snectar ifa->ifa_flags = ifflist[nlm_index]; 631103423Snectar break; 632103423Snectar default: 633103423Snectar continue; 634103423Snectar } 635233294Sstas 636103423Snectar if (!build){ 637103423Snectar if (max_ifindex < nlm_index) 638103423Snectar max_ifindex = nlm_index; 639103423Snectar } else { 640103423Snectar if (ifl != NULL) 641103423Snectar ifl->ifa_next = ifa; 642103423Snectar } 643103423Snectar 644103423Snectar rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); 645103423Snectar for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); 646103423Snectar RTA_OK(rta, rtasize); 647103423Snectar rta = RTA_NEXT(rta, rtasize)){ 648103423Snectar struct sockaddr **sap = NULL; 649103423Snectar void *rtadata = RTA_DATA(rta); 650103423Snectar size_t rtapayload = RTA_PAYLOAD(rta); 651103423Snectar socklen_t sa_len; 652103423Snectar 653103423Snectar switch(nlh->nlmsg_type){ 654103423Snectar case RTM_NEWLINK: 655103423Snectar switch(rta->rta_type){ 656103423Snectar case IFLA_ADDRESS: 657103423Snectar case IFLA_BROADCAST: 658103423Snectar if (build){ 659103423Snectar sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; 660103423Snectar *sap = (struct sockaddr *)data; 661103423Snectar } 662103423Snectar sa_len = ifa_sa_len(AF_PACKET, rtapayload); 663103423Snectar if (rta->rta_type == IFLA_ADDRESS) 664103423Snectar sockaddr_size = NLMSG_ALIGN(sa_len); 665103423Snectar if (!build){ 666103423Snectar dlen += NLMSG_ALIGN(sa_len); 667103423Snectar } else { 668103423Snectar memset(*sap, 0, sa_len); 669103423Snectar ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); 670103423Snectar ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; 671103423Snectar ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; 672103423Snectar data += NLMSG_ALIGN(sa_len); 673103423Snectar } 674103423Snectar break; 675103423Snectar case IFLA_IFNAME:/* Name of Interface */ 676103423Snectar if (!build) 677103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 678103423Snectar else{ 679103423Snectar ifa->ifa_name = ifname; 680103423Snectar if (iflist[nlm_index] == NULL) 681103423Snectar iflist[nlm_index] = ifa->ifa_name; 682103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 683103423Snectar ifa->ifa_name[rtapayload] = '\0'; 684103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 685103423Snectar } 686103423Snectar break; 687103423Snectar case IFLA_STATS:/* Statistics of Interface */ 688103423Snectar if (!build) 689103423Snectar xlen += NLMSG_ALIGN(rtapayload); 690103423Snectar else{ 691103423Snectar ifa->ifa_data = xdata; 692103423Snectar memcpy(ifa->ifa_data, rtadata, rtapayload); 693103423Snectar xdata += NLMSG_ALIGN(rtapayload); 694103423Snectar } 695103423Snectar break; 696103423Snectar case IFLA_UNSPEC: 697103423Snectar break; 698103423Snectar case IFLA_MTU: 699103423Snectar break; 700103423Snectar case IFLA_LINK: 701103423Snectar break; 702103423Snectar case IFLA_QDISC: 703103423Snectar break; 704103423Snectar default: 705178825Sdfr break; 706103423Snectar } 707103423Snectar break; 708103423Snectar case RTM_NEWADDR: 709103423Snectar if (nlm_family == AF_PACKET) break; 710103423Snectar switch(rta->rta_type){ 711103423Snectar case IFA_ADDRESS: 712103423Snectar ifamap.address = rtadata; 713103423Snectar ifamap.address_len = rtapayload; 714103423Snectar break; 715103423Snectar case IFA_LOCAL: 716103423Snectar ifamap.local = rtadata; 717103423Snectar ifamap.local_len = rtapayload; 718103423Snectar break; 719103423Snectar case IFA_BROADCAST: 720103423Snectar ifamap.broadcast = rtadata; 721103423Snectar ifamap.broadcast_len = rtapayload; 722103423Snectar break; 723103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 724103423Snectar case IFA_ANYCAST: 725103423Snectar ifamap.anycast = rtadata; 726103423Snectar ifamap.anycast_len = rtapayload; 727103423Snectar break; 728103423Snectar#endif 729103423Snectar case IFA_LABEL: 730103423Snectar if (!build) 731103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 732103423Snectar else{ 733103423Snectar ifa->ifa_name = ifname; 734103423Snectar if (iflist[nlm_index] == NULL) 735103423Snectar iflist[nlm_index] = ifname; 736103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 737103423Snectar ifa->ifa_name[rtapayload] = '\0'; 738103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 739103423Snectar } 740103423Snectar break; 741103423Snectar case IFA_UNSPEC: 742103423Snectar break; 743103423Snectar case IFA_CACHEINFO: 744103423Snectar break; 745103423Snectar default: 746178825Sdfr break; 747103423Snectar } 748103423Snectar } 749103423Snectar } 750103423Snectar if (nlh->nlmsg_type == RTM_NEWADDR && 751103423Snectar nlm_family != AF_PACKET) { 752103423Snectar if (!ifamap.local) { 753103423Snectar ifamap.local = ifamap.address; 754103423Snectar ifamap.local_len = ifamap.address_len; 755103423Snectar } 756103423Snectar if (!ifamap.address) { 757103423Snectar ifamap.address = ifamap.local; 758103423Snectar ifamap.address_len = ifamap.local_len; 759103423Snectar } 760103423Snectar if (ifamap.address_len != ifamap.local_len || 761103423Snectar (ifamap.address != NULL && 762103423Snectar memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { 763103423Snectar /* p2p; address is peer and local is ours */ 764103423Snectar ifamap.broadcast = ifamap.address; 765103423Snectar ifamap.broadcast_len = ifamap.address_len; 766103423Snectar ifamap.address = ifamap.local; 767103423Snectar ifamap.address_len = ifamap.local_len; 768103423Snectar } 769103423Snectar if (ifamap.address) { 770103423Snectar#ifndef IFA_NETMASK 771103423Snectar sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 772103423Snectar#endif 773103423Snectar if (!build) 774103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 775103423Snectar else { 776103423Snectar ifa->ifa_addr = (struct sockaddr *)data; 777103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, 778103423Snectar nlm_scope, nlm_index); 779103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); 780103423Snectar } 781103423Snectar } 782103423Snectar#ifdef IFA_NETMASK 783103423Snectar if (ifamap.netmask) { 784103423Snectar if (!build) 785103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); 786103423Snectar else { 787103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 788103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, 789103423Snectar nlm_scope, nlm_index); 790103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); 791103423Snectar } 792103423Snectar } 793103423Snectar#endif 794103423Snectar if (ifamap.broadcast) { 795103423Snectar if (!build) 796103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); 797103423Snectar else { 798103423Snectar ifa->ifa_broadaddr = (struct sockaddr *)data; 799103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, 800103423Snectar nlm_scope, nlm_index); 801103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); 802103423Snectar } 803103423Snectar } 804103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 805103423Snectar if (ifamap.anycast) { 806103423Snectar if (!build) 807103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); 808103423Snectar else { 809103423Snectar ifa->ifa_anycast = (struct sockaddr *)data; 810103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, 811103423Snectar nlm_scope, nlm_index); 812103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); 813103423Snectar } 814103423Snectar } 815103423Snectar#endif 816103423Snectar } 817103423Snectar if (!build){ 818103423Snectar#ifndef IFA_NETMASK 819103423Snectar dlen += sockaddr_size; 820103423Snectar#endif 821103423Snectar icnt++; 822103423Snectar } else { 823103423Snectar if (ifa->ifa_name == NULL) 824103423Snectar ifa->ifa_name = iflist[nlm_index]; 825103423Snectar#ifndef IFA_NETMASK 826233294Sstas if (ifa->ifa_addr && 827233294Sstas ifa->ifa_addr->sa_family != AF_UNSPEC && 828103423Snectar ifa->ifa_addr->sa_family != AF_PACKET){ 829103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 830103423Snectar ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); 831103423Snectar } 832103423Snectar data += sockaddr_size; 833103423Snectar#endif 834103423Snectar ifl = ifa++; 835103423Snectar } 836103423Snectar } 837103423Snectar } 838103423Snectar if (!build){ 839103423Snectar if (icnt == 0 && (dlen + nlen + xlen == 0)){ 840103423Snectar if (ifap != NULL) 841103423Snectar *ifap = NULL; 842103423Snectar break; /* cannot found any addresses */ 843103423Snectar } 844103423Snectar } 845103423Snectar else 846103423Snectar free_data(NULL, ifdata); 847103423Snectar } 848103423Snectar 849103423Snectar/* ---------------------------------- */ 850103423Snectar /* Finalize */ 851103423Snectar free_nlmsglist(nlmsg_list); 852103423Snectar nl_close(sd); 853103423Snectar return 0; 854103423Snectar} 855103423Snectar 856233294Sstasvoid ROKEN_LIB_FUNCTION 857233294Sstasrk_freeifaddrs(struct ifaddrs *ifp) 858233294Sstas{ 859233294Sstas /* AF_NETLINK method uses a single allocation for all interfaces */ 860233294Sstas free(ifp); 861233294Sstas} 862233294Sstas 863103423Snectar#else /* !AF_NETLINK */ 864103423Snectar 865103423Snectar/* 866103423Snectar * The generic SIOCGIFCONF version. 867103423Snectar */ 868103423Snectar 869103423Snectarstatic int 870233294Sstasgetifaddrs2(struct ifaddrs **ifap, 87172445Sassar int af, int siocgifconf, int siocgifflags, 87272445Sassar size_t ifreq_sz) 87372445Sassar{ 87472445Sassar int ret; 87572445Sassar int fd; 87672445Sassar size_t buf_size; 87772445Sassar char *buf; 87872445Sassar struct ifconf ifconf; 87972445Sassar char *p; 88072445Sassar size_t sz; 88172445Sassar struct sockaddr sa_zero; 88272445Sassar struct ifreq *ifr; 88390926Snectar struct ifaddrs *start = NULL, **end = &start; 88472445Sassar 88572445Sassar buf = NULL; 88672445Sassar 88772445Sassar memset (&sa_zero, 0, sizeof(sa_zero)); 88872445Sassar fd = socket(af, SOCK_DGRAM, 0); 88972445Sassar if (fd < 0) 89072445Sassar return -1; 89172445Sassar 89272445Sassar buf_size = 8192; 89372445Sassar for (;;) { 89472445Sassar buf = calloc(1, buf_size); 89572445Sassar if (buf == NULL) { 89672445Sassar ret = ENOMEM; 89772445Sassar goto error_out; 89872445Sassar } 89972445Sassar ifconf.ifc_len = buf_size; 90072445Sassar ifconf.ifc_buf = buf; 90172445Sassar 90272445Sassar /* 90372445Sassar * Solaris returns EINVAL when the buffer is too small. 90472445Sassar */ 90572445Sassar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 90672445Sassar ret = errno; 90772445Sassar goto error_out; 90872445Sassar } 90972445Sassar /* 91072445Sassar * Can the difference between a full and a overfull buf 91172445Sassar * be determined? 91272445Sassar */ 91372445Sassar 91472445Sassar if (ifconf.ifc_len < buf_size) 91572445Sassar break; 91672445Sassar free (buf); 91772445Sassar buf_size *= 2; 91872445Sassar } 91972445Sassar 92072445Sassar for (p = ifconf.ifc_buf; 92172445Sassar p < ifconf.ifc_buf + ifconf.ifc_len; 92272445Sassar p += sz) { 92372445Sassar struct ifreq ifreq; 92472445Sassar struct sockaddr *sa; 92572445Sassar size_t salen; 92672445Sassar 92772445Sassar ifr = (struct ifreq *)p; 92872445Sassar sa = &ifr->ifr_addr; 92972445Sassar 93072445Sassar sz = ifreq_sz; 93172445Sassar salen = sizeof(struct sockaddr); 93272445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 93372445Sassar salen = sa->sa_len; 93472445Sassar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 93572445Sassar#endif 93672445Sassar#ifdef SA_LEN 93772445Sassar salen = SA_LEN(sa); 93872445Sassar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 93972445Sassar#endif 94072445Sassar memset (&ifreq, 0, sizeof(ifreq)); 94172445Sassar memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); 94272445Sassar 94372445Sassar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 94472445Sassar ret = errno; 94572445Sassar goto error_out; 94672445Sassar } 94772445Sassar 94872445Sassar *end = malloc(sizeof(**end)); 94990926Snectar if (*end == NULL) { 95090926Snectar ret = ENOMEM; 95190926Snectar goto error_out; 95290926Snectar } 95372445Sassar 95472445Sassar (*end)->ifa_next = NULL; 95572445Sassar (*end)->ifa_name = strdup(ifr->ifr_name); 956178825Sdfr if ((*end)->ifa_name == NULL) { 957178825Sdfr ret = ENOMEM; 958178825Sdfr goto error_out; 959178825Sdfr } 96072445Sassar (*end)->ifa_flags = ifreq.ifr_flags; 96172445Sassar (*end)->ifa_addr = malloc(salen); 962178825Sdfr if ((*end)->ifa_addr == NULL) { 963178825Sdfr ret = ENOMEM; 964178825Sdfr goto error_out; 965178825Sdfr } 96672445Sassar memcpy((*end)->ifa_addr, sa, salen); 96772445Sassar (*end)->ifa_netmask = NULL; 96872445Sassar 96972445Sassar#if 0 97072445Sassar /* fix these when we actually need them */ 97172445Sassar if(ifreq.ifr_flags & IFF_BROADCAST) { 97272445Sassar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 973178825Sdfr if ((*end)->ifa_broadaddr == NULL) { 974178825Sdfr ret = ENOMEM; 975178825Sdfr goto error_out; 976178825Sdfr } 977233294Sstas memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 97872445Sassar sizeof(ifr->ifr_broadaddr)); 97972445Sassar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 98072445Sassar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 981178825Sdfr if ((*end)->ifa_dstaddr == NULL) { 982178825Sdfr ret = ENOMEM; 983178825Sdfr goto error_out; 984178825Sdfr } 985233294Sstas memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 98672445Sassar sizeof(ifr->ifr_dstaddr)); 98772445Sassar } else 98872445Sassar (*end)->ifa_dstaddr = NULL; 98972445Sassar#else 99072445Sassar (*end)->ifa_dstaddr = NULL; 99172445Sassar#endif 99272445Sassar 99372445Sassar (*end)->ifa_data = NULL; 99472445Sassar 99572445Sassar end = &(*end)->ifa_next; 996233294Sstas 99772445Sassar } 99872445Sassar *ifap = start; 99978527Sassar close(fd); 100072445Sassar free(buf); 100172445Sassar return 0; 100272445Sassar error_out: 1003178825Sdfr rk_freeifaddrs(start); 100478527Sassar close(fd); 100572445Sassar free(buf); 100672445Sassar errno = ret; 100772445Sassar return -1; 100872445Sassar} 100972445Sassar 101090926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 101190926Snectarstatic int 1012233294Sstasgetlifaddrs2(struct ifaddrs **ifap, 101390926Snectar int af, int siocgifconf, int siocgifflags, 101490926Snectar size_t ifreq_sz) 101590926Snectar{ 101690926Snectar int ret; 101790926Snectar int fd; 101890926Snectar size_t buf_size; 101990926Snectar char *buf; 102090926Snectar struct lifconf ifconf; 102190926Snectar char *p; 102290926Snectar size_t sz; 102390926Snectar struct sockaddr sa_zero; 102490926Snectar struct lifreq *ifr; 102590926Snectar struct ifaddrs *start = NULL, **end = &start; 102690926Snectar 102790926Snectar buf = NULL; 102890926Snectar 102990926Snectar memset (&sa_zero, 0, sizeof(sa_zero)); 103090926Snectar fd = socket(af, SOCK_DGRAM, 0); 103190926Snectar if (fd < 0) 103290926Snectar return -1; 103390926Snectar 103490926Snectar buf_size = 8192; 103590926Snectar for (;;) { 103690926Snectar buf = calloc(1, buf_size); 103790926Snectar if (buf == NULL) { 103890926Snectar ret = ENOMEM; 103990926Snectar goto error_out; 104090926Snectar } 1041178825Sdfr#ifndef __hpux 1042233294Sstas ifconf.lifc_family = af; 104390926Snectar ifconf.lifc_flags = 0; 1044178825Sdfr#endif 104590926Snectar ifconf.lifc_len = buf_size; 104690926Snectar ifconf.lifc_buf = buf; 104790926Snectar 104890926Snectar /* 104990926Snectar * Solaris returns EINVAL when the buffer is too small. 105090926Snectar */ 105190926Snectar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 105290926Snectar ret = errno; 105390926Snectar goto error_out; 105490926Snectar } 105590926Snectar /* 105690926Snectar * Can the difference between a full and a overfull buf 105790926Snectar * be determined? 105890926Snectar */ 105990926Snectar 106090926Snectar if (ifconf.lifc_len < buf_size) 106190926Snectar break; 106290926Snectar free (buf); 106390926Snectar buf_size *= 2; 106490926Snectar } 106590926Snectar 106690926Snectar for (p = ifconf.lifc_buf; 106790926Snectar p < ifconf.lifc_buf + ifconf.lifc_len; 106890926Snectar p += sz) { 106990926Snectar struct lifreq ifreq; 107090926Snectar struct sockaddr_storage *sa; 107190926Snectar size_t salen; 107290926Snectar 107390926Snectar ifr = (struct lifreq *)p; 107490926Snectar sa = &ifr->lifr_addr; 107590926Snectar 107690926Snectar sz = ifreq_sz; 107790926Snectar salen = sizeof(struct sockaddr_storage); 107890926Snectar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 107990926Snectar salen = sa->sa_len; 108090926Snectar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 108190926Snectar#endif 108290926Snectar#ifdef SA_LEN 108390926Snectar salen = SA_LEN(sa); 108490926Snectar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 108590926Snectar#endif 108690926Snectar memset (&ifreq, 0, sizeof(ifreq)); 108790926Snectar memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name)); 108890926Snectar 108990926Snectar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 109090926Snectar ret = errno; 109190926Snectar goto error_out; 109290926Snectar } 109390926Snectar 109490926Snectar *end = malloc(sizeof(**end)); 1095178825Sdfr if (*end == NULL) { 1096178825Sdfr ret = ENOMEM; 1097178825Sdfr goto error_out; 1098178825Sdfr } 109990926Snectar 110090926Snectar (*end)->ifa_next = NULL; 110190926Snectar (*end)->ifa_name = strdup(ifr->lifr_name); 1102178825Sdfr if ((*end)->ifa_name == NULL) { 1103178825Sdfr ret = ENOMEM; 1104178825Sdfr goto error_out; 1105178825Sdfr } 110690926Snectar (*end)->ifa_flags = ifreq.lifr_flags; 110790926Snectar (*end)->ifa_addr = malloc(salen); 1108178825Sdfr if ((*end)->ifa_addr == NULL) { 1109178825Sdfr ret = ENOMEM; 1110178825Sdfr goto error_out; 1111178825Sdfr } 111290926Snectar memcpy((*end)->ifa_addr, sa, salen); 111390926Snectar (*end)->ifa_netmask = NULL; 111490926Snectar 111590926Snectar#if 0 111690926Snectar /* fix these when we actually need them */ 111790926Snectar if(ifreq.ifr_flags & IFF_BROADCAST) { 111890926Snectar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 1119178825Sdfr if ((*end)->ifa_broadaddr == NULL) { 1120178825Sdfr ret = ENOMEM; 1121178825Sdfr goto error_out; 1122178825Sdfr } 1123233294Sstas memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 112490926Snectar sizeof(ifr->ifr_broadaddr)); 112590926Snectar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 112690926Snectar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 1127178825Sdfr if ((*end)->ifa_dstaddr == NULL) { 1128178825Sdfr ret = ENOMEM; 1129178825Sdfr goto error_out; 1130178825Sdfr } 1131233294Sstas memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 113290926Snectar sizeof(ifr->ifr_dstaddr)); 113390926Snectar } else 113490926Snectar (*end)->ifa_dstaddr = NULL; 113590926Snectar#else 113690926Snectar (*end)->ifa_dstaddr = NULL; 113790926Snectar#endif 113890926Snectar 113990926Snectar (*end)->ifa_data = NULL; 114090926Snectar 114190926Snectar end = &(*end)->ifa_next; 1142233294Sstas 114390926Snectar } 114490926Snectar *ifap = start; 114590926Snectar close(fd); 114690926Snectar free(buf); 114790926Snectar return 0; 114890926Snectar error_out: 1149178825Sdfr rk_freeifaddrs(start); 115090926Snectar close(fd); 115190926Snectar free(buf); 115290926Snectar errno = ret; 115390926Snectar return -1; 115490926Snectar} 115590926Snectar#endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */ 115690926Snectar 1157233294Sstas/** 1158233294Sstas * Join two struct ifaddrs lists by appending supp to base. 1159233294Sstas * Either may be NULL. The new list head (usually base) will be 1160233294Sstas * returned. 1161233294Sstas */ 1162233294Sstasstatic struct ifaddrs * 1163233294Sstasappend_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) { 1164233294Sstas if (!base) 1165233294Sstas return supp; 1166233294Sstas 1167233294Sstas if (!supp) 1168233294Sstas return base; 1169233294Sstas 1170233294Sstas while (base->ifa_next) 1171233294Sstas base = base->ifa_next; 1172233294Sstas 1173233294Sstas base->ifa_next = supp; 1174233294Sstas 1175233294Sstas return base; 1176233294Sstas} 1177233294Sstas 1178233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 1179233294Sstasrk_getifaddrs(struct ifaddrs **ifap) 118072445Sassar{ 118172445Sassar int ret = -1; 118272445Sassar errno = ENXIO; 118372445Sassar#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) 118472445Sassar if (ret) 118572445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, 118672445Sassar sizeof(struct in6_ifreq)); 118772445Sassar#endif 118890926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 1189233294Sstas /* Do IPv6 and IPv4 queries separately then join the result. 1190233294Sstas * 1191233294Sstas * HP-UX only returns IPv6 addresses using SIOCGLIFCONF, 1192233294Sstas * SIOCGIFCONF has to be used for IPv4 addresses. The result is then 1193233294Sstas * merged. 1194233294Sstas * 1195233294Sstas * Solaris needs particular care, because a SIOCGLIFCONF lookup using 1196233294Sstas * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just 1197233294Sstas * do them separately the same as for HP-UX. See 1198233294Sstas * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73 1199233294Sstas */ 1200233294Sstas if (ret) { 1201233294Sstas int v6err, v4err; 1202233294Sstas struct ifaddrs *v6addrs, *v4addrs; 1203233294Sstas 1204233294Sstas v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS, 120590926Snectar sizeof(struct lifreq)); 1206233294Sstas v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 1207233294Sstas sizeof(struct ifreq)); 1208233294Sstas if (v6err) 1209233294Sstas v6addrs = NULL; 1210233294Sstas if (v4err) 1211233294Sstas v4addrs = NULL; 1212233294Sstas 1213233294Sstas if (v6addrs) { 1214233294Sstas if (v4addrs) 1215233294Sstas *ifap = append_ifaddrs(v6addrs, v4addrs); 1216233294Sstas else 1217233294Sstas *ifap = v6addrs; 1218233294Sstas } else if (v4addrs) { 1219233294Sstas *ifap = v4addrs; 1220233294Sstas } else { 1221233294Sstas *ifap = NULL; 1222233294Sstas } 1223233294Sstas 1224233294Sstas ret = (v6err || v4err) ? -1 : 0; 1225233294Sstas } 122690926Snectar#endif 122772445Sassar#if defined(HAVE_IPV6) && defined(SIOCGIFCONF) 122872445Sassar if (ret) 122972445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, 123072445Sassar sizeof(struct ifreq)); 123172445Sassar#endif 123272445Sassar#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) 123372445Sassar if (ret) 123472445Sassar ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 123572445Sassar sizeof(struct ifreq)); 123672445Sassar#endif 123772445Sassar return ret; 123872445Sassar} 123972445Sassar 1240233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 1241178825Sdfrrk_freeifaddrs(struct ifaddrs *ifp) 124272445Sassar{ 124372445Sassar struct ifaddrs *p, *q; 1244233294Sstas 124572445Sassar for(p = ifp; p; ) { 124672445Sassar free(p->ifa_name); 124772445Sassar if(p->ifa_addr) 124872445Sassar free(p->ifa_addr); 1249233294Sstas if(p->ifa_dstaddr) 125072445Sassar free(p->ifa_dstaddr); 1251233294Sstas if(p->ifa_netmask) 125272445Sassar free(p->ifa_netmask); 125372445Sassar if(p->ifa_data) 125472445Sassar free(p->ifa_data); 125572445Sassar q = p; 125672445Sassar p = p->ifa_next; 125772445Sassar free(q); 125872445Sassar } 125972445Sassar} 126072445Sassar 1261233294Sstas#endif /* !AF_NETLINK */ 1262233294Sstas 126372445Sassar#ifdef TEST 126472445Sassar 126572445Sassarvoid 126672445Sassarprint_addr(const char *s, struct sockaddr *sa) 126772445Sassar{ 126872445Sassar int i; 126972445Sassar printf(" %s=%d/", s, sa->sa_family); 127072445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 127172445Sassar for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) 127272445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 127372445Sassar#else 1274233294Sstas for(i = 0; i < sizeof(sa->sa_data); i++) 127572445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 127672445Sassar#endif 127772445Sassar printf("\n"); 127872445Sassar} 127972445Sassar 1280233294Sstasvoid 128172445Sassarprint_ifaddrs(struct ifaddrs *x) 128272445Sassar{ 128372445Sassar struct ifaddrs *p; 1284233294Sstas 128572445Sassar for(p = x; p; p = p->ifa_next) { 128672445Sassar printf("%s\n", p->ifa_name); 128772445Sassar printf(" flags=%x\n", p->ifa_flags); 128872445Sassar if(p->ifa_addr) 128972445Sassar print_addr("addr", p->ifa_addr); 1290233294Sstas if(p->ifa_dstaddr) 129172445Sassar print_addr("dstaddr", p->ifa_dstaddr); 1292233294Sstas if(p->ifa_netmask) 129372445Sassar print_addr("netmask", p->ifa_netmask); 129472445Sassar printf(" %p\n", p->ifa_data); 129572445Sassar } 129672445Sassar} 129772445Sassar 129872445Sassarint 129972445Sassarmain() 130072445Sassar{ 130172445Sassar struct ifaddrs *a = NULL, *b; 130272445Sassar getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); 130372445Sassar print_ifaddrs(a); 130472445Sassar printf("---\n"); 130572445Sassar getifaddrs(&b); 130672445Sassar print_ifaddrs(b); 130772445Sassar return 0; 130872445Sassar} 130972445Sassar#endif 1310