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