1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/android/hardware/net/nlinterceptor/IInterceptor.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android/binder_manager.h>
#include <libnlinterceptor/libnlinterceptor.h>
#include <linux/netlink.h>
#include <mutex>
namespace android::nlinterceptor {
using namespace std::string_literals;
using namespace ::aidl::android::hardware::net::nlinterceptor;
using base::borrowed_fd;
using AidlInterceptedSocket =
::aidl::android::hardware::net::nlinterceptor::InterceptedSocket;
static const auto kServiceName = IInterceptor::descriptor + "/default"s;
InterceptedSocket::InterceptedSocket(
::aidl::android::hardware::net::nlinterceptor::InterceptedSocket sock)
: nlFamily(sock.nlFamily), portId(sock.portId) {}
InterceptedSocket::InterceptedSocket(uint32_t nlFamily, uint32_t portId)
: nlFamily(nlFamily), portId(portId) {}
std::ostream& operator<<(std::ostream& os, const InterceptedSocket& sock) {
return os << "family: " << sock.nlFamily << ", portId: " << sock.portId;
}
bool InterceptedSocket::operator<(const InterceptedSocket& other) const {
if (nlFamily != other.nlFamily) {
return nlFamily < other.nlFamily;
}
return portId < other.portId;
}
InterceptedSocket::operator sockaddr_nl() const {
return {
.nl_family = AF_NETLINK,
.nl_pad = 0,
.nl_pid = portId,
.nl_groups = 0,
};
}
InterceptedSocket::operator AidlInterceptedSocket() const {
return {
.nlFamily = static_cast<int32_t>(nlFamily),
.portId = static_cast<int32_t>(portId),
};
}
bool isEnabled() {
static std::mutex supportedMutex;
static std::optional<bool> interceptorSupported;
// Avoid querying service manager when we can cache the result.
if (interceptorSupported.has_value()) return *interceptorSupported;
std::lock_guard lock(supportedMutex);
if (interceptorSupported.has_value()) return *interceptorSupported;
if (!AServiceManager_isDeclared(kServiceName.c_str())) {
interceptorSupported = false;
return false;
}
interceptorSupported = true;
return true;
}
static IInterceptor& getInstance() {
static std::mutex instanceMutex;
static std::shared_ptr<IInterceptor> interceptorInstance;
CHECK(isEnabled()) << "Can't getInstance! Interceptor not supported!";
// Don't overwrite the pointer once we've acquired it.
if (interceptorInstance != nullptr) return *interceptorInstance;
std::lock_guard lock(instanceMutex);
if (interceptorInstance != nullptr) return *interceptorInstance;
interceptorInstance = IInterceptor::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(kServiceName.c_str())));
CHECK(interceptorInstance != nullptr)
<< "Failed to get Netlink Interceptor service!";
return *interceptorInstance;
}
std::optional<InterceptedSocket> createSocket(borrowed_fd clientSocket,
const std::string& clientName) {
sockaddr_nl nladdr = {};
socklen_t nlsize = sizeof(nladdr);
if (getsockname(clientSocket.get(), reinterpret_cast<sockaddr*>(&nladdr),
&nlsize) < 0) {
PLOG(ERROR) << "Failed to get pid of fd passed by " << clientName;
return std::nullopt;
}
::aidl::android::hardware::net::nlinterceptor::InterceptedSocket
interceptedSocket;
auto aidlStatus = getInstance().createSocket(
nladdr.nl_family, nladdr.nl_pid, clientName, &interceptedSocket);
if (!aidlStatus.isOk()) {
return std::nullopt;
}
return InterceptedSocket{nladdr.nl_family,
uint32_t(interceptedSocket.portId)};
}
void closeSocket(const InterceptedSocket& sock) {
auto aidlStatus = getInstance().closeSocket(sock);
if (!aidlStatus.isOk()) {
LOG(ERROR) << "Failed to close socket with pid = " << sock.portId;
}
}
bool subscribe(const InterceptedSocket& sock, uint32_t group) {
auto aidlStatus = getInstance().subscribeGroup(sock, group);
return aidlStatus.isOk();
}
bool unsubscribe(const InterceptedSocket& sock, uint32_t group) {
auto aidlStatus = getInstance().unsubscribeGroup(sock, group);
return aidlStatus.isOk();
}
extern "C" bool android_nlinterceptor_isEnabled() { return isEnabled(); }
extern "C" bool android_nlinterceptor_createSocket(
int clientSocketFd, const char* clientName,
android_nlinterceptor_InterceptedSocket* interceptedSocket) {
if (!clientName || clientSocketFd <= 0) return false;
const auto maybeSocket =
createSocket(borrowed_fd(clientSocketFd), clientName);
if (!maybeSocket) return false;
*interceptedSocket = {.nlFamily = maybeSocket->nlFamily,
.portId = maybeSocket->portId};
return true;
}
extern "C" void android_nlinterceptor_closeSocket(
const android_nlinterceptor_InterceptedSocket* sock) {
if (!sock) {
LOG(ERROR) << "Can't close socket identified by a null pointer!";
return;
}
closeSocket({sock->nlFamily, sock->portId});
}
extern "C" bool android_nlinterceptor_subscribe(
const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
if (!sock) return false;
return subscribe({sock->nlFamily, sock->portId}, group);
}
extern "C" bool android_nlinterceptor_unsubscribe(
const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
if (!sock) return false;
return unsubscribe({sock->nlFamily, sock->portId}, group);
}
} // namespace android::nlinterceptor
|