getifaddrs.c revision 103423
172445Sassar/* 2103423Snectar * Copyright (c) 2000 - 2002 Kungliga Tekniska H�gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 572445Sassar * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 972445Sassar * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 1272445Sassar * 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. 1672445Sassar * 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. 2072445Sassar * 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#ifdef HAVE_CONFIG_H 3572445Sassar#include <config.h> 36103423SnectarRCSID("$Id: getifaddrs.c,v 1.9 2002/09/05 03:36:23 assar Exp $"); 3772445Sassar#endif 3872445Sassar#include "roken.h" 3972445Sassar 4072445Sassar#ifdef __osf__ 4172445Sassar/* hate */ 4272445Sassarstruct rtentry; 4372445Sassarstruct mbuf; 4472445Sassar#endif 4572445Sassar#ifdef HAVE_NET_IF_H 4672445Sassar#include <net/if.h> 4772445Sassar#endif 4872445Sassar 4972445Sassar#ifdef HAVE_SYS_SOCKIO_H 5072445Sassar#include <sys/sockio.h> 5172445Sassar#endif /* HAVE_SYS_SOCKIO_H */ 5272445Sassar 5372445Sassar#ifdef HAVE_NETINET_IN6_VAR_H 5472445Sassar#include <netinet/in6_var.h> 5572445Sassar#endif /* HAVE_NETINET_IN6_VAR_H */ 5672445Sassar 5772445Sassar#include <ifaddrs.h> 5872445Sassar 59103423Snectar#ifdef AF_NETLINK 60103423Snectar 61103423Snectar/* 62103423Snectar * The linux - AF_NETLINK version of getifaddrs - from Usagi. 63103423Snectar * Linux does not return v6 addresses from SIOCGIFCONF. 64103423Snectar */ 65103423Snectar 66103423Snectar/* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */ 67103423Snectar 68103423Snectar/************************************************************************** 69103423Snectar * ifaddrs.c 70103423Snectar * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved. 71103423Snectar * 72103423Snectar * Redistribution and use in source and binary forms, with or without 73103423Snectar * modification, are permitted provided that the following conditions 74103423Snectar * are met: 75103423Snectar * 1. Redistributions of source code must retain the above copyright 76103423Snectar * notice, this list of conditions and the following disclaimer. 77103423Snectar * 2. Redistributions in binary form must reproduce the above copyright 78103423Snectar * notice, this list of conditions and the following disclaimer in the 79103423Snectar * documentation and/or other materials provided with the distribution. 80103423Snectar * 3. Neither the name of the author nor the names of its contributors 81103423Snectar * may be used to endorse or promote products derived from this software 82103423Snectar * without specific prior written permission. 83103423Snectar * 84103423Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 85103423Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86103423Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87103423Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 88103423Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89103423Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90103423Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91103423Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92103423Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93103423Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94103423Snectar * SUCH DAMAGE. 95103423Snectar */ 96103423Snectar 97103423Snectar#include "config.h" 98103423Snectar 99103423Snectar#include <string.h> 100103423Snectar#include <time.h> 101103423Snectar#include <malloc.h> 102103423Snectar#include <errno.h> 103103423Snectar#include <unistd.h> 104103423Snectar 105103423Snectar#include <sys/socket.h> 106103423Snectar#include <asm/types.h> 107103423Snectar#include <linux/netlink.h> 108103423Snectar#include <linux/rtnetlink.h> 109103423Snectar#include <sys/types.h> 110103423Snectar#include <sys/socket.h> 111103423Snectar#include <netpacket/packet.h> 112103423Snectar#include <net/ethernet.h> /* the L2 protocols */ 113103423Snectar#include <sys/uio.h> 114103423Snectar#include <net/if.h> 115103423Snectar#include <net/if_arp.h> 116103423Snectar#include <ifaddrs.h> 117103423Snectar#include <netinet/in.h> 118103423Snectar 119103423Snectar#define __set_errno(e) (errno = (e)) 120103423Snectar#define __close(fd) (close(fd)) 121103423Snectar#undef ifa_broadaddr 122103423Snectar#define ifa_broadaddr ifa_dstaddr 123103423Snectar#define IFA_NETMASK 124103423Snectar 125103423Snectar/* ====================================================================== */ 126103423Snectarstruct nlmsg_list{ 127103423Snectar struct nlmsg_list *nlm_next; 128103423Snectar struct nlmsghdr *nlh; 129103423Snectar int size; 130103423Snectar time_t seq; 131103423Snectar}; 132103423Snectar 133103423Snectarstruct rtmaddr_ifamap { 134103423Snectar void *address; 135103423Snectar void *local; 136103423Snectar#ifdef IFA_NETMASK 137103423Snectar void *netmask; 138103423Snectar#endif 139103423Snectar void *broadcast; 140103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 141103423Snectar void *anycast; 142103423Snectar#endif 143103423Snectar int address_len; 144103423Snectar int local_len; 145103423Snectar#ifdef IFA_NETMASK 146103423Snectar int netmask_len; 147103423Snectar#endif 148103423Snectar int broadcast_len; 149103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 150103423Snectar int anycast_len; 151103423Snectar#endif 152103423Snectar}; 153103423Snectar 154103423Snectar/* ====================================================================== */ 155103423Snectarstatic size_t 156103423Snectarifa_sa_len(sa_family_t family, int len) 157103423Snectar{ 158103423Snectar size_t size; 159103423Snectar switch(family){ 160103423Snectar case AF_INET: 161103423Snectar size = sizeof(struct sockaddr_in); 162103423Snectar break; 163103423Snectar case AF_INET6: 164103423Snectar size = sizeof(struct sockaddr_in6); 165103423Snectar break; 166103423Snectar case AF_PACKET: 167103423Snectar size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len; 168103423Snectar if (size < sizeof(struct sockaddr_ll)) 169103423Snectar size = sizeof(struct sockaddr_ll); 170103423Snectar break; 171103423Snectar default: 172103423Snectar size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len; 173103423Snectar if (size < sizeof(struct sockaddr)) 174103423Snectar size = sizeof(struct sockaddr); 175103423Snectar } 176103423Snectar return size; 177103423Snectar} 178103423Snectar 179103423Snectarstatic void 180103423Snectarifa_make_sockaddr(sa_family_t family, 181103423Snectar struct sockaddr *sa, 182103423Snectar void *p, size_t len, 183103423Snectar uint32_t scope, uint32_t scopeid) 184103423Snectar{ 185103423Snectar if (sa == NULL) return; 186103423Snectar switch(family){ 187103423Snectar case AF_INET: 188103423Snectar memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len); 189103423Snectar break; 190103423Snectar case AF_INET6: 191103423Snectar memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len); 192103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 193103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 194103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 195103423Snectar } 196103423Snectar break; 197103423Snectar case AF_PACKET: 198103423Snectar memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len); 199103423Snectar ((struct sockaddr_ll*)sa)->sll_halen = len; 200103423Snectar break; 201103423Snectar default: 202103423Snectar memcpy(sa->sa_data, p, len); /*XXX*/ 203103423Snectar break; 204103423Snectar } 205103423Snectar sa->sa_family = family; 206103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 207103423Snectar sa->sa_len = ifa_sa_len(family, len); 208103423Snectar#endif 209103423Snectar} 210103423Snectar 211103423Snectar#ifndef IFA_NETMASK 212103423Snectarstatic struct sockaddr * 213103423Snectarifa_make_sockaddr_mask(sa_family_t family, 214103423Snectar struct sockaddr *sa, 215103423Snectar uint32_t prefixlen) 216103423Snectar{ 217103423Snectar int i; 218103423Snectar char *p = NULL, c; 219103423Snectar uint32_t max_prefixlen = 0; 220103423Snectar 221103423Snectar if (sa == NULL) return NULL; 222103423Snectar switch(family){ 223103423Snectar case AF_INET: 224103423Snectar memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr)); 225103423Snectar p = (char *)&((struct sockaddr_in*)sa)->sin_addr; 226103423Snectar max_prefixlen = 32; 227103423Snectar break; 228103423Snectar case AF_INET6: 229103423Snectar memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr)); 230103423Snectar p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr; 231103423Snectar#if 0 /* XXX: fill scope-id? */ 232103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 233103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 234103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 235103423Snectar } 236103423Snectar#endif 237103423Snectar max_prefixlen = 128; 238103423Snectar break; 239103423Snectar default: 240103423Snectar return NULL; 241103423Snectar } 242103423Snectar sa->sa_family = family; 243103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 244103423Snectar sa->sa_len = ifa_sa_len(family, len); 245103423Snectar#endif 246103423Snectar if (p){ 247103423Snectar if (prefixlen > max_prefixlen) 248103423Snectar prefixlen = max_prefixlen; 249103423Snectar for (i=0; i<(prefixlen / 8); i++) 250103423Snectar *p++ = 0xff; 251103423Snectar c = 0xff; 252103423Snectar c <<= (8 - (prefixlen % 8)); 253103423Snectar *p = c; 254103423Snectar } 255103423Snectar return sa; 256103423Snectar} 257103423Snectar#endif 258103423Snectar 259103423Snectar/* ====================================================================== */ 260103423Snectarstatic int 261103423Snectarnl_sendreq(int sd, int request, int flags, int *seq) 262103423Snectar{ 263103423Snectar char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 264103423Snectar NLMSG_ALIGN(sizeof(struct rtgenmsg))]; 265103423Snectar struct sockaddr_nl nladdr; 266103423Snectar struct nlmsghdr *req_hdr; 267103423Snectar struct rtgenmsg *req_msg; 268103423Snectar time_t t = time(NULL); 269103423Snectar 270103423Snectar if (seq) *seq = t; 271103423Snectar memset(&reqbuf, 0, sizeof(reqbuf)); 272103423Snectar req_hdr = (struct nlmsghdr *)reqbuf; 273103423Snectar req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr); 274103423Snectar req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg)); 275103423Snectar req_hdr->nlmsg_type = request; 276103423Snectar req_hdr->nlmsg_flags = flags | NLM_F_REQUEST; 277103423Snectar req_hdr->nlmsg_pid = 0; 278103423Snectar req_hdr->nlmsg_seq = t; 279103423Snectar req_msg->rtgen_family = AF_UNSPEC; 280103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 281103423Snectar nladdr.nl_family = AF_NETLINK; 282103423Snectar return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0, 283103423Snectar (struct sockaddr *)&nladdr, sizeof(nladdr))); 284103423Snectar} 285103423Snectar 286103423Snectarstatic int 287103423Snectarnl_recvmsg(int sd, int request, int seq, 288103423Snectar void *buf, size_t buflen, 289103423Snectar int *flags) 290103423Snectar{ 291103423Snectar struct msghdr msg; 292103423Snectar struct iovec iov = { buf, buflen }; 293103423Snectar struct sockaddr_nl nladdr; 294103423Snectar int read_len; 295103423Snectar 296103423Snectar for (;;){ 297103423Snectar msg.msg_name = (void *)&nladdr; 298103423Snectar msg.msg_namelen = sizeof(nladdr); 299103423Snectar msg.msg_iov = &iov; 300103423Snectar msg.msg_iovlen = 1; 301103423Snectar msg.msg_control = NULL; 302103423Snectar msg.msg_controllen = 0; 303103423Snectar msg.msg_flags = 0; 304103423Snectar read_len = recvmsg(sd, &msg, 0); 305103423Snectar if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC)) 306103423Snectar continue; 307103423Snectar if (flags) *flags = msg.msg_flags; 308103423Snectar break; 309103423Snectar } 310103423Snectar return read_len; 311103423Snectar} 312103423Snectar 313103423Snectarstatic int 314103423Snectarnl_getmsg(int sd, int request, int seq, 315103423Snectar struct nlmsghdr **nlhp, 316103423Snectar int *done) 317103423Snectar{ 318103423Snectar struct nlmsghdr *nh; 319103423Snectar size_t bufsize = 65536, lastbufsize = 0; 320103423Snectar void *buff = NULL; 321103423Snectar int result = 0, read_size; 322103423Snectar int msg_flags; 323103423Snectar pid_t pid = getpid(); 324103423Snectar for (;;){ 325103423Snectar void *newbuff = realloc(buff, bufsize); 326103423Snectar if (newbuff == NULL || bufsize < lastbufsize) { 327103423Snectar result = -1; 328103423Snectar break; 329103423Snectar } 330103423Snectar buff = newbuff; 331103423Snectar result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags); 332103423Snectar if (read_size < 0 || (msg_flags & MSG_TRUNC)){ 333103423Snectar lastbufsize = bufsize; 334103423Snectar bufsize *= 2; 335103423Snectar continue; 336103423Snectar } 337103423Snectar if (read_size == 0) break; 338103423Snectar nh = (struct nlmsghdr *)buff; 339103423Snectar for (nh = (struct nlmsghdr *)buff; 340103423Snectar NLMSG_OK(nh, read_size); 341103423Snectar nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){ 342103423Snectar if (nh->nlmsg_pid != pid || 343103423Snectar nh->nlmsg_seq != seq) 344103423Snectar continue; 345103423Snectar if (nh->nlmsg_type == NLMSG_DONE){ 346103423Snectar (*done)++; 347103423Snectar break; /* ok */ 348103423Snectar } 349103423Snectar if (nh->nlmsg_type == NLMSG_ERROR){ 350103423Snectar struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh); 351103423Snectar result = -1; 352103423Snectar if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 353103423Snectar __set_errno(EIO); 354103423Snectar else 355103423Snectar __set_errno(-nlerr->error); 356103423Snectar break; 357103423Snectar } 358103423Snectar } 359103423Snectar break; 360103423Snectar } 361103423Snectar if (result < 0) 362103423Snectar if (buff){ 363103423Snectar int saved_errno = errno; 364103423Snectar free(buff); 365103423Snectar __set_errno(saved_errno); 366103423Snectar } 367103423Snectar *nlhp = (struct nlmsghdr *)buff; 368103423Snectar return result; 369103423Snectar} 370103423Snectar 37172445Sassarstatic int 372103423Snectarnl_getlist(int sd, int seq, 373103423Snectar int request, 374103423Snectar struct nlmsg_list **nlm_list, 375103423Snectar struct nlmsg_list **nlm_end) 376103423Snectar{ 377103423Snectar struct nlmsghdr *nlh = NULL; 378103423Snectar int status; 379103423Snectar int done = 0; 380103423Snectar 381103423Snectar status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq); 382103423Snectar if (status < 0) 383103423Snectar return status; 384103423Snectar if (seq == 0) 385103423Snectar seq = (int)time(NULL); 386103423Snectar while(!done){ 387103423Snectar status = nl_getmsg(sd, request, seq, &nlh, &done); 388103423Snectar if (status < 0) 389103423Snectar return status; 390103423Snectar if (nlh){ 391103423Snectar struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list)); 392103423Snectar if (nlm_next == NULL){ 393103423Snectar int saved_errno = errno; 394103423Snectar free(nlh); 395103423Snectar __set_errno(saved_errno); 396103423Snectar status = -1; 397103423Snectar } else { 398103423Snectar nlm_next->nlm_next = NULL; 399103423Snectar nlm_next->nlh = (struct nlmsghdr *)nlh; 400103423Snectar nlm_next->size = status; 401103423Snectar nlm_next->seq = seq; 402103423Snectar if (*nlm_list == NULL){ 403103423Snectar *nlm_list = nlm_next; 404103423Snectar *nlm_end = nlm_next; 405103423Snectar } else { 406103423Snectar (*nlm_end)->nlm_next = nlm_next; 407103423Snectar *nlm_end = nlm_next; 408103423Snectar } 409103423Snectar } 410103423Snectar } 411103423Snectar } 412103423Snectar return status >= 0 ? seq : status; 413103423Snectar} 414103423Snectar 415103423Snectar/* ---------------------------------------------------------------------- */ 416103423Snectarstatic void 417103423Snectarfree_nlmsglist(struct nlmsg_list *nlm0) 418103423Snectar{ 419103423Snectar struct nlmsg_list *nlm; 420103423Snectar int saved_errno; 421103423Snectar if (!nlm0) 422103423Snectar return; 423103423Snectar saved_errno = errno; 424103423Snectar for (nlm=nlm0; nlm; nlm=nlm->nlm_next){ 425103423Snectar if (nlm->nlh) 426103423Snectar free(nlm->nlh); 427103423Snectar } 428103423Snectar free(nlm0); 429103423Snectar __set_errno(saved_errno); 430103423Snectar} 431103423Snectar 432103423Snectarstatic void 433103423Snectarfree_data(void *data, void *ifdata) 434103423Snectar{ 435103423Snectar int saved_errno = errno; 436103423Snectar if (data != NULL) free(data); 437103423Snectar if (ifdata != NULL) free(ifdata); 438103423Snectar __set_errno(saved_errno); 439103423Snectar} 440103423Snectar 441103423Snectar/* ---------------------------------------------------------------------- */ 442103423Snectarstatic void 443103423Snectarnl_close(int sd) 444103423Snectar{ 445103423Snectar int saved_errno = errno; 446103423Snectar if (sd >= 0) __close(sd); 447103423Snectar __set_errno(saved_errno); 448103423Snectar} 449103423Snectar 450103423Snectar/* ---------------------------------------------------------------------- */ 451103423Snectarstatic int 452103423Snectarnl_open(void) 453103423Snectar{ 454103423Snectar struct sockaddr_nl nladdr; 455103423Snectar int sd; 456103423Snectar 457103423Snectar sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 458103423Snectar if (sd < 0) return -1; 459103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 460103423Snectar nladdr.nl_family = AF_NETLINK; 461103423Snectar if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){ 462103423Snectar nl_close(sd); 463103423Snectar return -1; 464103423Snectar } 465103423Snectar return sd; 466103423Snectar} 467103423Snectar 468103423Snectar/* ====================================================================== */ 469103423Snectarint getifaddrs(struct ifaddrs **ifap) 470103423Snectar{ 471103423Snectar int sd; 472103423Snectar struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; 473103423Snectar /* - - - - - - - - - - - - - - - */ 474103423Snectar int icnt; 475103423Snectar size_t dlen, xlen, nlen; 476103423Snectar uint32_t max_ifindex = 0; 477103423Snectar 478103423Snectar pid_t pid = getpid(); 479103423Snectar int seq; 480103423Snectar int result; 481103423Snectar int build ; /* 0 or 1 */ 482103423Snectar 483103423Snectar/* ---------------------------------- */ 484103423Snectar /* initialize */ 485103423Snectar icnt = dlen = xlen = nlen = 0; 486103423Snectar nlmsg_list = nlmsg_end = NULL; 487103423Snectar 488103423Snectar if (ifap) 489103423Snectar *ifap = NULL; 490103423Snectar 491103423Snectar/* ---------------------------------- */ 492103423Snectar /* open socket and bind */ 493103423Snectar sd = nl_open(); 494103423Snectar if (sd < 0) 495103423Snectar return -1; 496103423Snectar 497103423Snectar/* ---------------------------------- */ 498103423Snectar /* gather info */ 499103423Snectar if ((seq = nl_getlist(sd, 0, RTM_GETLINK, 500103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 501103423Snectar free_nlmsglist(nlmsg_list); 502103423Snectar nl_close(sd); 503103423Snectar return -1; 504103423Snectar } 505103423Snectar if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, 506103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 507103423Snectar free_nlmsglist(nlmsg_list); 508103423Snectar nl_close(sd); 509103423Snectar return -1; 510103423Snectar } 511103423Snectar 512103423Snectar/* ---------------------------------- */ 513103423Snectar /* Estimate size of result buffer and fill it */ 514103423Snectar for (build=0; build<=1; build++){ 515103423Snectar struct ifaddrs *ifl = NULL, *ifa = NULL; 516103423Snectar struct nlmsghdr *nlh, *nlh0; 517103423Snectar char *data = NULL, *xdata = NULL; 518103423Snectar void *ifdata = NULL; 519103423Snectar char *ifname = NULL, **iflist = NULL; 520103423Snectar uint16_t *ifflist = NULL; 521103423Snectar struct rtmaddr_ifamap ifamap; 522103423Snectar 523103423Snectar if (build){ 524103423Snectar data = calloc(1, 525103423Snectar NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) 526103423Snectar + dlen + xlen + nlen); 527103423Snectar ifa = (struct ifaddrs *)data; 528103423Snectar ifdata = calloc(1, 529103423Snectar NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) 530103423Snectar + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); 531103423Snectar if (ifap != NULL) 532103423Snectar *ifap = (ifdata != NULL) ? ifa : NULL; 533103423Snectar else{ 534103423Snectar free_data(data, ifdata); 535103423Snectar result = 0; 536103423Snectar break; 537103423Snectar } 538103423Snectar if (data == NULL || ifdata == NULL){ 539103423Snectar free_data(data, ifdata); 540103423Snectar result = -1; 541103423Snectar break; 542103423Snectar } 543103423Snectar ifl = NULL; 544103423Snectar data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; 545103423Snectar xdata = data + dlen; 546103423Snectar ifname = xdata + xlen; 547103423Snectar iflist = ifdata; 548103423Snectar ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))); 549103423Snectar } 550103423Snectar 551103423Snectar for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ 552103423Snectar int nlmlen = nlm->size; 553103423Snectar if (!(nlh0 = nlm->nlh)) 554103423Snectar continue; 555103423Snectar for (nlh = nlh0; 556103423Snectar NLMSG_OK(nlh, nlmlen); 557103423Snectar nlh=NLMSG_NEXT(nlh,nlmlen)){ 558103423Snectar struct ifinfomsg *ifim = NULL; 559103423Snectar struct ifaddrmsg *ifam = NULL; 560103423Snectar struct rtattr *rta; 561103423Snectar 562103423Snectar size_t nlm_struct_size = 0; 563103423Snectar sa_family_t nlm_family = 0; 564103423Snectar uint32_t nlm_scope = 0, nlm_index = 0; 565103423Snectar size_t sockaddr_size = 0; 566103423Snectar uint32_t nlm_prefixlen = 0; 567103423Snectar size_t rtasize; 568103423Snectar 569103423Snectar memset(&ifamap, 0, sizeof(ifamap)); 570103423Snectar 571103423Snectar /* check if the message is what we want */ 572103423Snectar if (nlh->nlmsg_pid != pid || 573103423Snectar nlh->nlmsg_seq != nlm->seq) 574103423Snectar continue; 575103423Snectar if (nlh->nlmsg_type == NLMSG_DONE){ 576103423Snectar break; /* ok */ 577103423Snectar } 578103423Snectar switch (nlh->nlmsg_type){ 579103423Snectar case RTM_NEWLINK: 580103423Snectar ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); 581103423Snectar nlm_struct_size = sizeof(*ifim); 582103423Snectar nlm_family = ifim->ifi_family; 583103423Snectar nlm_scope = 0; 584103423Snectar nlm_index = ifim->ifi_index; 585103423Snectar nlm_prefixlen = 0; 586103423Snectar if (build) 587103423Snectar ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; 588103423Snectar break; 589103423Snectar case RTM_NEWADDR: 590103423Snectar ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); 591103423Snectar nlm_struct_size = sizeof(*ifam); 592103423Snectar nlm_family = ifam->ifa_family; 593103423Snectar nlm_scope = ifam->ifa_scope; 594103423Snectar nlm_index = ifam->ifa_index; 595103423Snectar nlm_prefixlen = ifam->ifa_prefixlen; 596103423Snectar if (build) 597103423Snectar ifa->ifa_flags = ifflist[nlm_index]; 598103423Snectar break; 599103423Snectar default: 600103423Snectar continue; 601103423Snectar } 602103423Snectar 603103423Snectar if (!build){ 604103423Snectar if (max_ifindex < nlm_index) 605103423Snectar max_ifindex = nlm_index; 606103423Snectar } else { 607103423Snectar if (ifl != NULL) 608103423Snectar ifl->ifa_next = ifa; 609103423Snectar } 610103423Snectar 611103423Snectar rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); 612103423Snectar for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); 613103423Snectar RTA_OK(rta, rtasize); 614103423Snectar rta = RTA_NEXT(rta, rtasize)){ 615103423Snectar struct sockaddr **sap = NULL; 616103423Snectar void *rtadata = RTA_DATA(rta); 617103423Snectar size_t rtapayload = RTA_PAYLOAD(rta); 618103423Snectar socklen_t sa_len; 619103423Snectar 620103423Snectar switch(nlh->nlmsg_type){ 621103423Snectar case RTM_NEWLINK: 622103423Snectar switch(rta->rta_type){ 623103423Snectar case IFLA_ADDRESS: 624103423Snectar case IFLA_BROADCAST: 625103423Snectar if (build){ 626103423Snectar sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; 627103423Snectar *sap = (struct sockaddr *)data; 628103423Snectar } 629103423Snectar sa_len = ifa_sa_len(AF_PACKET, rtapayload); 630103423Snectar if (rta->rta_type == IFLA_ADDRESS) 631103423Snectar sockaddr_size = NLMSG_ALIGN(sa_len); 632103423Snectar if (!build){ 633103423Snectar dlen += NLMSG_ALIGN(sa_len); 634103423Snectar } else { 635103423Snectar memset(*sap, 0, sa_len); 636103423Snectar ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); 637103423Snectar ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; 638103423Snectar ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; 639103423Snectar data += NLMSG_ALIGN(sa_len); 640103423Snectar } 641103423Snectar break; 642103423Snectar case IFLA_IFNAME:/* Name of Interface */ 643103423Snectar if (!build) 644103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 645103423Snectar else{ 646103423Snectar ifa->ifa_name = ifname; 647103423Snectar if (iflist[nlm_index] == NULL) 648103423Snectar iflist[nlm_index] = ifa->ifa_name; 649103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 650103423Snectar ifa->ifa_name[rtapayload] = '\0'; 651103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 652103423Snectar } 653103423Snectar break; 654103423Snectar case IFLA_STATS:/* Statistics of Interface */ 655103423Snectar if (!build) 656103423Snectar xlen += NLMSG_ALIGN(rtapayload); 657103423Snectar else{ 658103423Snectar ifa->ifa_data = xdata; 659103423Snectar memcpy(ifa->ifa_data, rtadata, rtapayload); 660103423Snectar xdata += NLMSG_ALIGN(rtapayload); 661103423Snectar } 662103423Snectar break; 663103423Snectar case IFLA_UNSPEC: 664103423Snectar break; 665103423Snectar case IFLA_MTU: 666103423Snectar break; 667103423Snectar case IFLA_LINK: 668103423Snectar break; 669103423Snectar case IFLA_QDISC: 670103423Snectar break; 671103423Snectar default: 672103423Snectar } 673103423Snectar break; 674103423Snectar case RTM_NEWADDR: 675103423Snectar if (nlm_family == AF_PACKET) break; 676103423Snectar switch(rta->rta_type){ 677103423Snectar case IFA_ADDRESS: 678103423Snectar ifamap.address = rtadata; 679103423Snectar ifamap.address_len = rtapayload; 680103423Snectar break; 681103423Snectar case IFA_LOCAL: 682103423Snectar ifamap.local = rtadata; 683103423Snectar ifamap.local_len = rtapayload; 684103423Snectar break; 685103423Snectar case IFA_BROADCAST: 686103423Snectar ifamap.broadcast = rtadata; 687103423Snectar ifamap.broadcast_len = rtapayload; 688103423Snectar break; 689103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 690103423Snectar case IFA_ANYCAST: 691103423Snectar ifamap.anycast = rtadata; 692103423Snectar ifamap.anycast_len = rtapayload; 693103423Snectar break; 694103423Snectar#endif 695103423Snectar case IFA_LABEL: 696103423Snectar if (!build) 697103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 698103423Snectar else{ 699103423Snectar ifa->ifa_name = ifname; 700103423Snectar if (iflist[nlm_index] == NULL) 701103423Snectar iflist[nlm_index] = ifname; 702103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 703103423Snectar ifa->ifa_name[rtapayload] = '\0'; 704103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 705103423Snectar } 706103423Snectar break; 707103423Snectar case IFA_UNSPEC: 708103423Snectar break; 709103423Snectar case IFA_CACHEINFO: 710103423Snectar break; 711103423Snectar default: 712103423Snectar } 713103423Snectar } 714103423Snectar } 715103423Snectar if (nlh->nlmsg_type == RTM_NEWADDR && 716103423Snectar nlm_family != AF_PACKET) { 717103423Snectar if (!ifamap.local) { 718103423Snectar ifamap.local = ifamap.address; 719103423Snectar ifamap.local_len = ifamap.address_len; 720103423Snectar } 721103423Snectar if (!ifamap.address) { 722103423Snectar ifamap.address = ifamap.local; 723103423Snectar ifamap.address_len = ifamap.local_len; 724103423Snectar } 725103423Snectar if (ifamap.address_len != ifamap.local_len || 726103423Snectar (ifamap.address != NULL && 727103423Snectar memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { 728103423Snectar /* p2p; address is peer and local is ours */ 729103423Snectar ifamap.broadcast = ifamap.address; 730103423Snectar ifamap.broadcast_len = ifamap.address_len; 731103423Snectar ifamap.address = ifamap.local; 732103423Snectar ifamap.address_len = ifamap.local_len; 733103423Snectar } 734103423Snectar if (ifamap.address) { 735103423Snectar#ifndef IFA_NETMASK 736103423Snectar sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 737103423Snectar#endif 738103423Snectar if (!build) 739103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 740103423Snectar else { 741103423Snectar ifa->ifa_addr = (struct sockaddr *)data; 742103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, 743103423Snectar nlm_scope, nlm_index); 744103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); 745103423Snectar } 746103423Snectar } 747103423Snectar#ifdef IFA_NETMASK 748103423Snectar if (ifamap.netmask) { 749103423Snectar if (!build) 750103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); 751103423Snectar else { 752103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 753103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, 754103423Snectar nlm_scope, nlm_index); 755103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); 756103423Snectar } 757103423Snectar } 758103423Snectar#endif 759103423Snectar if (ifamap.broadcast) { 760103423Snectar if (!build) 761103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); 762103423Snectar else { 763103423Snectar ifa->ifa_broadaddr = (struct sockaddr *)data; 764103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, 765103423Snectar nlm_scope, nlm_index); 766103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); 767103423Snectar } 768103423Snectar } 769103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 770103423Snectar if (ifamap.anycast) { 771103423Snectar if (!build) 772103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); 773103423Snectar else { 774103423Snectar ifa->ifa_anycast = (struct sockaddr *)data; 775103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, 776103423Snectar nlm_scope, nlm_index); 777103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); 778103423Snectar } 779103423Snectar } 780103423Snectar#endif 781103423Snectar } 782103423Snectar if (!build){ 783103423Snectar#ifndef IFA_NETMASK 784103423Snectar dlen += sockaddr_size; 785103423Snectar#endif 786103423Snectar icnt++; 787103423Snectar } else { 788103423Snectar if (ifa->ifa_name == NULL) 789103423Snectar ifa->ifa_name = iflist[nlm_index]; 790103423Snectar#ifndef IFA_NETMASK 791103423Snectar if (ifa->ifa_addr && 792103423Snectar ifa->ifa_addr->sa_family != AF_UNSPEC && 793103423Snectar ifa->ifa_addr->sa_family != AF_PACKET){ 794103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 795103423Snectar ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); 796103423Snectar } 797103423Snectar data += sockaddr_size; 798103423Snectar#endif 799103423Snectar ifl = ifa++; 800103423Snectar } 801103423Snectar } 802103423Snectar } 803103423Snectar if (!build){ 804103423Snectar if (icnt == 0 && (dlen + nlen + xlen == 0)){ 805103423Snectar if (ifap != NULL) 806103423Snectar *ifap = NULL; 807103423Snectar break; /* cannot found any addresses */ 808103423Snectar } 809103423Snectar } 810103423Snectar else 811103423Snectar free_data(NULL, ifdata); 812103423Snectar } 813103423Snectar 814103423Snectar/* ---------------------------------- */ 815103423Snectar /* Finalize */ 816103423Snectar free_nlmsglist(nlmsg_list); 817103423Snectar nl_close(sd); 818103423Snectar return 0; 819103423Snectar} 820103423Snectar 821103423Snectar/* ---------------------------------------------------------------------- */ 822103423Snectarvoid 823103423Snectarfreeifaddrs(struct ifaddrs *ifa) 824103423Snectar{ 825103423Snectar free(ifa); 826103423Snectar} 827103423Snectar 828103423Snectar 829103423Snectar#else /* !AF_NETLINK */ 830103423Snectar 831103423Snectar/* 832103423Snectar * The generic SIOCGIFCONF version. 833103423Snectar */ 834103423Snectar 835103423Snectarstatic int 83672445Sassargetifaddrs2(struct ifaddrs **ifap, 83772445Sassar int af, int siocgifconf, int siocgifflags, 83872445Sassar size_t ifreq_sz) 83972445Sassar{ 84072445Sassar int ret; 84172445Sassar int fd; 84272445Sassar size_t buf_size; 84372445Sassar char *buf; 84472445Sassar struct ifconf ifconf; 84572445Sassar char *p; 84672445Sassar size_t sz; 84772445Sassar struct sockaddr sa_zero; 84872445Sassar struct ifreq *ifr; 84990926Snectar struct ifaddrs *start = NULL, **end = &start; 85072445Sassar 85172445Sassar buf = NULL; 85272445Sassar 85372445Sassar memset (&sa_zero, 0, sizeof(sa_zero)); 85472445Sassar fd = socket(af, SOCK_DGRAM, 0); 85572445Sassar if (fd < 0) 85672445Sassar return -1; 85772445Sassar 85872445Sassar buf_size = 8192; 85972445Sassar for (;;) { 86072445Sassar buf = calloc(1, buf_size); 86172445Sassar if (buf == NULL) { 86272445Sassar ret = ENOMEM; 86372445Sassar goto error_out; 86472445Sassar } 86572445Sassar ifconf.ifc_len = buf_size; 86672445Sassar ifconf.ifc_buf = buf; 86772445Sassar 86872445Sassar /* 86972445Sassar * Solaris returns EINVAL when the buffer is too small. 87072445Sassar */ 87172445Sassar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 87272445Sassar ret = errno; 87372445Sassar goto error_out; 87472445Sassar } 87572445Sassar /* 87672445Sassar * Can the difference between a full and a overfull buf 87772445Sassar * be determined? 87872445Sassar */ 87972445Sassar 88072445Sassar if (ifconf.ifc_len < buf_size) 88172445Sassar break; 88272445Sassar free (buf); 88372445Sassar buf_size *= 2; 88472445Sassar } 88572445Sassar 88672445Sassar for (p = ifconf.ifc_buf; 88772445Sassar p < ifconf.ifc_buf + ifconf.ifc_len; 88872445Sassar p += sz) { 88972445Sassar struct ifreq ifreq; 89072445Sassar struct sockaddr *sa; 89172445Sassar size_t salen; 89272445Sassar 89372445Sassar ifr = (struct ifreq *)p; 89472445Sassar sa = &ifr->ifr_addr; 89572445Sassar 89672445Sassar sz = ifreq_sz; 89772445Sassar salen = sizeof(struct sockaddr); 89872445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 89972445Sassar salen = sa->sa_len; 90072445Sassar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 90172445Sassar#endif 90272445Sassar#ifdef SA_LEN 90372445Sassar salen = SA_LEN(sa); 90472445Sassar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 90572445Sassar#endif 90672445Sassar memset (&ifreq, 0, sizeof(ifreq)); 90772445Sassar memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); 90872445Sassar 90972445Sassar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 91072445Sassar ret = errno; 91172445Sassar goto error_out; 91272445Sassar } 91372445Sassar 91472445Sassar *end = malloc(sizeof(**end)); 91590926Snectar if (*end == NULL) { 91690926Snectar ret = ENOMEM; 91790926Snectar goto error_out; 91890926Snectar } 91972445Sassar 92072445Sassar (*end)->ifa_next = NULL; 92172445Sassar (*end)->ifa_name = strdup(ifr->ifr_name); 92272445Sassar (*end)->ifa_flags = ifreq.ifr_flags; 92372445Sassar (*end)->ifa_addr = malloc(salen); 92472445Sassar memcpy((*end)->ifa_addr, sa, salen); 92572445Sassar (*end)->ifa_netmask = NULL; 92672445Sassar 92772445Sassar#if 0 92872445Sassar /* fix these when we actually need them */ 92972445Sassar if(ifreq.ifr_flags & IFF_BROADCAST) { 93072445Sassar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 93172445Sassar memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 93272445Sassar sizeof(ifr->ifr_broadaddr)); 93372445Sassar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 93472445Sassar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 93572445Sassar memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 93672445Sassar sizeof(ifr->ifr_dstaddr)); 93772445Sassar } else 93872445Sassar (*end)->ifa_dstaddr = NULL; 93972445Sassar#else 94072445Sassar (*end)->ifa_dstaddr = NULL; 94172445Sassar#endif 94272445Sassar 94372445Sassar (*end)->ifa_data = NULL; 94472445Sassar 94572445Sassar end = &(*end)->ifa_next; 94672445Sassar 94772445Sassar } 94872445Sassar *ifap = start; 94978527Sassar close(fd); 95072445Sassar free(buf); 95172445Sassar return 0; 95272445Sassar error_out: 95390926Snectar freeifaddrs(start); 95478527Sassar close(fd); 95572445Sassar free(buf); 95672445Sassar errno = ret; 95772445Sassar return -1; 95872445Sassar} 95972445Sassar 96090926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 96190926Snectarstatic int 96290926Snectargetlifaddrs2(struct ifaddrs **ifap, 96390926Snectar int af, int siocgifconf, int siocgifflags, 96490926Snectar size_t ifreq_sz) 96590926Snectar{ 96690926Snectar int ret; 96790926Snectar int fd; 96890926Snectar size_t buf_size; 96990926Snectar char *buf; 97090926Snectar struct lifconf ifconf; 97190926Snectar char *p; 97290926Snectar size_t sz; 97390926Snectar struct sockaddr sa_zero; 97490926Snectar struct lifreq *ifr; 97590926Snectar struct ifaddrs *start = NULL, **end = &start; 97690926Snectar 97790926Snectar buf = NULL; 97890926Snectar 97990926Snectar memset (&sa_zero, 0, sizeof(sa_zero)); 98090926Snectar fd = socket(af, SOCK_DGRAM, 0); 98190926Snectar if (fd < 0) 98290926Snectar return -1; 98390926Snectar 98490926Snectar buf_size = 8192; 98590926Snectar for (;;) { 98690926Snectar buf = calloc(1, buf_size); 98790926Snectar if (buf == NULL) { 98890926Snectar ret = ENOMEM; 98990926Snectar goto error_out; 99090926Snectar } 99190926Snectar ifconf.lifc_family = AF_UNSPEC; 99290926Snectar ifconf.lifc_flags = 0; 99390926Snectar ifconf.lifc_len = buf_size; 99490926Snectar ifconf.lifc_buf = buf; 99590926Snectar 99690926Snectar /* 99790926Snectar * Solaris returns EINVAL when the buffer is too small. 99890926Snectar */ 99990926Snectar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 100090926Snectar ret = errno; 100190926Snectar goto error_out; 100290926Snectar } 100390926Snectar /* 100490926Snectar * Can the difference between a full and a overfull buf 100590926Snectar * be determined? 100690926Snectar */ 100790926Snectar 100890926Snectar if (ifconf.lifc_len < buf_size) 100990926Snectar break; 101090926Snectar free (buf); 101190926Snectar buf_size *= 2; 101290926Snectar } 101390926Snectar 101490926Snectar for (p = ifconf.lifc_buf; 101590926Snectar p < ifconf.lifc_buf + ifconf.lifc_len; 101690926Snectar p += sz) { 101790926Snectar struct lifreq ifreq; 101890926Snectar struct sockaddr_storage *sa; 101990926Snectar size_t salen; 102090926Snectar 102190926Snectar ifr = (struct lifreq *)p; 102290926Snectar sa = &ifr->lifr_addr; 102390926Snectar 102490926Snectar sz = ifreq_sz; 102590926Snectar salen = sizeof(struct sockaddr_storage); 102690926Snectar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 102790926Snectar salen = sa->sa_len; 102890926Snectar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 102990926Snectar#endif 103090926Snectar#ifdef SA_LEN 103190926Snectar salen = SA_LEN(sa); 103290926Snectar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 103390926Snectar#endif 103490926Snectar memset (&ifreq, 0, sizeof(ifreq)); 103590926Snectar memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name)); 103690926Snectar 103790926Snectar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 103890926Snectar ret = errno; 103990926Snectar goto error_out; 104090926Snectar } 104190926Snectar 104290926Snectar *end = malloc(sizeof(**end)); 104390926Snectar 104490926Snectar (*end)->ifa_next = NULL; 104590926Snectar (*end)->ifa_name = strdup(ifr->lifr_name); 104690926Snectar (*end)->ifa_flags = ifreq.lifr_flags; 104790926Snectar (*end)->ifa_addr = malloc(salen); 104890926Snectar memcpy((*end)->ifa_addr, sa, salen); 104990926Snectar (*end)->ifa_netmask = NULL; 105090926Snectar 105190926Snectar#if 0 105290926Snectar /* fix these when we actually need them */ 105390926Snectar if(ifreq.ifr_flags & IFF_BROADCAST) { 105490926Snectar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 105590926Snectar memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 105690926Snectar sizeof(ifr->ifr_broadaddr)); 105790926Snectar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 105890926Snectar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 105990926Snectar memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 106090926Snectar sizeof(ifr->ifr_dstaddr)); 106190926Snectar } else 106290926Snectar (*end)->ifa_dstaddr = NULL; 106390926Snectar#else 106490926Snectar (*end)->ifa_dstaddr = NULL; 106590926Snectar#endif 106690926Snectar 106790926Snectar (*end)->ifa_data = NULL; 106890926Snectar 106990926Snectar end = &(*end)->ifa_next; 107090926Snectar 107190926Snectar } 107290926Snectar *ifap = start; 107390926Snectar close(fd); 107490926Snectar free(buf); 107590926Snectar return 0; 107690926Snectar error_out: 107790926Snectar freeifaddrs(start); 107890926Snectar close(fd); 107990926Snectar free(buf); 108090926Snectar errno = ret; 108190926Snectar return -1; 108290926Snectar} 108390926Snectar#endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */ 108490926Snectar 108572445Sassarint 108672445Sassargetifaddrs(struct ifaddrs **ifap) 108772445Sassar{ 108872445Sassar int ret = -1; 108972445Sassar errno = ENXIO; 109072445Sassar#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) 109172445Sassar if (ret) 109272445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, 109372445Sassar sizeof(struct in6_ifreq)); 109472445Sassar#endif 109590926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 109690926Snectar if (ret) 109790926Snectar ret = getlifaddrs2 (ifap, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS, 109890926Snectar sizeof(struct lifreq)); 109990926Snectar#endif 110072445Sassar#if defined(HAVE_IPV6) && defined(SIOCGIFCONF) 110172445Sassar if (ret) 110272445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, 110372445Sassar sizeof(struct ifreq)); 110472445Sassar#endif 110572445Sassar#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) 110672445Sassar if (ret) 110772445Sassar ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 110872445Sassar sizeof(struct ifreq)); 110972445Sassar#endif 111072445Sassar return ret; 111172445Sassar} 111272445Sassar 111372445Sassarvoid 111472445Sassarfreeifaddrs(struct ifaddrs *ifp) 111572445Sassar{ 111672445Sassar struct ifaddrs *p, *q; 111772445Sassar 111872445Sassar for(p = ifp; p; ) { 111972445Sassar free(p->ifa_name); 112072445Sassar if(p->ifa_addr) 112172445Sassar free(p->ifa_addr); 112272445Sassar if(p->ifa_dstaddr) 112372445Sassar free(p->ifa_dstaddr); 112472445Sassar if(p->ifa_netmask) 112572445Sassar free(p->ifa_netmask); 112672445Sassar if(p->ifa_data) 112772445Sassar free(p->ifa_data); 112872445Sassar q = p; 112972445Sassar p = p->ifa_next; 113072445Sassar free(q); 113172445Sassar } 113272445Sassar} 113372445Sassar 1134103423Snectar#endif /* !AF_NETLINK */ 1135103423Snectar 113672445Sassar#ifdef TEST 113772445Sassar 113872445Sassarvoid 113972445Sassarprint_addr(const char *s, struct sockaddr *sa) 114072445Sassar{ 114172445Sassar int i; 114272445Sassar printf(" %s=%d/", s, sa->sa_family); 114372445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 114472445Sassar for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) 114572445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 114672445Sassar#else 114772445Sassar for(i = 0; i < sizeof(sa->sa_data); i++) 114872445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 114972445Sassar#endif 115072445Sassar printf("\n"); 115172445Sassar} 115272445Sassar 115372445Sassarvoid 115472445Sassarprint_ifaddrs(struct ifaddrs *x) 115572445Sassar{ 115672445Sassar struct ifaddrs *p; 115772445Sassar 115872445Sassar for(p = x; p; p = p->ifa_next) { 115972445Sassar printf("%s\n", p->ifa_name); 116072445Sassar printf(" flags=%x\n", p->ifa_flags); 116172445Sassar if(p->ifa_addr) 116272445Sassar print_addr("addr", p->ifa_addr); 116372445Sassar if(p->ifa_dstaddr) 116472445Sassar print_addr("dstaddr", p->ifa_dstaddr); 116572445Sassar if(p->ifa_netmask) 116672445Sassar print_addr("netmask", p->ifa_netmask); 116772445Sassar printf(" %p\n", p->ifa_data); 116872445Sassar } 116972445Sassar} 117072445Sassar 117172445Sassarint 117272445Sassarmain() 117372445Sassar{ 117472445Sassar struct ifaddrs *a = NULL, *b; 117572445Sassar getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); 117672445Sassar print_ifaddrs(a); 117772445Sassar printf("---\n"); 117872445Sassar getifaddrs(&b); 117972445Sassar print_ifaddrs(b); 118072445Sassar return 0; 118172445Sassar} 118272445Sassar#endif 1183