OSDN Git Service

Add netd support for uid based routing for DNS
authorChad Brubaker <cbrubaker@google.com>
Fri, 21 Jun 2013 22:26:35 +0000 (15:26 -0700)
committerChad Brubaker <cbrubaker@google.com>
Wed, 26 Jun 2013 22:21:46 +0000 (15:21 -0700)
DNSProxyListener now supports bionic changes for marking DNS requests
for routing DNS requests with the uid routing rules

Change-Id: Iac9aa1bb14834be6da5e512405f23c6a72dc71ed

Android.mk
CommandListener.cpp
CommandListener.h
DnsProxyListener.cpp
DnsProxyListener.h
SecondaryTableController.cpp
SecondaryTableController.h
UidMarkMap.cpp [new file with mode: 0644]
UidMarkMap.h [new file with mode: 0644]
main.cpp

index f49a7f9..da4a7ad 100644 (file)
@@ -22,6 +22,7 @@ LOCAL_SRC_FILES:=                                      \
                   SoftapController.cpp                 \
                   TetherController.cpp                 \
                   oem_iptables_hook.cpp                \
+                  UidMarkMap.cpp                       \
                   main.cpp                             \
 
 
index 026797f..a480d67 100644 (file)
@@ -128,7 +128,7 @@ static void createChildChains(IptablesTarget target, const char* table, const ch
     } while (*(++childChain) != NULL);
 }
 
-CommandListener::CommandListener() :
+CommandListener::CommandListener(UidMarkMap *map) :
                  FrameworkListener("netd", true) {
     registerCmd(new InterfaceCmd());
     registerCmd(new IpFwdCmd());
@@ -144,7 +144,7 @@ CommandListener::CommandListener() :
     registerCmd(new ClatdCmd());
 
     if (!sSecondaryTableCtrl)
-        sSecondaryTableCtrl = new SecondaryTableController();
+        sSecondaryTableCtrl = new SecondaryTableController(map);
     if (!sTetherCtrl)
         sTetherCtrl = new TetherController();
     if (!sNatCtrl)
index 1db81f8..23b8dd1 100644 (file)
@@ -31,6 +31,7 @@
 #include "SecondaryTableController.h"
 #include "FirewallController.h"
 #include "ClatdController.h"
+#include "UidMarkMap.h"
 
 class CommandListener : public FrameworkListener {
     static TetherController *sTetherCtrl;
@@ -46,7 +47,7 @@ class CommandListener : public FrameworkListener {
     static ClatdController *sClatdCtrl;
 
 public:
-    CommandListener();
+    CommandListener(UidMarkMap *map);
     virtual ~CommandListener() {}
 
 private:
index 18fa267..a025828 100644 (file)
 #include <cutils/log.h>
 #include <sysutils/SocketClient.h>
 
+#include "NetdConstants.h"
 #include "DnsProxyListener.h"
 #include "ResponseCode.h"
 
-DnsProxyListener::DnsProxyListener() :
+DnsProxyListener::DnsProxyListener(UidMarkMap *map) :
                  FrameworkListener("dnsproxyd") {
-    registerCmd(new GetAddrInfoCmd());
-    registerCmd(new GetHostByAddrCmd());
-    registerCmd(new GetHostByNameCmd());
+    registerCmd(new GetAddrInfoCmd(map));
+    registerCmd(new GetHostByAddrCmd(map));
+    registerCmd(new GetHostByNameCmd(map));
+    mUidMarkMap = map;
 }
 
 DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
@@ -51,14 +53,16 @@ DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
                                                          struct addrinfo* hints,
                                                          char* iface,
                                                          pid_t pid,
-                                                         uid_t uid)
+                                                         uid_t uid,
+                                                         int mark)
         : mClient(c),
           mHost(host),
           mService(service),
           mHints(hints),
           mIface(iface),
           mPid(pid),
-          mUid(uid) {
+          mUid(uid),
+          mMark(mark) {
 }
 
 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
@@ -133,7 +137,7 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
 
     struct addrinfo* result = NULL;
     uint32_t rv = android_getaddrinfoforiface(mHost, mService, mHints, mIface ? mIface : tmp,
-            &result);
+            mMark, &result);
     if (rv) {
         // getaddrinfo failed
         mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
@@ -159,8 +163,9 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
     mClient->decRef();
 }
 
-DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() :
+DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(UidMarkMap *uidMarkMap) :
     NetdCommand("getaddrinfo") {
+        mUidMarkMap = uidMarkMap;
 }
 
 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
@@ -227,7 +232,8 @@ int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
 
     cli->incRef();
     DnsProxyListener::GetAddrInfoHandler* handler =
-        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid, uid);
+        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid, uid,
+                                    mUidMarkMap->getMark(uid));
     handler->start();
 
     return 0;
@@ -236,8 +242,9 @@ int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
 /*******************************************************
  *                  GetHostByName                      *
  *******************************************************/
-DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd() :
+DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(UidMarkMap *uidMarkMap) :
         NetdCommand("gethostbyname") {
+            mUidMarkMap = uidMarkMap;
 }
 
 int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
@@ -276,7 +283,8 @@ int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
 
     cli->incRef();
     DnsProxyListener::GetHostByNameHandler* handler =
-            new DnsProxyListener::GetHostByNameHandler(cli, pid, uid, iface, name, af);
+            new DnsProxyListener::GetHostByNameHandler(cli, pid, uid, iface, name, af,
+                    mUidMarkMap->getMark(uid));
     handler->start();
 
     return 0;
@@ -287,13 +295,15 @@ DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
                                                              uid_t uid,
                                                              char* iface,
                                                              char* name,
-                                                             int af)
+                                                             int af,
+                                                             int mark)
         : mClient(c),
           mPid(pid),
           mUid(uid),
           mIface(iface),
           mName(name),
-          mAf(af) {
+          mAf(af),
+          mMark(mark) {
 }
 
 DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
@@ -330,7 +340,7 @@ void DnsProxyListener::GetHostByNameHandler::run() {
 
     struct hostent* hp;
 
-    hp = android_gethostbynameforiface(mName, mAf, mIface ? mIface : iface);
+    hp = android_gethostbynameforiface(mName, mAf, mIface ? mIface : iface, mMark);
 
     if (DBG) {
         ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %d\n",
@@ -357,8 +367,9 @@ void DnsProxyListener::GetHostByNameHandler::run() {
 /*******************************************************
  *                  GetHostByAddr                      *
  *******************************************************/
-DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() :
+DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd(UidMarkMap *uidMarkMap) :
         NetdCommand("gethostbyaddr") {
+        mUidMarkMap = uidMarkMap;
 }
 
 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli,
@@ -405,7 +416,8 @@ int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli,
 
     cli->incRef();
     DnsProxyListener::GetHostByAddrHandler* handler =
-            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface, pid, uid);
+            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface, pid,
+                    uid, mUidMarkMap->getMark(uid));
     handler->start();
 
     return 0;
@@ -417,14 +429,16 @@ DnsProxyListener::GetHostByAddrHandler::GetHostByAddrHandler(SocketClient* c,
                                                              int   addressFamily,
                                                              char* iface,
                                                              pid_t pid,
-                                                             uid_t uid)
+                                                             uid_t uid,
+                                                             int mark)
         : mClient(c),
           mAddress(address),
           mAddressLen(addressLen),
           mAddressFamily(addressFamily),
           mIface(iface),
           mPid(pid),
-          mUid(uid) {
+          mUid(uid),
+          mMark(mark) {
 }
 
 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() {
@@ -462,7 +476,7 @@ void DnsProxyListener::GetHostByAddrHandler::run() {
 
     // NOTE gethostbyaddr should take a void* but bionic thinks it should be char*
     hp = android_gethostbyaddrforiface((char*)mAddress, mAddressLen, mAddressFamily,
-            mIface ? mIface : tmp);
+            mIface ? mIface : tmp, mMark);
 
     if (DBG) {
         ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
index 758ca76..2061d71 100644 (file)
 #include <sysutils/FrameworkListener.h>
 
 #include "NetdCommand.h"
+#include "UidMarkMap.h"
 
 class DnsProxyListener : public FrameworkListener {
 public:
-    DnsProxyListener();
+    DnsProxyListener(UidMarkMap *map);
     virtual ~DnsProxyListener() {}
 
 private:
+    UidMarkMap *mUidMarkMap;
     class GetAddrInfoCmd : public NetdCommand {
     public:
-        GetAddrInfoCmd();
+        GetAddrInfoCmd(UidMarkMap *uidMarkMap);
         virtual ~GetAddrInfoCmd() {}
         int runCommand(SocketClient *c, int argc, char** argv);
+    private:
+        UidMarkMap *mUidMarkMap;
     };
 
     class GetAddrInfoHandler {
@@ -43,7 +47,8 @@ private:
                            struct addrinfo* hints,
                            char* iface,
                            pid_t pid,
-                           uid_t uid);
+                           uid_t uid,
+                           int mark);
         ~GetAddrInfoHandler();
 
         static void* threadStart(void* handler);
@@ -58,14 +63,17 @@ private:
         char* mIface; // owned
         pid_t mPid;
         uid_t mUid;
+        int mMark;
     };
 
     /* ------ gethostbyname ------*/
     class GetHostByNameCmd : public NetdCommand {
     public:
-        GetHostByNameCmd();
+        GetHostByNameCmd(UidMarkMap *uidMarkMap);
         virtual ~GetHostByNameCmd() {}
         int runCommand(SocketClient *c, int argc, char** argv);
+    private:
+        UidMarkMap *mUidMarkMap;
     };
 
     class GetHostByNameHandler {
@@ -75,7 +83,8 @@ private:
                             uid_t uid,
                             char *iface,
                             char *name,
-                            int af);
+                            int af,
+                            int mark);
         ~GetHostByNameHandler();
         static void* threadStart(void* handler);
         void start();
@@ -87,14 +96,17 @@ private:
         char* mIface; // owned
         char* mName; // owned
         int mAf;
+        int mMark;
     };
 
     /* ------ gethostbyaddr ------*/
     class GetHostByAddrCmd : public NetdCommand {
     public:
-        GetHostByAddrCmd();
+        GetHostByAddrCmd(UidMarkMap *uidMarkMap);
         virtual ~GetHostByAddrCmd() {}
         int runCommand(SocketClient *c, int argc, char** argv);
+    private:
+        UidMarkMap *mUidMarkMap;
     };
 
     class GetHostByAddrHandler {
@@ -105,7 +117,8 @@ private:
                             int   addressFamily,
                             char* iface,
                             pid_t pid,
-                            uid_t uid);
+                            uid_t uid,
+                            int mark);
         ~GetHostByAddrHandler();
 
         static void* threadStart(void* handler);
@@ -120,6 +133,7 @@ private:
         char* mIface; // owned
         pid_t mPid;
         uid_t mUid;
+        int   mMark;
     };
 };
 
index 222a0e0..89a307b 100644 (file)
@@ -39,7 +39,7 @@
 const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
 const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
 
-SecondaryTableController::SecondaryTableController() {
+SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) {
     int i;
     for (i=0; i < INTERFACES_TRACKED; i++) {
         mInterfaceTable[i][0] = 0;
@@ -301,10 +301,23 @@ int SecondaryTableController::removeUidRule(const char *iface, int uid_start, in
 int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
     int tableIndex = findTableNumber(iface);
     if (tableIndex == -1) {
+        errno = EINVAL;
         return -1;
     }
-    char tableIndex_str[11] = {0};
-    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
+    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 mark_str[11] = {0};
+    snprintf(mark_str, sizeof(mark_str), "%d", mark);
     char uid_str[24] = {0};
     snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
     return execIptables(V4V6,
@@ -319,7 +332,7 @@ int SecondaryTableController::setUidRule(const char *iface, int uid_start, int u
             "-j",
             "MARK",
             "--set-mark",
-            tableIndex_str,
+            mark_str,
             NULL);
 }
 
index 3941ba1..48baa9f 100644 (file)
@@ -20,6 +20,7 @@
 #include <sysutils/FrameworkListener.h>
 
 #include <net/if.h>
+#include "UidMarkMap.h"
 
 #ifndef IFNAMSIZ
 #define IFNAMSIZ 16
@@ -32,7 +33,7 @@ static int MAX_TABLE_NUMBER = BASE_TABLE_NUMBER + INTERFACES_TRACKED;
 class SecondaryTableController {
 
 public:
-    SecondaryTableController();
+    SecondaryTableController(UidMarkMap *map);
     virtual ~SecondaryTableController();
 
     int addRoute(SocketClient *cli, char *iface, char *dest, int prefixLen, char *gateway);
@@ -50,6 +51,8 @@ public:
 
 
 private:
+    UidMarkMap *mUidMarkMap;
+
     int setUidRule(const char* iface, int uid_start, int uid_end, bool add);
     int setFwmarkRule(const char *iface, bool add);
     int modifyRoute(SocketClient *cli, const char *action, char *iface, char *dest, int prefix,
diff --git a/UidMarkMap.cpp b/UidMarkMap.cpp
new file mode 100644 (file)
index 0000000..34764cf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 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 "UidMarkMap.h"
+
+UidMarkMap::UidMarkEntry::UidMarkEntry(int start, int end, int new_mark) :
+                                            uid_start(start),
+                                            uid_end(end),
+                                            mark(new_mark) {
+};
+
+bool UidMarkMap::add(int uid_start, int uid_end, int mark) {
+    android::RWLock::AutoWLock lock(mRWLock);
+    if (uid_start > uid_end) {
+        return false;
+    }
+    android::netd::List<UidMarkEntry*>::iterator it;
+    for (it = mMap.begin(); it != mMap.end(); it++) {
+        UidMarkEntry *entry = *it;
+        if (entry->uid_start <= uid_end && uid_start <= entry->uid_end) {
+            return false;
+        }
+    }
+
+    UidMarkEntry *e = new UidMarkEntry(uid_start, uid_end, mark);
+    mMap.push_back(e);
+    return true;
+};
+
+bool UidMarkMap::remove(int uid_start, int uid_end, int mark) {
+    android::RWLock::AutoWLock lock(mRWLock);
+    android::netd::List<UidMarkEntry*>::iterator it;
+    for (it = mMap.begin(); it != mMap.end(); it++) {
+        UidMarkEntry *entry = *it;
+        if (entry->uid_start == uid_start && entry->uid_end == uid_end && entry->mark == mark) {
+            mMap.erase(it);
+            delete entry;
+            return true;
+        }
+    }
+    return false;
+};
+
+int UidMarkMap::getMark(int uid) {
+    android::RWLock::AutoRLock lock(mRWLock);
+    android::netd::List<UidMarkEntry*>::iterator it;
+    for (it = mMap.begin(); it != mMap.end(); it++) {
+        UidMarkEntry *entry = *it;
+        if (entry->uid_start <= uid && entry->uid_end >= uid) {
+            return entry->mark;
+        }
+    }
+    return -1;
+};
diff --git a/UidMarkMap.h b/UidMarkMap.h
new file mode 100644 (file)
index 0000000..52b9e83
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 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_UIDMARKMAP_H
+#define _NETD_UIDMARKMAP_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <List.h>
+#include <utils/RWLock.h>
+
+class UidMarkMap {
+public:
+    bool add(int uid_start, int uid_end, int mark);
+    bool remove(int uid_start, int uid_end, int mark);
+    int getMark(int uid);
+
+private:
+    struct UidMarkEntry {
+        int uid_start;
+        int uid_end;
+        int mark;
+        UidMarkEntry(int uid_start, int uid_end, int mark);
+    };
+
+    android::RWLock mRWLock;
+    android::netd::List<UidMarkEntry*> mMap;
+};
+#endif
index b466e42..104ebe1 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -34,6 +34,7 @@
 #include "NetlinkManager.h"
 #include "DnsProxyListener.h"
 #include "MDnsSdListener.h"
+#include "UidMarkMap.h"
 
 static void coldboot(const char *path);
 static void sigchld_handler(int sig);
@@ -56,8 +57,9 @@ int main() {
         exit(1);
     };
 
+    UidMarkMap *rangeMap = new UidMarkMap();
 
-    cl = new CommandListener();
+    cl = new CommandListener(rangeMap);
     nm->setBroadcaster((SocketListener *) cl);
 
     if (nm->start()) {
@@ -68,7 +70,7 @@ int main() {
     // Set local DNS mode, to prevent bionic from proxying
     // back to this service, recursively.
     setenv("ANDROID_DNS_MODE", "local", 1);
-    dpl = new DnsProxyListener();
+    dpl = new DnsProxyListener(rangeMap);
     if (dpl->startListener()) {
         ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
         exit(1);