Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2017 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 #define LOG_TAG "NetlinkListener"
     18 
     19 #include <sstream>
     20 #include <vector>
     21 
     22 #include <linux/netfilter/nfnetlink.h>
     23 
     24 #include <cutils/log.h>
     25 #include <netdutils/Misc.h>
     26 #include <netdutils/Syscalls.h>
     27 
     28 #include "NetlinkListener.h"
     29 
     30 namespace android {
     31 namespace net {
     32 
     33 using netdutils::Fd;
     34 using netdutils::Slice;
     35 using netdutils::Status;
     36 using netdutils::UniqueFd;
     37 using netdutils::findWithDefault;
     38 using netdutils::forEachNetlinkMessage;
     39 using netdutils::makeSlice;
     40 using netdutils::sSyscalls;
     41 using netdutils::status::ok;
     42 using netdutils::statusFromErrno;
     43 
     44 namespace {
     45 
     46 constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
     47 
     48 constexpr sockaddr_nl kKernelAddr = {
     49     .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
     50 };
     51 
     52 const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
     53     std::stringstream ss;
     54     ss << nlmsg;
     55     ALOGE("unhandled netlink message: %s", ss.str().c_str());
     56 };
     57 
     58 }  // namespace
     59 
     60 NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock)
     61     : mEvent(std::move(event)), mSock(std::move(sock)), mWorker([this]() { run(); }) {
     62     const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
     63         std::stringstream ss;
     64         ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
     65         ALOGE("unhandled netlink message: %s", ss.str().c_str());
     66     };
     67     expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
     68 }
     69 
     70 NetlinkListener::~NetlinkListener() {
     71     const auto& sys = sSyscalls.get();
     72     const uint64_t data = 1;
     73     // eventfd should never enter an error state unexpectedly
     74     expectOk(sys.write(mEvent, makeSlice(data)).status());
     75     mWorker.join();
     76 }
     77 
     78 Status NetlinkListener::send(const Slice msg) {
     79     const auto& sys = sSyscalls.get();
     80     ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
     81     if (sent != msg.size()) {
     82         return statusFromErrno(EMSGSIZE, "unexpect message size");
     83     }
     84     return ok;
     85 }
     86 
     87 Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
     88     std::lock_guard<std::mutex> guard(mMutex);
     89     mDispatchMap[type] = fn;
     90     return ok;
     91 }
     92 
     93 Status NetlinkListener::unsubscribe(uint16_t type) {
     94     std::lock_guard<std::mutex> guard(mMutex);
     95     mDispatchMap.erase(type);
     96     return ok;
     97 }
     98 
     99 Status NetlinkListener::run() {
    100     std::vector<char> rxbuf(4096);
    101 
    102     const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
    103         std::lock_guard<std::mutex> guard(mMutex);
    104         const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
    105         fn(nlmsg, buf);
    106     };
    107 
    108     const auto& sys = sSyscalls.get();
    109     const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
    110     const int events = POLLIN | POLLRDHUP | POLLERR | POLLHUP;
    111     const double timeout = 3600;
    112     while (true) {
    113         ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
    114         // After mEvent becomes readable, we should stop servicing mSock and return
    115         if (revents[0] & POLLIN) {
    116             break;
    117         }
    118         if (revents[1] & POLLIN) {
    119             auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
    120             if (rx.status().code() == ENOBUFS) {
    121                 // Ignore ENOBUFS - the socket is still usable
    122                 // TODO: Users other than NFLOG may need to know about this
    123                 continue;
    124             }
    125             forEachNetlinkMessage(rx.value(), rxHandler);
    126         }
    127     }
    128     return ok;
    129 }
    130 
    131 }  // namespace net
    132 }  // namespace android
    133