OSDN Git Service

Introduce a SELECT_FOR_USER fwmarkd command.
authorSreeram Ramachandran <sreeram@google.com>
Fri, 11 Jul 2014 23:27:02 +0000 (16:27 -0700)
committerSreeram Ramachandran <sreeram@google.com>
Fri, 11 Jul 2014 23:27:02 +0000 (16:27 -0700)
This lets SYSTEM apps mark a socket with the network that would apply to an
arbitrary UID. I.e., either the VPN that applies to that user, or the default
network, if there's no such VPN.

This command will be used by system apps that proxy stuff for a user, so that
they can route the same way that user would have. Examples of such system apps
are the DnsProxyListener, MediaServer and DownloadManager.

The "explicit" bit is NOT set, so that if the user's VPN is a split tunnel, the
route lookup will fall-through to the default network as desired.

The "protect" bit is set, so that the socket bypasses any VPN applicable to the
system app itself. Note that even if the uid being proxied for is also subject
to the same VPN, this still works because the relevant rule doesn't care about
the protected bit (see modifyVpnSystemPermissionRule() in RouteController.cpp).

Change-Id: I4d501e5214b127f4ae9eaeb7befb1751cd102308

client/NetdClient.cpp
include/FwmarkCommand.h
include/NetdClient.h
server/FwmarkServer.cpp

index 68f1f31..fce362e 100644 (file)
@@ -62,7 +62,7 @@ int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
         }
     }
     if (FwmarkClient::shouldSetFwmark(family)) {
-        FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0};
+        FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
         if (int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket)) {
             return closeFdAndSetErrno(acceptedSocket, error);
         }
@@ -72,7 +72,7 @@ int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
 
 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
-        FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0};
+        FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
         if (int error = FwmarkClient().send(&command, sizeof(command), sockfd)) {
             errno = -error;
             return -1;
@@ -182,7 +182,7 @@ extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
     if (socketFd < 0) {
         return -EBADF;
     }
-    FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId};
+    FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
     return FwmarkClient().send(&command, sizeof(command), socketFd);
 }
 
@@ -198,6 +198,14 @@ extern "C" int protectFromVpn(int socketFd) {
     if (socketFd < 0) {
         return -EBADF;
     }
-    FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0};
+    FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
+    return FwmarkClient().send(&command, sizeof(command), socketFd);
+}
+
+extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
+    if (socketFd < 0) {
+        return -EBADF;
+    }
+    FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
     return FwmarkClient().send(&command, sizeof(command), socketFd);
 }
index 9ec93e2..57464b4 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef NETD_INCLUDE_FWMARK_COMMAND_H
 #define NETD_INCLUDE_FWMARK_COMMAND_H
 
+#include <sys/types.h>
+
 // Commands sent from clients to the fwmark server to mark sockets (i.e., set their SO_MARK).
 struct FwmarkCommand {
     enum {
@@ -24,8 +26,10 @@ struct FwmarkCommand {
         ON_CONNECT,
         SELECT_NETWORK,
         PROTECT_FROM_VPN,
+        SELECT_FOR_USER,
     } cmdId;
     unsigned netId;  // used only in the SELECT_NETWORK command; ignored otherwise.
+    uid_t uid;  // used only in the SELECT_FOR_USER command; ignored otherwise.
 };
 
 #endif  // NETD_INCLUDE_FWMARK_COMMAND_H
index 742902f..71529a3 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <stdbool.h>
 #include <sys/cdefs.h>
+#include <sys/types.h>
 
 __BEGIN_DECLS
 
@@ -34,6 +35,8 @@ int setNetworkForResolv(unsigned netId);
 
 int protectFromVpn(int socketFd);
 
+int setNetworkForUser(uid_t uid, int socketFd);
+
 __END_DECLS
 
 #endif  // NETD_INCLUDE_NETD_CLIENT_H
index 3a540bd..39a8d74 100644 (file)
@@ -134,6 +134,15 @@ int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
             break;
         }
 
+        case FwmarkCommand::SELECT_FOR_USER: {
+            if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
+                return -EPERM;
+            }
+            fwmark.netId = mNetworkController->getNetworkForUser(command.uid, NETID_UNSET, false);
+            fwmark.protectedFromVpn = true;
+            break;
+        }
+
         default: {
             // unknown command
             return -EPROTO;