Implement the "select network" fwmark command.
Change-Id: Id4a49eb288b18022d53014d1ae2211ed7d1099a6
diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp
index 56127ca..605e724 100644
--- a/server/FwmarkServer.cpp
+++ b/server/FwmarkServer.cpp
@@ -20,6 +20,7 @@
#include "FwmarkCommand.h"
#include "NetworkController.h"
#include "PermissionsController.h"
+#include "resolv_netid.h"
#include <sys/socket.h>
#include <unistd.h>
@@ -87,7 +88,7 @@
}
if (*fd < 0) {
- errno = ENOENT;
+ errno = EBADF;
return;
}
@@ -97,6 +98,8 @@
return;
}
+ fwmark.permission = mPermissionsController->getPermissionForUser(client->getUid());
+
switch (command.cmdId) {
case FwmarkCommand::ON_ACCEPT: {
// Called after a socket accept(). The kernel would've marked the netId into the socket
@@ -118,8 +121,26 @@
}
case FwmarkCommand::SELECT_NETWORK: {
- // set socket mark
- // TODO
+ fwmark.netId = command.netId;
+ if (command.netId == NETID_UNSET) {
+ fwmark.explicitlySelected = false;
+ } else {
+ fwmark.explicitlySelected = true;
+ // If the socket already has the protectedFromVpn bit set, don't reset it, because
+ // non-CONNECTIVITY_INTERNAL apps (e.g.: VpnService) may also protect sockets.
+ if (fwmark.permission & PERMISSION_CONNECTIVITY_INTERNAL) {
+ fwmark.protectedFromVpn = true;
+ }
+ if (!mNetworkController->isValidNetwork(command.netId)) {
+ errno = ENONET;
+ return;
+ }
+ if (!mPermissionsController->isUserPermittedOnNetwork(client->getUid(),
+ command.netId)) {
+ errno = EPERM;
+ return;
+ }
+ }
break;
}
@@ -136,8 +157,6 @@
}
}
- fwmark.permission = mPermissionsController->getPermissionForUser(client->getUid());
-
if (setsockopt(*fd, SOL_SOCKET, SO_MARK, &fwmark.intValue, sizeof(fwmark.intValue)) == -1) {
return;
}