/* * Copyright 2018, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "if_monitor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "RIL-IFMON" #include static const size_t kReadBufferSize = 32768; static const size_t kControlServer = 0; static const size_t kControlClient = 1; // A list of commands that can be sent to the monitor. These should be one // character long as that is all that the monitor will read and process. static const char kMonitorStopCommand[] = "\1"; static const char kMonitorAckCommand[] = "\2"; static size_t addrLength(int addrFamily) { switch (addrFamily) { case AF_INET: return 4; case AF_INET6: return 16; default: return 0; } } static const void* getSockAddrData(const struct sockaddr* addr) { switch (addr->sa_family) { case AF_INET: return &reinterpret_cast(addr)->sin_addr; case AF_INET6: return &reinterpret_cast(addr)->sin6_addr; default: return nullptr; } } bool operator==(const struct ifAddress& left, const struct ifAddress& right) { // The prefix length does not factor in to whether two addresses are the // same or not. Only the family and the address data. This matches the // kernel behavior when attempting to add the same address with different // prefix lengths, those changes are rejected because the address already // exists. return left.family == right.family && memcmp(&left.addr, &right.addr, addrLength(left.family)) == 0; } class InterfaceMonitor { public: InterfaceMonitor() : mSocketFd(-1) { mControlSocket[kControlServer] = -1; mControlSocket[kControlClient] = -1; } ~InterfaceMonitor() { if (mControlSocket[kControlClient] != -1) { ::close(mControlSocket[kControlClient]); mControlSocket[kControlClient] = -1; } if (mControlSocket[kControlServer] != -1) { ::close(mControlSocket[kControlServer]); mControlSocket[kControlServer] = -1; } if (mSocketFd != -1) { ::close(mSocketFd); mSocketFd = -1; } } bool init() { if (mSocketFd != -1) { RLOGE("InterfaceMonitor already initialized"); return false; } mSocketFd = ::socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); if (mSocketFd == -1) { RLOGE("InterfaceMonitor failed to open socket: %s", strerror(errno)); return false; } if (::socketpair(AF_UNIX, SOCK_DGRAM, 0, mControlSocket) != 0) { RLOGE("Unable to create control socket pair: %s", strerror(errno)); return false; } struct sockaddr_nl addr; memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = (1 << (RTNLGRP_IPV4_IFADDR - 1)) | (1 << (RTNLGRP_IPV6_IFADDR - 1)); struct sockaddr* sa = reinterpret_cast(&addr); if (::bind(mSocketFd, sa, sizeof(addr)) != 0) { RLOGE("InterfaceMonitor failed to bind socket: %s", strerror(errno)); return false; } return true; } void setCallback(ifMonitorCallback callback) { mOnAddressChangeCallback = callback; } void runAsync() { std::unique_lock lock(mThreadMutex); mThread = std::make_unique([this]() { run(); }); } void requestAddresses() { struct ifaddrs* addresses = nullptr; if (getifaddrs(&addresses) != 0) { RLOGE("Unable to retrieve list of interfaces, cannot get initial " "interface addresses: %s", strerror(errno)); return; } for (struct ifaddrs* cur = addresses; cur; cur = cur->ifa_next) { if (cur->ifa_name == nullptr || cur->ifa_addr == nullptr || cur->ifa_netmask == nullptr) { // Interface doesn't have all the information we need. Rely on // the netlink notification to catch this interface later if it // is configured correctly. continue; } if (cur->ifa_flags & IFF_LOOPBACK) { // Not interested in loopback devices, they will never be radio // interfaces. continue; } unsigned int ifIndex = if_nametoindex(cur->ifa_name); if (ifIndex == 0) { RLOGE("Encountered interface %s with no index: %s", cur->ifa_name, strerror(errno)); continue; } ifAddress addr; addr.family = cur->ifa_addr->sa_family; addr.prefix = getPrefix(cur->ifa_netmask); memcpy(addr.addr, getSockAddrData(cur->ifa_addr), addrLength(cur->ifa_addr->sa_family)); mAddresses[ifIndex].push_back(addr); } freeifaddrs(addresses); if (mOnAddressChangeCallback) { for (const auto& ifAddr : mAddresses) { mOnAddressChangeCallback(ifAddr.first, ifAddr.second.data(), ifAddr.second.size()); } } } int getPrefix(const struct sockaddr* addr) { // This uses popcnt, a built-in instruction on some CPUs, to count // the number of bits in a 32-bit word. The number of bits in a netmask // equals the width of the prefix. For example a netmask of // 255.255.255.0 has 24 bits set and that's also its width. if (addr->sa_family == AF_INET) { auto v4 = reinterpret_cast(addr); return __builtin_popcount(v4->sin_addr.s_addr); } else if (addr->sa_family == AF_INET6) { auto v6 = reinterpret_cast(addr); // Copy to our own array to avoid aliasing uint64_t words[2]; memcpy(words, v6->sin6_addr.s6_addr, sizeof(words)); return __builtin_popcountll(words[0]) + __builtin_popcountll(words[1]); } return 0; } void run() { requestAddresses(); std::vector fds(2); fds[0].events = POLLIN; fds[0].fd = mControlSocket[kControlServer]; fds[1].events = POLLIN; fds[1].fd = mSocketFd; while (true) { int status = ::poll(fds.data(), fds.size(), -1); if (status < 0) { if (errno == EINTR) { // Interrupted, just keep going continue; } // Actual error, time to quit RLOGE("Polling failed: %s", strerror(errno)); break; } else if (status == 0) { // Timeout continue; } if (fds[0].revents & POLLIN) { // Control message received char command = -1; if (::read(mControlSocket[kControlServer], &command, sizeof(command)) == 1) { if (command == kMonitorStopCommand[0]) { break; } } } else if (fds[1].revents & POLLIN) { onReadAvailable(); } } ::write(mControlSocket[kControlServer], kMonitorAckCommand, 1); } void stop() { std::unique_lock lock(mThreadMutex); if (mThread) { ::write(mControlSocket[kControlClient], kMonitorStopCommand, 1); char ack = -1; while (ack != kMonitorAckCommand[0]) { ::read(mControlSocket[kControlClient], &ack, sizeof(ack)); } mThread->join(); mThread.reset(); } } private: void onReadAvailable() { char buffer[kReadBufferSize]; struct sockaddr_storage storage; while (true) { socklen_t addrSize = sizeof(storage); int status = ::recvfrom(mSocketFd, buffer, sizeof(buffer), MSG_DONTWAIT, reinterpret_cast(&storage), &addrSize); if (status < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { // Nothing to receive, everything is fine return; } else if (status < 0 && errno == EINTR) { // Caught interrupt, try again continue; } else if (status < 0) { RLOGE("InterfaceMonitor receive failed: %s", strerror(errno)); return; } else if (addrSize < 0 || static_cast(addrSize) != sizeof(struct sockaddr_nl)) { RLOGE("InterfaceMonitor received invalid address size"); return; } size_t length = static_cast(status); auto hdr = reinterpret_cast(buffer); while (NLMSG_OK(hdr, length) && hdr->nlmsg_type != NLMSG_DONE) { switch (hdr->nlmsg_type) { case RTM_NEWADDR: case RTM_DELADDR: handleAddressChange(hdr); break; default: RLOGE("Received message type %d", (int)hdr->nlmsg_type); break; } hdr = NLMSG_NEXT(hdr, length); } } } std::string getInterfaceName(unsigned int ifIndex) { char buffer[IF_NAMESIZE] = { '\0' }; return if_indextoname(ifIndex, buffer); } void handleAddressChange(const struct nlmsghdr* hdr) { if (!mOnAddressChangeCallback) { return; } auto msg = reinterpret_cast(NLMSG_DATA(hdr)); std::vector& ifAddrs = mAddresses[msg->ifa_index]; auto attr = reinterpret_cast(IFA_RTA(msg)); int attrLen = IFA_PAYLOAD(hdr); bool somethingChanged = false; for (;attr && RTA_OK(attr, attrLen); attr = RTA_NEXT(attr, attrLen)) { if (attr->rta_type != IFA_LOCAL && attr->rta_type != IFA_ADDRESS) { continue; } ifAddress addr; memset(&addr, 0, sizeof(addr)); // Ensure that the payload matches the expected address length if (RTA_PAYLOAD(attr) >= addrLength(msg->ifa_family)) { addr.family = msg->ifa_family; addr.prefix = msg->ifa_prefixlen; memcpy(&addr.addr, RTA_DATA(attr), addrLength(addr.family)); } else { RLOGE("Invalid address family (%d) and size (%d) combination", int(msg->ifa_family), int(RTA_PAYLOAD(attr))); continue; } auto it = std::find(ifAddrs.begin(), ifAddrs.end(), addr); if (hdr->nlmsg_type == RTM_NEWADDR && it == ifAddrs.end()) { // New address does not exist, add it ifAddrs.push_back(addr); somethingChanged = true; } else if (hdr->nlmsg_type == RTM_DELADDR && it != ifAddrs.end()) { // Address was removed and it exists, remove it ifAddrs.erase(it); somethingChanged = true; } } if (somethingChanged) { mOnAddressChangeCallback(msg->ifa_index, ifAddrs.data(), ifAddrs.size()); } } ifMonitorCallback mOnAddressChangeCallback; std::unordered_map> mAddresses; std::unique_ptr mThread; std::mutex mThreadMutex; int mSocketFd; int mControlSocket[2]; }; extern "C" struct ifMonitor* ifMonitorCreate() { auto monitor = std::make_unique(); if (!monitor || !monitor->init()) { return nullptr; } return reinterpret_cast(monitor.release()); } extern "C" void ifMonitorFree(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast(ifMonitor); delete monitor; } extern "C" void ifMonitorSetCallback(struct ifMonitor* ifMonitor, ifMonitorCallback callback) { InterfaceMonitor* monitor = reinterpret_cast(ifMonitor); monitor->setCallback(callback); } extern "C" void ifMonitorRunAsync(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast(ifMonitor); monitor->runAsync(); } extern "C" void ifMonitorStop(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast(ifMonitor); monitor->stop(); }