PanController.cpp \
PppController.cpp \
ResolverController.cpp \
+ SecondaryTableController.cpp \
SoftapController.cpp \
TetherController.cpp \
ThrottleController.cpp \
#include "ResponseCode.h"
#include "ThrottleController.h"
#include "BandwidthController.h"
-
+#include "SecondaryTableController.h"
TetherController *CommandListener::sTetherCtrl = NULL;
SoftapController *CommandListener::sSoftapCtrl = NULL;
BandwidthController * CommandListener::sBandwidthCtrl = NULL;
ResolverController *CommandListener::sResolverCtrl = NULL;
+SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
CommandListener::CommandListener() :
FrameworkListener("netd") {
registerCmd(new BandwidthControlCmd());
registerCmd(new ResolverCmd());
+ if (!sSecondaryTableCtrl)
+ sSecondaryTableCtrl = new SecondaryTableController();
if (!sTetherCtrl)
sTetherCtrl = new TetherController();
if (!sNatCtrl)
- sNatCtrl = new NatController();
+ sNatCtrl = new NatController(sSecondaryTableCtrl);
if (!sPppCtrl)
sPppCtrl = new PppController();
if (!sPanCtrl)
return 0;
}
+ // 0 1 2 3 4 5 6 7
+ // interface route add/remove iface default/secondary dest prefix gateway
if (!strcmp(argv[1], "route")) {
int prefix_length = 0;
- if (argc < 7) {
+ if (argc < 8) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
return 0;
}
- if (sscanf(argv[5], "%d", &prefix_length) != 1) {
+ if (sscanf(argv[6], "%d", &prefix_length) != 1) {
cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route prefix", false);
return 0;
}
if (!strcmp(argv[2], "add")) {
- if (ifc_add_route(argv[3], argv[4], prefix_length, argv[6])) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to add route", true);
+ if (!strcmp(argv[4], "default")) {
+ if (ifc_add_route(argv[3], argv[5], prefix_length, argv[7])) {
+ cli->sendMsg(ResponseCode::OperationFailed,
+ "Failed to add route to default table", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay,
+ "Route added to default table", false);
+ }
+ } else if (!strcmp(argv[4], "secondary")) {
+ return sSecondaryTableCtrl->addRoute(cli, argv[3], argv[5],
+ prefix_length, argv[7]);
} else {
- cli->sendMsg(ResponseCode::CommandOkay, "Route added", false);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid route type, expecting 'default' or 'secondary'", false);
+ return 0;
}
} else if (!strcmp(argv[2], "remove")) {
- if (ifc_remove_route(argv[3], argv[4], prefix_length, argv[6])) {
- cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove route", true);
+ if (!strcmp(argv[4], "default")) {
+ if (ifc_remove_route(argv[3], argv[5], prefix_length, argv[7])) {
+ cli->sendMsg(ResponseCode::OperationFailed,
+ "Failed to remove route from default table", true);
+ } else {
+ cli->sendMsg(ResponseCode::CommandOkay,
+ "Route removed from default table", false);
+ }
+ } else if (!strcmp(argv[4], "secondary")) {
+ return sSecondaryTableCtrl->removeRoute(cli, argv[3], argv[5],
+ prefix_length, argv[7]);
} else {
- cli->sendMsg(ResponseCode::CommandOkay, "Route removed", false);
+ cli->sendMsg(ResponseCode::CommandParameterError,
+ "Invalid route type, expecting 'default' or 'secondary'", false);
+ return 0;
}
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
int argc, char **argv) {
int rc = 0;
- if (argc < 3) {
+ if (argc < 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
return 0;
}
if (!strcmp(argv[1], "enable")) {
- rc = sNatCtrl->enableNat(argv[2], argv[3]);
+ rc = sNatCtrl->enableNat(argc, argv);
if(!rc) {
/* Ignore ifaces for now. */
rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
}
} else if (!strcmp(argv[1], "disable")) {
- rc = sNatCtrl->disableNat(argv[2], argv[3]);
/* Ignore ifaces for now. */
- rc |= sBandwidthCtrl->removeGlobalAlertInForwardChain();
+ rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
+ rc |= sNatCtrl->disableNat(argc, argv);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
return 0;
#include "SoftapController.h"
#include "BandwidthController.h"
#include "ResolverController.h"
+#include "SecondaryTableController.h"
class CommandListener : public FrameworkListener {
static TetherController *sTetherCtrl;
static SoftapController *sSoftapCtrl;
static BandwidthController *sBandwidthCtrl;
static ResolverController *sResolverCtrl;
+ static SecondaryTableController *sSecondaryTableCtrl;
public:
CommandListener();
#include <cutils/log.h>
#include "NatController.h"
+#include "SecondaryTableController.h"
extern "C" int logwrap(int argc, const char **argv, int background);
static char IPTABLES_PATH[] = "/system/bin/iptables";
+static char IP_PATH[] = "/system/bin/ip";
-NatController::NatController() {
- natCount = 0;
+NatController::NatController(SecondaryTableController *ctrl) {
+ secondaryTableCtrl = ctrl;
+ setDefaults();
}
NatController::~NatController() {
}
-int NatController::runIptablesCmd(const char *cmd) {
+int NatController::runCmd(const char *path, const char *cmd) {
char *buffer;
size_t len = strnlen(cmd, 255);
int res;
if (len == 255) {
- LOGE("iptables command too long");
+ LOGE("command too long");
errno = E2BIG;
return -1;
}
- asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd);
+ asprintf(&buffer, "%s %s", path, cmd);
res = system(buffer);
free(buffer);
return res;
int NatController::setDefaults() {
- if (runIptablesCmd("-P INPUT ACCEPT"))
+ if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
return -1;
- if (runIptablesCmd("-P OUTPUT ACCEPT"))
+ if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
return -1;
- if (runIptablesCmd("-P FORWARD DROP"))
+ if (runCmd(IPTABLES_PATH, "-P FORWARD DROP"))
return -1;
- if (runIptablesCmd("-F FORWARD"))
+ if (runCmd(IPTABLES_PATH, "-F FORWARD"))
return -1;
- if (runIptablesCmd("-t nat -F"))
+ if (runCmd(IPTABLES_PATH, "-t nat -F"))
return -1;
+
+ runCmd(IP_PATH, "rule flush");
+ runCmd(IP_PATH, "rule add from all lookup default prio 32767");
+ runCmd(IP_PATH, "rule add from all lookup main prio 32766");
+
+ natCount = 0;
return 0;
}
-bool NatController::interfaceExists(const char *iface) {
- // XXX: Implement this
+bool NatController::checkInterface(const char *iface) {
+ if (strlen(iface) > MAX_IFACE_LENGTH) return false;
return true;
}
-// when un-doing NAT, we should report errors, but also try to do as much cleanup
-// as we can - don't short circuit on error.
-int NatController::doNatCommands(const char *intIface, const char *extIface, bool add) {
+// 0 1 2 3 4 5
+// nat enable intface extface addrcnt nated-ipaddr/prelength
+int NatController::enableNat(const int argc, char **argv) {
char cmd[255];
+ int i;
+ int addrCount = atoi(argv[4]);
+ int ret = 0;
+ const char *intIface = argv[2];
+ const char *extIface = argv[3];
+ int tableNumber;
+
+ if (!checkInterface(intIface) || !checkInterface(extIface)) {
+ LOGE("Invalid interface specified");
+ errno = ENODEV;
+ return -1;
+ }
- char bootmode[PROPERTY_VALUE_MAX] = {0};
- property_get("ro.bootmode", bootmode, "unknown");
- if (0 != strcmp("bp-tools", bootmode)) {
- // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
- if (add == false) {
- if (natCount <= 1) {
- int ret = setDefaults();
- if (ret == 0) {
- natCount=0;
- }
- LOGE("setDefaults returned %d", ret);
- return ret;
- }
+ if (argc < 5 + addrCount) {
+ LOGE("Missing Argument");
+ errno = EINVAL;
+ return -1;
+ }
+
+ tableNumber = secondaryTableCtrl->findTableNumber(extIface);
+ if (tableNumber != -1) {
+ for(i = 0; i < addrCount && ret == 0; i++) {
+ snprintf(cmd, sizeof(cmd), "rule add from %s table %d", argv[5+i],
+ tableNumber + BASE_TABLE_NUMBER);
+ ret |= runCmd(IP_PATH, cmd);
+ if (ret) LOGE("IP rule %s got %d", cmd, ret);
+
+ snprintf(cmd, sizeof(cmd), "route add %s dev %s table %d", argv[5+i], intIface,
+ tableNumber + BASE_TABLE_NUMBER);
+ ret |= runCmd(IP_PATH, cmd);
+ if (ret) LOGE("IP route %s got %d", cmd, ret);
}
}
- if (!interfaceExists(intIface) || !interfaceExists (extIface)) {
- LOGE("Invalid interface specified");
+ if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
+ if (tableNumber != -1) {
+ for (i = 0; i < addrCount; i++) {
+ snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
+ tableNumber + BASE_TABLE_NUMBER);
+ runCmd(IP_PATH, cmd);
+
+ snprintf(cmd, sizeof(cmd), "rule del from %s table %d", argv[5+i],
+ tableNumber + BASE_TABLE_NUMBER);
+ runCmd(IP_PATH, cmd);
+ }
+ }
+ LOGE("Error setting forward rules");
errno = ENODEV;
return -1;
}
+ natCount++;
+ // add this if we are the first added nat
+ if (natCount == 1) {
+ snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
+ if (runCmd(IPTABLES_PATH, cmd)) {
+ LOGE("Error seting postroute rule: %s", cmd);
+ // unwind what's been done, but don't care about success - what more could we do?
+ for (i = 0; i < addrCount; i++) {
+ snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
+ tableNumber + BASE_TABLE_NUMBER);
+ runCmd(IP_PATH, cmd);
+ }
+ setDefaults();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
+ char cmd[255];
+
snprintf(cmd, sizeof(cmd),
"-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
(add ? "A" : "D"),
extIface, intIface);
- if (runIptablesCmd(cmd) && add) {
- // only bail out if we are adding, not removing nat rules
+ if (runCmd(IPTABLES_PATH, cmd) && add) {
return -1;
}
"-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
(add ? "A" : "D"),
intIface, extIface);
- if (runIptablesCmd(cmd) && add) {
+ if (runCmd(IPTABLES_PATH, cmd) && add) {
// bail on error, but only if adding
snprintf(cmd, sizeof(cmd),
"-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
(!add ? "A" : "D"),
extIface, intIface);
- runIptablesCmd(cmd);
+ runCmd(IPTABLES_PATH, cmd);
return -1;
}
snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
intIface, extIface);
- if (runIptablesCmd(cmd) && add) {
+ if (runCmd(IPTABLES_PATH, cmd) && add) {
// unwind what's been done, but don't care about success - what more could we do?
snprintf(cmd, sizeof(cmd),
"-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
(!add ? "A" : "D"),
intIface, extIface);
- runIptablesCmd(cmd);
+ runCmd(IPTABLES_PATH, cmd);
snprintf(cmd, sizeof(cmd),
"-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
(!add ? "A" : "D"),
extIface, intIface);
- runIptablesCmd(cmd);
+ runCmd(IPTABLES_PATH, cmd);
return -1;
}
+ return 0;
+}
- // add this if we are the first added nat
- if (add && natCount == 0) {
- snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
- if (runIptablesCmd(cmd)) {
- if (0 != strcmp("bp-tools", bootmode)) {
- // unwind what's been done, but don't care about success - what more could we do?
- setDefaults();;
- }
- return -1;
- }
+// nat disable intface extface
+// 0 1 2 3 4 5
+// nat enable intface extface addrcnt nated-ipaddr/prelength
+int NatController::disableNat(const int argc, char **argv) {
+ char cmd[255];
+ int i;
+ int addrCount = atoi(argv[4]);
+ const char *intIface = argv[2];
+ const char *extIface = argv[3];
+ int tableNumber;
+
+ if (!checkInterface(intIface) || !checkInterface(extIface)) {
+ LOGE("Invalid interface specified");
+ errno = ENODEV;
+ return -1;
}
- if (add) {
- natCount++;
- } else {
- natCount--;
+ if (argc < 5 + addrCount) {
+ LOGE("Missing Argument");
+ errno = EINVAL;
+ return -1;
}
- return 0;
-}
-int NatController::enableNat(const char *intIface, const char *extIface) {
- return doNatCommands(intIface, extIface, true);
-}
+ setForwardRules(false, intIface, extIface);
-int NatController::disableNat(const char *intIface, const char *extIface) {
- return doNatCommands(intIface, extIface, false);
+ tableNumber = secondaryTableCtrl->findTableNumber(extIface);
+ if (tableNumber != -1) {
+ for (i = 0; i < addrCount; i++) {
+ snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface,
+ tableNumber + BASE_TABLE_NUMBER);
+ // if the interface has gone down these will be gone already and give errors
+ // ignore them.
+ runCmd(IP_PATH, cmd);
+ }
+ }
+
+ if (--natCount <= 0) {
+ char bootmode[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.bootmode", bootmode, "unknown");
+ if (0 != strcmp("bp-tools", bootmode)) {
+ // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
+ setDefaults();
+ }
+ natCount = 0;
+ }
+ return 0;
}
#include <utils/List.h>
+#include "SecondaryTableController.h"
+
class NatController {
public:
- NatController();
+ NatController(SecondaryTableController *ctrl);
virtual ~NatController();
- int enableNat(const char *intIface, const char *extIface);
- int disableNat(const char *intIface, const char *extIface);
+ int enableNat(const int argc, char **argv);
+ int disableNat(const int argc, char **argv);
private:
int natCount;
+ SecondaryTableController *secondaryTableCtrl;
int setDefaults();
- int runIptablesCmd(const char *cmd);
- bool interfaceExists(const char *iface);
- int doNatCommands(const char *intIface, const char *extIface, bool add);
+ int runCmd(const char *path, const char *cmd);
+ bool checkInterface(const char *iface);
+ int setForwardRules(bool set, const char *intIface, const char *extIface);
};
#endif
--- /dev/null
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define LOG_TAG "SecondaryTablController"
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "ResponseCode.h"
+#include "SecondaryTableController.h"
+
+static char IP_PATH[] = "/system/bin/ip";
+
+SecondaryTableController::SecondaryTableController() {
+ int i;
+ for (i=0; i < INTERFACES_TRACKED; i++) {
+ mInterfaceTable[i][0] = 0;
+ // TODO - use a hashtable or other prebuilt container class
+ mInterfaceRuleCount[i] = 0;
+ }
+}
+
+SecondaryTableController::~SecondaryTableController() {
+}
+
+int SecondaryTableController::findTableNumber(const char *iface) {
+ int i;
+ for (i = 0; i < INTERFACES_TRACKED; i++) {
+ if (strncmp(iface, mInterfaceTable[i], MAX_IFACE_LENGTH) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
+ char *gateway) {
+ char *cmd;
+
+ int tableIndex = findTableNumber(iface);
+ if (tableIndex == -1) {
+ tableIndex = findTableNumber(""); // look for an empty slot
+ if (tableIndex == -1) {
+ LOGE("Max number of NATed interfaces reached");
+ errno = ENODEV;
+ cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
+ return -1;
+ }
+ strncpy(mInterfaceTable[tableIndex], iface, MAX_IFACE_LENGTH);
+ }
+
+ asprintf(&cmd, "%s route add %s/%d via %s table %d",
+ IP_PATH, dest, prefix, gateway, tableIndex+BASE_TABLE_NUMBER);
+ if (runAndFree(cli, cmd)) {
+ LOGE("ip route add failed: %s", cmd);
+ errno = ENODEV;
+ cli->sendMsg(ResponseCode::OperationFailed, "ip route add failed", true);
+ return -1;
+ }
+ mInterfaceRuleCount[tableIndex]++;
+ cli->sendMsg(ResponseCode::CommandOkay, "Route added", false);
+ return 0;
+}
+
+int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
+ char *gateway) {
+ char *cmd;
+ int tableIndex = findTableNumber(iface);
+ if (tableIndex == -1) {
+ LOGE("Interface not found");
+ errno = ENODEV;
+ cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
+ return -1;
+ }
+
+ asprintf(&cmd, "%s route del %s/%d via %s table %d",
+ IP_PATH, dest, prefix, gateway, tableIndex+BASE_TABLE_NUMBER);
+ if (runAndFree(cli, cmd)) {
+ LOGE("ip route del failed");
+ errno = ENODEV;
+ cli->sendMsg(ResponseCode::OperationFailed, "ip route del failed", true);
+ return -1;
+ }
+ if (--mInterfaceRuleCount[tableIndex]<1) {
+ mInterfaceTable[tableIndex][0]=0;
+ }
+ cli->sendMsg(ResponseCode::CommandOkay, "Route removed", false);
+ return 0;
+}
+
+int SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) {
+ int ret = 0;
+ if (strlen(cmd) >= 255) {
+ LOGE("ip command (%s) too long", cmd);
+ errno = E2BIG;
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
+ free(cmd);
+ return -1;
+ }
+ ret = system(cmd);
+ free(cmd);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _SECONDARY_TABLE_CONTROLLER_H
+#define _SECONDARY_TABLE_CONTROLLER_H
+
+#include <sysutils/FrameworkListener.h>
+
+static const unsigned int MAX_IFACE_LENGTH = 10;
+static const int INTERFACES_TRACKED = 10;
+static const int BASE_TABLE_NUMBER = 60;
+static int MAX_TABLE_NUMBER = BASE_TABLE_NUMBER + INTERFACES_TRACKED;
+
+class SecondaryTableController {
+
+public:
+ SecondaryTableController();
+ virtual ~SecondaryTableController();
+
+ int addRoute(SocketClient *cli, char *iface, char *dest, int prefixLen, char *gateway);
+ int removeRoute(SocketClient *cli, char *iface, char *dest, int prefixLen, char *gateway);
+ int findTableNumber(const char *iface);
+
+private:
+ char mInterfaceTable[INTERFACES_TRACKED][MAX_IFACE_LENGTH];
+ int mInterfaceRuleCount[INTERFACES_TRACKED];
+
+ int runAndFree(SocketClient *cli, char *cmd);
+};
+
+#endif