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