/* * 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 <errno.h> #include <linux/rtnetlink.h> #include <net/if.h> #include <poll.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> #include <memory> #include <mutex> #include <thread> #include <unordered_map> #include <vector> #define LOG_TAG "RIL-IFMON" #include <utils/Log.h> 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; } } 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<struct sockaddr*>(&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<std::mutex> lock(mThreadMutex); mThread = std::make_unique<std::thread>([this]() { run(); }); } void requestAddress() { struct { struct nlmsghdr hdr; struct ifaddrmsg msg; char padding[16]; } request; memset(&request, 0, sizeof(request)); request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg)); request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; request.hdr.nlmsg_type = RTM_GETADDR; int status = ::send(mSocketFd, &request, request.hdr.nlmsg_len, 0); if (status < 0 || static_cast<unsigned int>(status) != request.hdr.nlmsg_len) { if (status < 0) { RLOGE("Failed to send netlink request: %s", strerror(errno)); } else { RLOGE("Short send only sent %d out of %d bytes", status, (int)request.hdr.nlmsg_len); } } } void run() { requestAddress(); std::vector<struct pollfd> 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<std::mutex> 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<struct sockaddr*>(&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<size_t>(addrSize) != sizeof(struct sockaddr_nl)) { RLOGE("InterfaceMonitor received invalid address size"); return; } size_t length = static_cast<size_t>(status); auto hdr = reinterpret_cast<struct nlmsghdr*>(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; } NLMSG_NEXT(hdr, length); } } } void handleAddressChange(const struct nlmsghdr* hdr) { if (!mOnAddressChangeCallback) { return; } auto msg = reinterpret_cast<const struct ifaddrmsg*>(NLMSG_DATA(hdr)); std::vector<ifAddress>& ifAddrs = mAddresses[msg->ifa_index]; auto attr = reinterpret_cast<const struct rtattr*>(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<unsigned int, std::vector<ifAddress>> mAddresses; std::unique_ptr<std::thread> mThread; std::mutex mThreadMutex; int mSocketFd; int mControlSocket[2]; }; extern "C" struct ifMonitor* ifMonitorCreate() { auto monitor = std::make_unique<InterfaceMonitor>(); if (!monitor || !monitor->init()) { return nullptr; } return reinterpret_cast<struct ifMonitor*>(monitor.release()); } extern "C" void ifMonitorFree(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor); delete monitor; } extern "C" void ifMonitorSetCallback(struct ifMonitor* ifMonitor, ifMonitorCallback callback) { InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor); monitor->setCallback(callback); } extern "C" void ifMonitorRunAsync(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor); monitor->runAsync(); } extern "C" void ifMonitorStop(struct ifMonitor* ifMonitor) { InterfaceMonitor* monitor = reinterpret_cast<InterfaceMonitor*>(ifMonitor); monitor->stop(); }