1 /*
2  * Copyright (C) 2021 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 #include "InterceptorRelay.h"
18 
19 #include <android-base/logging.h>
20 #include <libnl++/printer.h>
21 #include <poll.h>
22 
23 #include <chrono>
24 
25 #include "util.h"
26 
27 namespace android::nlinterceptor {
28 using namespace std::chrono_literals;
29 
30 static constexpr std::chrono::milliseconds kPollTimeout = 300ms;
31 static constexpr bool kSuperVerbose = false;
32 
InterceptorRelay(uint32_t nlFamily,uint32_t clientNlPid,const std::string & clientName)33 InterceptorRelay::InterceptorRelay(uint32_t nlFamily, uint32_t clientNlPid,
34                                    const std::string& clientName)
35     : mClientName(clientName),
36       mNlSocket(std::make_optional<nl::Socket>(nlFamily, 0, 0)),
37       mClientNlPid(clientNlPid) {}
38 
~InterceptorRelay()39 InterceptorRelay::~InterceptorRelay() {
40     mRunning = false;
41     if (mRelayThread.joinable()) mRelayThread.join();
42 }
43 
getPid()44 uint32_t InterceptorRelay::getPid() {
45     auto pidMaybe = mNlSocket->getPid();
46     CHECK(pidMaybe.has_value()) << "Failed to get pid of nl::Socket!";
47     return *pidMaybe;
48 }
49 
relayMessages()50 void InterceptorRelay::relayMessages() {
51     pollfd fds[] = {
52         mNlSocket->preparePoll(POLLIN),
53     };
54     while (mRunning) {
55         if (poll(fds, countof(fds), kPollTimeout.count()) < 0) {
56             PLOG(FATAL) << "poll failed";
57             return;
58         }
59         const auto nlsockEvents = fds[0].revents;
60 
61         if (isSocketBad(nlsockEvents)) {
62             LOG(ERROR) << "Netlink socket is bad";
63             mRunning = false;
64             return;
65         }
66         if (!isSocketReadable(nlsockEvents)) continue;
67 
68         const auto [msgMaybe, sa] = mNlSocket->receiveFrom();
69         if (!msgMaybe.has_value()) {
70             LOG(ERROR) << "Failed to receive Netlink data!";
71             mRunning = false;
72             return;
73         }
74         const auto msg = *msgMaybe;
75         if (!msg.firstOk()) {
76             LOG(ERROR) << "Netlink packet is malformed!";
77             // Test messages might be empty, this isn't fatal.
78             continue;
79         }
80         if constexpr (kSuperVerbose) {
81             LOG(VERBOSE) << "[" << mClientName
82                          << "] nlMsg: " << nl::toString(msg, NETLINK_GENERIC);
83         }
84 
85         uint32_t destinationPid = 0;
86         if (sa.nl_pid == 0) {
87             destinationPid = mClientNlPid;
88         }
89 
90         if (!mNlSocket->send(msg, destinationPid)) {
91             LOG(ERROR) << "Failed to send Netlink message!";
92             mRunning = false;
93             return;
94         }
95     }
96     LOG(VERBOSE) << "[" << mClientName << "] Exiting relay thread!";
97 }
98 
start()99 bool InterceptorRelay::start() {
100     if (mRunning) {
101         LOG(ERROR)
102             << "Can't relay messages: InterceptorRelay is already running!";
103         return false;
104     }
105     if (mRelayThread.joinable()) {
106         LOG(ERROR) << "relay thread is already running!";
107         return false;
108     }
109     if (!mNlSocket.has_value()) {
110         LOG(ERROR) << "Netlink socket not initialized!";
111         return false;
112     }
113 
114     mRunning = true;
115     mRelayThread = std::thread(&InterceptorRelay::relayMessages, this);
116 
117     LOG(VERBOSE) << "Relay threads initialized";
118     return true;
119 }
120 
subscribeGroup(uint32_t nlGroup)121 bool InterceptorRelay::subscribeGroup(uint32_t nlGroup) {
122     return mNlSocket->addMembership(nlGroup);
123 }
124 
unsubscribeGroup(uint32_t nlGroup)125 bool InterceptorRelay::unsubscribeGroup(uint32_t nlGroup) {
126     return mNlSocket->dropMembership(nlGroup);
127 }
128 
129 }  // namespace android::nlinterceptor
130