1 /*
2 * Copyright 2016 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 * TetherControllerTest.cpp - unit tests for TetherController.cpp
17 */
18
19 #include <string>
20 #include <vector>
21
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26
27 #include <gtest/gtest.h>
28
29 #include <android-base/stringprintf.h>
30 #include <android-base/strings.h>
31 #include <netdutils/StatusOr.h>
32
33 #include "TetherController.h"
34 #include "IptablesBaseTest.h"
35
36 using android::base::Join;
37 using android::base::StringPrintf;
38 using android::netdutils::StatusOr;
39 using TetherStats = android::net::TetherController::TetherStats;
40 using TetherStatsList = android::net::TetherController::TetherStatsList;
41
42 namespace android {
43 namespace net {
44
45 class TetherControllerTest : public IptablesBaseTest {
46 public:
TetherControllerTest()47 TetherControllerTest() {
48 TetherController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
49 }
50
51 protected:
52 TetherController mTetherCtrl;
53
setDefaults()54 int setDefaults() {
55 return mTetherCtrl.setDefaults();
56 }
57
58 const ExpectedIptablesCommands FLUSH_COMMANDS = {
59 { V4, "*filter\n"
60 ":tetherctrl_FORWARD -\n"
61 "-A tetherctrl_FORWARD -j DROP\n"
62 "COMMIT\n"
63 "*nat\n"
64 ":tetherctrl_nat_POSTROUTING -\n"
65 "COMMIT\n" },
66 { V6, "*filter\n"
67 ":tetherctrl_FORWARD -\n"
68 "COMMIT\n"
69 "*raw\n"
70 ":tetherctrl_raw_PREROUTING -\n"
71 "COMMIT\n" },
72 };
73
74 const ExpectedIptablesCommands SETUP_COMMANDS = {
75 { V4, "*filter\n"
76 ":tetherctrl_FORWARD -\n"
77 "-A tetherctrl_FORWARD -j DROP\n"
78 "COMMIT\n"
79 "*nat\n"
80 ":tetherctrl_nat_POSTROUTING -\n"
81 "COMMIT\n" },
82 { V6, "*filter\n"
83 ":tetherctrl_FORWARD -\n"
84 "COMMIT\n"
85 "*raw\n"
86 ":tetherctrl_raw_PREROUTING -\n"
87 "COMMIT\n" },
88 { V4, "*mangle\n"
89 "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
90 "-j TCPMSS --clamp-mss-to-pmtu\n"
91 "COMMIT\n" },
92 { V4V6, "*filter\n"
93 ":tetherctrl_counters -\n"
94 "COMMIT\n" },
95 };
96
firstIPv4UpstreamCommands(const char * extIf)97 ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
98 std::string v4Cmd = StringPrintf(
99 "*nat\n"
100 "-A tetherctrl_nat_POSTROUTING -o %s -j MASQUERADE\n"
101 "COMMIT\n", extIf);
102 return {
103 { V4, v4Cmd },
104 };
105 }
106
firstIPv6UpstreamCommands()107 ExpectedIptablesCommands firstIPv6UpstreamCommands() {
108 std::string v6Cmd =
109 "*filter\n"
110 "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
111 "COMMIT\n";
112 return {
113 { V6, v6Cmd },
114 };
115 }
116
117 template<typename T>
appendAll(std::vector<T> & cmds,const std::vector<T> & appendCmds)118 void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
119 cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
120 }
121
startNatCommands(const char * intIf,const char * extIf,bool withCounterChainRules)122 ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf,
123 bool withCounterChainRules) {
124 std::string rpfilterCmd = StringPrintf(
125 "*raw\n"
126 "-A tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
127 "COMMIT\n", intIf);
128
129 std::vector<std::string> v4Cmds = {
130 "*filter",
131 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state"
132 " ESTABLISHED,RELATED -g tetherctrl_counters", extIf, intIf),
133 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
134 intIf, extIf),
135 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters",
136 intIf, extIf),
137 };
138
139 std::vector<std::string> v6Cmds = {
140 "*filter",
141 };
142
143 if (withCounterChainRules) {
144 const std::vector<std::string> counterRules = {
145 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", intIf, extIf),
146 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", extIf, intIf),
147 };
148
149 appendAll(v4Cmds, counterRules);
150 appendAll(v6Cmds, counterRules);
151 }
152
153 appendAll(v4Cmds, {
154 "-D tetherctrl_FORWARD -j DROP",
155 "-A tetherctrl_FORWARD -j DROP",
156 "COMMIT\n",
157 });
158
159 v6Cmds.push_back("COMMIT\n");
160
161 return {
162 { V6, rpfilterCmd },
163 { V4, Join(v4Cmds, '\n') },
164 { V6, Join(v6Cmds, '\n') },
165 };
166 }
167
168 constexpr static const bool WITH_COUNTERS = true;
169 constexpr static const bool NO_COUNTERS = false;
170 constexpr static const bool WITH_IPV6 = true;
171 constexpr static const bool NO_IPV6 = false;
allNewNatCommands(const char * intIf,const char * extIf,bool withCounterChainRules,bool withIPv6Upstream)172 ExpectedIptablesCommands allNewNatCommands(
173 const char *intIf, const char *extIf, bool withCounterChainRules,
174 bool withIPv6Upstream) {
175
176 ExpectedIptablesCommands commands;
177 ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
178 ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
179 withCounterChainRules);
180
181 appendAll(commands, setupFirstIPv4Commands);
182 if (withIPv6Upstream) {
183 ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
184 appendAll(commands, setupFirstIPv6Commands);
185 }
186 appendAll(commands, startFirstNatCommands);
187
188 return commands;
189 }
190
stopNatCommands(const char * intIf,const char * extIf)191 ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) {
192 std::string rpfilterCmd = StringPrintf(
193 "*raw\n"
194 "-D tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
195 "COMMIT\n", intIf);
196
197 std::vector<std::string> v4Cmds = {
198 "*filter",
199 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state"
200 " ESTABLISHED,RELATED -g tetherctrl_counters", extIf, intIf),
201 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
202 intIf, extIf),
203 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters",
204 intIf, extIf),
205 "COMMIT\n",
206 };
207
208 return {
209 { V6, rpfilterCmd },
210 { V4, Join(v4Cmds, '\n') },
211 };
212
213 }
214 };
215
TEST_F(TetherControllerTest,TestSetupIptablesHooks)216 TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
217 mTetherCtrl.setupIptablesHooks();
218 expectIptablesRestoreCommands(SETUP_COMMANDS);
219 }
220
TEST_F(TetherControllerTest,TestSetDefaults)221 TEST_F(TetherControllerTest, TestSetDefaults) {
222 setDefaults();
223 expectIptablesRestoreCommands(FLUSH_COMMANDS);
224 }
225
TEST_F(TetherControllerTest,TestAddAndRemoveNat)226 TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
227 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
228 ExpectedIptablesCommands firstNat = allNewNatCommands(
229 "wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6);
230 mTetherCtrl.enableNat("wlan0", "rmnet0");
231 expectIptablesRestoreCommands(firstNat);
232
233 // Start second NAT on same upstream. Expect only the counter rules to be created.
234 ExpectedIptablesCommands startOtherNatOnSameUpstream = startNatCommands(
235 "usb0", "rmnet0", WITH_COUNTERS);
236 mTetherCtrl.enableNat("usb0", "rmnet0");
237 expectIptablesRestoreCommands(startOtherNatOnSameUpstream);
238
239 // Remove the first NAT.
240 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
241 mTetherCtrl.disableNat("wlan0", "rmnet0");
242 expectIptablesRestoreCommands(stopFirstNat);
243
244 // Remove the last NAT. Expect rules to be cleared.
245 ExpectedIptablesCommands stopLastNat = stopNatCommands("usb0", "rmnet0");
246
247 appendAll(stopLastNat, FLUSH_COMMANDS);
248 mTetherCtrl.disableNat("usb0", "rmnet0");
249 expectIptablesRestoreCommands(stopLastNat);
250
251 // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
252 firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6);
253 mTetherCtrl.enableNat("wlan0", "rmnet0");
254 expectIptablesRestoreCommands(firstNat);
255
256 // Remove it again. Expect rules to be cleared.
257 stopLastNat = stopNatCommands("wlan0", "rmnet0");
258 appendAll(stopLastNat, FLUSH_COMMANDS);
259 mTetherCtrl.disableNat("wlan0", "rmnet0");
260 expectIptablesRestoreCommands(stopLastNat);
261 }
262
TEST_F(TetherControllerTest,TestMultipleUpstreams)263 TEST_F(TetherControllerTest, TestMultipleUpstreams) {
264 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
265 ExpectedIptablesCommands firstNat = allNewNatCommands(
266 "wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6);
267 mTetherCtrl.enableNat("wlan0", "rmnet0");
268 expectIptablesRestoreCommands(firstNat);
269
270 // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
271 // but no counter rules for IPv6.
272 ExpectedIptablesCommands secondNat = allNewNatCommands(
273 "wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6);
274 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
275 expectIptablesRestoreCommands(secondNat);
276
277 // Pretend that the caller has forgotten that it set up the second NAT, and asks us to do so
278 // again. Expect that we take no action.
279 const ExpectedIptablesCommands NONE = {};
280 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
281 expectIptablesRestoreCommands(NONE);
282
283 // Remove the second NAT.
284 ExpectedIptablesCommands stopSecondNat = stopNatCommands("wlan0", "v4-rmnet0");
285 mTetherCtrl.disableNat("wlan0", "v4-rmnet0");
286 expectIptablesRestoreCommands(stopSecondNat);
287
288 // Remove the first NAT. Expect rules to be cleared.
289 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
290 appendAll(stopFirstNat, FLUSH_COMMANDS);
291 mTetherCtrl.disableNat("wlan0", "rmnet0");
292 expectIptablesRestoreCommands(stopFirstNat);
293 }
294
295 std::string kTetherCounterHeaders = Join(std::vector<std::string> {
296 "Chain tetherctrl_counters (4 references)",
297 " pkts bytes target prot opt in out source destination",
298 }, '\n');
299
300 std::string kIPv4TetherCounters = Join(std::vector<std::string> {
301 "Chain tetherctrl_counters (4 references)",
302 " pkts bytes target prot opt in out source destination",
303 " 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0",
304 " 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0",
305 " 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0",
306 " 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0",
307 }, '\n');
308
309 std::string kIPv6TetherCounters = Join(std::vector<std::string> {
310 "Chain tetherctrl_counters (2 references)",
311 " pkts bytes target prot opt in out source destination",
312 " 10000 10000000 RETURN all wlan0 rmnet0 ::/0 ::/0",
313 " 20000 20000000 RETURN all rmnet0 wlan0 ::/0 ::/0",
314 }, '\n');
315
expectTetherStatsEqual(const TetherController::TetherStats & expected,const TetherController::TetherStats & actual)316 void expectTetherStatsEqual(const TetherController::TetherStats& expected,
317 const TetherController::TetherStats& actual) {
318 EXPECT_EQ(expected.intIface, actual.intIface);
319 EXPECT_EQ(expected.extIface, actual.extIface);
320 EXPECT_EQ(expected.rxBytes, actual.rxBytes);
321 EXPECT_EQ(expected.txBytes, actual.txBytes);
322 EXPECT_EQ(expected.rxPackets, actual.rxPackets);
323 EXPECT_EQ(expected.txPackets, actual.txPackets);
324 }
325
TEST_F(TetherControllerTest,TestGetTetherStats)326 TEST_F(TetherControllerTest, TestGetTetherStats) {
327 // Finding no headers is an error.
328 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
329 clearIptablesRestoreOutput();
330
331 // Finding only v4 or only v6 headers is an error.
332 addIptablesRestoreOutput(kTetherCounterHeaders, "");
333 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
334 clearIptablesRestoreOutput();
335
336 addIptablesRestoreOutput("", kTetherCounterHeaders);
337 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
338 clearIptablesRestoreOutput();
339
340 // Finding headers but no stats is not an error.
341 addIptablesRestoreOutput(kTetherCounterHeaders, kTetherCounterHeaders);
342 StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
343 ASSERT_TRUE(isOk(result));
344 TetherStatsList actual = result.value();
345 ASSERT_EQ(0U, actual.size());
346 clearIptablesRestoreOutput();
347
348
349 addIptablesRestoreOutput(kIPv6TetherCounters);
350 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
351 clearIptablesRestoreOutput();
352
353 // IPv4 and IPv6 counters are properly added together.
354 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
355 TetherStats expected0("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
356 TetherStats expected1("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
357 result = mTetherCtrl.getTetherStats();
358 ASSERT_TRUE(isOk(result));
359 actual = result.value();
360 ASSERT_EQ(2U, actual.size());
361 expectTetherStatsEqual(expected0, result.value()[0]);
362 expectTetherStatsEqual(expected1, result.value()[1]);
363 clearIptablesRestoreOutput();
364
365 // No stats: error.
366 addIptablesRestoreOutput("", kIPv6TetherCounters);
367 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
368 clearIptablesRestoreOutput();
369
370 addIptablesRestoreOutput(kIPv4TetherCounters, "");
371 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
372 clearIptablesRestoreOutput();
373
374 // Include only one pair of interfaces and things are fine.
375 std::vector<std::string> counterLines = android::base::Split(kIPv4TetherCounters, "\n");
376 std::vector<std::string> brokenCounterLines = counterLines;
377 counterLines.resize(4);
378 std::string counters = Join(counterLines, "\n") + "\n";
379 addIptablesRestoreOutput(counters, counters);
380 TetherStats expected1_0("wlan0", "rmnet0", 4004, 54, 4746, 52);
381 result = mTetherCtrl.getTetherStats();
382 ASSERT_TRUE(isOk(result));
383 actual = result.value();
384 ASSERT_EQ(1U, actual.size());
385 expectTetherStatsEqual(expected1_0, actual[0]);
386 clearIptablesRestoreOutput();
387
388 // But if interfaces aren't paired, it's always an error.
389 counterLines.resize(3);
390 counters = Join(counterLines, "\n") + "\n";
391 addIptablesRestoreOutput(counters, counters);
392 result = mTetherCtrl.getTetherStats();
393 ASSERT_FALSE(isOk(result));
394 clearIptablesRestoreOutput();
395
396 // Token unit test of the fact that we return the stats in the error message which the caller
397 // ignores.
398 std::string expectedError = counters;
399 std::string err = result.status().msg();
400 ASSERT_LE(expectedError.size(), err.size());
401 EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
402 }
403
404 } // namespace net
405 } // namespace android
406