/* ******************************************************************** * * ni_lifreq.c version 0.05 3-7-09 * * * * COPYRIGHT 2008-2009 Michael Robinton * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of either: * * * * a) the GNU General Public License as published by the Free * * Software Foundation; either version 2, or (at your option) any * * later version, or * * * * b) the "Artistic License" which comes with this distribution. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either * * the GNU General Public License or the Artistic License for more * * details. * * * * You should have received a copy of the Artistic License with this * * distribution, in the file named "Artistic". If not, I'll be glad * * to provide one. * * * * You should also have received a copy of the GNU General Public * * License along with this program in the file named "Copying". If not, * * write to the * * * * Free Software Foundation, Inc. * * 59 Temple Place, Suite 330 * * Boston, MA 02111-1307, USA * * * * or visit their web page on the internet at: * * * * http://www.gnu.org/copyleft/gpl.html. * * ******************************************************************** * * * DESCRIPTION Accessor functions for 'lifconf' and 'lifreq' * */ #include "localconf.h" #ifdef HAVE_STRUCT_LIFREQ #ifndef LIFC_TEMPORARY #define LIFC_TEMPORARY 0 #endif #ifndef LIFC_ALLZONES #define LIFC_ALLZONES 0 #endif static int _ni_get_ifaddrs(int fd, struct ifaddrs * thisif, struct lifreq * ifr,...) { int cmd; if (ioctl(fd,SIOCGLIFFLAGS,ifr) < 0) return -1; thisif->ifa_flags = (u_int)(ifr->lifr_flags & 0xFFFFu); if (ioctl(fd,SIOCGLIFNETMASK,ifr) != -1) { if ((thisif->ifa_netmask = ni_memdup(&(ifr->lifr_addr), SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL) return -1; } if (thisif->ifa_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) { if (thisif->ifa_flags & IFF_POINTOPOINT) cmd = SIOCGLIFDSTADDR; else cmd = SIOCGLIFBRDADDR; if (ioctl(fd,cmd,ifr) != -1) { if ((thisif->ifa_dstaddr = ni_memdup(&(ifr->lifr_addr), SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL) return -1; } } return 0; } /* nifp points to me */ static int ni_lifreq_gifaddrs(struct ifaddrs **ifap, struct ni_ifconf_flavor * nifp) { struct lifconf ifc; struct lifreq * ifr; struct ifaddrs * thisif, * lastif = NULL; struct sockaddr * sa; int fd, af, inc, ret, n; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return errno; if (nifp->getifreqs(fd,&ifc) == NULL) { close(fd); return errno; } ifr = ifc.lifc_req; for (n = 0; n < ifc.lifc_len; n += sizeof(struct lifreq)) { if ((thisif = calloc(1, sizeof(struct ifaddrs))) == NULL) { errno = ENOMEM; goto error_out; } if (lastif == NULL) /* taken care of in init statement */ *ifap = thisif; else lastif->ifa_next = thisif; if ((thisif->ifa_name = strdup(ifr->lifr_name)) == NULL) { errno = ENOMEM; goto error_out; } af = ifr->lifr_addr.ss_family; if ((thisif->ifa_addr = ni_memdup(&(ifr->lifr_addr), SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL) goto error_out; if (af == AF_INET) { fd = ni_clos_reopn_dgrm(fd,af); if (_ni_get_ifaddrs(fd,thisif,ifr) < 0) goto error_out; } /* == AF_INET */ #ifdef LOCAL_SIZEOF_SOCKADDR_IN6 else if (af == AF_INET6) { fd = ni_clos_reopn_dgrm(fd,af); if (_ni_get_ifaddrs(fd,thisif,ifr) < 0) goto error_out; } /* == AF_INET6 */ #endif /* for AF_LINK, AF_PACKET nothing is used except the contents of the addr record */ lastif = thisif; ifr = (struct lifreq *)((char *)ifr + sizeof(struct lifreq)); } close(fd); free(ifc.lifc_req); /* free ifreq */ return nifp->ni_type; /* return family type */ error_out: ret = errno; /* preserve errno */ free(ifc.lifc_req); ni_freeifaddrs(*ifap); close(fd); errno = ret; return -1; } static void * _ni_getifreqs(int fd, void * vifc) { int n, af, size; struct lifconf * ifc = vifc; struct lifnum lifn; void * buf; bzero(ifc,sizeof(struct lifconf)); errno = ENOSYS; n = 2; buf = NULL; while (1) { size = n * PAGE_SIZE; if (size > NI_IFREQ_MEM_MAX) { free(buf); errno = ENOMEM; return NULL; } buf = realloc(buf, size); if (buf == NULL) { free(ifc->lifc_buf); errno = ENOMEM; return NULL; } ifc->lifc_family = AF_UNSPEC; ifc->lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; ifc->lifc_buf = buf; ifc->lifc_len = size; if (ioctl( fd, SIOCGLIFCONF, ifc) < 0 && errno != EINVAL) { free(buf); return NULL; } if (ifc->lifc_len < size - PAGE_SIZE) break; n *= 2; /* printf("n %d, len %d, buf %d, ifclen %d, ifr %u\n",size,buf,ifc->lifc_len,ifc->lifc_req); */ } return ifc->lifc_req; } static void _ni_common_flags(u_int64_t flags) { int i, n; #include "ni_IFF_inc.c" if (flags & IFF_UP) printf("UP "); else printf("DOWN "); n = sizeof(ni_iff_tab) / sizeof(ni_iff_t); for (i=0;ilifr_addr.ss_family; printf("%s\t",ifr->lifr_name); if (af == AF_INET) { fd = ni_clos_reopn_dgrm(fd,AF_INET); if (ioctl(fd, SIOCGLIFFLAGS,ifr) != -1) { flags = ifr->lifr_flags; printf("flags=%0llx<",flags); _ni_common_flags(flags); if (flags == 0) printf(" "); printf("\b> "); } if (ioctl(fd,SIOCGLIFMETRIC,ifr) != -1 ); printf("metric %d ",ifr->lifr_metric); if (ioctl(fd,SIOCGLIFMTU,ifr) != -1 ) printf("mtu %d",ifr->lifr_mtu); printf("\n\t"); if (ioctl(fd,SIOCGLIFADDR,ifr) != -1 ) { sin = (struct sockaddr_in *) &ifr->lifr_addr; #ifdef HAVE_GETNAMEINFO if (getnameinfo(&sin->sin_addr, LOCAL_SIZEOF_SOCKADDR_IN,namebuf,NI_MAXHOST,NULL,0,NI_NUMERICHOST) != 0) #endif strcpy(namebuf,inet_ntoa(sin->sin_addr)); printf("address %s\t",namebuf); } if (ioctl(fd,SIOCGLIFNETMASK,ifr) != -1 ) { sin = (struct sockaddr_in *) &ifr->lifr_addr; printf("mask 0x%lx\t",(unsigned long)ntohl(sin->sin_addr.s_addr)); } /* want to include here.... flags & IFF_BROADCAST */ if (ioctl(fd,SIOCGLIFBRDADDR,ifr) != -1) { sin = (struct sockaddr_in *) &ifr->lifr_addr; strcpy(namebuf,inet_ntoa(sin->sin_addr)); printf("netmask %s\t",namebuf); } } else if (af == AF_INET6) { fd = ni_clos_reopn_dgrm(fd,AF_INET6); if (ioctl(fd,SIOCGLIFADDR,ifr) != -1 ) { sin6 = (struct sockaddr_in6 *)&ifr->lifr_addr; #ifdef HAVE_GETNAMEINFO if (getnameinfo(&ifr->ni_saddr,LOCAL_SIZEOF_SOCKADDR_IN6,namebuf,NI_MAXHOST,NULL,0,NI_NUMERICHOST) != 0) #endif strcpy(namebuf,inet_ntop(AF_INET6,&sin6->sin6_addr,namebuf,NI_MAXHOST)); namegood = 1; } if (ioctl(fd,SIOCGLIFFLAGS,ifr) < 0 ) { printf("\nflags error: %d %s",errno, strerror(errno)); } else { flags = ifr->lifr_flags; printf("flags=%0llx<",flags); _ni_common_flags(flags); if (flags == 0) printf(" "); printf("\b> "); } if (ioctl(fd,SIOCGLIFMETRIC,ifr) != -1 ); printf("metric %d ",ifr->lifr_metric); if (ioctl(fd,SIOCGLIFMTU,ifr) != -1 ) printf("mtu %d",ifr->lifr_mtu); } printf("\n\t"); if (namegood) printf("address %s\n\t",namebuf); printf("af=%d sz=%d ",af,sizeof(struct lifreq)); #if defined SIOCENADDR if (ioctl(fd,SIOCENADDR,ifr) != -1) macgood = 1; #endif if (macgood == 1) macp = (unsigned char *)&ifr->lifr_enaddr; else { strlcpy(mifr.ifr_name,ifr->lifr_name,IFNAMSIZ); close(fd); fd = -1; if ((macp = ni_fallbackhwaddr(af,&mifr)) != NULL) macgood = 1; } if (macgood) printf("MAC addr %02X:%02X:%02X:%02X:%02X:%02X", macp[0],macp[1],macp[2],macp[3],macp[4],macp[5]); printf("\n"); ifr++; } close(fd); free(lifc.lifc_req); return 0; } static struct ni_ifconf_flavor ni_flavor_lifreq = { .ni_type = NI_LIFREQ, .siocgifindex = SIOCGLIFINDEX, .siocsifaddr = SIOCSLIFADDR, .siocgifaddr = SIOCGLIFADDR, .siocdifaddr = SIOCLIFREMOVEIF, .siocaifaddr = SIOCLIFADDIF, .siocsifdstaddr = SIOCSLIFDSTADDR, .siocgifdstaddr = SIOCGLIFDSTADDR, .siocsifflags = SIOCSLIFFLAGS, .siocgifflags = SIOCGLIFFLAGS, .siocsifmtu = SIOCSLIFMTU, .siocgifmtu = SIOCGLIFMTU, .siocsifbrdaddr = SIOCSLIFBRDADDR, .siocgifbrdaddr = SIOCGLIFBRDADDR, .siocsifnetmask = SIOCGLIFNETMASK, .siocgifnetmask = SIOCGLIFNETMASK, .siocsifmetric = SIOCSLIFMETRIC, .siocgifmetric = SIOCGLIFMETRIC, .ifr_offset = NI_LIFREQ_OFFSET, .gifaddrs = ni_lifreq_gifaddrs, .fifaddrs = ni_freeifaddrs, .refreshifr = NULL, .getifreqs = _ni_getifreqs, .developer = ni_flav_lifreq_developer, }; void ni_lifreq_ctor() { ni_ifcf_register(&ni_flavor_lifreq); } #else void ni_lifreq_ctor() { return; } #endif /* have lifreq */