• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
__anonfd0bf43c0202(const nlmsghdr& nlmsg, const Slice) 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 
NetlinkListener(UniqueFd event,UniqueFd sock)60 NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock)
61     : mEvent(std::move(event)), mSock(std::move(sock)), mWorker([this]() { run(); }) {
__anonfd0bf43c0402(const nlmsghdr& nlmsg, const Slice msg) 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 
~NetlinkListener()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 
send(const Slice msg)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 
subscribe(uint16_t type,const DispatchFn & fn)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 
unsubscribe(uint16_t type)93 Status NetlinkListener::unsubscribe(uint16_t type) {
94     std::lock_guard<std::mutex> guard(mMutex);
95     mDispatchMap.erase(type);
96     return ok;
97 }
98 
run()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