Firewall-related commands porting
Test: built, flashed, booted
system/netd/tests/runtests.sh passes
Change-Id: I0fcf6ac4e5d96cbf63d6752bee7202cdef940e82
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 421af95..a6a9257 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -1997,4 +1997,327 @@
status = mNetd->tetherDnsList(&dnsList);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
expectTetherDnsListEquals(dnsList, testDnsAddrs);
-}
\ No newline at end of file
+}
+
+namespace {
+
+constexpr char FIREWALL_INPUT[] = "fw_INPUT";
+constexpr char FIREWALL_OUTPUT[] = "fw_OUTPUT";
+constexpr char FIREWALL_FORWARD[] = "fw_FORWARD";
+constexpr char FIREWALL_DOZABLE[] = "fw_dozable";
+constexpr char FIREWALL_POWERSAVE[] = "fw_powersave";
+constexpr char FIREWALL_STANDBY[] = "fw_standby";
+constexpr char targetReturn[] = "RETURN";
+constexpr char targetDrop[] = "DROP";
+
+void expectFirewallWhitelistMode() {
+ static const char dropRule[] = "DROP all";
+ static const char rejectRule[] = "REJECT all";
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesRuleExists(binary, FIREWALL_INPUT, dropRule));
+ EXPECT_TRUE(iptablesRuleExists(binary, FIREWALL_OUTPUT, rejectRule));
+ EXPECT_TRUE(iptablesRuleExists(binary, FIREWALL_FORWARD, rejectRule));
+ }
+}
+
+void expectFirewallBlacklistMode() {
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_INPUT));
+ EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_OUTPUT));
+ EXPECT_EQ(2, iptablesRuleLineLength(binary, FIREWALL_FORWARD));
+ }
+}
+
+bool iptablesFirewallInterfaceFirstRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedInterface,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ // Expected rule:
+ // Chain fw_INPUT (1 references)
+ // pkts bytes target prot opt in out source destination
+ // 0 0 RETURN all -- expectedInterface * 0.0.0.0/0 0.0.0.0/0
+ // 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
+ int firstRuleIndex = 2;
+ if (rules.size() < 4) return false;
+ if (rules[firstRuleIndex].find(expectedInterface) != std::string::npos) {
+ if (rules[firstRuleIndex].find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// TODO: It is a duplicate function, need to remove it
+bool iptablesFirewallInterfaceRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedInterface,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ for (const auto& rule : rules) {
+ if (rule.find(expectedInterface) != std::string::npos) {
+ if (rule.find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void expectFirewallInterfaceRuleAllowExists(const std::string& ifname) {
+ static const char returnRule[] = "RETURN all";
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesFirewallInterfaceFirstRuleExists(binary, FIREWALL_INPUT, ifname,
+ returnRule));
+ EXPECT_TRUE(iptablesFirewallInterfaceFirstRuleExists(binary, FIREWALL_OUTPUT, ifname,
+ returnRule));
+ }
+}
+
+void expectFireWallInterfaceRuleAllowDoesNotExist(const std::string& ifname) {
+ static const char returnRule[] = "RETURN all";
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(
+ iptablesFirewallInterfaceRuleExists(binary, FIREWALL_INPUT, ifname, returnRule));
+ EXPECT_FALSE(
+ iptablesFirewallInterfaceRuleExists(binary, FIREWALL_OUTPUT, ifname, returnRule));
+ }
+}
+
+bool iptablesFirewallUidFirstRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedTarget,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ int firstRuleIndex = 2;
+ if (rules.size() < 4) return false;
+ if (rules[firstRuleIndex].find(expectedTarget) != std::string::npos) {
+ if (rules[firstRuleIndex].find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool iptablesFirewallUidLastRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedTarget,
+ const std::string& expectedRule) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, FILTER_TABLE, chainName);
+ int lastRuleIndex = rules.size() - 1;
+ if (lastRuleIndex < 0) return false;
+ if (rules[lastRuleIndex].find(expectedTarget) != std::string::npos) {
+ if (rules[lastRuleIndex].find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void expectFirewallUidFirstRuleExists(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallUidFirstRuleExists(binary, chainName, targetReturn, uidRule));
+}
+
+void expectFirewallUidFirstRuleDoesNotExist(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_FALSE(iptablesFirewallUidFirstRuleExists(binary, chainName, targetReturn, uidRule));
+}
+
+void expectFirewallUidLastRuleExists(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallUidLastRuleExists(binary, chainName, targetDrop, uidRule));
+}
+
+void expectFirewallUidLastRuleDoesNotExist(const char* chainName, int32_t uid) {
+ std::string uidRule = StringPrintf("owner UID match %u", uid);
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_FALSE(iptablesFirewallUidLastRuleExists(binary, chainName, targetDrop, uidRule));
+}
+
+bool iptablesFirewallChildChainsLastRuleExists(const char* binary, const char* chainName) {
+ std::vector<std::string> inputRules =
+ listIptablesRuleByTable(binary, FILTER_TABLE, FIREWALL_INPUT);
+ std::vector<std::string> outputRules =
+ listIptablesRuleByTable(binary, FILTER_TABLE, FIREWALL_OUTPUT);
+ int inputLastRuleIndex = inputRules.size() - 1;
+ int outputLastRuleIndex = outputRules.size() - 1;
+
+ if (inputLastRuleIndex < 0 || outputLastRuleIndex < 0) return false;
+ if (inputRules[inputLastRuleIndex].find(chainName) != std::string::npos) {
+ if (outputRules[outputLastRuleIndex].find(chainName) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void expectFirewallChildChainsLastRuleExists(const char* chainRule) {
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH})
+ EXPECT_TRUE(iptablesFirewallChildChainsLastRuleExists(binary, chainRule));
+}
+
+void expectFirewallChildChainsLastRuleDoesNotExist(const char* chainRule) {
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesRuleExists(binary, FIREWALL_INPUT, chainRule));
+ EXPECT_FALSE(iptablesRuleExists(binary, FIREWALL_OUTPUT, chainRule));
+ }
+}
+
+} // namespace
+
+TEST_F(BinderTest, FirewallSetFirewallType) {
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallWhitelistMode();
+
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+
+ // set firewall type blacklist twice
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+
+ // set firewall type whitelist twice
+ mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallWhitelistMode();
+
+ // reset firewall type to default
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+}
+
+TEST_F(BinderTest, FirewallSetInterfaceRule) {
+ // setinterfaceRule is not supported in BLACKLIST MODE
+ binder::Status status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+ status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_FALSE(status.isOk()) << status.exceptionMessage();
+
+ // set WHITELIST mode first
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+ status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallInterfaceRuleAllowExists(sTun.name());
+
+ status = mNetd->firewallSetInterfaceRule(sTun.name(), INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFireWallInterfaceRuleAllowDoesNotExist(sTun.name());
+
+ // reset firewall mode to default
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+}
+
+TEST_F(BinderTest, FirewallSetUidRule) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ int32_t uid = randomUid();
+
+ // Doze allow
+ binder::Status status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_DOZABLE, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_DOZABLE, uid);
+
+ // Doze deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_DOZABLE, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_DOZABLE, uid);
+
+ // Powersave allow
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_POWERSAVE, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_POWERSAVE, uid);
+
+ // Powersave deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_POWERSAVE, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_POWERSAVE, uid);
+
+ // Standby deny
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, uid,
+ INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleExists(FIREWALL_STANDBY, uid);
+
+ // Standby allow
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, uid,
+ INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_STANDBY, uid);
+
+ // None deny in BLACKLIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleExists(FIREWALL_INPUT, uid);
+ expectFirewallUidLastRuleExists(FIREWALL_OUTPUT, uid);
+
+ // None allow in BLACKLIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_INPUT, uid);
+ expectFirewallUidLastRuleDoesNotExist(FIREWALL_OUTPUT, uid);
+
+ // set firewall type whitelist twice
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_WHITELIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallWhitelistMode();
+
+ // None allow in WHITELIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_ALLOW);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleExists(FIREWALL_INPUT, uid);
+ expectFirewallUidFirstRuleExists(FIREWALL_OUTPUT, uid);
+
+ // None deny in WHITELIST
+ status = mNetd->firewallSetUidRule(INetd::FIREWALL_CHAIN_NONE, uid, INetd::FIREWALL_RULE_DENY);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_INPUT, uid);
+ expectFirewallUidFirstRuleDoesNotExist(FIREWALL_OUTPUT, uid);
+
+ // reset firewall mode to default
+ status = mNetd->firewallSetFirewallType(INetd::FIREWALL_BLACKLIST);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallBlacklistMode();
+}
+
+TEST_F(BinderTest, FirewallEnableDisableChildChains) {
+ SKIP_IF_BPF_SUPPORTED;
+
+ binder::Status status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_DOZABLE, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_DOZABLE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_STANDBY, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_STANDBY);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_POWERSAVE, true);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleExists(FIREWALL_POWERSAVE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_DOZABLE, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_DOZABLE);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_STANDBY, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_STANDBY);
+
+ status = mNetd->firewallEnableChildChain(INetd::FIREWALL_CHAIN_POWERSAVE, false);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectFirewallChildChainsLastRuleDoesNotExist(FIREWALL_POWERSAVE);
+}