OSDN Git Service

am 535b94fa: Merge "Offer to detect non-SSL/TLS network traffic."
authorJeff Sharkey <jsharkey@android.com>
Fri, 16 Jan 2015 01:49:08 +0000 (01:49 +0000)
committerAndroid Git Automerger <android-git-automerger@android.com>
Fri, 16 Jan 2015 01:49:08 +0000 (01:49 +0000)
* commit '535b94fa9d88097220de3ea04cb8d9a91114baa8':
  Offer to detect non-SSL/TLS network traffic.

server/ClatdController.cpp
server/ClatdController.h
server/CommandListener.cpp
server/InterfaceController.cpp
server/InterfaceController.h
server/ResolverController.cpp
server/ResolverController.h
server/RouteController.cpp
server/SoftapController.cpp
server/main.cpp

index c19e299..348a0dd 100644 (file)
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <map>
+#include <string>
+
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
 #define LOG_TAG "ClatdController"
 #include <cutils/log.h>
 
+#include <resolv_netid.h>
+
 #include "NetdConstants.h"
 #include "ClatdController.h"
 #include "Fwmark.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
 
+static const char* kClatdPath = "/system/bin/clatd";
+
 ClatdController::ClatdController(NetworkController* controller)
-        : mNetCtrl(controller), mClatdPid(0) {
+        : mNetCtrl(controller) {
 }
 
 ClatdController::~ClatdController() {
 }
 
-int ClatdController::startClatd(char *interface) {
-    pid_t pid;
+// Returns the PID of the clatd running on interface |interface|, or 0 if clatd is not running on
+// |interface|.
+pid_t ClatdController::getClatdPid(char* interface) {
+    auto it = mClatdPids.find(interface);
+    return (it == mClatdPids.end() ? 0 : it->second);
+}
 
-    if(mClatdPid != 0) {
-        ALOGE("clatd already running");
+int ClatdController::startClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
+
+    if (pid != 0) {
+        ALOGE("clatd pid=%d already started on %s", pid, interface);
         errno = EBUSY;
         return -1;
     }
 
-    if (!isIfaceName(interface)) {
-        errno = ENOENT;
+    // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
+    unsigned netId = mNetCtrl->getNetworkForInterface(interface);
+    if (netId == NETID_UNSET) {
+        ALOGE("interface %s not assigned to any netId", interface);
+        errno = ENODEV;
         return -1;
     }
 
-    ALOGD("starting clatd");
+    char netIdString[UINT32_STRLEN];
+    snprintf(netIdString, sizeof(netIdString), "%u", netId);
+
+    Fwmark fwmark;
+    fwmark.netId = netId;
+    fwmark.explicitlySelected = true;
+    fwmark.protectedFromVpn = true;
+    fwmark.permission = PERMISSION_SYSTEM;
+
+    char fwmarkString[UINT32_HEX_STRLEN];
+    snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
+
+    ALOGD("starting clatd on %s", interface);
+
+    std::string progname("clatd-");
+    progname += interface;
 
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
@@ -56,23 +88,8 @@ int ClatdController::startClatd(char *interface) {
     }
 
     if (!pid) {
-        // Pass in the interface, a netid to use for DNS lookups, and a fwmark for outgoing packets.
-        unsigned netId = mNetCtrl->getNetworkForInterface(interface);
-        char netIdString[UINT32_STRLEN];
-        snprintf(netIdString, sizeof(netIdString), "%u", netId);
-
-        Fwmark fwmark;
-
-        fwmark.netId = netId;
-        fwmark.explicitlySelected = true;
-        fwmark.protectedFromVpn = true;
-        fwmark.permission = PERMISSION_SYSTEM;
-
-        char fwmarkString[UINT32_HEX_STRLEN];
-        snprintf(fwmarkString, sizeof(fwmarkString), "0x%x", fwmark.intValue);
-
         char *args[] = {
-            (char *) "/system/bin/clatd",
+            (char *) progname.c_str(),
             (char *) "-i",
             interface,
             (char *) "-n",
@@ -82,44 +99,48 @@ int ClatdController::startClatd(char *interface) {
             NULL
         };
 
-        if (execv(args[0], args)) {
+        if (execv(kClatdPath, args)) {
             ALOGE("execv failed (%s)", strerror(errno));
+            _exit(1);
         }
         ALOGE("Should never get here!");
-        _exit(0);
+        _exit(1);
     } else {
-        mClatdPid = pid;
-        ALOGD("clatd started");
+        mClatdPids[interface] = pid;
+        ALOGD("clatd started on %s", interface);
     }
 
     return 0;
 }
 
-int ClatdController::stopClatd() {
-    if (mClatdPid == 0) {
+int ClatdController::stopClatd(char* interface) {
+    pid_t pid = getClatdPid(interface);
+
+    if (pid == 0) {
         ALOGE("clatd already stopped");
         return -1;
     }
 
-    ALOGD("Stopping clatd");
+    ALOGD("Stopping clatd pid=%d on %s", pid, interface);
 
-    kill(mClatdPid, SIGTERM);
-    waitpid(mClatdPid, NULL, 0);
-    mClatdPid = 0;
+    kill(pid, SIGTERM);
+    waitpid(pid, NULL, 0);
+    mClatdPids.erase(interface);
 
-    ALOGD("clatd stopped");
+    ALOGD("clatd on %s stopped", interface);
 
     return 0;
 }
 
-bool ClatdController::isClatdStarted() {
+bool ClatdController::isClatdStarted(char* interface) {
     pid_t waitpid_status;
-    if(mClatdPid == 0) {
+    pid_t pid = getClatdPid(interface);
+    if (pid == 0) {
         return false;
     }
-    waitpid_status = waitpid(mClatdPid, NULL, WNOHANG);
-    if(waitpid_status != 0) {
-        mClatdPid = 0; // child exited, don't call waitpid on it again
+    waitpid_status = waitpid(pid, NULL, WNOHANG);
+    if (waitpid_status != 0) {
+        mClatdPids.erase(interface);  // child exited, don't call waitpid on it again
     }
     return waitpid_status == 0; // 0 while child is running
 }
index 5bf48d9..1985836 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _CLATD_CONTROLLER_H
 #define _CLATD_CONTROLLER_H
 
+#include <map>
+
 class NetworkController;
 
 class ClatdController {
@@ -25,12 +27,13 @@ public:
     virtual ~ClatdController();
 
     int startClatd(char *interface);
-    int stopClatd();
-    bool isClatdStarted();
+    int stopClatd(char* interface);
+    bool isClatdStarted(char* interface);
 
 private:
     NetworkController* const mNetCtrl;
-    pid_t mClatdPid;
+    std::map<std::string, pid_t> mClatdPids;
+    pid_t getClatdPid(char* interface);
 };
 
 #endif
index d9acce9..b508d3f 100644 (file)
@@ -54,10 +54,10 @@ namespace {
 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
 
 Permission stringToPermission(const char* arg) {
-    if (!strcmp(arg, "android.permission.CHANGE_NETWORK_STATE")) {
+    if (!strcmp(arg, "NETWORK")) {
         return PERMISSION_NETWORK;
     }
-    if (!strcmp(arg, "android.permission.CONNECTIVITY_INTERNAL")) {
+    if (!strcmp(arg, "SYSTEM")) {
         return PERMISSION_SYSTEM;
     }
     return PERMISSION_NONE;
@@ -449,6 +449,21 @@ int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
                         "Failed to change IPv6 state", true);
             }
             return 0;
+        } else if (!strcmp(argv[1], "ipv6ndoffload")) {
+            if (argc != 4) {
+                cli->sendMsg(ResponseCode::CommandSyntaxError,
+                        "Usage: interface ipv6ndoffload <interface> <enable|disable>",
+                        false);
+                return 0;
+            }
+            int enable = !strncmp(argv[3], "enable", 7);
+            if (sInterfaceCtrl->setIPv6NdOffload(argv[2], enable) == 0) {
+                cli->sendMsg(ResponseCode::CommandOkay, "IPv6 ND offload changed", false);
+            } else {
+                cli->sendMsg(ResponseCode::OperationFailed,
+                        "Failed to change IPv6 ND offload state", true);
+            }
+            return 0;
         } else if (!strcmp(argv[1], "setmtu")) {
             if (argc != 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError,
@@ -796,6 +811,14 @@ int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char *
                     "Wrong number of arguments to resolver setnetdns", false);
             return 0;
         }
+    } else if (!strcmp(argv[1], "clearnetdns")) { // "resolver clearnetdns <netId>"
+        if (argc == 3) {
+            rc = sResolverCtrl->clearDnsServers(strtoul(argv[2], NULL, 0));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver clearnetdns", false);
+            return 0;
+        }
     } else if (!strcmp(argv[1], "flushnet")) { // "resolver flushnet <netId>"
         if (argc == 3) {
             rc = sResolverCtrl->flushDnsCache(strtoul(argv[2], NULL, 0));
@@ -1323,26 +1346,21 @@ CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
                                                             char **argv) {
     int rc = 0;
-    if (argc < 2) {
+    if (argc < 3) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
         return 0;
     }
 
-    if(!strcmp(argv[1], "stop")) {
-        rc = sClatdCtrl->stopClatd();
+    if (!strcmp(argv[1], "stop")) {
+        rc = sClatdCtrl->stopClatd(argv[2]);
     } else if (!strcmp(argv[1], "status")) {
         char *tmp = NULL;
-
-        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted() ?
-                                                        "started" : "stopped"));
+        asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted(argv[2]) ?
+                                            "started" : "stopped"));
         cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
         free(tmp);
         return 0;
-    } else if(!strcmp(argv[1], "start")) {
-        if (argc < 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
-            return 0;
-        }
+    } else if (!strcmp(argv[1], "start")) {
         rc = sClatdCtrl->startClatd(argv[2]);
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
index 14f0da7..448fc9c 100644 (file)
@@ -19,6 +19,7 @@
 
 #define LOG_TAG "InterfaceController"
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 
 #include "InterfaceController.h"
 #include "RouteController.h"
@@ -27,6 +28,8 @@ const char ipv6_proc_path[] = "/proc/sys/net/ipv6/conf";
 
 const char sys_net_path[] = "/sys/class/net";
 
+const char wl_util_path[] = "/system/xbin/wlutil";
+
 InterfaceController::InterfaceController() {
        // Initial IPv6 settings.
        // By default, accept_ra is set to 1 (accept RAs unless forwarding is on) on all interfaces.
@@ -36,6 +39,9 @@ InterfaceController::InterfaceController() {
        setAcceptRA("2");
 
        setAcceptRARouteTable(-RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX);
+
+       // Enable optimistic DAD for IPv6 addresses on all interfaces.
+       setIPv6OptimisticMode("1");
 }
 
 InterfaceController::~InterfaceController() {
@@ -67,6 +73,29 @@ int InterfaceController::setIPv6PrivacyExtensions(const char *interface, const i
        return writeIPv6ProcPath(interface, "use_tempaddr", on ? "2" : "0");
 }
 
+// Enables or disables IPv6 ND offload. This is useful for 464xlat on wifi, IPv6 tethering, and
+// generally implementing IPv6 neighbour discovery and duplicate address detection properly.
+// TODO: This should be implemented in wpa_supplicant via driver commands instead.
+int InterfaceController::setIPv6NdOffload(char* interface, const int on) {
+    // Only supported on Broadcom chipsets via wlutil for now.
+    if (access(wl_util_path, X_OK) == 0) {
+        const char *argv[] = {
+            wl_util_path,
+            "-a",
+            interface,
+            "ndoe",
+            on ? "1" : "0"
+        };
+        int ret = android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL,
+                                      false, false);
+        ALOGD("%s ND offload on %s: %d (%s)",
+              (on ? "enabling" : "disabling"), interface, ret, strerror(errno));
+        return ret;
+    } else {
+        return 0;
+    }
+}
+
 int InterfaceController::isInterfaceName(const char *name) {
        return strcmp(name, ".") &&
                strcmp(name, "..") &&
@@ -122,3 +151,8 @@ int InterfaceController::setMtu(const char *interface, const char *mtu)
        free(path);
        return success;
 }
+
+void InterfaceController::setIPv6OptimisticMode(const char *value) {
+       setOnAllInterfaces("optimistic_dad", value);
+       setOnAllInterfaces("use_optimistic", value);
+}
index f6e8cbd..60e2131 100644 (file)
@@ -23,6 +23,7 @@ class InterfaceController {
        virtual ~InterfaceController();
        int setEnableIPv6(const char *interface, const int on);
        int setIPv6PrivacyExtensions(const char *interface, const int on);
+       int setIPv6NdOffload(char* interface, const int on);
        int setMtu(const char *interface, const char *mtu);
 
  private:
@@ -31,6 +32,7 @@ class InterfaceController {
        void setOnAllInterfaces(const char* filename, const char* value);
        void setAcceptRA(const char* value);
        void setAcceptRARouteTable(int tableOrOffset);
+       void setIPv6OptimisticMode(const char *value);
 };
 
 #endif
index a5d69ae..639423d 100644 (file)
@@ -38,6 +38,14 @@ int ResolverController::setDnsServers(unsigned netId, const char* domains,
     return 0;
 }
 
+int ResolverController::clearDnsServers(unsigned netId) {
+    _resolv_set_nameservers_for_net(netId, NULL, 0, "");
+    if (DBG) {
+        ALOGD("clearDnsServers netId = %u\n", netId);
+    }
+    return 0;
+}
+
 int ResolverController::flushDnsCache(unsigned netId) {
     if (DBG) {
         ALOGD("flushDnsCache netId = %u\n", netId);
index 0c245d7..39f002d 100644 (file)
@@ -27,6 +27,7 @@ public:
 
     int setDnsServers(unsigned netid, const char * domains, const char** servers,
             int numservers);
+    int clearDnsServers(unsigned netid);
     int flushDnsCache(unsigned netid);
     // TODO: Add deleteDnsCache(unsigned netId)
 };
index 4cb145b..56e3c28 100644 (file)
@@ -815,11 +815,8 @@ WARN_UNUSED_RESULT int modifyRoute(uint16_t action, const char* interface, const
     }
 
     int ret = modifyIpRoute(action, table, interface, destination, nexthop);
-    // We allow apps to call requestRouteToHost() multiple times with the same route, so ignore
-    // EEXIST failures when adding routes to legacy tables.
-    if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST &&
-                 (tableType == RouteController::LEGACY_NETWORK ||
-                  tableType == RouteController::LEGACY_SYSTEM))) {
+    // Trying to add a route that already exists shouldn't cause an error.
+    if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
         return ret;
     }
 
index 07c77b0..270bd51 100644 (file)
@@ -59,6 +59,10 @@ int SoftapController::startSoftap() {
         return ResponseCode::SoftapStatusResult;
     }
 
+    if (ensure_entropy_file_exists() < 0) {
+        ALOGE("Wi-Fi entropy file was not created");
+    }
+
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
         return ResponseCode::ServiceStartFailed;
index 6af1e4e..5e189cc 100644 (file)
 #include "FwmarkServer.h"
 
 static void blockSigpipe();
+static void remove_pid_file();
+static bool write_pid_file();
+
+const char* const PID_FILE_PATH = "/data/misc/net/netd_pid";
+const int PID_FILE_FLAGS = O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC;
+const mode_t PID_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;  // mode 0644, rw-r--r--
 
 int main() {
 
@@ -47,6 +53,7 @@ int main() {
     FwmarkServer* fwmarkServer;
 
     ALOGI("Netd 1.0 starting");
+    remove_pid_file();
 
     blockSigpipe();
 
@@ -92,15 +99,52 @@ int main() {
         exit(1);
     }
 
-    // Eventually we'll become the monitoring thread
+    bool wrote_pid = write_pid_file();
+
     while(1) {
-        sleep(1000);
+        sleep(30); // 30 sec
+        if (!wrote_pid) {
+            wrote_pid = write_pid_file();
+        }
     }
 
     ALOGI("Netd exiting");
+    remove_pid_file();
     exit(0);
 }
 
+static bool write_pid_file() {
+    char pid_buf[20];  // current pid_max is 32768, so plenty of room
+    snprintf(pid_buf, sizeof(pid_buf), "%ld\n", (long)getpid());
+
+    int fd = open(PID_FILE_PATH, PID_FILE_FLAGS, PID_FILE_MODE);
+    if (fd == -1) {
+        ALOGE("Unable to create pid file (%s)", strerror(errno));
+        return false;
+    }
+
+    // File creation is affected by umask, so make sure the right mode bits are set.
+    if (fchmod(fd, PID_FILE_MODE) == -1) {
+        ALOGE("failed to set mode 0%o on %s (%s)", PID_FILE_MODE, PID_FILE_PATH, strerror(errno));
+        close(fd);
+        remove_pid_file();
+        return false;
+    }
+
+    if (write(fd, pid_buf, strlen(pid_buf)) != (ssize_t)strlen(pid_buf)) {
+        ALOGE("Unable to write to pid file (%s)", strerror(errno));
+        close(fd);
+        remove_pid_file();
+        return false;
+    }
+    close(fd);
+    return true;
+}
+
+static void remove_pid_file() {
+    unlink(PID_FILE_PATH);
+}
+
 static void blockSigpipe()
 {
     sigset_t mask;