• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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