summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiaohui Chen <xiaohuic@google.com>2015-06-08 16:28:12 -0700
committerXiaohui Chen <xiaohuic@google.com>2015-06-15 09:39:57 -0700
commit1cdfa9adfa584029cb6d9ac13a2896786001b3a1 (patch)
tree1cc5e6460e04227ed5dbe08f021d59f9807157dc
parent3f95777d2aafa6c0ac4671d55557cad0d04a223f (diff)
downloadnetd-1cdfa9adfa584029cb6d9ac13a2896786001b3a1.tar.gz
netd: add two child chains to firewall
This is an attempt to speed up getting out of device idle. It groups uid firewall rules in these child chains so we can attach/detach a whole chain instead of individual uid rules. BUG:21446713 Change-Id: I61dc7d14110e633c5994e466481b9cac633a7a4f
-rw-r--r--server/CommandListener.cpp56
-rw-r--r--server/CommandListener.h1
-rw-r--r--server/FirewallController.cpp137
-rw-r--r--server/FirewallController.h18
4 files changed, 180 insertions, 32 deletions
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 6d1ff520..7ecbffc4 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -1294,6 +1294,19 @@ FirewallType CommandListener::FirewallCmd::parseFirewallType(const char* arg) {
}
}
+ChildChain CommandListener::FirewallCmd::parseChildChain(const char* arg) {
+ if (!strcmp(arg, "dozable")) {
+ return DOZABLE;
+ } else if (!strcmp(arg, "standby")) {
+ return STANDBY;
+ } else if (!strcmp(arg, "none")) {
+ return NONE;
+ } else {
+ ALOGE("failed to parse child firewall chain (%s)", arg);
+ return INVALID_CHAIN;
+ }
+}
+
int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
char **argv) {
if (argc < 2) {
@@ -1369,16 +1382,49 @@ int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
}
if (!strcmp(argv[1], "set_uid_rule")) {
- if (argc != 4) {
+ if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
- "Usage: firewall set_uid_rule <1000> <allow|deny>",
+ "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
false);
return 0;
}
- int uid = atoi(argv[2]);
- FirewallRule rule = parseRule(argv[3]);
- int res = sFirewallCtrl->setUidRule(uid, rule);
+ ChildChain childChain = parseChildChain(argv[2]);
+ if (childChain == INVALID_CHAIN) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Invalid chain name. Valid names are: <dozable|standby|none>",
+ false);
+ return 0;
+ }
+ int uid = atoi(argv[3]);
+ FirewallRule rule = parseRule(argv[4]);
+ int res = sFirewallCtrl->setUidRule(childChain, uid, rule);
+ return sendGenericOkFail(cli, res);
+ }
+
+ if (!strcmp(argv[1], "enable_chain")) {
+ if (argc != 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: firewall enable_chain <dozable|standby>",
+ false);
+ return 0;
+ }
+
+ ChildChain childChain = parseChildChain(argv[2]);
+ int res = sFirewallCtrl->enableChildChains(childChain, true);
+ return sendGenericOkFail(cli, res);
+ }
+
+ if (!strcmp(argv[1], "disable_chain")) {
+ if (argc != 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError,
+ "Usage: firewall disable_chain <dozable|standby>",
+ false);
+ return 0;
+ }
+
+ ChildChain childChain = parseChildChain(argv[2]);
+ int res = sFirewallCtrl->enableChildChains(childChain, false);
return sendGenericOkFail(cli, res);
}
diff --git a/server/CommandListener.h b/server/CommandListener.h
index 99dea5ac..72f4da17 100644
--- a/server/CommandListener.h
+++ b/server/CommandListener.h
@@ -137,6 +137,7 @@ private:
int sendGenericOkFail(SocketClient *cli, int cond);
static FirewallRule parseRule(const char* arg);
static FirewallType parseFirewallType(const char* arg);
+ static ChildChain parseChildChain(const char* arg);
};
class ClatdCmd : public NetdCommand {
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 3f71d025..4847c85d 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -27,42 +27,55 @@
#include "NetdConstants.h"
#include "FirewallController.h"
+const char* FirewallController::TABLE = "filter";
+
const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
+const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
+const char* FirewallController::LOCAL_STANDBY = "fw_standby";
+
FirewallController::FirewallController(void) {
// If no rules are set, it's in BLACKLIST mode
- firewallType = BLACKLIST;
+ mFirewallType = BLACKLIST;
}
int FirewallController::setupIptablesHooks(void) {
- return 0;
+ int res = 0;
+ // child chains are created but not attached, they will be attached explicitly.
+ FirewallType firewallType = getFirewallType(DOZABLE);
+ res |= createChain(LOCAL_DOZABLE, LOCAL_INPUT, firewallType);
+
+ firewallType = getFirewallType(STANDBY);
+ res |= createChain(LOCAL_STANDBY, LOCAL_INPUT, firewallType);
+
+ return res;
}
int FirewallController::enableFirewall(FirewallType ftype) {
int res = 0;
-
- // flush any existing rules
- disableFirewall();
-
- if (ftype == WHITELIST) {
- // create default rule to drop all traffic
- res |= execIptables(V4V6, "-A", LOCAL_INPUT, "-j", "DROP", NULL);
- res |= execIptables(V4V6, "-A", LOCAL_OUTPUT, "-j", "REJECT", NULL);
- res |= execIptables(V4V6, "-A", LOCAL_FORWARD, "-j", "REJECT", NULL);
+ if (mFirewallType != ftype) {
+ // flush any existing rules
+ disableFirewall();
+
+ if (ftype == WHITELIST) {
+ // create default rule to drop all traffic
+ res |= execIptables(V4V6, "-A", LOCAL_INPUT, "-j", "DROP", NULL);
+ res |= execIptables(V4V6, "-A", LOCAL_OUTPUT, "-j", "REJECT", NULL);
+ res |= execIptables(V4V6, "-A", LOCAL_FORWARD, "-j", "REJECT", NULL);
+ }
+
+ // Set this after calling disableFirewall(), since it defaults to WHITELIST there
+ mFirewallType = ftype;
}
-
- // Set this after calling disableFirewall(), since it defaults to WHITELIST there
- firewallType = ftype;
-
return res;
}
int FirewallController::disableFirewall(void) {
int res = 0;
- firewallType = WHITELIST;
+ mFirewallType = WHITELIST;
// flush any existing rules
res |= execIptables(V4V6, "-F", LOCAL_INPUT, NULL);
@@ -72,13 +85,37 @@ int FirewallController::disableFirewall(void) {
return res;
}
+int FirewallController::enableChildChains(ChildChain chain, bool enable) {
+ int res = 0;
+ const char* name;
+ switch(chain) {
+ case DOZABLE:
+ name = LOCAL_DOZABLE;
+ break;
+ case STANDBY:
+ name = LOCAL_STANDBY;
+ break;
+ default:
+ return res;
+ }
+
+ if (enable) {
+ res |= attachChain(name, LOCAL_INPUT);
+ res |= attachChain(name, LOCAL_OUTPUT);
+ } else {
+ res |= detachChain(name, LOCAL_INPUT);
+ res |= detachChain(name, LOCAL_OUTPUT);
+ }
+ return res;
+}
+
int FirewallController::isFirewallEnabled(void) {
// TODO: verify that rules are still in place near top
return -1;
}
int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
- if (firewallType == BLACKLIST) {
+ if (mFirewallType == BLACKLIST) {
// Unsupported in BLACKLIST mode
return -1;
}
@@ -102,7 +139,7 @@ int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
}
int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule) {
- if (firewallType == BLACKLIST) {
+ if (mFirewallType == BLACKLIST) {
// Unsupported in BLACKLIST mode
return -1;
}
@@ -127,7 +164,7 @@ int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule)
int FirewallController::setEgressDestRule(const char* addr, int protocol, int port,
FirewallRule rule) {
- if (firewallType == BLACKLIST) {
+ if (mFirewallType == BLACKLIST) {
// Unsupported in BLACKLIST mode
return -1;
}
@@ -158,12 +195,26 @@ int FirewallController::setEgressDestRule(const char* addr, int protocol, int po
return res;
}
-int FirewallController::setUidRule(int uid, FirewallRule rule) {
+FirewallType FirewallController::getFirewallType(ChildChain chain) {
+ switch(chain) {
+ case DOZABLE:
+ return WHITELIST;
+ case STANDBY:
+ return BLACKLIST;
+ case NONE:
+ return mFirewallType;
+ default:
+ return BLACKLIST;
+ }
+}
+
+int FirewallController::setUidRule(ChildChain chain, int uid, FirewallRule rule) {
char uidStr[16];
sprintf(uidStr, "%d", uid);
const char* op;
const char* target;
+ FirewallType firewallType = getFirewallType(chain);
if (firewallType == WHITELIST) {
target = "RETURN";
op = (rule == ALLOW)? "-I" : "-D";
@@ -173,9 +224,47 @@ int FirewallController::setUidRule(int uid, FirewallRule rule) {
}
int res = 0;
- res |= execIptables(V4V6, op, LOCAL_INPUT, "-m", "owner", "--uid-owner", uidStr,
- "-j", target, NULL);
- res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-m", "owner", "--uid-owner", uidStr,
- "-j", target, NULL);
+ switch(chain) {
+ case DOZABLE:
+ res |= execIptables(V4V6, op, LOCAL_DOZABLE, "-m", "owner", "--uid-owner",
+ uidStr, "-j", target, NULL);
+ break;
+ case STANDBY:
+ res |= execIptables(V4V6, op, LOCAL_STANDBY, "-m", "owner", "--uid-owner",
+ uidStr, "-j", target, NULL);
+ break;
+ case NONE:
+ res |= execIptables(V4V6, op, LOCAL_INPUT, "-m", "owner", "--uid-owner", uidStr,
+ "-j", target, NULL);
+ res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-m", "owner", "--uid-owner", uidStr,
+ "-j", target, NULL);
+ break;
+ default:
+ ALOGW("Unknown child chain: %d", chain);
+ break;
+ }
+ return res;
+}
+
+int FirewallController::attachChain(const char* childChain, const char* parentChain) {
+ return execIptables(V4V6, "-t", TABLE, "-A", parentChain, "-j", childChain, NULL);
+}
+
+int FirewallController::detachChain(const char* childChain, const char* parentChain) {
+ return execIptables(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
+}
+
+int FirewallController::createChain(const char* childChain,
+ const char* parentChain, FirewallType type) {
+ // Order is important, otherwise later steps may fail.
+ execIptablesSilently(V4V6, "-t", TABLE, "-D", parentChain, "-j", childChain, NULL);
+ execIptablesSilently(V4V6, "-t", TABLE, "-F", childChain, NULL);
+ execIptablesSilently(V4V6, "-t", TABLE, "-X", childChain, NULL);
+ int res = 0;
+ res |= execIptables(V4V6, "-t", TABLE, "-N", childChain, NULL);
+ if (type == WHITELIST) {
+ // create default rule to drop all traffic
+ res |= execIptables(V4V6, "-A", childChain, "-j", "DROP", NULL);
+ }
return res;
}
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 8051a736..b32072e7 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -26,6 +26,8 @@ enum FirewallRule { DENY, ALLOW };
enum FirewallType { WHITELIST, BLACKLIST };
+enum ChildChain { NONE, DOZABLE, STANDBY, INVALID_CHAIN };
+
#define PROTOCOL_TCP 6
#define PROTOCOL_UDP 17
@@ -49,15 +51,25 @@ public:
int setEgressSourceRule(const char*, FirewallRule);
/* Match traffic coming-in-from or going-out-to given address, port, and protocol. */
int setEgressDestRule(const char*, int, int, FirewallRule);
- /* Match traffic owned by given UID. */
- int setUidRule(int, FirewallRule);
+ /* Match traffic owned by given UID. This is specific to a particular chain. */
+ int setUidRule(ChildChain, int, FirewallRule);
+
+ int enableChildChains(ChildChain, bool);
+
+ static const char* TABLE;
static const char* LOCAL_INPUT;
static const char* LOCAL_OUTPUT;
static const char* LOCAL_FORWARD;
+ static const char* LOCAL_DOZABLE;
+ static const char* LOCAL_STANDBY;
private:
- FirewallType firewallType;
+ FirewallType mFirewallType;
+ int attachChain(const char*, const char*);
+ int detachChain(const char*, const char*);
+ int createChain(const char*, const char*, FirewallType);
+ FirewallType getFirewallType(ChildChain);
};
#endif