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