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 <log/log.h>
25 #include <netdutils/Misc.h>
26 #include <netdutils/NetlinkListener.h>
27 #include <netdutils/Syscalls.h>
28 
29 namespace android {
30 namespace netdutils {
31 
32 using netdutils::Fd;
33 using netdutils::Slice;
34 using netdutils::Status;
35 using netdutils::UniqueFd;
36 using netdutils::findWithDefault;
37 using netdutils::forEachNetlinkMessage;
38 using netdutils::makeSlice;
39 using netdutils::sSyscalls;
40 using netdutils::status::ok;
41 using netdutils::statusFromErrno;
42 
43 namespace {
44 
45 constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
46 
47 constexpr sockaddr_nl kKernelAddr = {
48     .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
49 };
50 
__anonf086d5cc0202(const nlmsghdr& nlmsg, const Slice) 51 const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
52     std::stringstream ss;
53     ss << nlmsg;
54     ALOGE("unhandled netlink message: %s", ss.str().c_str());
55 };
56 
57 }  // namespace
58 
NetlinkListener(UniqueFd event,UniqueFd sock,const std::string & name)59 NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name)
60     : mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) {
61     const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
62         std::stringstream ss;
63         ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
64         ALOGE("unhandled netlink message: %s", ss.str().c_str());
65     };
66     expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
67 
68     mErrorHandler = [& name = mThreadName](const int fd, const int err) {
69         ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err));
70     };
71 
72     // Start the thread
73     mWorker = std::thread([this]() { run().ignoreError(); });
74 }
75 
~NetlinkListener()76 NetlinkListener::~NetlinkListener() {
77     const auto& sys = sSyscalls.get();
78     const uint64_t data = 1;
79     // eventfd should never enter an error state unexpectedly
80     expectOk(sys.write(mEvent, makeSlice(data)).status());
81     mWorker.join();
82 }
83 
send(const Slice msg)84 Status NetlinkListener::send(const Slice msg) {
85     const auto& sys = sSyscalls.get();
86     ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
87     if (sent != msg.size()) {
88         return statusFromErrno(EMSGSIZE, "unexpect message size");
89     }
90     return ok;
91 }
92 
subscribe(uint16_t type,const DispatchFn & fn)93 Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
94     std::lock_guard guard(mMutex);
95     mDispatchMap[type] = fn;
96     return ok;
97 }
98 
unsubscribe(uint16_t type)99 Status NetlinkListener::unsubscribe(uint16_t type) {
100     std::lock_guard guard(mMutex);
101     mDispatchMap.erase(type);
102     return ok;
103 }
104 
registerSkErrorHandler(const SkErrorHandler & handler)105 void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) {
106     mErrorHandler = handler;
107 }
108 
run()109 Status NetlinkListener::run() {
110     std::vector<char> rxbuf(4096);
111 
112     const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
113         std::lock_guard guard(mMutex);
114         const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
115         fn(nlmsg, buf);
116     };
117 
118     if (mThreadName.length() > 0) {
119         int ret = pthread_setname_np(pthread_self(), mThreadName.c_str());
120         if (ret) {
121             ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret));
122         }
123     }
124     const auto& sys = sSyscalls.get();
125     const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
126     const int events = POLLIN;
127     const double timeout = 3600;
128     while (true) {
129         ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
130         // After mEvent becomes readable, we should stop servicing mSock and return
131         if (revents[0] & POLLIN) {
132             break;
133         }
134         if (revents[1] & (POLLIN|POLLERR)) {
135             auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
136             int err = rx.status().code();
137             if (err) {
138                 // Ignore errors. The only error we expect to see here is ENOBUFS, and there's
139                 // nothing we can do about that. The recvfrom above will already have cleared the
140                 // error indication and ensured we won't get EPOLLERR again.
141                 // TODO: Consider using NETLINK_NO_ENOBUFS.
142                 mErrorHandler(((Fd) mSock).get(), err);
143                 continue;
144             }
145             forEachNetlinkMessage(rx.value(), rxHandler);
146         }
147     }
148     return ok;
149 }
150 
151 }  // namespace netdutils
152 }  // namespace android
153