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 <aidl/android/hardware/net/nlinterceptor/IInterceptor.h>
18 #include <android-base/logging.h>
19 #include <android-base/macros.h>
20 #include <android/binder_manager.h>
21 #include <libnlinterceptor/libnlinterceptor.h>
22 #include <linux/netlink.h>
23 
24 #include <mutex>
25 
26 namespace android::nlinterceptor {
27 using namespace std::string_literals;
28 using namespace ::aidl::android::hardware::net::nlinterceptor;
29 using base::borrowed_fd;
30 using AidlInterceptedSocket =
31     ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket;
32 
33 static const auto kServiceName = IInterceptor::descriptor + "/default"s;
34 
InterceptedSocket(::aidl::android::hardware::net::nlinterceptor::InterceptedSocket sock)35 InterceptedSocket::InterceptedSocket(
36     ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket sock)
37     : nlFamily(sock.nlFamily), portId(sock.portId) {}
38 
InterceptedSocket(uint32_t nlFamily,uint32_t portId)39 InterceptedSocket::InterceptedSocket(uint32_t nlFamily, uint32_t portId)
40     : nlFamily(nlFamily), portId(portId) {}
41 
operator <<(std::ostream & os,const InterceptedSocket & sock)42 std::ostream& operator<<(std::ostream& os, const InterceptedSocket& sock) {
43     return os << "family: " << sock.nlFamily << ", portId: " << sock.portId;
44 }
45 
operator <(const InterceptedSocket & other) const46 bool InterceptedSocket::operator<(const InterceptedSocket& other) const {
47     if (nlFamily != other.nlFamily) {
48         return nlFamily < other.nlFamily;
49     }
50     return portId < other.portId;
51 }
52 
operator sockaddr_nl() const53 InterceptedSocket::operator sockaddr_nl() const {
54     return {
55         .nl_family = AF_NETLINK,
56         .nl_pad = 0,
57         .nl_pid = portId,
58         .nl_groups = 0,
59     };
60 }
61 
operator AidlInterceptedSocket() const62 InterceptedSocket::operator AidlInterceptedSocket() const {
63     return {
64         .nlFamily = static_cast<int32_t>(nlFamily),
65         .portId = static_cast<int32_t>(portId),
66     };
67 }
68 
isEnabled()69 bool isEnabled() {
70     static std::mutex supportedMutex;
71     static std::optional<bool> interceptorSupported;
72     // Avoid querying service manager when we can cache the result.
73     if (interceptorSupported.has_value()) return *interceptorSupported;
74     std::lock_guard lock(supportedMutex);
75     if (interceptorSupported.has_value()) return *interceptorSupported;
76 
77     if (!AServiceManager_isDeclared(kServiceName.c_str())) {
78         interceptorSupported = false;
79         return false;
80     }
81     interceptorSupported = true;
82     return true;
83 }
84 
getInstance()85 static IInterceptor& getInstance() {
86     static std::mutex instanceMutex;
87     static std::shared_ptr<IInterceptor> interceptorInstance;
88     CHECK(isEnabled()) << "Can't getInstance! Interceptor not supported!";
89     // Don't overwrite the pointer once we've acquired it.
90     if (interceptorInstance != nullptr) return *interceptorInstance;
91     std::lock_guard lock(instanceMutex);
92     if (interceptorInstance != nullptr) return *interceptorInstance;
93     interceptorInstance = IInterceptor::fromBinder(
94         ndk::SpAIBinder(AServiceManager_waitForService(kServiceName.c_str())));
95     CHECK(interceptorInstance != nullptr)
96         << "Failed to get Netlink Interceptor service!";
97     return *interceptorInstance;
98 }
99 
createSocket(borrowed_fd clientSocket,const std::string & clientName)100 std::optional<InterceptedSocket> createSocket(borrowed_fd clientSocket,
101                                               const std::string& clientName) {
102     sockaddr_nl nladdr = {};
103     socklen_t nlsize = sizeof(nladdr);
104     if (getsockname(clientSocket.get(), reinterpret_cast<sockaddr*>(&nladdr),
105                     &nlsize) < 0) {
106         PLOG(ERROR) << "Failed to get pid of fd passed by " << clientName;
107         return std::nullopt;
108     }
109 
110     ::aidl::android::hardware::net::nlinterceptor::InterceptedSocket
111         interceptedSocket;
112     auto aidlStatus = getInstance().createSocket(
113         nladdr.nl_family, nladdr.nl_pid, clientName, &interceptedSocket);
114     if (!aidlStatus.isOk()) {
115         return std::nullopt;
116     }
117 
118     return InterceptedSocket{nladdr.nl_family,
119                              uint32_t(interceptedSocket.portId)};
120 }
121 
closeSocket(const InterceptedSocket & sock)122 void closeSocket(const InterceptedSocket& sock) {
123     auto aidlStatus = getInstance().closeSocket(sock);
124     if (!aidlStatus.isOk()) {
125         LOG(ERROR) << "Failed to close socket with pid = " << sock.portId;
126     }
127 }
128 
subscribe(const InterceptedSocket & sock,uint32_t group)129 bool subscribe(const InterceptedSocket& sock, uint32_t group) {
130     auto aidlStatus = getInstance().subscribeGroup(sock, group);
131     return aidlStatus.isOk();
132 }
133 
unsubscribe(const InterceptedSocket & sock,uint32_t group)134 bool unsubscribe(const InterceptedSocket& sock, uint32_t group) {
135     auto aidlStatus = getInstance().unsubscribeGroup(sock, group);
136     return aidlStatus.isOk();
137 }
138 
android_nlinterceptor_isEnabled()139 extern "C" bool android_nlinterceptor_isEnabled() { return isEnabled(); }
140 
android_nlinterceptor_createSocket(int clientSocketFd,const char * clientName,android_nlinterceptor_InterceptedSocket * interceptedSocket)141 extern "C" bool android_nlinterceptor_createSocket(
142     int clientSocketFd, const char* clientName,
143     android_nlinterceptor_InterceptedSocket* interceptedSocket) {
144     if (!clientName || clientSocketFd <= 0) return false;
145     const auto maybeSocket =
146         createSocket(borrowed_fd(clientSocketFd), clientName);
147     if (!maybeSocket) return false;
148     *interceptedSocket = {.nlFamily = maybeSocket->nlFamily,
149                           .portId = maybeSocket->portId};
150     return true;
151 }
152 
android_nlinterceptor_closeSocket(android_nlinterceptor_InterceptedSocket sock)153 extern "C" void android_nlinterceptor_closeSocket(android_nlinterceptor_InterceptedSocket sock) {
154     closeSocket({sock.nlFamily, sock.portId});
155 }
156 
android_nlinterceptor_subscribe(android_nlinterceptor_InterceptedSocket sock,uint32_t group)157 extern "C" bool android_nlinterceptor_subscribe(android_nlinterceptor_InterceptedSocket sock,
158                                                 uint32_t group) {
159     return subscribe({sock.nlFamily, sock.portId}, group);
160 }
161 
android_nlinterceptor_unsubscribe(android_nlinterceptor_InterceptedSocket sock,uint32_t group)162 extern "C" bool android_nlinterceptor_unsubscribe(android_nlinterceptor_InterceptedSocket sock,
163                                                   uint32_t group) {
164     return unsubscribe({sock.nlFamily, sock.portId}, group);
165 }
166 
167 }  // namespace android::nlinterceptor
168