blob: 8b089ab581509e5a59c047f0f54ecffbd0b74fa3 [file] [log] [blame]
Tyler Wearb37f5512021-10-01 13:22:00 -07001/*
2 * Copyright (C) 2022 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 <android-modules-utils/sdk_level.h>
18#include <cutils/misc.h> // FIRST_APPLICATION_UID
19#include <gtest/gtest.h>
20#include <netinet/in.h>
21#include <android/binder_manager.h>
22#include <android/binder_process.h>
23
24#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
25
26using aidl::android::net::connectivity::aidl::IConnectivityNative;
27
28class ConnectivityNativeBinderTest : public ::testing::Test {
29 public:
30 std::vector<int32_t> mActualBlockedPorts;
31
32 ConnectivityNativeBinderTest() {
33 AIBinder* binder = AServiceManager_getService("connectivity_native");
34 ndk::SpAIBinder sBinder = ndk::SpAIBinder(binder);
35 mService = aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder);
36 }
37
38 void SetUp() override {
39 // Skip test case if not on T.
40 if (!android::modules::sdklevel::IsAtLeastT()) GTEST_SKIP() <<
41 "Should be at least T device.";
42
43 ASSERT_NE(nullptr, mService.get());
44
45 // If there are already ports being blocked on device unblockAllPortsForBind() store
46 // the currently blocked ports and add them back at the end of the test. Do this for
47 // every test case so additional test cases do not forget to add ports back.
48 ndk::ScopedAStatus status = mService->getPortsBlockedForBind(&mActualBlockedPorts);
49 EXPECT_TRUE(status.isOk()) << status.getDescription ();
50
51 }
52
53 void TearDown() override {
54 ndk::ScopedAStatus status;
55 if (mActualBlockedPorts.size() > 0) {
56 for (int i : mActualBlockedPorts) {
57 mService->blockPortForBind(i);
58 EXPECT_TRUE(status.isOk()) << status.getDescription ();
59 }
60 }
61 }
62
63 protected:
64 std::shared_ptr<IConnectivityNative> mService;
65
66 void runSocketTest (sa_family_t family, const int type, bool blockPort) {
67 ndk::ScopedAStatus status;
68 in_port_t port = 0;
69 int sock, sock2;
70 // Open two sockets with SO_REUSEADDR and expect they can both bind to port.
71 sock = openSocket(&port, family, type, false /* expectBindFail */);
72 sock2 = openSocket(&port, family, type, false /* expectBindFail */);
73
74 int blockedPort = 0;
75 if (blockPort) {
76 blockedPort = ntohs(port);
77 status = mService->blockPortForBind(blockedPort);
78 EXPECT_TRUE(status.isOk()) << status.getDescription ();
79 }
80
81 int sock3 = openSocket(&port, family, type, blockPort /* expectBindFail */);
82
83 if (blockPort) {
84 EXPECT_EQ(-1, sock3);
85 status = mService->unblockPortForBind(blockedPort);
86 EXPECT_TRUE(status.isOk()) << status.getDescription ();
87 } else {
88 EXPECT_NE(-1, sock3);
89 }
90
91 close(sock);
92 close(sock2);
93 close(sock3);
94 }
95
96 /*
97 * Open the socket and update the port.
98 */
99 int openSocket(in_port_t* port, sa_family_t family, const int type, bool expectBindFail) {
100 int ret = 0;
101 int enable = 1;
102 const int sock = socket(family, type, 0);
103 ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
104 EXPECT_EQ(0, ret);
105
106 if (family == AF_INET) {
107 struct sockaddr_in addr4 = { .sin_family = family, .sin_port = htons(*port) };
108 ret = bind(sock, (struct sockaddr*) &addr4, sizeof(addr4));
109 } else {
110 struct sockaddr_in6 addr6 = { .sin6_family = family, .sin6_port = htons(*port) };
111 ret = bind(sock, (struct sockaddr*) &addr6, sizeof(addr6));
112 }
113
114 if (expectBindFail) {
115 EXPECT_NE(0, ret);
116 // If port is blocked, return here since the port is not needed
117 // for subsequent sockets.
118 close(sock);
119 return -1;
120 }
121 EXPECT_EQ(0, ret) << "bind unexpectedly failed, errno: " << errno;
122
123 if (family == AF_INET) {
124 struct sockaddr_in sin;
125 socklen_t len = sizeof(sin);
126 EXPECT_NE(-1, getsockname(sock, (struct sockaddr *)&sin, &len));
127 EXPECT_NE(0, ntohs(sin.sin_port));
128 if (*port != 0) EXPECT_EQ(*port, ntohs(sin.sin_port));
129 *port = ntohs(sin.sin_port);
130 } else {
131 struct sockaddr_in6 sin;
132 socklen_t len = sizeof(sin);
133 EXPECT_NE(-1, getsockname(sock, (struct sockaddr *)&sin, &len));
134 EXPECT_NE(0, ntohs(sin.sin6_port));
135 if (*port != 0) EXPECT_EQ(*port, ntohs(sin.sin6_port));
136 *port = ntohs(sin.sin6_port);
137 }
138 return sock;
139 }
140};
141
142TEST_F(ConnectivityNativeBinderTest, PortUnblockedV4Udp) {
143 runSocketTest(AF_INET, SOCK_DGRAM, false);
144}
145
146TEST_F(ConnectivityNativeBinderTest, PortUnblockedV4Tcp) {
147 runSocketTest(AF_INET, SOCK_STREAM, false);
148}
149
150TEST_F(ConnectivityNativeBinderTest, PortUnblockedV6Udp) {
151 runSocketTest(AF_INET6, SOCK_DGRAM, false);
152}
153
154TEST_F(ConnectivityNativeBinderTest, PortUnblockedV6Tcp) {
155 runSocketTest(AF_INET6, SOCK_STREAM, false);
156}
157
158TEST_F(ConnectivityNativeBinderTest, BlockPort4Udp) {
159 runSocketTest(AF_INET, SOCK_DGRAM, true);
160}
161
162TEST_F(ConnectivityNativeBinderTest, BlockPort4Tcp) {
163 runSocketTest(AF_INET, SOCK_STREAM, true);
164}
165
166TEST_F(ConnectivityNativeBinderTest, BlockPort6Udp) {
167 runSocketTest(AF_INET6, SOCK_DGRAM, true);
168}
169
170TEST_F(ConnectivityNativeBinderTest, BlockPort6Tcp) {
171 runSocketTest(AF_INET6, SOCK_STREAM, true);
172}
173
174TEST_F(ConnectivityNativeBinderTest, BlockPortTwice) {
175 ndk::ScopedAStatus status = mService->blockPortForBind(5555);
176 EXPECT_TRUE(status.isOk()) << status.getDescription ();
177 status = mService->blockPortForBind(5555);
178 EXPECT_TRUE(status.isOk()) << status.getDescription ();
179 status = mService->unblockPortForBind(5555);
180 EXPECT_TRUE(status.isOk()) << status.getDescription ();
181}
182
183TEST_F(ConnectivityNativeBinderTest, GetBlockedPorts) {
184 ndk::ScopedAStatus status;
185 std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
186 for (int i : blockedPorts) {
187 status = mService->blockPortForBind(i);
188 EXPECT_TRUE(status.isOk()) << status.getDescription ();
189 }
190 std::vector<int32_t> actualBlockedPorts;
191 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
192 EXPECT_TRUE(status.isOk()) << status.getDescription ();
193 EXPECT_FALSE(actualBlockedPorts.empty());
194 EXPECT_EQ(blockedPorts, actualBlockedPorts);
195
196 // Remove the ports we added.
197 status = mService->unblockAllPortsForBind();
198 EXPECT_TRUE(status.isOk()) << status.getDescription ();
199 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
200 EXPECT_TRUE(status.isOk()) << status.getDescription ();
201 EXPECT_TRUE(actualBlockedPorts.empty());
202}
203
204TEST_F(ConnectivityNativeBinderTest, UnblockAllPorts) {
205 ndk::ScopedAStatus status;
206 std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
207
208 if (mActualBlockedPorts.size() > 0) {
209 status = mService->unblockAllPortsForBind();
210 }
211
212 for (int i : blockedPorts) {
213 status = mService->blockPortForBind(i);
214 EXPECT_TRUE(status.isOk()) << status.getDescription ();
215 }
216
217 std::vector<int32_t> actualBlockedPorts;
218 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
219 EXPECT_TRUE(status.isOk()) << status.getDescription ();
220 EXPECT_FALSE(actualBlockedPorts.empty());
221
222 status = mService->unblockAllPortsForBind();
223 EXPECT_TRUE(status.isOk()) << status.getDescription ();
224 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
225 EXPECT_TRUE(status.isOk()) << status.getDescription ();
226 EXPECT_TRUE(actualBlockedPorts.empty());
227 // If mActualBlockedPorts is not empty, ports will be added back in teardown.
228}
229
230TEST_F(ConnectivityNativeBinderTest, BlockNegativePort) {
231 int retry = 0;
232 ndk::ScopedAStatus status;
233 do {
234 status = mService->blockPortForBind(-1);
235 // TODO: find out why transaction failed is being thrown on the first attempt.
236 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
237 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
238}
239
240TEST_F(ConnectivityNativeBinderTest, UnblockNegativePort) {
241 int retry = 0;
242 ndk::ScopedAStatus status;
243 do {
244 status = mService->unblockPortForBind(-1);
245 // TODO: find out why transaction failed is being thrown on the first attempt.
246 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
247 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
248}
249
250TEST_F(ConnectivityNativeBinderTest, BlockMaxPort) {
251 int retry = 0;
252 ndk::ScopedAStatus status;
253 do {
254 status = mService->blockPortForBind(65536);
255 // TODO: find out why transaction failed is being thrown on the first attempt.
256 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
257 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
258}
259
260TEST_F(ConnectivityNativeBinderTest, UnblockMaxPort) {
261 int retry = 0;
262 ndk::ScopedAStatus status;
263 do {
264 status = mService->unblockPortForBind(65536);
265 // TODO: find out why transaction failed is being thrown on the first attempt.
266 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
267 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
268}
269
270TEST_F(ConnectivityNativeBinderTest, CheckPermission) {
271 int retry = 0;
272 int curUid = getuid();
273 EXPECT_EQ(0, seteuid(FIRST_APPLICATION_UID + 2000)) << "seteuid failed: " << strerror(errno);
274 ndk::ScopedAStatus status;
275 do {
276 status = mService->blockPortForBind(5555);
277 // TODO: find out why transaction failed is being thrown on the first attempt.
278 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
279 EXPECT_EQ(EX_SECURITY, status.getExceptionCode());
280 EXPECT_EQ(0, seteuid(curUid)) << "seteuid failed: " << strerror(errno);
281}