1/* 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#if defined(WEBRTC_ANDROID) 12#include "webrtc/base/ifaddrs-android.h" 13#include <stdlib.h> 14#include <string.h> 15#include <sys/types.h> 16#include <sys/socket.h> 17#include <sys/utsname.h> 18#include <sys/ioctl.h> 19#include <netinet/in.h> 20#include <net/if.h> 21#include <unistd.h> 22#include <errno.h> 23#include <linux/netlink.h> 24#include <linux/rtnetlink.h> 25 26namespace { 27 28struct netlinkrequest { 29 nlmsghdr header; 30 ifaddrmsg msg; 31}; 32 33const int kMaxReadSize = 4096; 34 35} // namespace 36 37namespace rtc { 38 39int set_ifname(struct ifaddrs* ifaddr, int interface) { 40 char buf[IFNAMSIZ] = {0}; 41 char* name = if_indextoname(interface, buf); 42 if (name == NULL) { 43 return -1; 44 } 45 ifaddr->ifa_name = new char[strlen(name) + 1]; 46 strncpy(ifaddr->ifa_name, name, strlen(name) + 1); 47 return 0; 48} 49 50int set_flags(struct ifaddrs* ifaddr) { 51 int fd = socket(AF_INET, SOCK_DGRAM, 0); 52 if (fd == -1) { 53 return -1; 54 } 55 ifreq ifr; 56 memset(&ifr, 0, sizeof(ifr)); 57 strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1); 58 int rc = ioctl(fd, SIOCGIFFLAGS, &ifr); 59 close(fd); 60 if (rc == -1) { 61 return -1; 62 } 63 ifaddr->ifa_flags = ifr.ifr_flags; 64 return 0; 65} 66 67int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data, 68 size_t len) { 69 if (msg->ifa_family == AF_INET) { 70 sockaddr_in* sa = new sockaddr_in; 71 sa->sin_family = AF_INET; 72 memcpy(&sa->sin_addr, data, len); 73 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); 74 } else if (msg->ifa_family == AF_INET6) { 75 sockaddr_in6* sa = new sockaddr_in6; 76 sa->sin6_family = AF_INET6; 77 sa->sin6_scope_id = msg->ifa_index; 78 memcpy(&sa->sin6_addr, data, len); 79 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa); 80 } else { 81 return -1; 82 } 83 return 0; 84} 85 86int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) { 87 char* prefix = NULL; 88 if (family == AF_INET) { 89 sockaddr_in* mask = new sockaddr_in; 90 mask->sin_family = AF_INET; 91 memset(&mask->sin_addr, 0, sizeof(in_addr)); 92 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); 93 if (prefixlen > 32) { 94 prefixlen = 32; 95 } 96 prefix = reinterpret_cast<char*>(&mask->sin_addr); 97 } else if (family == AF_INET6) { 98 sockaddr_in6* mask = new sockaddr_in6; 99 mask->sin6_family = AF_INET6; 100 memset(&mask->sin6_addr, 0, sizeof(in6_addr)); 101 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask); 102 if (prefixlen > 128) { 103 prefixlen = 128; 104 } 105 prefix = reinterpret_cast<char*>(&mask->sin6_addr); 106 } else { 107 return -1; 108 } 109 for (int i = 0; i < (prefixlen / 8); i++) { 110 *prefix++ = 0xFF; 111 } 112 char remainder = 0xff; 113 remainder <<= (8 - prefixlen % 8); 114 *prefix = remainder; 115 return 0; 116} 117 118int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes, 119 size_t len) { 120 if (set_ifname(ifaddr, msg->ifa_index) != 0) { 121 return -1; 122 } 123 if (set_flags(ifaddr) != 0) { 124 return -1; 125 } 126 if (set_addresses(ifaddr, msg, bytes, len) != 0) { 127 return -1; 128 } 129 if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) { 130 return -1; 131 } 132 return 0; 133} 134 135int getifaddrs(struct ifaddrs** result) { 136 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 137 if (fd < 0) { 138 return -1; 139 } 140 141 netlinkrequest ifaddr_request; 142 memset(&ifaddr_request, 0, sizeof(ifaddr_request)); 143 ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST; 144 ifaddr_request.header.nlmsg_type = RTM_GETADDR; 145 ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg)); 146 147 ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0); 148 if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) { 149 close(fd); 150 return -1; 151 } 152 struct ifaddrs* start = NULL; 153 struct ifaddrs* current = NULL; 154 char buf[kMaxReadSize]; 155 ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0); 156 while (amount_read > 0) { 157 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]); 158 size_t header_size = static_cast<size_t>(amount_read); 159 for ( ; NLMSG_OK(header, header_size); 160 header = NLMSG_NEXT(header, header_size)) { 161 switch (header->nlmsg_type) { 162 case NLMSG_DONE: 163 // Success. Return. 164 *result = start; 165 close(fd); 166 return 0; 167 case NLMSG_ERROR: 168 close(fd); 169 freeifaddrs(start); 170 return -1; 171 case RTM_NEWADDR: { 172 ifaddrmsg* address_msg = 173 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header)); 174 rtattr* rta = IFA_RTA(address_msg); 175 ssize_t payload_len = IFA_PAYLOAD(header); 176 while (RTA_OK(rta, payload_len)) { 177 if (rta->rta_type == IFA_ADDRESS) { 178 int family = address_msg->ifa_family; 179 if (family == AF_INET || family == AF_INET6) { 180 ifaddrs* newest = new ifaddrs; 181 memset(newest, 0, sizeof(ifaddrs)); 182 if (current) { 183 current->ifa_next = newest; 184 } else { 185 start = newest; 186 } 187 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta), 188 RTA_PAYLOAD(rta)) != 0) { 189 freeifaddrs(start); 190 *result = NULL; 191 return -1; 192 } 193 current = newest; 194 } 195 } 196 rta = RTA_NEXT(rta, payload_len); 197 } 198 break; 199 } 200 } 201 } 202 amount_read = recv(fd, &buf, kMaxReadSize, 0); 203 } 204 close(fd); 205 freeifaddrs(start); 206 return -1; 207} 208 209void freeifaddrs(struct ifaddrs* addrs) { 210 struct ifaddrs* last = NULL; 211 struct ifaddrs* cursor = addrs; 212 while (cursor) { 213 delete[] cursor->ifa_name; 214 delete cursor->ifa_addr; 215 delete cursor->ifa_netmask; 216 last = cursor; 217 cursor = cursor->ifa_next; 218 delete last; 219 } 220} 221 222} // namespace rtc 223#endif // defined(WEBRTC_ANDROID) 224