Firewall-related commands porting

Test: built, flashed, booted
      system/netd/tests/runtests.sh passes

Change-Id: I0fcf6ac4e5d96cbf63d6752bee7202cdef940e82
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 5669a96..6a40ba2 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -72,9 +72,10 @@
 using android::base::Join;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
+using android::net::FirewallController;
 using android::net::gCtls;
-using android::netdutils::StatusOr;
 using android::netdutils::Status;
+using android::netdutils::StatusOr;
 using android::netdutils::UniqueFile;
 
 namespace {
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 4e1887f..7629c9a 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -1058,11 +1058,7 @@
         }
         FirewallType firewallType = parseFirewallType(argv[2]);
 
-        int res = gCtls->firewallCtrl.enableFirewall(firewallType);
-        return sendGenericOkFail(cli, res);
-    }
-    if (!strcmp(argv[1], "disable")) {
-        int res = gCtls->firewallCtrl.disableFirewall();
+        int res = gCtls->firewallCtrl.setFirewallType(firewallType);
         return sendGenericOkFail(cli, res);
     }
     if (!strcmp(argv[1], "is_enabled")) {
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 4e5e3e5..890ab5b 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -59,6 +59,9 @@
 
 }  // namespace
 
+namespace android {
+namespace net {
+
 auto FirewallController::execIptablesRestore = ::execIptablesRestore;
 
 const char* FirewallController::TABLE = "filter";
@@ -101,11 +104,11 @@
     return res;
 }
 
-int FirewallController::enableFirewall(FirewallType ftype) {
+int FirewallController::setFirewallType(FirewallType ftype) {
     int res = 0;
     if (mFirewallType != ftype) {
         // flush any existing rules
-        disableFirewall();
+        resetFirewall();
 
         if (ftype == WHITELIST) {
             // create default rule to drop all traffic
@@ -121,10 +124,10 @@
         // Set this after calling disableFirewall(), since it defaults to WHITELIST there
         mFirewallType = ftype;
     }
-    return res;
+    return res ? -EREMOTEIO : 0;
 }
 
-int FirewallController::disableFirewall(void) {
+int FirewallController::resetFirewall(void) {
     mFirewallType = WHITELIST;
     mIfaceRules.clear();
 
@@ -136,7 +139,7 @@
         ":fw_FORWARD -\n"
         "COMMIT\n";
 
-    return execIptablesRestore(V4V6, command.c_str());
+    return (execIptablesRestore(V4V6, command.c_str()) == 0) ? 0 : -EREMOTEIO;
 }
 
 int FirewallController::enableChildChains(ChildChain chain, bool enable) {
@@ -177,12 +180,12 @@
 int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
     if (mFirewallType == BLACKLIST) {
         // Unsupported in BLACKLIST mode
-        return -1;
+        return -EINVAL;
     }
 
     if (!isIfaceName(iface)) {
         errno = ENOENT;
-        return -1;
+        return -ENOENT;
     }
 
     // Only delete rules if we actually added them, because otherwise our iptables-restore
@@ -205,7 +208,7 @@
         StringPrintf("%s fw_OUTPUT -o %s -j RETURN", op, iface),
         "COMMIT\n"
     }, "\n");
-    return execIptablesRestore(V4V6, command);
+    return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
 }
 
 FirewallType FirewallController::getFirewallType(ChildChain chain) {
@@ -253,7 +256,7 @@
             break;
         default:
             ALOGW("Unknown child chain: %d", chain);
-            return -1;
+            return -EINVAL;
     }
     if (mUseBpfOwnerMatch) {
         return gCtls->trafficCtrl.changeUidOwnerRule(chain, uid, rule, firewallType);
@@ -266,7 +269,7 @@
     }
     StringAppendF(&command, "COMMIT\n");
 
-    return execIptablesRestore(V4V6, command);
+    return (execIptablesRestore(V4V6, command) == 0) ? 0 : -EREMOTEIO;
 }
 
 int FirewallController::createChain(const char* chain, FirewallType type) {
@@ -393,3 +396,6 @@
 
     return maxUid;
 }
+
+}  // namespace net
+}  // namespace android
\ No newline at end of file
diff --git a/server/FirewallController.h b/server/FirewallController.h
index c43e94e..a7082da 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -23,16 +23,27 @@
 #include <string>
 #include <vector>
 
+#include "android/net/INetd.h"
+
 #include "NetdConstants.h"
 
-enum FirewallRule { DENY, ALLOW };
+namespace android {
+namespace net {
+
+enum FirewallRule { ALLOW = INetd::FIREWALL_RULE_ALLOW, DENY = INetd::FIREWALL_RULE_DENY };
 
 // WHITELIST means the firewall denies all by default, uids must be explicitly ALLOWed
 // BLACKLIST means the firewall allows all by default, uids must be explicitly DENYed
 
-enum FirewallType { WHITELIST, BLACKLIST };
+enum FirewallType { WHITELIST = INetd::FIREWALL_WHITELIST, BLACKLIST = INetd::FIREWALL_BLACKLIST };
 
-enum ChildChain { NONE, DOZABLE, STANDBY, POWERSAVE, INVALID_CHAIN };
+enum ChildChain {
+    NONE = INetd::FIREWALL_CHAIN_NONE,
+    DOZABLE = INetd::FIREWALL_CHAIN_DOZABLE,
+    STANDBY = INetd::FIREWALL_CHAIN_STANDBY,
+    POWERSAVE = INetd::FIREWALL_CHAIN_POWERSAVE,
+    INVALID_CHAIN
+};
 
 /*
  * Simple firewall that drops all packets except those matching explicitly
@@ -48,8 +59,8 @@
 
     int setupIptablesHooks(void);
 
-    int enableFirewall(FirewallType);
-    int disableFirewall(void);
+    int setFirewallType(FirewallType);
+    int resetFirewall(void);
     int isFirewallEnabled(void);
 
     /* Match traffic going in/out over the given iface. */
@@ -100,4 +111,7 @@
   FirewallType getFirewallType(ChildChain);
 };
 
+}  // namespace net
+}  // namespace android
+
 #endif
diff --git a/server/FirewallControllerTest.cpp b/server/FirewallControllerTest.cpp
index 240c85d..836adb8 100644
--- a/server/FirewallControllerTest.cpp
+++ b/server/FirewallControllerTest.cpp
@@ -33,6 +33,9 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
+namespace android {
+namespace net {
+
 class FirewallControllerTest : public IptablesBaseTest {
 protected:
     FirewallControllerTest() {
@@ -51,7 +54,6 @@
     }
 };
 
-
 TEST_F(FirewallControllerTest, TestCreateWhitelistChain) {
     std::vector<std::string> expectedRestore4 = {
         "*filter",
@@ -241,16 +243,16 @@
     };
     std::vector<std::string> noCommands = {};
 
-    EXPECT_EQ(0, mFw.disableFirewall());
+    EXPECT_EQ(0, mFw.resetFirewall());
     expectIptablesRestoreCommands(disableCommands);
 
-    EXPECT_EQ(0, mFw.disableFirewall());
+    EXPECT_EQ(0, mFw.resetFirewall());
     expectIptablesRestoreCommands(disableCommands);
 
-    EXPECT_EQ(0, mFw.enableFirewall(BLACKLIST));
+    EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
     expectIptablesRestoreCommands(disableCommands);
 
-    EXPECT_EQ(0, mFw.enableFirewall(BLACKLIST));
+    EXPECT_EQ(0, mFw.setFirewallType(BLACKLIST));
     expectIptablesRestoreCommands(noCommands);
 
     std::vector<std::string> disableEnableCommands;
@@ -259,7 +261,7 @@
     disableEnableCommands.insert(
             disableEnableCommands.end(), enableCommands.begin(), enableCommands.end());
 
-    EXPECT_EQ(0, mFw.enableFirewall(WHITELIST));
+    EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
     expectIptablesRestoreCommands(disableEnableCommands);
 
     std::vector<std::string> ifaceCommands = {
@@ -286,15 +288,15 @@
     EXPECT_EQ(0, mFw.setInterfaceRule("rmnet_data0", DENY));
     expectIptablesRestoreCommands(noCommands);
 
-    EXPECT_EQ(0, mFw.enableFirewall(WHITELIST));
+    EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
     expectIptablesRestoreCommands(noCommands);
 
-    EXPECT_EQ(0, mFw.disableFirewall());
+    EXPECT_EQ(0, mFw.resetFirewall());
     expectIptablesRestoreCommands(disableCommands);
 
-    // TODO: calling disableFirewall and then enableFirewall(WHITELIST) does
+    // TODO: calling resetFirewall and then setFirewallType(WHITELIST) does
     // nothing. This seems like a clear bug.
-    EXPECT_EQ(0, mFw.enableFirewall(WHITELIST));
+    EXPECT_EQ(0, mFw.setFirewallType(WHITELIST));
     expectIptablesRestoreCommands(noCommands);
 }
 
@@ -344,3 +346,6 @@
     EXPECT_NE(0, access(tempFile.c_str(), F_OK));
     EXPECT_EQ(4294967294, FirewallController::discoverMaximumValidUid(tempFile));
 }
+
+}  // namespace net
+}  // namespace android
\ No newline at end of file
diff --git a/server/InterfaceController.cpp b/server/InterfaceController.cpp
index 7006fee..fde7f4f 100644
--- a/server/InterfaceController.cpp
+++ b/server/InterfaceController.cpp
@@ -21,7 +21,6 @@
 #include <sys/socket.h>
 
 #include <functional>
-
 #define LOG_TAG "InterfaceController"
 #include <android-base/file.h>
 #include <android-base/properties.h>
diff --git a/server/NetdHwService.h b/server/NetdHwService.h
index a814fe4..458c6fa 100644
--- a/server/NetdHwService.h
+++ b/server/NetdHwService.h
@@ -19,16 +19,16 @@
 
 #include <android/system/net/netd/1.1/INetd.h>
 
-using android::hardware::Return;
-using android::hardware::hidl_string;
-using android::system::net::netd::V1_1::INetd;
-using StatusCode = android::system::net::netd::V1_1::INetd::StatusCode;
-
 namespace android {
 namespace net {
 
-class NetdHwService : public INetd {
-public:
+using android::hardware::Return;
+using android::hardware::hidl_string;
+using INetdHw = android::system::net::netd::V1_1::INetd;
+using StatusCode = android::system::net::netd::V1_1::INetd::StatusCode;
+
+class NetdHwService : INetdHw {
+  public:
     // 1.0
     status_t start();
     Return<void> createOemNetwork(createOemNetwork_cb _hidl_cb) override;
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 09b7efc..1e993c1 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -959,6 +959,7 @@
     gLog.log(entry.returns(res).withAutomaticDuration());
     return statusFromErrcode(res);
 }
+
 binder::Status NetdNativeService::clatdStart(const std::string& ifName) {
     NETD_LOCKING_RPC(NETWORK_STACK, gCtls->clatdCtrl.mutex);
     auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName);
@@ -1259,5 +1260,95 @@
     return binder::Status::ok();
 }
 
+namespace {
+std::string ruleToString(int32_t rule) {
+    switch (rule) {
+        case INetd::FIREWALL_RULE_DENY:
+            return "DENY";
+        case INetd::FIREWALL_RULE_ALLOW:
+            return "ALLOW";
+        default:
+            return "INVALID";
+    }
+}
+
+std::string typeToString(int32_t type) {
+    switch (type) {
+        case INetd::FIREWALL_WHITELIST:
+            return "WHITELIST";
+        case INetd::FIREWALL_BLACKLIST:
+            return "BLACKLIST";
+        default:
+            return "INVALID";
+    }
+}
+
+std::string chainToString(int32_t chain) {
+    switch (chain) {
+        case INetd::FIREWALL_CHAIN_NONE:
+            return "NONE";
+        case INetd::FIREWALL_CHAIN_DOZABLE:
+            return "DOZABLE";
+        case INetd::FIREWALL_CHAIN_STANDBY:
+            return "STANDBY";
+        case INetd::FIREWALL_CHAIN_POWERSAVE:
+            return "POWERSAVE";
+        default:
+            return "INVALID";
+    }
+}
+
+}  // namespace
+
+binder::Status NetdNativeService::firewallSetFirewallType(int32_t firewallType) {
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->firewallCtrl.lock);
+    auto entry =
+            gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(typeToString(firewallType));
+    auto type = static_cast<FirewallType>(firewallType);
+
+    int res = gCtls->firewallCtrl.setFirewallType(type);
+    gLog.log(entry.returns(res).withAutomaticDuration());
+    return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::firewallSetInterfaceRule(const std::string& ifName,
+                                                           int32_t firewallRule) {
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->firewallCtrl.lock);
+    auto entry = gLog.newEntry()
+                         .prettyFunction(__PRETTY_FUNCTION__)
+                         .args(ifName, ruleToString(firewallRule));
+    auto rule = static_cast<FirewallRule>(firewallRule);
+
+    int res = gCtls->firewallCtrl.setInterfaceRule(ifName.c_str(), rule);
+    gLog.log(entry.returns(res).withAutomaticDuration());
+    return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::firewallSetUidRule(int32_t childChain, int32_t uid,
+                                                     int32_t firewallRule) {
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->firewallCtrl.lock);
+    auto entry = gLog.newEntry()
+                         .prettyFunction(__PRETTY_FUNCTION__)
+                         .args(chainToString(childChain), uid, ruleToString(firewallRule));
+    auto chain = static_cast<ChildChain>(childChain);
+    auto rule = static_cast<FirewallRule>(firewallRule);
+
+    int res = gCtls->firewallCtrl.setUidRule(chain, uid, rule);
+    gLog.log(entry.returns(res).withAutomaticDuration());
+    return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::firewallEnableChildChain(int32_t childChain, bool enable) {
+    NETD_LOCKING_RPC(NETWORK_STACK, gCtls->firewallCtrl.lock);
+    auto entry = gLog.newEntry()
+                         .prettyFunction(__PRETTY_FUNCTION__)
+                         .args(chainToString(childChain), enable);
+    auto chain = static_cast<ChildChain>(childChain);
+
+    int res = gCtls->firewallCtrl.enableChildChains(chain, enable);
+    gLog.log(entry.returns(res).withAutomaticDuration());
+    return statusFromErrcode(res);
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 1d5caf6..77179cd 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -40,6 +40,12 @@
     binder::Status firewallReplaceUidChain(
             const std::string& chainName, bool isWhitelist,
             const std::vector<int32_t>& uids, bool *ret) override;
+    binder::Status firewallSetFirewallType(int32_t firewallType) override;
+    binder::Status firewallSetInterfaceRule(const std::string& ifName,
+                                            int32_t firewallRule) override;
+    binder::Status firewallSetUidRule(int32_t childChain, int32_t uid,
+                                      int32_t firewallRule) override;
+    binder::Status firewallEnableChildChain(int32_t childChain, bool enable) override;
 
     // Bandwidth control commands.
     binder::Status bandwidthEnableDataSaver(bool enable, bool *ret) override;
@@ -249,6 +255,8 @@
   private:
     std::vector<uid_t> intsToUids(const std::vector<int32_t>& intUids);
     Permission convertPermission(int32_t permission);
+    static FirewallRule parseRule(int32_t firewallRule);
+    static ChildChain parseChildChain(int32_t childChain);
 };
 
 }  // namespace net
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 19a3e40..395d706 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -996,4 +996,66 @@
     * @return true if the user can protect sockets from VPN, false otherwise.
     */
     boolean networkCanProtect(int uid);
+
+    // Whitelist only allows packets from specific UID/Interface
+    const int FIREWALL_WHITELIST = 0;
+    // Blacklist blocks packets from specific UID/Interface
+    const int FIREWALL_BLACKLIST = 1;
+
+   /**
+    * Set type of firewall
+    * Type whitelist only allows packets from specific UID/Interface
+    * Type blacklist blocks packets from specific UID/Interface
+    *
+    * @param firewalltype type of firewall, either FIREWALL_WHITELIST or FIREWALL_BLACKLIST
+    * @throws ServiceSpecificException in case of failure, with an error code indicating the
+    *         cause of the the failure.
+    */
+    void firewallSetFirewallType(int firewalltype);
+
+    // Specify allow Rule which allows packets
+    const int FIREWALL_RULE_ALLOW = 1;
+    // Specify deny Rule which drops packets
+    const int FIREWALL_RULE_DENY = 2;
+
+    // No specific chain is chosen, use general firewall chain(fw_input, fw_output)
+    const int FIREWALL_CHAIN_NONE = 0;
+    // Specify DOZABLE chain(fw_dozable) which is used in dozable mode
+    const int FIREWALL_CHAIN_DOZABLE = 1;
+    // Specify STANDBY chain(fw_standby) which is used in standby mode
+    const int FIREWALL_CHAIN_STANDBY = 2;
+    // Specify POWERSAVE chain(fw_powersave) which is used in power save mode
+    const int FIREWALL_CHAIN_POWERSAVE = 3;
+
+   /**
+    * Set firewall rule for interface
+    *
+    * @param ifName the interface to allow/deny
+    * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+    * @throws ServiceSpecificException in case of failure, with an error code indicating the
+    *         cause of the the failure.
+    */
+    void firewallSetInterfaceRule(in @utf8InCpp String ifName, int firewallRule);
+
+   /**
+    * Set firewall rule for uid
+    *
+    * @param childChain target chain
+    * @param uid uid to allow/deny
+    * @param firewallRule either FIREWALL_RULE_ALLOW or FIREWALL_RULE_DENY
+    * @throws ServiceSpecificException in case of failure, with an error code indicating the
+    *         cause of the the failure.
+    */
+    void firewallSetUidRule(int childChain, int uid, int firewallRule);
+
+   /**
+    * Enable/Disable target firewall child chain
+    *
+    * @param childChain target chain to enable
+    * @param enable whether to enable or disable child chain.
+    * @throws ServiceSpecificException in case of failure, with an error code indicating the
+    *         cause of the the failure.
+    */
+    void firewallEnableChildChain(int childChain, boolean enable);
+
 }