"Wrong number of arguments to resolver setifaceforuid", false);
return 0;
}
- } else if (!strcmp(argv[1], "clearifaceforuidrange")) { // resolver clearifaceforuid <l> <h>
- if (argc == 4) {
- rc = !sNetCtrl->setNetworkForUidRange(atoi(argv[2]), atoi(argv[3]), NETID_UNSET, false);
+ } else if (!strcmp(argv[1], "clearifaceforuidrange")) {
+ // resolver clearifaceforuid <if> <l> <h>
+ if (argc == 5) {
- rc = sResolverCtrl->clearDnsInterfaceForUidRange(argv[2], atoi(argv[3]),
- atoi(argv[4]));
++ unsigned netId = sNetCtrl->getNetworkId(argv[2]);
++ rc = !sNetCtrl->clearNetworkForUidRange(atoi(argv[3]), atoi(argv[4]), netId);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Wrong number of arguments to resolver clearifaceforuid", false);
--- /dev/null
- if (uid_start > uid_end)
+/*
+ * Copyright (C) 2014 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 <resolv_netid.h>
+
+#define LOG_TAG "NetworkController"
+#include <cutils/log.h>
+
+#include "NetworkController.h"
+
+// Mark 1 is reserved for SecondaryTableController::PROTECT_MARK.
+NetworkController::NetworkController()
+ : mDefaultNetId(NETID_UNSET),
+ mNextFreeNetId(10) {}
+
+void NetworkController::clearNetworkPreference() {
+ android::RWLock::AutoWLock lock(mRWLock);
+ mUidMap.clear();
+ mPidMap.clear();
+}
+
+unsigned NetworkController::getDefaultNetwork() const {
+ return mDefaultNetId;
+}
+
+void NetworkController::setDefaultNetwork(unsigned netId) {
+ android::RWLock::AutoWLock lock(mRWLock);
+ mDefaultNetId = netId;
+}
+
+void NetworkController::setNetworkForPid(int pid, unsigned netId) {
+ android::RWLock::AutoWLock lock(mRWLock);
+ if (netId == 0) {
+ mPidMap.erase(pid);
+ } else {
+ mPidMap[pid] = netId;
+ }
+}
+
+bool NetworkController::setNetworkForUidRange(int uid_start, int uid_end, unsigned netId,
+ bool forward_dns) {
+ android::RWLock::AutoWLock lock(mRWLock);
- if (it->uid_start > uid_end || uid_start > it->uid_end)
++ if (uid_start > uid_end || netId == NETID_UNSET)
+ return false;
+
+ for (std::list<UidEntry>::iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
- /* Overlapping or identical range. */
- if (it->uid_start != uid_start || it->uid_end != uid_end) {
- ALOGE("Overlapping but not identical uid range detected.");
- return false;
- }
-
- if (netId == NETID_UNSET) {
- mUidMap.erase(it);
- } else {
- it->netId = netId;
- it->forward_dns = forward_dns;
- }
++ if (it->uid_start != uid_start || it->uid_end != uid_end || it->netId != netId)
+ continue;
- mUidMap.push_back(UidEntry(uid_start, uid_end, netId, forward_dns));
++ it->forward_dns = forward_dns;
+ return true;
+ }
+
++ mUidMap.push_front(UidEntry(uid_start, uid_end, netId, forward_dns));
+ return true;
+}
+
++bool NetworkController::clearNetworkForUidRange(int uid_start, int uid_end, unsigned netId) {
++ android::RWLock::AutoWLock lock(mRWLock);
++ if (uid_start > uid_end || netId == NETID_UNSET)
++ return false;
++
++ for (std::list<UidEntry>::iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
++ if (it->uid_start != uid_start || it->uid_end != uid_end || it->netId != netId)
++ continue;
++ mUidMap.erase(it);
++ return true;
++ }
++ return false;
++}
++
+unsigned NetworkController::getNetwork(int uid, unsigned requested_netId, int pid,
+ bool for_dns) const {
+ android::RWLock::AutoRLock lock(mRWLock);
+ for (std::list<UidEntry>::const_iterator it = mUidMap.begin(); it != mUidMap.end(); ++it) {
+ if (uid < it->uid_start || it->uid_end < uid)
+ continue;
+ if (for_dns && !it->forward_dns)
+ break;
+ return it->netId;
+ }
+ if (requested_netId != NETID_UNSET)
+ return requested_netId;
+ if (pid != PID_UNSPECIFIED) {
+ std::map<int, unsigned>::const_iterator it = mPidMap.find(pid);
+ if (it != mPidMap.end())
+ return it->second;
+ }
+ return mDefaultNetId;
+}
+
+unsigned NetworkController::getNetworkId(const char* interface) {
+ std::map<std::string, unsigned>::const_iterator it = mIfaceNetidMap.find(interface);
+ if (it != mIfaceNetidMap.end())
+ return it->second;
+
+ unsigned netId = mNextFreeNetId++;
+ mIfaceNetidMap[interface] = netId;
+ return netId;
+}
+
+NetworkController::UidEntry::UidEntry(
+ int start, int end, unsigned netId, bool forward_dns)
+ : uid_start(start),
+ uid_end(end),
+ netId(netId),
+ forward_dns(forward_dns) {
+}
--- /dev/null
- // Returns false if a partially overlapping range exists.
- // Specify NETID_UNSET for netId to clear a mapping.
+/*
+ * Copyright (C) 2014 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 _NETD_NETWORKCONTROLLER_H
+#define _NETD_NETWORKCONTROLLER_H
+
+#include <list>
+#include <map>
+#include <string>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <utils/RWLock.h>
+
+/*
+ * Keeps track of default, per-pid, and per-uid-range network selection, as
+ * well as the mark associated with each network. Networks are identified
+ * by netid. In all set* commands netid == 0 means "unspecified" and is
+ * equivalent to clearing the mapping.
+ */
+class NetworkController {
+public:
+ enum {
+ // For use with getNetwork().
+ PID_UNSPECIFIED = 0,
+ };
+
+ NetworkController();
+
+ void clearNetworkPreference();
+ unsigned getDefaultNetwork() const;
+ void setDefaultNetwork(unsigned netId);
+ void setNetworkForPid(int pid, unsigned netId);
+ bool setNetworkForUidRange(int uid_start, int uid_end, unsigned netId, bool forward_dns);
++ bool clearNetworkForUidRange(int uid_start, int uid_end, unsigned netId);
+
+ // Order of preference: UID-specific, requested_netId, PID-specific, default.
+ // Specify NETID_UNSET for requested_netId if the default network is preferred.
+ // Specify PID_UNSPECIFIED for pid to ignore PID-specific overrides.
+ // for_dns indicates if we're querrying the netId for a DNS request. This avoids sending DNS
+ // requests to VPNs without DNS servers.
+ unsigned getNetwork(int uid, unsigned requested_netId, int pid, bool for_dns) const;
+
+ unsigned getNetworkId(const char* interface);
+
+private:
+ struct UidEntry {
+ int uid_start;
+ int uid_end;
+ unsigned netId;
+ bool forward_dns;
+ UidEntry(int uid_start, int uid_end, unsigned netId, bool forward_dns);
+ };
+
+ mutable android::RWLock mRWLock;
+ std::list<UidEntry> mUidMap;
+ std::map<int, unsigned> mPidMap;
+ unsigned mDefaultNetId;
+
+ std::map<std::string, unsigned> mIfaceNetidMap;
+ unsigned mNextFreeNetId;
+};
+
+#endif
#include "SecondaryTableController.h"
const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
- const char* SecondaryTableController::LOCAL_MANGLE_EXEMPT = "st_mangle_EXEMPT";
- const char* SecondaryTableController::LOCAL_MANGLE_IFACE_FORMAT = "st_mangle_%s_OUTPUT";
+ const char* SecondaryTableController::LOCAL_MANGLE_POSTROUTING = "st_mangle_POSTROUTING";
const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
- const char* SecondaryTableController::LOCAL_FILTER_OUTPUT = "st_filter_OUTPUT";
-SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) {
- 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(NetworkController* controller) :
+ mNetCtrl(controller) {
}
SecondaryTableController::~SecondaryTableController() {
int SecondaryTableController::setFwmarkRoute(const char* iface, const char *dest, int prefix,
bool add) {
- int tableIndex = findTableNumber(iface);
- if (tableIndex == -1) {
- errno = EINVAL;
- return -1;
- }
- int mark = tableIndex + BASE_TABLE_NUMBER;
+ unsigned netId = mNetCtrl->getNetworkId(iface);
char mark_str[11] = {0};
- char chain_str[IFNAMSIZ + 18];
char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
- snprintf(mark_str, sizeof(mark_str), "%d", mark);
+ snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
- snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
- return execIptables(getIptablesTarget(dest),
- "-t",
- "mangle",
- add ? "-A" : "-D",
- chain_str,
- "-d",
- dest_str,
- "-j",
- "MARK",
- "--set-mark",
- mark_str,
- NULL);
+ const char *rule_cmd[] = {
+ IP_PATH,
+ getVersion(dest_str),
+ "rule",
+ add ? "add" : "del",
+ "prio",
+ RULE_PRIO,
+ "to",
+ dest_str,
+ "fwmark",
+ mark_str,
+ "table",
+ mark_str
+ };
+ return runCmd(ARRAY_SIZE(rule_cmd), rule_cmd);
}
int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
errno = EINVAL;
return -1;
}
- int mark = tableIndex + BASE_TABLE_NUMBER;
- if (add) {
- if (!mUidMarkMap->add(uid_start, uid_end, mark)) {
- errno = EINVAL;
- return -1;
- }
- } else {
- if (!mUidMarkMap->remove(uid_start, uid_end, mark)) {
- errno = EINVAL;
- return -1;
- }
- }
+
char uid_str[24] = {0};
- char chain_str[IFNAMSIZ + 18];
snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
- snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
+ char mark_str[11] = {0};
- snprintf(mark_str, sizeof(mark_str), "%d", mark);
++ snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
return execIptables(V4V6,
"-t",
"mangle",
#define IFNAMSIZ 16
#endif
-static const int INTERFACES_TRACKED = 10;
static const int BASE_TABLE_NUMBER = 60;
- static const int PROTECT_MARK = 0x1;
-static int MAX_TABLE_NUMBER = BASE_TABLE_NUMBER + INTERFACES_TRACKED;
static const char *EXEMPT_PRIO = "99";
static const char *RULE_PRIO = "100";