1/* 2 * libjingle 3 * Copyright 2012, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#if defined(ANDROID) 29#include "talk/base/ifaddrs-android.h" 30#include <stdlib.h> 31#include <string.h> 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <sys/utsname.h> 35#include <sys/ioctl.h> 36#include <netinet/in.h> 37#include <net/if.h> 38#include <unistd.h> 39#include <errno.h> 40#include <linux/netlink.h> 41#include <linux/rtnetlink.h> 42 43struct netlinkrequest { 44 nlmsghdr header; 45 ifaddrmsg msg; 46}; 47 48namespace { 49const int kMaxReadSize = 4096; 50}; 51 52int set_ifname(struct ifaddrs* ifaddr, int interface) { 53 char buf[IFNAMSIZ] = {0}; 54 char* name = if_indextoname(interface, buf); 55 if (name == NULL) { 56 return -1; 57 } 58 ifaddr->ifa_name = new char[strlen(name) + 1]; 59 strncpy(ifaddr->ifa_name, name, strlen(name) + 1); 60 return 0; 61} 62 63int set_flags(struct ifaddrs* ifaddr) { 64 int fd = socket(AF_INET, SOCK_DGRAM, 0); 65 if (fd == -1) { 66 return -1; 67 } 68 ifreq ifr; 69 memset(&ifr, 0, sizeof(ifr)); 70 strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1); 71 int rc = ioctl(fd, SIOCGIFFLAGS, &ifr); 72 close(fd); 73 if (rc == -1) { 74 return -1; 75 } 76 ifaddr->ifa_flags = ifr.ifr_flags; 77 return 0; 78} 79 80int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data, 81 size_t len) { 82 if (msg->ifa_family == AF_INET) { 83 sockaddr_in* sa = new sockaddr_in; 84 sa->sin_family = AF_INET; 85 memcpy(&sa->sin_addr, data, len); 86 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); 87 } else if (msg->ifa_family == AF_INET6) { 88 sockaddr_in6* sa = new sockaddr_in6; 89 sa->sin6_family = AF_INET6; 90 sa->sin6_scope_id = msg->ifa_index; 91 memcpy(&sa->sin6_addr, data, len); 92 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); 93 } else { 94 return -1; 95 } 96 return 0; 97} 98 99int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { 100 char* prefix = NULL; 101 if (family == AF_INET) { 102 sockaddr_in* mask = new sockaddr_in; 103 mask->sin_family = AF_INET; 104 memset(&mask->sin_addr, 0, sizeof(in_addr)); 105 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); 106 if (prefixlen > 32) { 107 prefixlen = 32; 108 } 109 prefix = reinterpret_cast<char*>(&mask->sin_addr); 110 } else if (family == AF_INET6) { 111 sockaddr_in6* mask = new sockaddr_in6; 112 mask->sin6_family = AF_INET6; 113 memset(&mask->sin6_addr, 0, sizeof(in6_addr)); 114 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); 115 if (prefixlen > 128) { 116 prefixlen = 128; 117 } 118 prefix = reinterpret_cast<char*>(&mask->sin6_addr); 119 } else { 120 return -1; 121 } 122 for (int i = 0; i < (prefixlen / 8); i++) { 123 *prefix++ = 0xFF; 124 } 125 char remainder = 0xff; 126 remainder <<= (8 - prefixlen % 8); 127 *prefix = remainder; 128 return 0; 129} 130 131int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes, 132 size_t len) { 133 if (set_ifname(ifaddr, msg->ifa_index) != 0) { 134 return -1; 135 } 136 if (set_flags(ifaddr) != 0) { 137 return -1; 138 } 139 if (set_addresses(ifaddr, msg, bytes, len) != 0) { 140 return -1; 141 } 142 if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) { 143 return -1; 144 } 145 return 0; 146} 147 148int getifaddrs(struct ifaddrs** result) { 149 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 150 if (fd < 0) { 151 return -1; 152 } 153 154 netlinkrequest ifaddr_request; 155 memset(&ifaddr_request, 0, sizeof(ifaddr_request)); 156 ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; 157 ifaddr_request.header.nlmsg_type = RTM_GETADDR; 158 ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); 159 160 ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0); 161 if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) { 162 close(fd); 163 return -1; 164 } 165 struct ifaddrs* start = NULL; 166 struct ifaddrs* current = NULL; 167 char buf[kMaxReadSize]; 168 ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0); 169 while (amount_read > 0) { 170 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]); 171 size_t header_size = static_cast<size_t>(amount_read); 172 for ( ; NLMSG_OK(header, header_size); 173 header = NLMSG_NEXT(header, header_size)) { 174 switch (header->nlmsg_type) { 175 case NLMSG_DONE: 176 // Success. Return. 177 *result = start; 178 close(fd); 179 return 0; 180 case NLMSG_ERROR: 181 close(fd); 182 freeifaddrs(start); 183 return -1; 184 case RTM_NEWADDR: { 185 ifaddrmsg* address_msg = 186 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header)); 187 rtattr* rta = IFA_RTA(address_msg); 188 ssize_t payload_len = IFA_PAYLOAD(header); 189 while (RTA_OK(rta, payload_len)) { 190 if (rta->rta_type == IFA_ADDRESS) { 191 int family = address_msg->ifa_family; 192 if (family == AF_INET || family == AF_INET6) { 193 ifaddrs* newest = new ifaddrs; 194 memset(newest, 0, sizeof(ifaddrs)); 195 if (current) { 196 current->ifa_next = newest; 197 } else { 198 start = newest; 199 } 200 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta), 201 RTA_PAYLOAD(rta)) != 0) { 202 freeifaddrs(start); 203 *result = NULL; 204 return -1; 205 } 206 current = newest; 207 } 208 } 209 rta = RTA_NEXT(rta, payload_len); 210 } 211 break; 212 } 213 } 214 } 215 amount_read = recv(fd, &buf, kMaxReadSize, 0); 216 } 217 close(fd); 218 freeifaddrs(start); 219 return -1; 220} 221 222void freeifaddrs(struct ifaddrs* addrs) { 223 struct ifaddrs* last = NULL; 224 struct ifaddrs* cursor = addrs; 225 while (cursor) { 226 delete[] cursor->ifa_name; 227 delete cursor->ifa_addr; 228 delete cursor->ifa_netmask; 229 last = cursor; 230 cursor = cursor->ifa_next; 231 delete last; 232 } 233} 234#endif // defined(ANDROID) 235