Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef IFADDRS_ANDROID_H_included
     18 #define IFADDRS_ANDROID_H_included
     19 
     20 #include <arpa/inet.h>
     21 #include <cstring>
     22 #include <errno.h>
     23 #include <net/if.h>
     24 #include <netinet/in.h>
     25 #include <new>
     26 #include <sys/ioctl.h>
     27 #include <sys/types.h>
     28 #include <sys/socket.h>
     29 #include <stdio.h>
     30 #include <linux/netlink.h>
     31 #include <linux/rtnetlink.h>
     32 
     33 #include "LocalArray.h"
     34 #include "ScopedFd.h"
     35 
     36 // Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).
     37 // We fake it here, so java_net_NetworkInterface.cpp can use that API
     38 // with all the non-portable code being in this file.
     39 
     40 // Source-compatible subset of the BSD struct.
     41 struct ifaddrs {
     42     // Pointer to next struct in list, or NULL at end.
     43     ifaddrs* ifa_next;
     44 
     45     // Interface name.
     46     char* ifa_name;
     47 
     48     // Interface flags.
     49     unsigned int ifa_flags;
     50 
     51     // Interface network address.
     52     sockaddr* ifa_addr;
     53 
     54     // Interface netmask.
     55     sockaddr* ifa_netmask;
     56 
     57     ifaddrs(ifaddrs* next)
     58     : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL)
     59     {
     60     }
     61 
     62     ~ifaddrs() {
     63         delete ifa_next;
     64         delete[] ifa_name;
     65         delete ifa_addr;
     66         delete ifa_netmask;
     67     }
     68 
     69     // Sadly, we can't keep the interface index for portability with BSD.
     70     // We'll have to keep the name instead, and re-query the index when
     71     // we need it later.
     72     bool setNameAndFlagsByIndex(int interfaceIndex) {
     73         // Get the name.
     74         char buf[IFNAMSIZ];
     75         char* name = if_indextoname(interfaceIndex, buf);
     76         if (name == NULL) {
     77             return false;
     78         }
     79         ifa_name = new char[strlen(name) + 1];
     80         strcpy(ifa_name, name);
     81 
     82         // Get the flags.
     83         ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
     84         if (fd.get() == -1) {
     85             return false;
     86         }
     87         ifreq ifr;
     88         memset(&ifr, 0, sizeof(ifr));
     89         strcpy(ifr.ifr_name, name);
     90         int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
     91         if (rc == -1) {
     92             return false;
     93         }
     94         ifa_flags = ifr.ifr_flags;
     95         return true;
     96     }
     97 
     98     // Netlink gives us the address family in the header, and the
     99     // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
    100     // stitch the two bits together into the sockaddr that's part of
    101     // our portable interface.
    102     void setAddress(int family, void* data, size_t byteCount) {
    103         // Set the address proper...
    104         sockaddr_storage* ss = new sockaddr_storage;
    105         memset(ss, 0, sizeof(*ss));
    106         ifa_addr = reinterpret_cast<sockaddr*>(ss);
    107         ss->ss_family = family;
    108         uint8_t* dst = sockaddrBytes(family, ss);
    109         memcpy(dst, data, byteCount);
    110     }
    111 
    112     // Netlink gives us the prefix length as a bit count. We need to turn
    113     // that into a BSD-compatible netmask represented by a sockaddr*.
    114     void setNetmask(int family, size_t prefixLength) {
    115         // ...and work out the netmask from the prefix length.
    116         sockaddr_storage* ss = new sockaddr_storage;
    117         memset(ss, 0, sizeof(*ss));
    118         ifa_netmask = reinterpret_cast<sockaddr*>(ss);
    119         ss->ss_family = family;
    120         uint8_t* dst = sockaddrBytes(family, ss);
    121         memset(dst, 0xff, prefixLength / 8);
    122         if ((prefixLength % 8) != 0) {
    123             dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));
    124         }
    125     }
    126 
    127     // Returns a pointer to the first byte in the address data (which is
    128     // stored in network byte order).
    129     uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {
    130         if (family == AF_INET) {
    131             sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
    132             return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
    133         } else if (family == AF_INET6) {
    134             sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
    135             return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
    136         }
    137         return NULL;
    138     }
    139 
    140 private:
    141     // Disallow copy and assignment.
    142     ifaddrs(const ifaddrs&);
    143     void operator=(const ifaddrs&);
    144 };
    145 
    146 // FIXME: use iovec instead.
    147 struct addrReq_struct {
    148     nlmsghdr netlinkHeader;
    149     ifaddrmsg msg;
    150 };
    151 
    152 inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
    153     ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
    154     return (sentByteCount == static_cast<ssize_t>(byteCount));
    155 }
    156 
    157 inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
    158     return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
    159 }
    160 
    161 // Source-compatible with the BSD function.
    162 inline int getifaddrs(ifaddrs** result) {
    163     // Simplify cleanup for callers.
    164     *result = NULL;
    165 
    166     // Create a netlink socket.
    167     ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
    168     if (fd.get() < 0) {
    169         return -1;
    170     }
    171 
    172     // Ask for the address information.
    173     addrReq_struct addrRequest;
    174     memset(&addrRequest, 0, sizeof(addrRequest));
    175     addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
    176     addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
    177     addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
    178     addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
    179     addrRequest.msg.ifa_index = 0; // All interfaces.
    180     if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
    181         return -1;
    182     }
    183 
    184     // Read the responses.
    185     LocalArray<0> buf(65536); // We don't necessarily have std::vector.
    186     ssize_t bytesRead;
    187     while ((bytesRead  = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
    188         nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);
    189         for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
    190             switch (hdr->nlmsg_type) {
    191             case NLMSG_DONE:
    192                 return 0;
    193             case NLMSG_ERROR:
    194                 return -1;
    195             case RTM_NEWADDR:
    196                 {
    197                     ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
    198                     rtattr* rta = IFA_RTA(address);
    199                     size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
    200                     while (RTA_OK(rta, ifaPayloadLength)) {
    201                         if (rta->rta_type == IFA_LOCAL) {
    202                             int family = address->ifa_family;
    203                             if (family == AF_INET || family == AF_INET6) {
    204                                 *result = new ifaddrs(*result);
    205                                 if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {
    206                                     return -1;
    207                                 }
    208                                 (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));
    209                                 (*result)->setNetmask(family, address->ifa_prefixlen);
    210                             }
    211                         }
    212                         rta = RTA_NEXT(rta, ifaPayloadLength);
    213                     }
    214                 }
    215                 break;
    216             }
    217         }
    218     }
    219     // We only get here if recv fails before we see a NLMSG_DONE.
    220     return -1;
    221 }
    222 
    223 // Source-compatible with the BSD function.
    224 inline void freeifaddrs(ifaddrs* addresses) {
    225     delete addresses;
    226 }
    227 
    228 #endif  // IFADDRS_ANDROID_H_included
    229