OSDN Git Service

Add general /proc/sys/net/ipv[46]/{conf,neigh}/ interface
authorErik Kline <ek@google.com>
Mon, 4 Jul 2016 00:57:18 +0000 (09:57 +0900)
committerErik Kline <ek@google.com>
Fri, 2 Sep 2016 07:32:32 +0000 (16:32 +0900)
Bug: 21859053
Bug: 28135208
Change-Id: Ia3232706a697fd149ed87f74586efe3d434261f8

server/InterfaceController.cpp
server/InterfaceController.h
server/NetdNativeService.cpp
server/NetdNativeService.h
server/binder/android/net/INetd.aidl
tests/binder_test.cpp

index eac4fbf..1d0a8e0 100644 (file)
@@ -17,6 +17,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <malloc.h>
+#include <sys/socket.h>
 
 #define LOG_TAG "InterfaceController"
 #include <android-base/file.h>
@@ -29,6 +30,7 @@
 #include "RouteController.h"
 
 using android::base::StringPrintf;
+using android::base::ReadFileToString;
 using android::base::WriteStringToFile;
 
 namespace {
@@ -39,15 +41,25 @@ const char ipv4_neigh_conf_dir[] = "/proc/sys/net/ipv4/neigh";
 
 const char ipv6_neigh_conf_dir[] = "/proc/sys/net/ipv6/neigh";
 
+const char proc_net_path[] = "/proc/sys/net";
 const char sys_net_path[] = "/sys/class/net";
 
 const char wl_util_path[] = "/vendor/xbin/wlutil";
 
-bool isInterfaceName(const char *name) {
-    return strcmp(name, ".") &&
-            strcmp(name, "..") &&
-            strcmp(name, "default") &&
-            strcmp(name, "all");
+inline bool isNormalPathComponent(const char *component) {
+    return (strcmp(component, ".") != 0) &&
+           (strcmp(component, "..") != 0) &&
+           (strchr(component, '/') == nullptr);
+}
+
+inline bool isAddressFamilyPathComponent(const char *component) {
+    return strcmp(component, "ipv4") == 0 || strcmp(component, "ipv6") == 0;
+}
+
+inline bool isInterfaceName(const char *name) {
+    return isNormalPathComponent(name) &&
+           (strcmp(name, "default") != 0) &&
+           (strcmp(name, "all") != 0);
 }
 
 int writeValueToPath(
@@ -81,6 +93,21 @@ void setIPv6UseOutgoingInterfaceAddrsOnly(const char *value) {
     setOnAllInterfaces(ipv6_proc_path, "use_oif_addrs_only", value);
 }
 
+std::string getParameterPathname(
+        const char *family, const char *which, const char *interface, const char *parameter) {
+    if (!isAddressFamilyPathComponent(family)) {
+        errno = EAFNOSUPPORT;
+        return "";
+    } else if (!isNormalPathComponent(which) ||
+               !isInterfaceName(interface) ||
+               !isNormalPathComponent(parameter)) {
+        errno = EINVAL;
+        return "";
+    }
+
+    return StringPrintf("%s/%s/%s/%s/%s", proc_net_path, family, which, interface, parameter);
+}
+
 }  // namespace
 
 void InterfaceController::initializeAll() {
@@ -201,7 +228,6 @@ int InterfaceController::setMtu(const char *interface, const char *mtu)
     return writeValueToPath(sys_net_path, interface, "mtu", mtu);
 }
 
-
 int InterfaceController::addAddress(const char *interface,
         const char *addrString, int prefixLength) {
     return ifc_add_address(interface, addrString, prefixLength);
@@ -212,6 +238,26 @@ int InterfaceController::delAddress(const char *interface,
     return ifc_del_address(interface, addrString, prefixLength);
 }
 
+int InterfaceController::getParameter(
+        const char *family, const char *which, const char *interface, const char *parameter,
+        std::string *value) {
+    const std::string path(getParameterPathname(family, which, interface, parameter));
+    if (path.empty()) {
+        return -errno;
+    }
+    return ReadFileToString(path, value) ? 0 : -errno;
+}
+
+int InterfaceController::setParameter(
+        const char *family, const char *which, const char *interface, const char *parameter,
+        const char *value) {
+    const std::string path(getParameterPathname(family, which, interface, parameter));
+    if (path.empty()) {
+        return -errno;
+    }
+    return WriteStringToFile(value, path) ? 0 : -errno;
+}
+
 void InterfaceController::setBaseReachableTimeMs(unsigned int millis) {
     std::string value(StringPrintf("%u", millis));
     setOnAllInterfaces(ipv4_neigh_conf_dir, "base_reachable_time_ms", value.c_str());
index 98c8b8f..80ebe5c 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _INTERFACE_CONTROLLER_H
 #define _INTERFACE_CONTROLLER_H
 
+#include <string>
+
 class InterfaceController {
 public:
     static void initializeAll();
@@ -31,6 +33,15 @@ public:
     static int addAddress(const char *interface, const char *addrString, int prefixLength);
     static int delAddress(const char *interface, const char *addrString, int prefixLength);
 
+    // Read and write values in files of the form:
+    //     /proc/sys/net/<family>/<which>/<interface>/<parameter>
+    static int getParameter(
+            const char *family, const char *which, const char *interface, const char *parameter,
+            std::string *value);
+    static int setParameter(
+            const char *family, const char *which, const char *interface, const char *parameter,
+            const char *value);
+
 private:
     static void setAcceptRA(const char* value);
     static void setAcceptRARouteTable(int tableOrOffset);
index 8dc4d93..f8f300a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "Controllers.h"
 #include "DumpWriter.h"
+#include "InterfaceController.h"
 #include "NetdConstants.h"
 #include "NetdNativeService.h"
 #include "RouteController.h"
@@ -235,5 +236,44 @@ binder::Status NetdNativeService::interfaceDelAddress(const std::string &ifName,
     return binder::Status::ok();
 }
 
+binder::Status NetdNativeService::setProcSysNet(
+        int32_t family, int32_t which, const std::string &ifname, const std::string &parameter,
+        const std::string &value) {
+    ENFORCE_PERMISSION(CONNECTIVITY_INTERNAL);
+
+    const char *familyStr;
+    switch (family) {
+        case INetd::IPV4:
+            familyStr = "ipv4";
+            break;
+        case INetd::IPV6:
+            familyStr = "ipv6";
+            break;
+        default:
+            return binder::Status::fromServiceSpecificError(EAFNOSUPPORT, String8("Bad family"));
+    }
+
+    const char *whichStr;
+    switch (which) {
+        case INetd::CONF:
+            whichStr = "conf";
+            break;
+        case INetd::NEIGH:
+            whichStr = "neigh";
+            break;
+        default:
+            return binder::Status::fromServiceSpecificError(EINVAL, String8("Bad category"));
+    }
+
+    const int err = InterfaceController::setParameter(
+            familyStr, whichStr, ifname.c_str(), parameter.c_str(),
+            value.c_str());
+    if (err != 0) {
+        return binder::Status::fromServiceSpecificError(-err,
+                String8::format("ResolverController error: %s", strerror(-err)));
+    }
+    return binder::Status::ok();
+}
+
 }  // namespace net
 }  // namespace android
index c39e2a8..7e1d75e 100644 (file)
@@ -55,6 +55,10 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
             const std::string &addrString, int prefixLength) override;
     binder::Status interfaceDelAddress(const std::string &ifName,
             const std::string &addrString, int prefixLength) override;
+
+    binder::Status setProcSysNet(
+            int32_t family, int32_t which, const std::string &ifname, const std::string &parameter,
+            const std::string &value) override;
 };
 
 }  // namespace net
index e092b76..9df392a 100644 (file)
@@ -170,4 +170,22 @@ interface INetd {
             int prefixLength);
     void interfaceDelAddress(in @utf8InCpp String ifName, in @utf8InCpp String addrString,
             int prefixLength);
+
+    /*
+     * Set and get /proc/sys/net interface configuration parameters.
+     *
+     * @param family One of IPV4/IPV6 integers, indicating the desired address family directory.
+     * @param which One of CONF/NEIGH integers, indicating the desired parameter category directory.
+     * @param ifname The interface name portion of the path; may also be "all" or "default".
+     * @param parameter The parameter name portion of the path.
+     * @param value The value string to be written into the assembled path.
+     */
+
+    const int IPV4  = 4;
+    const int IPV6  = 6;
+    const int CONF  = 1;
+    const int NEIGH = 2;
+    void setProcSysNet(int family, int which, in @utf8InCpp String ifname,
+            in @utf8InCpp String parameter, in @utf8InCpp String value);
+    // TODO: add corresponding getProcSysNet().
 }
index 9909aef..fd94d2e 100644 (file)
@@ -617,3 +617,40 @@ TEST_F(BinderTest, TestInterfaceAddRemoveAddress) {
         EXPECT_FALSE(interfaceHasAddress(sTunIfName, td.addrString, -1));
     }
 }
+
+TEST_F(BinderTest, TestSetProcSysNet) {
+    static const struct TestData {
+        const int family;
+        const int which;
+        const char *ifname;
+        const char *parameter;
+        const char *value;
+        const int expectedReturnCode;
+    } kTestData[] = {
+        { INetd::IPV4, INetd::CONF, sTunIfName.c_str(), "arp_ignore", "1", 0 },
+        { -1, INetd::CONF, sTunIfName.c_str(), "arp_ignore", "1", EAFNOSUPPORT },
+        { INetd::IPV4, -1, sTunIfName.c_str(), "arp_ignore", "1", EINVAL },
+        { INetd::IPV4, INetd::CONF, "..", "conf/lo/arp_ignore", "1", EINVAL },
+        { INetd::IPV4, INetd::CONF, ".", "lo/arp_ignore", "1", EINVAL },
+        { INetd::IPV4, INetd::CONF, sTunIfName.c_str(), "../all/arp_ignore", "1", EINVAL },
+        { INetd::IPV6, INetd::NEIGH, sTunIfName.c_str(), "ucast_solicit", "7", 0 },
+    };
+
+    for (unsigned int i = 0; i < arraysize(kTestData); i++) {
+        const auto &td = kTestData[i];
+
+        const binder::Status status = mNetd->setProcSysNet(
+                    td.family, td.which, td.ifname, td.parameter,
+                    td.value);
+
+        if (td.expectedReturnCode == 0) {
+            SCOPED_TRACE(String8::format("test case %d should have passed", i));
+            EXPECT_EQ(0, status.exceptionCode());
+            EXPECT_EQ(0, status.serviceSpecificErrorCode());
+        } else {
+            SCOPED_TRACE(String8::format("test case %d should have failed", i));
+            EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+            EXPECT_EQ(td.expectedReturnCode, status.serviceSpecificErrorCode());
+        }
+    }
+}