1aa6411e2SAugustin Cavalier /* 2aa6411e2SAugustin Cavalier * Copyright 2015, Haiku, Inc. All Rights Reserved. 3aa6411e2SAugustin Cavalier * Distributed under the terms of the MIT License. 4aa6411e2SAugustin Cavalier * 5aa6411e2SAugustin Cavalier * Authors: 6aa6411e2SAugustin Cavalier * Adrien Destugues, pulkomandy@pulkomandy.tk 7aa6411e2SAugustin Cavalier * Axel Dörfler, axeld@pinc-software.de 8aa6411e2SAugustin Cavalier */ 9aa6411e2SAugustin Cavalier 10aa6411e2SAugustin Cavalier 11aa6411e2SAugustin Cavalier #include <algorithm> 12aa6411e2SAugustin Cavalier #include <new> 13aa6411e2SAugustin Cavalier 14aa6411e2SAugustin Cavalier #include <errno.h> 15aa6411e2SAugustin Cavalier #include <net/if.h> 16aa6411e2SAugustin Cavalier #include <netinet/in.h> 17aa6411e2SAugustin Cavalier #include <stdlib.h> 18aa6411e2SAugustin Cavalier #include <string.h> 19aa6411e2SAugustin Cavalier #include <sys/socket.h> 20aa6411e2SAugustin Cavalier #include <sys/sockio.h> 21aa6411e2SAugustin Cavalier #include <unistd.h> 22aa6411e2SAugustin Cavalier 23aa6411e2SAugustin Cavalier #include <AutoDeleter.h> 24aa6411e2SAugustin Cavalier 25aa6411e2SAugustin Cavalier #include <ifaddrs.h> 26aa6411e2SAugustin Cavalier 27aa6411e2SAugustin Cavalier 28aa6411e2SAugustin Cavalier static sockaddr* 29aa6411e2SAugustin Cavalier copy_address(const sockaddr& address) 30aa6411e2SAugustin Cavalier { 31aa6411e2SAugustin Cavalier if (address.sa_family == AF_UNSPEC) 32aa6411e2SAugustin Cavalier return NULL; 33aa6411e2SAugustin Cavalier 34aa6411e2SAugustin Cavalier sockaddr_storage* copy = new (std::nothrow) sockaddr_storage; 35aa6411e2SAugustin Cavalier if (copy == NULL) 36aa6411e2SAugustin Cavalier return NULL; 37aa6411e2SAugustin Cavalier 38aa6411e2SAugustin Cavalier size_t length = std::min(sizeof(sockaddr_storage), (size_t)address.sa_len); 39aa6411e2SAugustin Cavalier switch (address.sa_family) { 40aa6411e2SAugustin Cavalier case AF_INET: 41aa6411e2SAugustin Cavalier length = sizeof(sockaddr_in); 42aa6411e2SAugustin Cavalier break; 43aa6411e2SAugustin Cavalier case AF_INET6: 44aa6411e2SAugustin Cavalier length = sizeof(sockaddr_in6); 45aa6411e2SAugustin Cavalier break; 46aa6411e2SAugustin Cavalier } 47aa6411e2SAugustin Cavalier memcpy(copy, &address, length); 48aa6411e2SAugustin Cavalier copy->ss_len = length; 49aa6411e2SAugustin Cavalier return (sockaddr*)copy; 50aa6411e2SAugustin Cavalier } 51aa6411e2SAugustin Cavalier 52aa6411e2SAugustin Cavalier 53b6ec8338SLeorize static int 54b6ec8338SLeorize _getifaddrs(int domain, char* buffer, size_t len, struct ifaddrs** previous) 55aa6411e2SAugustin Cavalier { 56*fce7f3a7SX512 FileDescriptorCloser socket (::socket(domain, SOCK_DGRAM, 0)); 57*fce7f3a7SX512 if (!socket.IsSet()) 58aa6411e2SAugustin Cavalier return -1; 59aa6411e2SAugustin Cavalier 60aa6411e2SAugustin Cavalier // Get interfaces configuration 61b6ec8338SLeorize ifconf config; 62aa6411e2SAugustin Cavalier config.ifc_buf = buffer; 63b6ec8338SLeorize config.ifc_len = len; 64*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0) 65aa6411e2SAugustin Cavalier return -1; 66aa6411e2SAugustin Cavalier 67aa6411e2SAugustin Cavalier ifreq* interfaces = (ifreq*)buffer; 68aa6411e2SAugustin Cavalier ifreq* end = (ifreq*)(buffer + config.ifc_len); 69aa6411e2SAugustin Cavalier 70b6ec8338SLeorize while (interfaces < end) { 71aa6411e2SAugustin Cavalier struct ifaddrs* current = new(std::nothrow) ifaddrs(); 72aa6411e2SAugustin Cavalier if (current == NULL) { 73aa6411e2SAugustin Cavalier errno = B_NO_MEMORY; 74aa6411e2SAugustin Cavalier return -1; 75aa6411e2SAugustin Cavalier } 76aa6411e2SAugustin Cavalier 77aa6411e2SAugustin Cavalier // Chain this interface with the next one 78b6ec8338SLeorize current->ifa_next = *previous; 79b6ec8338SLeorize *previous = current; 80aa6411e2SAugustin Cavalier 81aa6411e2SAugustin Cavalier current->ifa_name = strdup(interfaces[0].ifr_name); 82aa6411e2SAugustin Cavalier current->ifa_addr = copy_address(interfaces[0].ifr_addr); 83aa6411e2SAugustin Cavalier current->ifa_netmask = NULL; 84aa6411e2SAugustin Cavalier current->ifa_dstaddr = NULL; 85aa6411e2SAugustin Cavalier current->ifa_data = NULL; 86aa6411e2SAugustin Cavalier 87aa6411e2SAugustin Cavalier ifreq request; 88aa6411e2SAugustin Cavalier strlcpy(request.ifr_name, interfaces[0].ifr_name, IF_NAMESIZE); 89aa6411e2SAugustin Cavalier 90*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGIFFLAGS, &request, sizeof(struct ifreq)) 91*fce7f3a7SX512 == 0) 92aa6411e2SAugustin Cavalier current->ifa_flags = request.ifr_flags; 93*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGIFNETMASK, &request, sizeof(struct ifreq)) 94aa6411e2SAugustin Cavalier == 0) { 95aa6411e2SAugustin Cavalier current->ifa_netmask = copy_address(request.ifr_mask); 96aa6411e2SAugustin Cavalier } 97*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGIFDSTADDR, &request, sizeof(struct ifreq)) 98aa6411e2SAugustin Cavalier == 0) { 99aa6411e2SAugustin Cavalier current->ifa_dstaddr = copy_address(request.ifr_dstaddr); 100aa6411e2SAugustin Cavalier } 101aa6411e2SAugustin Cavalier 102aa6411e2SAugustin Cavalier // Move on to next interface 103aa6411e2SAugustin Cavalier interfaces = (ifreq*)((uint8_t*)interfaces 104aa6411e2SAugustin Cavalier + _SIZEOF_ADDR_IFREQ(interfaces[0])); 105aa6411e2SAugustin Cavalier } 106aa6411e2SAugustin Cavalier 107b6ec8338SLeorize return 0; 108b6ec8338SLeorize } 109b6ec8338SLeorize 110b6ec8338SLeorize 111b6ec8338SLeorize /*! Returns a chained list of all interfaces. */ 112b6ec8338SLeorize int 113b6ec8338SLeorize getifaddrs(struct ifaddrs** _ifaddrs) 114b6ec8338SLeorize { 115b6ec8338SLeorize if (_ifaddrs == NULL) { 116b6ec8338SLeorize errno = B_BAD_VALUE; 117b6ec8338SLeorize return -1; 118b6ec8338SLeorize } 119b6ec8338SLeorize 120*fce7f3a7SX512 FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0)); 121*fce7f3a7SX512 if (!socket.IsSet()) 122b6ec8338SLeorize return -1; 123b6ec8338SLeorize 124b6ec8338SLeorize // Get interface count 125b6ec8338SLeorize ifconf config; 126b6ec8338SLeorize config.ifc_len = sizeof(config.ifc_value); 127*fce7f3a7SX512 if (ioctl(socket.Get(), SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0) 128b6ec8338SLeorize return -1; 129b6ec8338SLeorize 130*fce7f3a7SX512 socket.Unset(); 131b6ec8338SLeorize 132b6ec8338SLeorize size_t count = (size_t)config.ifc_value; 133b6ec8338SLeorize if (count == 0) { 134b6ec8338SLeorize // No interfaces found 135b6ec8338SLeorize *_ifaddrs = NULL; 136b6ec8338SLeorize return 0; 137b6ec8338SLeorize } 138b6ec8338SLeorize 139b6ec8338SLeorize // Allocate a buffer for ifreqs for all interfaces 140b6ec8338SLeorize size_t buflen = count * sizeof(struct ifreq); 141*fce7f3a7SX512 ArrayDeleter<char> buffer(new(std::nothrow) char[buflen]); 142*fce7f3a7SX512 if (!buffer.IsSet()) { 143b6ec8338SLeorize errno = B_NO_MEMORY; 144b6ec8338SLeorize return -1; 145b6ec8338SLeorize } 146b6ec8338SLeorize 147b6ec8338SLeorize struct ifaddrs* previous = NULL; 148b6ec8338SLeorize int serrno = errno; 149*fce7f3a7SX512 if (_getifaddrs(AF_INET, buffer.Get(), buflen, &previous) < 0 && 150b6ec8338SLeorize errno != B_UNSUPPORTED) { 151b6ec8338SLeorize freeifaddrs(previous); 152b6ec8338SLeorize return -1; 153b6ec8338SLeorize } 154*fce7f3a7SX512 if (_getifaddrs(AF_INET6, buffer.Get(), buflen, &previous) < 0 && 155b6ec8338SLeorize errno != B_UNSUPPORTED) { 156b6ec8338SLeorize freeifaddrs(previous); 157b6ec8338SLeorize return -1; 158b6ec8338SLeorize } 159*fce7f3a7SX512 if (_getifaddrs(AF_LINK, buffer.Get(), buflen, &previous) < 0 && 160b6ec8338SLeorize errno != B_UNSUPPORTED) { 161b6ec8338SLeorize freeifaddrs(previous); 162b6ec8338SLeorize return -1; 163b6ec8338SLeorize } 164b6ec8338SLeorize if (previous == NULL) 165b6ec8338SLeorize return -1; 166b6ec8338SLeorize errno = serrno; 167b6ec8338SLeorize 168aa6411e2SAugustin Cavalier *_ifaddrs = previous; 169aa6411e2SAugustin Cavalier return 0; 170aa6411e2SAugustin Cavalier } 171aa6411e2SAugustin Cavalier 172aa6411e2SAugustin Cavalier 173aa6411e2SAugustin Cavalier void 174aa6411e2SAugustin Cavalier freeifaddrs(struct ifaddrs* ifa) 175aa6411e2SAugustin Cavalier { 176aa6411e2SAugustin Cavalier while (ifa != NULL) { 177aa6411e2SAugustin Cavalier free((void*)ifa->ifa_name); 178aa6411e2SAugustin Cavalier delete ifa->ifa_addr; 179aa6411e2SAugustin Cavalier delete ifa->ifa_netmask; 180aa6411e2SAugustin Cavalier delete ifa->ifa_dstaddr; 181aa6411e2SAugustin Cavalier 182aa6411e2SAugustin Cavalier struct ifaddrs* next = ifa->ifa_next; 183aa6411e2SAugustin Cavalier delete ifa; 184aa6411e2SAugustin Cavalier ifa = next; 185aa6411e2SAugustin Cavalier } 186aa6411e2SAugustin Cavalier } 187aa6411e2SAugustin Cavalier 188