Home | History | Annotate | Download | only in server
      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:
     47     TetherControllerTest() {
     48         TetherController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
     49     }
     50 
     51 protected:
     52     TetherController mTetherCtrl;
     53 
     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 
     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 
    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>
    118     void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
    119         cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
    120     }
    121 
    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;
    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 
    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 
    216 TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
    217     mTetherCtrl.setupIptablesHooks();
    218     expectIptablesRestoreCommands(SETUP_COMMANDS);
    219 }
    220 
    221 TEST_F(TetherControllerTest, TestSetDefaults) {
    222     setDefaults();
    223     expectIptablesRestoreCommands(FLUSH_COMMANDS);
    224 }
    225 
    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 
    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 
    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 
    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