Add UID range support to VPNs.
This adds the necessary routing rules.
Future CLs will add the ability to select the right netId for connect(),
setNetworkForSocket(), DNS resolutions, etc.
Bug: 15409918
Change-Id: I88a67660d49cecda834dd72ab947fbfed250f09d
diff --git a/server/Android.mk b/server/Android.mk
index 99795a2..541644e 100644
--- a/server/Android.mk
+++ b/server/Android.mk
@@ -64,6 +64,7 @@
SecondaryTableController.cpp \
SoftapController.cpp \
TetherController.cpp \
+ UidRanges.cpp \
VirtualNetwork.cpp \
main.cpp \
oem_iptables_hook.cpp \
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index fd99555..7e408f0 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -45,6 +45,7 @@
#include "NetdConstants.h"
#include "FirewallController.h"
#include "RouteController.h"
+#include "UidRanges.h"
#include <string>
#include <vector>
@@ -1746,8 +1747,33 @@
return success(client);
}
- // network <bind|unbind> <netId> <uid1> .. <uidN>
- // -- uid range can be specified as "uidX-uidY"
+ // 0 1 2 3 4
+ // network users add <netId> [<uid>[-<uid>]] ...
+ // network users remove <netId> [<uid>[-<uid>]] ...
+ if (!strcmp(argv[1], "users")) {
+ if (argc < 4) {
+ return syntaxError(client, "Missing argument");
+ }
+ // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
+ unsigned netId = strtoul(argv[3], NULL, 0);
+ UidRanges uidRanges;
+ if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
+ return syntaxError(client, "Invalid UIDs");
+ }
+ if (!strcmp(argv[2], "add")) {
+ if (int ret = sNetCtrl->addUsersToNetwork(netId, uidRanges)) {
+ return operationError(client, "addUsersToNetwork() failed", ret);
+ }
+ } else if (!strcmp(argv[2], "remove")) {
+ if (int ret = sNetCtrl->removeUsersFromNetwork(netId, uidRanges)) {
+ return operationError(client, "removeUsersFromNetwork() failed", ret);
+ }
+ } else {
+ return syntaxError(client, "Unknown argument");
+ }
+ return success(client);
+ }
+
// TODO:
// o tethering
// o p2p
diff --git a/server/NetdConstants.h b/server/NetdConstants.h
index 4291bbc..7b894a8 100644
--- a/server/NetdConstants.h
+++ b/server/NetdConstants.h
@@ -49,4 +49,6 @@
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+const uid_t INVALID_UID = static_cast<uid_t>(-1);
+
#endif
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 8a51bcb..0ce82c3 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -302,6 +302,32 @@
return 0;
}
+int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
+ android::RWLock::AutoWLock lock(mRWLock);
+ auto iter = mVirtualNetworks.find(netId);
+ if (iter == mVirtualNetworks.end()) {
+ ALOGE("invalid netId %u", netId);
+ return -EINVAL;
+ }
+ if (int ret = iter->second->addUsers(uidRanges)) {
+ return ret;
+ }
+ return 0;
+}
+
+int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
+ android::RWLock::AutoWLock lock(mRWLock);
+ auto iter = mVirtualNetworks.find(netId);
+ if (iter == mVirtualNetworks.end()) {
+ ALOGE("invalid netId %u", netId);
+ return -EINVAL;
+ }
+ if (int ret = iter->second->removeUsers(uidRanges)) {
+ return ret;
+ }
+ return 0;
+}
+
int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
const char* nexthop, bool legacy, uid_t uid) {
return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 7f572d6..cc6e953 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -29,6 +29,7 @@
class Network;
class PhysicalNetwork;
+class UidRanges;
class VirtualNetwork;
/*
@@ -68,6 +69,9 @@
int setPermissionForNetworks(Permission permission,
const std::vector<unsigned>& netIds) WARN_UNUSED_RESULT;
+ int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+ int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+
// Routes are added to tables determined by the interface, so only |interface| is actually used.
// |netId| is given only to sanity check that the interface has the correct netId.
int addRoute(unsigned netId, const char* interface, const char* destination,
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 2d8e75f..30bdae8 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -17,6 +17,7 @@
#include "RouteController.h"
#include "Fwmark.h"
+#include "UidRanges.h"
#define LOG_TAG "Netd"
#include "log/log.h"
@@ -58,8 +59,6 @@
"Android-specific FRA_UID_{START,END} values also assigned in Linux uapi. "
"Check that these values match what the kernel does and then update this assertion.");
-const uid_t INVALID_UID = static_cast<uid_t>(-1);
-
const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK;
const uint16_t NETLINK_CREATE_REQUEST_FLAGS = NETLINK_REQUEST_FLAGS | NLM_F_CREATE | NLM_F_EXCL;
@@ -305,12 +304,33 @@
return sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
}
-WARN_UNUSED_RESULT int modifyPerNetworkRules(unsigned netId, const char* interface,
- Permission permission, bool add, bool modifyIptables) {
- uint32_t table = getRouteTableForInterface(interface);
+WARN_UNUSED_RESULT int modifyIncomingPacketMark(unsigned netId, const char* interface, bool add) {
+ // An iptables rule to mark incoming packets on a network with the netId of the network.
+ //
+ // This is so that the kernel can:
+ // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
+ // ping replies).
+ // + Mark sockets that accept connections from this interface so that the connection stays on
+ // the same interface.
+ char markString[UINT32_HEX_STRLEN];
+ snprintf(markString, sizeof(markString), "0x%x", netId);
+ if (execIptables(V4V6, "-t", "mangle", add ? "-A" : "-D", "INPUT", "-i", interface, "-j",
+ "MARK", "--set-mark", markString, NULL)) {
+ ALOGE("failed to change iptables rule that sets incoming packet mark");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+WARN_UNUSED_RESULT int modifyPerNetworkRules(unsigned netId, const char* interface, uint32_t table,
+ Permission permission, uid_t uidStart, uid_t uidEnd,
+ bool add, bool modifyIptables) {
if (!table) {
- ALOGE("cannot find interface %s", interface);
- return -ESRCH;
+ table = getRouteTableForInterface(interface);
+ if (!table) {
+ ALOGE("cannot find interface %s", interface);
+ return -ESRCH;
+ }
}
uint16_t action = add ? RTM_NEWRULE : RTM_DELRULE;
@@ -325,7 +345,7 @@
fwmark.permission = permission;
mask.permission = permission;
if (int ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark.intValue,
- mask.intValue, interface, INVALID_UID, INVALID_UID)) {
+ mask.intValue, interface, uidStart, uidEnd)) {
return ret;
}
@@ -337,7 +357,7 @@
fwmark.netId = netId;
mask.netId = FWMARK_NET_ID_MASK;
if (int ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark.intValue,
- mask.intValue, NULL, INVALID_UID, INVALID_UID)) {
+ mask.intValue, NULL, uidStart, uidEnd)) {
return ret;
}
@@ -351,70 +371,83 @@
fwmark.explicitlySelected = true;
mask.explicitlySelected = true;
if (int ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark.intValue,
- mask.intValue, NULL, INVALID_UID, INVALID_UID)) {
+ mask.intValue, NULL, uidStart, uidEnd)) {
return ret;
}
- // An iptables rule to mark incoming packets on a network with the netId of the network.
- //
- // This is so that the kernel can:
- // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
- // ping replies).
- // + Mark sockets that accept connections from this interface so that the connection stays on
- // the same interface.
if (modifyIptables) {
- char markString[UINT32_HEX_STRLEN];
- snprintf(markString, sizeof(markString), "0x%x", netId);
- if (execIptables(V4V6, "-t", "mangle", add ? "-A" : "-D", "INPUT", "-i", interface,
- "-j", "MARK", "--set-mark", markString, NULL)) {
- ALOGE("failed to change iptables rule that sets incoming packet mark");
- return -EREMOTEIO;
+ if (int ret = modifyIncomingPacketMark(netId, interface, add)) {
+ return ret;
}
}
return 0;
}
-WARN_UNUSED_RESULT int modifyVpnRules(unsigned netId, const char* interface, uint16_t action) {
+// Adds or removes rules for VPNs that affect UIDs in |uidRanges|. If |modifyInterfaceBasedRules|
+// is true, also modifies the rules that are based only on the |interface| and not on |uidRanges|.
+// When adding or removing an interface to the VPN, set it to true. When adding or removing UIDs
+// without changing the VPN's interfaces, set it to false.
+WARN_UNUSED_RESULT int modifyVpnRules(unsigned netId, const char* interface,
+ const UidRanges& uidRanges, bool add,
+ bool modifyInterfaceBasedRules) {
uint32_t table = getRouteTableForInterface(interface);
if (!table) {
ALOGE("cannot find interface %s", interface);
return -ESRCH;
}
+ uint16_t action = add ? RTM_NEWRULE : RTM_DELRULE;
+
Fwmark fwmark;
Fwmark mask;
- // A rule to route all traffic from a given set of UIDs to go over the VPN.
- //
- // Notice that this rule doesn't use the netId. I.e., no matter what netId the user's socket may
- // have, if they are subject to this VPN, their traffic has to go through it. Allows the traffic
- // to bypass the VPN if the protectedFromVpn bit is set.
- //
- // TODO: Actually implement the "from a set of UIDs" part.
fwmark.protectedFromVpn = false;
mask.protectedFromVpn = true;
- if (int ret = modifyIpRule(action, RULE_PRIORITY_SECURE_VPN, table, fwmark.intValue,
- mask.intValue, NULL, INVALID_UID, INVALID_UID)) {
- return ret;
+
+ for (const std::pair<uid_t, uid_t>& range : uidRanges.getRanges()) {
+ if (int ret = modifyPerNetworkRules(netId, interface, table, PERMISSION_NONE, range.first,
+ range.second, add, false)) {
+ return ret;
+ }
+
+ // A rule to route all traffic from a given set of UIDs to go over the VPN.
+ //
+ // Notice that this rule doesn't use the netId. I.e., no matter what netId the user's socket
+ // may have, if they are subject to this VPN, their traffic has to go through it. Allows the
+ // traffic to bypass the VPN if the protectedFromVpn bit is set.
+ if (int ret = modifyIpRule(action, RULE_PRIORITY_SECURE_VPN, table, fwmark.intValue,
+ mask.intValue, NULL, range.first, range.second)) {
+ return ret;
+ }
}
- // A rule to allow privileged apps to send traffic over this VPN even if they are not part of
- // the target set of UIDs.
- //
- // This is needed for DnsProxyListener to correctly resolve a request for a user who is in the
- // target set, but where the DnsProxyListener itself is not.
- fwmark.protectedFromVpn = false;
- mask.protectedFromVpn = false;
+ if (modifyInterfaceBasedRules) {
+ if (int ret = modifyIncomingPacketMark(netId, interface, add)) {
+ return ret;
+ }
- fwmark.netId = netId;
- mask.netId = FWMARK_NET_ID_MASK;
+ // A rule to allow privileged apps to send traffic over this VPN even if they are not part
+ // of the target set of UIDs.
+ //
+ // This is needed for DnsProxyListener to correctly resolve a request for a user who is in
+ // the target set, but where the DnsProxyListener itself is not.
+ fwmark.protectedFromVpn = false;
+ mask.protectedFromVpn = false;
- fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL;
- mask.permission = PERMISSION_CONNECTIVITY_INTERNAL;
+ fwmark.netId = netId;
+ mask.netId = FWMARK_NET_ID_MASK;
- return modifyIpRule(action, RULE_PRIORITY_SECURE_VPN, table, fwmark.intValue, mask.intValue,
- NULL, INVALID_UID, INVALID_UID);
+ fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL;
+ mask.permission = PERMISSION_CONNECTIVITY_INTERNAL;
+
+ if (int ret = modifyIpRule(action, RULE_PRIORITY_SECURE_VPN, table, fwmark.intValue,
+ mask.intValue, NULL, INVALID_UID, INVALID_UID)) {
+ return ret;
+ }
+ }
+
+ return 0;
}
WARN_UNUSED_RESULT int modifyDefaultNetworkRules(const char* interface, Permission permission,
@@ -579,29 +612,27 @@
int RouteController::addInterfaceToNetwork(unsigned netId, const char* interface,
Permission permission) {
- return modifyPerNetworkRules(netId, interface, permission, true, true);
+ return modifyPerNetworkRules(netId, interface, 0, permission, INVALID_UID, INVALID_UID, true,
+ true);
}
int RouteController::removeInterfaceFromNetwork(unsigned netId, const char* interface,
Permission permission) {
- if (int ret = modifyPerNetworkRules(netId, interface, permission, false, true)) {
+ if (int ret = modifyPerNetworkRules(netId, interface, 0, permission, INVALID_UID, INVALID_UID,
+ false, true)) {
return ret;
}
return flushRoutes(interface);
}
-int RouteController::addInterfaceToVpn(unsigned netId, const char* interface) {
- if (int ret = modifyPerNetworkRules(netId, interface, PERMISSION_NONE, true, true)) {
- return ret;
- }
- return modifyVpnRules(netId, interface, RTM_NEWRULE);
+int RouteController::addInterfaceToVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) {
+ return modifyVpnRules(netId, interface, uidRanges, true, true);
}
-int RouteController::removeInterfaceFromVpn(unsigned netId, const char* interface) {
- if (int ret = modifyPerNetworkRules(netId, interface, PERMISSION_NONE, false, true)) {
- return ret;
- }
- if (int ret = modifyVpnRules(netId, interface, RTM_DELRULE)) {
+int RouteController::removeInterfaceFromVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) {
+ if (int ret = modifyVpnRules(netId, interface, uidRanges, false, true)) {
return ret;
}
return flushRoutes(interface);
@@ -610,10 +641,22 @@
int RouteController::modifyNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission, Permission newPermission) {
// Add the new rules before deleting the old ones, to avoid race conditions.
- if (int ret = modifyPerNetworkRules(netId, interface, newPermission, true, false)) {
+ if (int ret = modifyPerNetworkRules(netId, interface, 0, newPermission, INVALID_UID,
+ INVALID_UID, true, false)) {
return ret;
}
- return modifyPerNetworkRules(netId, interface, oldPermission, false, false);
+ return modifyPerNetworkRules(netId, interface, 0, oldPermission, INVALID_UID, INVALID_UID,
+ false, false);
+}
+
+int RouteController::addUsersToVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) {
+ return modifyVpnRules(netId, interface, uidRanges, true, false);
+}
+
+int RouteController::removeUsersFromVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) {
+ return modifyVpnRules(netId, interface, uidRanges, false, false);
}
int RouteController::addToDefaultNetwork(const char* interface, Permission permission) {
diff --git a/server/RouteController.h b/server/RouteController.h
index c6cd760..9162023 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -22,6 +22,8 @@
#include <sys/types.h>
+class UidRanges;
+
class RouteController {
public:
// How the routing table number is determined for route modification requests.
@@ -40,8 +42,10 @@
static int removeInterfaceFromNetwork(unsigned netId, const char* interface,
Permission permission) WARN_UNUSED_RESULT;
- static int addInterfaceToVpn(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
- static int removeInterfaceFromVpn(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
+ static int addInterfaceToVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+ static int removeInterfaceFromVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) WARN_UNUSED_RESULT;
static int modifyNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
@@ -51,6 +55,11 @@
static int removeFromDefaultNetwork(const char* interface,
Permission permission) WARN_UNUSED_RESULT;
+ static int addUsersToVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+ static int removeUsersFromVpn(unsigned netId, const char* interface,
+ const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+
static int addRoute(const char* interface, const char* destination, const char* nexthop,
TableType tableType, uid_t uid) WARN_UNUSED_RESULT;
static int removeRoute(const char* interface, const char* destination, const char* nexthop,
diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp
new file mode 100644
index 0000000..d752cbf
--- /dev/null
+++ b/server/UidRanges.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "UidRanges.h"
+
+#include "NetdConstants.h"
+
+#include <stdlib.h>
+
+const std::vector<std::pair<uid_t, uid_t>>& UidRanges::getRanges() const {
+ return mRanges;
+}
+
+bool UidRanges::parseFrom(int argc, char* argv[]) {
+ mRanges.clear();
+ for (int i = 0; i < argc; ++i) {
+ if (!*argv[i]) {
+ // The UID string is empty.
+ return false;
+ }
+ char* endPtr;
+ uid_t uidStart = strtoul(argv[i], &endPtr, 0);
+ uid_t uidEnd;
+ if (!*endPtr) {
+ // Found a single UID. The range contains just the one UID.
+ uidEnd = uidStart;
+ } else if (*endPtr == '-') {
+ if (!*++endPtr) {
+ // Unexpected end of string.
+ return false;
+ }
+ uidEnd = strtoul(endPtr, &endPtr, 0);
+ if (*endPtr) {
+ // Illegal trailing chars.
+ return false;
+ }
+ if (uidEnd < uidStart) {
+ // Invalid order.
+ return false;
+ }
+ } else {
+ // Not a single uid, not a range. Found some other illegal char.
+ return false;
+ }
+ if (uidStart == INVALID_UID || uidEnd == INVALID_UID) {
+ // Invalid UIDs.
+ return false;
+ }
+ mRanges.push_back(std::pair<uid_t, uid_t>(uidStart, uidEnd));
+ }
+ std::sort(mRanges.begin(), mRanges.end());
+ return true;
+}
+
+void UidRanges::add(const UidRanges& other) {
+ auto middle = mRanges.insert(mRanges.end(), other.mRanges.begin(), other.mRanges.end());
+ std::inplace_merge(mRanges.begin(), middle, mRanges.end());
+}
+
+void UidRanges::remove(const UidRanges& other) {
+ auto end = std::set_difference(mRanges.begin(), mRanges.end(), other.mRanges.begin(),
+ other.mRanges.end(), mRanges.begin());
+ mRanges.erase(end, mRanges.end());
+}
diff --git a/server/UidRanges.h b/server/UidRanges.h
new file mode 100644
index 0000000..88685b4
--- /dev/null
+++ b/server/UidRanges.h
@@ -0,0 +1,37 @@
+/*
+ * 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_SERVER_UID_RANGES_H
+#define NETD_SERVER_UID_RANGES_H
+
+#include <sys/types.h>
+#include <utility>
+#include <vector>
+
+class UidRanges {
+public:
+ const std::vector<std::pair<uid_t, uid_t>>& getRanges() const;
+
+ bool parseFrom(int argc, char* argv[]);
+
+ void add(const UidRanges& other);
+ void remove(const UidRanges& other);
+
+private:
+ std::vector<std::pair<uid_t, uid_t>> mRanges;
+};
+
+#endif // NETD_SERVER_UID_RANGES_H
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 11998da..bc94d00 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -31,7 +31,7 @@
if (hasInterface(interface)) {
return 0;
}
- if (int ret = RouteController::addInterfaceToVpn(mNetId, interface.c_str())) {
+ if (int ret = RouteController::addInterfaceToVpn(mNetId, interface.c_str(), mUidRanges)) {
ALOGE("failed to add interface %s to VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -43,10 +43,32 @@
if (!hasInterface(interface)) {
return 0;
}
- if (int ret = RouteController::removeInterfaceFromVpn(mNetId, interface.c_str())) {
+ if (int ret = RouteController::removeInterfaceFromVpn(mNetId, interface.c_str(), mUidRanges)) {
ALOGE("failed to remove interface %s from VPN netId %u", interface.c_str(), mNetId);
return ret;
}
mInterfaces.erase(interface);
return 0;
}
+
+int VirtualNetwork::addUsers(const UidRanges& uidRanges) {
+ for (const std::string& interface : mInterfaces) {
+ if (int ret = RouteController::addUsersToVpn(mNetId, interface.c_str(), uidRanges)) {
+ ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
+ return ret;
+ }
+ }
+ mUidRanges.add(uidRanges);
+ return 0;
+}
+
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges) {
+ for (const std::string& interface : mInterfaces) {
+ if (int ret = RouteController::removeUsersFromVpn(mNetId, interface.c_str(), uidRanges)) {
+ ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
+ return ret;
+ }
+ }
+ mUidRanges.remove(uidRanges);
+ return 0;
+}
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index cb412bb..fad28fd 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -18,15 +18,21 @@
#define NETD_SERVER_VIRTUAL_NETWORK_H
#include "Network.h"
+#include "UidRanges.h"
class VirtualNetwork : public Network {
public:
VirtualNetwork(unsigned netId, uid_t ownerUid);
virtual ~VirtualNetwork();
+ int addUsers(const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+ int removeUsers(const UidRanges& uidRanges) WARN_UNUSED_RESULT;
+
private:
int addInterface(const std::string& interface) override WARN_UNUSED_RESULT;
int removeInterface(const std::string& interface) override WARN_UNUSED_RESULT;
+
+ UidRanges mUidRanges;
};
#endif // NETD_SERVER_VIRTUAL_NETWORK_H