Nat-related commands porting
Test: built, flashed, booted
system/netd/tests/runtests.sh passes
Change-Id: I14e80377bc1b7c08993c3cf8fbf2b6fd0f99f4ba
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 458a0ed..883020f 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -61,6 +61,7 @@
#define RAW_TABLE "raw"
#define MANGLE_TABLE "mangle"
#define FILTER_TABLE "filter"
+#define NAT_TABLE "nat"
namespace binder = android::binder;
namespace netdutils = android::netdutils;
@@ -123,12 +124,15 @@
// Static because setting up the tun interface takes about 40ms.
static void SetUpTestCase() {
ASSERT_EQ(0, sTun.init());
+ ASSERT_EQ(0, sTun2.init());
ASSERT_LE(sTun.name().size(), static_cast<size_t>(IFNAMSIZ));
+ ASSERT_LE(sTun2.name().size(), static_cast<size_t>(IFNAMSIZ));
}
static void TearDownTestCase() {
// Closing the socket removes the interface and IP addresses.
sTun.destroy();
+ sTun2.destroy();
}
static void fakeRemoteSocketPair(int *clientSocket, int *serverSocket, int *acceptedSocket);
@@ -136,9 +140,11 @@
protected:
sp<INetd> mNetd;
static TunInterface sTun;
+ static TunInterface sTun2;
};
TunInterface BinderTest::sTun;
+TunInterface BinderTest::sTun2;
class TimedOperation : public Stopwatch {
public:
@@ -1116,6 +1122,7 @@
return runCommand(command);
}
+// TODO: It is a duplicate function, need to remove it
bool iptablesIdleTimerInterfaceRuleExists(const char* binary, const char* chainName,
const std::string& expectedInterface,
const std::string& expectedRule, const char* table) {
@@ -1368,7 +1375,8 @@
constexpr char BANDWIDTH_NAUGHTY[] = "bw_penalty_box";
constexpr char BANDWIDTH_NICE[] = "bw_happy_box";
-// TODO: move iptablesTargetsExists and listIptablesRuleByTable to the top.
+// TODO: Move iptablesTargetsExists and listIptablesRuleByTable to the top.
+// Use either a std::vector<std::string> of things to match, or a variadic function.
bool iptablesTargetsExists(const char* binary, int expectedCount, const char* table,
const char* chainName, const std::string& expectedTargetA,
const std::string& expectedTargetB) {
@@ -2639,3 +2647,106 @@
// Remove test physical network
EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
}
+
+namespace {
+
+constexpr const char TETHER_FORWARD[] = "tetherctrl_FORWARD";
+constexpr const char TETHER_NAT_POSTROUTING[] = "tetherctrl_nat_POSTROUTING";
+constexpr const char TETHER_PREROUTING[] = "tetherctrl_raw_PREROUTING";
+constexpr const char TETHER_COUNTERS_CHAIN[] = "tetherctrl_counters";
+
+int iptablesRuleLineLengthByTable(const char* binary, const char* table, const char* chainName) {
+ return listIptablesRuleByTable(binary, table, chainName).size();
+}
+
+bool iptablesChainMatch(const char* binary, const char* table, const char* chainName,
+ const std::vector<std::string>& targetVec) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, table, chainName);
+ if (targetVec.size() != rules.size() - 2) {
+ return false;
+ }
+
+ /*
+ * Do the fully match here.
+ * Skip first two lines since rules start from third line.
+ * Chain chainName (x references)
+ * pkts bytes target prot opt in out source destination
+ * ...
+ */
+ int rIndex = 2;
+ for (const auto& target : targetVec) {
+ if (rules[rIndex].find(target) == std::string::npos) {
+ return false;
+ }
+ rIndex++;
+ }
+ return true;
+}
+
+void expectNatEnable(const std::string& intIf, const std::string& extIf) {
+ std::vector<std::string> postroutingV4Match = {"MASQUERADE"};
+ std::vector<std::string> preroutingV4Match = {"CT helper ftp", "CT helper pptp"};
+ std::vector<std::string> forwardV4Match = {
+ "state RELATED", "state INVALID",
+ StringPrintf("tetherctrl_counters all -- %s %s", intIf.c_str(), extIf.c_str()),
+ "DROP"};
+
+ // V4
+ EXPECT_TRUE(iptablesChainMatch(IPTABLES_PATH, NAT_TABLE, TETHER_NAT_POSTROUTING,
+ postroutingV4Match));
+ EXPECT_TRUE(iptablesChainMatch(IPTABLES_PATH, RAW_TABLE, TETHER_PREROUTING, preroutingV4Match));
+ EXPECT_TRUE(iptablesChainMatch(IPTABLES_PATH, FILTER_TABLE, TETHER_FORWARD, forwardV4Match));
+
+ std::vector<std::string> forwardV6Match = {"tetherctrl_counters"};
+ std::vector<std::string> preroutingV6Match = {"rpfilter invert"};
+
+ // V6
+ EXPECT_TRUE(iptablesChainMatch(IP6TABLES_PATH, FILTER_TABLE, TETHER_FORWARD, forwardV6Match));
+ EXPECT_TRUE(
+ iptablesChainMatch(IP6TABLES_PATH, RAW_TABLE, TETHER_PREROUTING, preroutingV6Match));
+
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesTargetsExists(binary, 2, FILTER_TABLE, TETHER_COUNTERS_CHAIN, intIf,
+ extIf));
+ }
+}
+
+void expectNatDisable() {
+ // It is the default DROP rule with tethering disable.
+ // Chain tetherctrl_FORWARD (1 references)
+ // pkts bytes target prot opt in out source destination
+ // 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
+ std::vector<std::string> forwardV4Match = {"DROP"};
+ EXPECT_TRUE(iptablesChainMatch(IPTABLES_PATH, FILTER_TABLE, TETHER_FORWARD, forwardV4Match));
+
+ // We expect that these chains should be empty.
+ EXPECT_EQ(2, iptablesRuleLineLengthByTable(IPTABLES_PATH, NAT_TABLE, TETHER_NAT_POSTROUTING));
+ EXPECT_EQ(2, iptablesRuleLineLengthByTable(IPTABLES_PATH, RAW_TABLE, TETHER_PREROUTING));
+
+ EXPECT_EQ(2, iptablesRuleLineLengthByTable(IP6TABLES_PATH, FILTER_TABLE, TETHER_FORWARD));
+ EXPECT_EQ(2, iptablesRuleLineLengthByTable(IP6TABLES_PATH, RAW_TABLE, TETHER_PREROUTING));
+
+ // Netd won't clear tether quota rule, we don't care rule in tetherctrl_counters.
+}
+
+} // namespace
+
+TEST_F(BinderTest, TetherForwardAddRemove) {
+ // Add test physical network
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, INetd::PERMISSION_NONE).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+ EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID2, INetd::PERMISSION_NONE).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID2, sTun2.name()).isOk());
+
+ binder::Status status = mNetd->tetherAddForward(sTun.name(), sTun2.name());
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectNatEnable(sTun.name(), sTun2.name());
+
+ status = mNetd->tetherRemoveForward(sTun.name(), sTun2.name());
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectNatDisable();
+
+ // Remove test physical network
+ EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
+ EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID2).isOk());
+}