/* * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ * * This file is not normally used. * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS * in CFSocket.c. It is included mainly as sample code for people building * for other platforms that (like Puma) lack the getifaddrs() call. * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma * that works just like the Jaguar one, because Puma lacks other necessary * functionality (like the LibInfo support to receive MIG messages from clients). Change History (most recent first): $Log: CFSocketPuma.c,v $ Revision 1.4 2003/08/12 19:56:25 cheshire Update to APSL 2.0 Revision 1.3 2003/07/02 21:19:51 cheshire Update copyright notices, etc., in source code comments Revision 1.2 2002/09/21 20:44:51 zarzycki Added APSL info Revision 1.1 2002/09/17 01:36:23 cheshire Move Puma support to CFSocketPuma.c */ #include #include #define ifaddrs ifa_info #ifndef ifa_broadaddr #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ #endif #include /* Our own header for the programs that need interface configuration info. Include this file, instead of "unp.h". */ #define IFA_NAME 16 /* same as IFNAMSIZ in */ #define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */ struct ifa_info { char ifa_name[IFA_NAME]; /* interface name, null terminated */ u_char ifa_haddr[IFA_HADDR]; /* hardware address */ u_short ifa_hlen; /* #bytes in hardware address: 0, 6, 8 */ short ifa_flags; /* IFF_xxx constants from */ short ifa_myflags; /* our own IFI_xxx flags */ struct sockaddr *ifa_addr; /* primary address */ struct sockaddr *ifa_brdaddr;/* broadcast address */ struct sockaddr *ifa_dstaddr;/* destination address */ struct ifa_info *ifa_next; /* next of these structures */ }; #define IFI_ALIAS 1 /* ifa_addr is an alias */ /* function prototypes */ struct ifa_info *get_ifa_info(int, int); struct ifa_info *Get_ifa_info(int, int); void free_ifa_info(struct ifa_info *); #define HAVE_SOCKADDR_SA_LEN 1 struct ifa_info * get_ifa_info(int family, int doaliases) { struct ifa_info *ifi, *ifihead, **ifipnext; int sockfd, len, lastlen, flags, myflags; char *ptr, *buf, lastname[IFNAMSIZ], *cptr; struct ifconf ifc; struct ifreq *ifr, ifrcopy; struct sockaddr_in *sinptr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); lastlen = 0; len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ for ( ; ; ) { buf = (char *) malloc(len); ifc.ifc_len = len; ifc.ifc_buf = buf; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { if (errno != EINVAL || lastlen != 0) debugf("ioctl error"); } else { if (ifc.ifc_len == lastlen) break; /* success, len has not changed */ lastlen = ifc.ifc_len; } len += 10 * sizeof(struct ifreq); /* increment */ free(buf); } ifihead = NULL; ifipnext = &ifihead; lastname[0] = 0; /* end get_ifa_info1 */ /* include get_ifa_info2 */ for (ptr = buf; ptr < buf + ifc.ifc_len; ) { ifr = (struct ifreq *) ptr; #ifdef HAVE_SOCKADDR_SA_LEN len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); #else switch (ifr->ifr_addr.sa_family) { #ifdef IPV6 case AF_INET6: len = sizeof(struct sockaddr_in6); break; #endif case AF_INET: default: len = sizeof(struct sockaddr); break; } #endif /* HAVE_SOCKADDR_SA_LEN */ ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ if (ifr->ifr_addr.sa_family != family) continue; /* ignore if not desired address family */ myflags = 0; if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) *cptr = 0; /* replace colon will null */ if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { if (doaliases == 0) continue; /* already processed this interface */ myflags = IFI_ALIAS; } memcpy(lastname, ifr->ifr_name, IFNAMSIZ); ifrcopy = *ifr; ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); flags = ifrcopy.ifr_flags; if ((flags & IFF_UP) == 0) continue; /* ignore if interface not up */ ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info)); *ifipnext = ifi; /* prev points to this new one */ ifipnext = &ifi->ifa_next; /* pointer to next one goes here */ ifi->ifa_flags = flags; /* IFF_xxx values */ ifi->ifa_myflags = myflags; /* IFI_xxx values */ memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME); ifi->ifa_name[IFA_NAME-1] = '\0'; /* end get_ifa_info2 */ /* include get_ifa_info3 */ switch (ifr->ifr_addr.sa_family) { case AF_INET: sinptr = (struct sockaddr_in *) &ifr->ifr_addr; if (ifi->ifa_addr == NULL) { ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in)); #ifdef SIOCGIFBRDADDR if (flags & IFF_BROADCAST) { ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in)); } #endif #ifdef SIOCGIFDSTADDR if (flags & IFF_POINTOPOINT) { ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in)); } #endif } break; default: break; } } free(buf); return(ifihead); /* pointer to first structure in linked list */ } /* end get_ifa_info3 */ /* include free_ifa_info */ mDNSlocal void freeifaddrs(struct ifa_info *ifihead) { struct ifa_info *ifi, *ifinext; for (ifi = ifihead; ifi != NULL; ifi = ifinext) { if (ifi->ifa_addr != NULL) free(ifi->ifa_addr); if (ifi->ifa_brdaddr != NULL) free(ifi->ifa_brdaddr); if (ifi->ifa_dstaddr != NULL) free(ifi->ifa_dstaddr); ifinext = ifi->ifa_next; /* can't fetch ifa_next after free() */ free(ifi); /* the ifa_info{} itself */ } } /* end free_ifa_info */ struct ifa_info * Get_ifa_info(int family, int doaliases) { struct ifa_info *ifi; if ( (ifi = get_ifa_info(family, doaliases)) == NULL) debugf("get_ifa_info error"); return(ifi); } mDNSlocal int getifaddrs(struct ifa_info **ifalist) { *ifalist = get_ifa_info(PF_INET, false); if( ifalist == nil ) return -1; else return(0); }