From 8e1cee9064af5b2e0d8095d5a6a05953616d7d4c Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 9 Jul 2016 14:24:08 +0900 Subject: [PATCH] Add a test for NatController. Bug: 9580643 Change-Id: I6ac3b754ec0b720674c6221e3a776314e86fe58c --- server/Android.mk | 2 +- server/IptablesBaseTest.cpp | 14 ++++- server/IptablesBaseTest.h | 2 + server/NatController.cpp | 4 +- server/NatController.h | 4 ++ server/NatControllerTest.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 server/NatControllerTest.cpp diff --git a/server/Android.mk b/server/Android.mk index 352d1e0..625d3b2 100644 --- a/server/Android.mk +++ b/server/Android.mk @@ -140,7 +140,7 @@ LOCAL_SRC_FILES := \ NetdConstants.cpp IptablesBaseTest.cpp \ BandwidthController.cpp BandwidthControllerTest.cpp \ FirewallControllerTest.cpp FirewallController.cpp \ - NatController.cpp \ + NatControllerTest.cpp NatController.cpp \ SockDiagTest.cpp SockDiag.cpp \ StrictController.cpp StrictControllerTest.cpp \ UidRanges.cpp \ diff --git a/server/IptablesBaseTest.cpp b/server/IptablesBaseTest.cpp index 9e75cb6..b52ff9b 100644 --- a/server/IptablesBaseTest.cpp +++ b/server/IptablesBaseTest.cpp @@ -38,11 +38,14 @@ IptablesBaseTest::IptablesBaseTest() { int IptablesBaseTest::fake_android_fork_exec(int argc, char* argv[], int *status, bool, bool) { std::string cmd = argv[0]; for (int i = 1; i < argc; i++) { + if (argv[i] == NULL) break; // NatController likes to pass in invalid argc values. cmd += " "; cmd += argv[i]; } sCmds.push_back(cmd); - *status = 0; + if (status) { + *status = 0; + } return 0; } @@ -128,6 +131,15 @@ void IptablesBaseTest::expectIptablesCommands(const ExpectedIptablesCommands& ex sCmds.clear(); } +void IptablesBaseTest::expectIptablesCommands( + const std::vector& snippets) { + ExpectedIptablesCommands expected; + for (const auto& snippet: snippets) { + expected.insert(expected.end(), snippet.begin(), snippet.end()); + } + expectIptablesCommands(expected); +} + void IptablesBaseTest::expectIptablesRestoreCommands(const std::vector& expectedCmds) { ExpectedIptablesCommands expected; for (auto cmd : expectedCmds) { diff --git a/server/IptablesBaseTest.h b/server/IptablesBaseTest.h index a354ef2..d175c5b 100644 --- a/server/IptablesBaseTest.h +++ b/server/IptablesBaseTest.h @@ -27,11 +27,13 @@ public: typedef std::vector> ExpectedIptablesCommands; static int fake_android_fork_exec(int argc, char* argv[], int *status, bool, bool); + static int fake_android_fork_execvp(int argc, char* argv[], int *status, bool, bool); static int fakeExecIptables(IptablesTarget target, ...); static int fakeExecIptablesRestore(IptablesTarget target, const std::string& commands); static FILE *fake_popen(const char *cmd, const char *type); void expectIptablesCommands(const std::vector& expectedCmds); void expectIptablesCommands(const ExpectedIptablesCommands& expectedCmds); + void expectIptablesCommands(const std::vector& snippets); void expectIptablesRestoreCommands(const std::vector& expectedCmds); void expectIptablesRestoreCommands(const ExpectedIptablesCommands& expectedCmds); diff --git a/server/NatController.cpp b/server/NatController.cpp index 19d19c7..fba96ca 100644 --- a/server/NatController.cpp +++ b/server/NatController.cpp @@ -40,6 +40,8 @@ const char* NatController::LOCAL_MANGLE_FORWARD = "natctrl_mangle_FORWARD"; const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING"; const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters"; +auto NatController::execFunction = android_fork_execvp; + NatController::NatController() { } @@ -55,7 +57,7 @@ struct CommandsAndArgs { int NatController::runCmd(int argc, const char **argv) { int res; - res = android_fork_execvp(argc, (char **)argv, NULL, false, false); + res = execFunction(argc, (char **)argv, NULL, false, false); #if !LOG_NDEBUG std::string full_cmd = argv[0]; diff --git a/server/NatController.h b/server/NatController.h index f23bf84..500385b 100644 --- a/server/NatController.h +++ b/server/NatController.h @@ -47,6 +47,10 @@ private: int runCmd(int argc, const char **argv); int setForwardRules(bool set, const char *intIface, const char *extIface); int setTetherCountingRules(bool add, const char *intIface, const char *extIface); + + // For testing. + friend class NatControllerTest; + static int (*execFunction)(int, char **, int *, bool, bool); }; #endif diff --git a/server/NatControllerTest.cpp b/server/NatControllerTest.cpp new file mode 100644 index 0000000..551efc6 --- /dev/null +++ b/server/NatControllerTest.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NatControllerTest.cpp - unit tests for NatController.cpp + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "NatController.h" +#include "IptablesBaseTest.h" + +using android::base::StringPrintf; + +class NatControllerTest : public IptablesBaseTest { +public: + NatControllerTest() { + NatController::execFunction = fake_android_fork_exec; + } + +protected: + NatController mNatCtrl; + + int setDefaults() { + return mNatCtrl.setDefaults(); + } + + const ExpectedIptablesCommands FLUSH_COMMANDS = { + { V4, "-F natctrl_FORWARD" }, + { V4, "-A natctrl_FORWARD -j DROP" }, + { V4, "-t nat -F natctrl_nat_POSTROUTING" }, + }; + + const ExpectedIptablesCommands SETUP_COMMANDS = { + { V4, "-F natctrl_FORWARD" }, + { V4, "-A natctrl_FORWARD -j DROP" }, + { V4, "-t nat -F natctrl_nat_POSTROUTING" }, + { V4, "-F natctrl_tether_counters" }, + { V4, "-X natctrl_tether_counters" }, + { V4, "-N natctrl_tether_counters" }, + { V4, "-t mangle -A natctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN " + "-j TCPMSS --clamp-mss-to-pmtu" }, + }; + + const ExpectedIptablesCommands TWIDDLE_COMMANDS = { + { V4, "-D natctrl_FORWARD -j DROP" }, + { V4, "-A natctrl_FORWARD -j DROP" }, + }; + + ExpectedIptablesCommands enableMasqueradeCommand(const char *extIf) { + return { + { V4, StringPrintf("-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIf) }, + }; + } + + ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf) { + return { + { V4, StringPrintf("-A natctrl_FORWARD -i %s -o %s -m state --state" + " ESTABLISHED,RELATED -g natctrl_tether_counters", extIf, intIf) }, + { V4, StringPrintf("-A natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP", + intIf, extIf) }, + { V4, StringPrintf("-A natctrl_FORWARD -i %s -o %s -g natctrl_tether_counters", + intIf, extIf) }, + { V4, StringPrintf("-A natctrl_tether_counters -i %s -o %s -j RETURN", intIf, extIf) }, + { V4, StringPrintf("-A natctrl_tether_counters -i %s -o %s -j RETURN", extIf, intIf) }, + }; + } + + ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) { + return { + { V4, StringPrintf("-D natctrl_FORWARD -i %s -o %s -m state --state" + " ESTABLISHED,RELATED -g natctrl_tether_counters", extIf, intIf) }, + { V4, StringPrintf("-D natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP", + intIf, extIf) }, + { V4, StringPrintf("-D natctrl_FORWARD -i %s -o %s -g natctrl_tether_counters", + intIf, extIf) }, + }; + } +}; + +TEST_F(NatControllerTest, TestSetupIptablesHooks) { + mNatCtrl.setupIptablesHooks(); + expectIptablesCommands(SETUP_COMMANDS); +} + +TEST_F(NatControllerTest, TestSetDefaults) { + setDefaults(); + expectIptablesCommands(FLUSH_COMMANDS); +} + +TEST_F(NatControllerTest, TestAddAndRemoveNat) { + + std::vector startFirstNat = { + enableMasqueradeCommand("rmnet0"), + startNatCommands("wlan0", "rmnet0"), + TWIDDLE_COMMANDS, + }; + mNatCtrl.enableNat("wlan0", "rmnet0"); + expectIptablesCommands(startFirstNat); + + std::vector startOtherNat = { + startNatCommands("usb0", "rmnet0"), + TWIDDLE_COMMANDS, + }; + mNatCtrl.enableNat("usb0", "rmnet0"); + expectIptablesCommands(startOtherNat); + + ExpectedIptablesCommands stopOtherNat = stopNatCommands("wlan0", "rmnet0"); + mNatCtrl.disableNat("wlan0", "rmnet0"); + expectIptablesCommands(stopOtherNat); + + std::vector stopLastNat = { + stopNatCommands("usb0", "rmnet0"), + FLUSH_COMMANDS, + }; + mNatCtrl.disableNat("usb0", "rmnet0"); + expectIptablesCommands(stopLastNat); +} -- 2.11.0