diff options
author | Luke Huang <huangluke@google.com> | 2018-08-21 17:17:19 +0800 |
---|---|---|
committer | Luke Huang <huangluke@google.com> | 2018-09-26 09:00:03 +0000 |
commit | b5733d781fb375cef99971eaa91962a1e71db5d2 (patch) | |
tree | 0699a97d5cc9b4141d36bd5b33f38e0d50fecc5d | |
parent | a4387187be6f8f4a7bc2465d1f782fab0648efd5 (diff) | |
download | netd-b5733d781fb375cef99971eaa91962a1e71db5d2.tar.gz |
Tether-related commands porting
Test: built, flashed, booted
system/netd/tests/runtests.sh passes
Change-Id: I5f0888f6e44d383bc52af01888d095e62a670d70
-rw-r--r-- | server/NetdNativeService.cpp | 72 | ||||
-rw-r--r-- | server/NetdNativeService.h | 8 | ||||
-rw-r--r-- | server/TetherController.cpp | 58 | ||||
-rw-r--r-- | server/TetherController.h | 4 | ||||
-rw-r--r-- | server/binder/android/net/INetd.aidl | 69 | ||||
-rw-r--r-- | tests/binder_test.cpp | 127 |
6 files changed, 324 insertions, 14 deletions
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp index 0563af41..0a923e62 100644 --- a/server/NetdNativeService.cpp +++ b/server/NetdNativeService.cpp @@ -969,5 +969,77 @@ binder::Status NetdNativeService::ipfwdRemoveInterfaceForward(const std::string& return statusFromErrcode(res); } +binder::Status NetdNativeService::tetherStart(const std::vector<std::string>& dhcpRanges) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(dhcpRanges); + if (dhcpRanges.size() % 2 == 1) { + return statusFromErrcode(-EINVAL); + } + int res = gCtls->tetherCtrl.startTethering(dhcpRanges); + gLog.log(entry.returns(res).withAutomaticDuration()); + return statusFromErrcode(res); +} + +binder::Status NetdNativeService::tetherStop() { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__); + int res = gCtls->tetherCtrl.stopTethering(); + gLog.log(entry.returns(res).withAutomaticDuration()); + return statusFromErrcode(res); +} + +binder::Status NetdNativeService::tetherIsEnabled(bool* enabled) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__); + *enabled = gCtls->tetherCtrl.isTetheringStarted(); + gLog.log(entry.returns(*enabled).withAutomaticDuration()); + return binder::Status::ok(); +} + +binder::Status NetdNativeService::tetherInterfaceAdd(const std::string& ifName) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName); + int res = gCtls->tetherCtrl.tetherInterface(ifName.c_str()); + gLog.log(entry.returns(res).withAutomaticDuration()); + return statusFromErrcode(res); +} + +binder::Status NetdNativeService::tetherInterfaceRemove(const std::string& ifName) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName); + int res = gCtls->tetherCtrl.untetherInterface(ifName.c_str()); + gLog.log(entry.returns(res).withAutomaticDuration()); + return statusFromErrcode(res); +} + +binder::Status NetdNativeService::tetherInterfaceList(std::vector<std::string>* ifList) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__); + for (const auto& ifname : gCtls->tetherCtrl.getTetheredInterfaceList()) { + ifList->push_back(ifname); + } + gLog.log(entry.returns(true).withAutomaticDuration()); + return binder::Status::ok(); +} + +binder::Status NetdNativeService::tetherDnsSet(int32_t netId, + const std::vector<std::string>& dnsAddrs) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(netId).arg(dnsAddrs); + int res = gCtls->tetherCtrl.setDnsForwarders(netId, dnsAddrs); + gLog.log(entry.returns(res).withAutomaticDuration()); + return statusFromErrcode(res); +} + +binder::Status NetdNativeService::tetherDnsList(std::vector<std::string>* dnsList) { + NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock); + auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__); + for (const auto& fwdr : gCtls->tetherCtrl.getDnsForwarders()) { + dnsList->push_back(fwdr); + } + gLog.log(entry.returns(true).withAutomaticDuration()); + return binder::Status::ok(); +} + } // namespace net } // namespace android diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h index 57d99dbe..89c04f7f 100644 --- a/server/NetdNativeService.h +++ b/server/NetdNativeService.h @@ -95,6 +95,14 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd // Tethering-related commands. binder::Status tetherApplyDnsInterfaces(bool *ret) override; binder::Status tetherGetStats(android::os::PersistableBundle *ret) override; + binder::Status tetherStart(const std::vector<std::string>& dhcpRanges) override; + binder::Status tetherStop() override; + binder::Status tetherIsEnabled(bool* enabled) override; + binder::Status tetherInterfaceAdd(const std::string& ifName) override; + binder::Status tetherInterfaceRemove(const std::string& ifName) override; + binder::Status tetherInterfaceList(std::vector<std::string>* ifList) override; + binder::Status tetherDnsSet(int32_t netId, const std::vector<std::string>& dnsAddrs) override; + binder::Status tetherDnsList(std::vector<std::string>* dnsList) override; // Interface-related commands. binder::Status interfaceAddAddress(const std::string &ifName, diff --git a/server/TetherController.cpp b/server/TetherController.cpp index 84bab0a0..b11f4dc8 100644 --- a/server/TetherController.cpp +++ b/server/TetherController.cpp @@ -192,7 +192,7 @@ int TetherController::startTethering(int num_addrs, char **dhcp_ranges) { if (mDaemonPid != 0) { ALOGE("Tethering already started"); errno = EBUSY; - return -1; + return -errno; } ALOGD("Starting tethering services"); @@ -201,8 +201,9 @@ int TetherController::startTethering(int num_addrs, char **dhcp_ranges) { int pipefd[2]; if (pipe(pipefd) < 0) { + int res = errno; ALOGE("pipe failed (%s)", strerror(errno)); - return -1; + return -res; } /* @@ -210,18 +211,20 @@ int TetherController::startTethering(int num_addrs, char **dhcp_ranges) { * the daemon if it exits prematurely */ if ((pid = fork()) < 0) { + int res = errno; ALOGE("fork failed (%s)", strerror(errno)); close(pipefd[0]); close(pipefd[1]); - return -1; + return -res; } if (!pid) { close(pipefd[1]); if (pipefd[0] != STDIN_FILENO) { if (dup2(pipefd[0], STDIN_FILENO) != STDIN_FILENO) { + int res = errno; ALOGE("dup2 failed (%s)", strerror(errno)); - return -1; + return -res; } close(pipefd[0]); } @@ -275,6 +278,26 @@ int TetherController::startTethering(int num_addrs, char **dhcp_ranges) { return 0; } +std::vector<char*> TetherController::toCstrVec(const std::vector<std::string>& addrs) { + std::vector<char*> addrsCstrVec{}; + addrsCstrVec.reserve(addrs.size()); + for (const auto& addr : addrs) { + addrsCstrVec.push_back(const_cast<char*>(addr.data())); + } + return addrsCstrVec; +} + +int TetherController::startTethering(const std::vector<std::string>& dhcpRanges) { + struct in_addr v4_addr; + for (const auto& dhcpRange : dhcpRanges) { + if (!inet_aton(dhcpRange.c_str(), &v4_addr)) { + return -EINVAL; + } + } + auto dhcp_ranges = toCstrVec(dhcpRanges); + return startTethering(dhcp_ranges.size(), dhcp_ranges.data()); +} + int TetherController::stopTethering() { configureForTethering(false); @@ -326,7 +349,7 @@ int TetherController::setDnsForwarders(unsigned netId, char **servers, int numSe ALOGE("Failed to parse DNS server '%s'", servers[i]); mDnsForwarders.clear(); errno = EINVAL; - return -1; + return -errno; } if (daemonCmd.size() + 1 + strlen(servers[i]) >= MAX_CMD_SIZE) { @@ -345,12 +368,25 @@ int TetherController::setDnsForwarders(unsigned netId, char **servers, int numSe if (mDnsmasqState.sendAllState(mDaemonFd) != 0) { mDnsForwarders.clear(); errno = EREMOTEIO; - return -1; + return -errno; } } return 0; } +int TetherController::setDnsForwarders(unsigned netId, const std::vector<std::string>& servers) { + struct in_addr v4_addr; + struct in6_addr v6_addr; + for (const auto& server : servers) { + if (!inet_pton(AF_INET, server.c_str(), &v4_addr) && + !inet_pton(AF_INET6, server.c_str(), &v6_addr)) { + return -EINVAL; + } + } + auto dnsServers = toCstrVec(servers); + return setDnsForwarders(netId, dnsServers.data(), dnsServers.size()); +} + unsigned TetherController::getDnsNetId() { return mDnsNetId; } @@ -387,19 +423,19 @@ int TetherController::tetherInterface(const char *interface) { ALOGD("tetherInterface(%s)", interface); if (!isIfaceName(interface)) { errno = ENOENT; - return -1; + return -errno; } if (!configureForIPv6Router(interface)) { configureForIPv6Client(interface); - return -1; + return -EREMOTEIO; } mInterfaces.push_back(interface); if (!applyDnsInterfaces()) { mInterfaces.pop_back(); configureForIPv6Client(interface); - return -1; + return -EREMOTEIO; } else { return 0; } @@ -413,11 +449,11 @@ int TetherController::untetherInterface(const char *interface) { mInterfaces.erase(it); configureForIPv6Client(interface); - return applyDnsInterfaces() ? 0 : -1; + return applyDnsInterfaces() ? 0 : -EREMOTEIO; } } errno = ENOENT; - return -1; + return -errno; } const std::list<std::string> &TetherController::getTetheredInterfaceList() const { diff --git a/server/TetherController.h b/server/TetherController.h index d1d337ef..54fa6da8 100644 --- a/server/TetherController.h +++ b/server/TetherController.h @@ -74,11 +74,13 @@ private: size_t forwardingRequestCount(); int startTethering(int num_addrs, char **dhcp_ranges); + int startTethering(const std::vector<std::string>& dhcpRanges); int stopTethering(); bool isTetheringStarted(); unsigned getDnsNetId(); int setDnsForwarders(unsigned netId, char **servers, int numServers); + int setDnsForwarders(unsigned netId, const std::vector<std::string>& servers); const std::list<std::string> &getDnsForwarders() const; int tetherInterface(const char *interface); @@ -142,7 +144,7 @@ private: private: bool setIpFwdEnabled(); - + std::vector<char*> toCstrVec(const std::vector<std::string>& addrs); int setupIPv6CountersChain(); static std::string makeTetherCountingRule(const char *if1, const char *if2); ForwardingDownstream* findForwardingDownstream(const std::string& intIface, diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl index e69025a7..5f429c6c 100644 --- a/server/binder/android/net/INetd.aidl +++ b/server/binder/android/net/INetd.aidl @@ -765,4 +765,73 @@ interface INetd { */ void bandwidthRemoveNiceApp(int uid); + /** + * Start tethering + * + * @param dhcpRanges dhcp ranges to set. + * dhcpRanges might contain many addresss {addr1, addr2, aadr3, addr4...} + * Netd splits them into ranges: addr1-addr2, addr3-addr4, etc. + * An odd number of addrs will fail. + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the the failure. + */ + void tetherStart(in @utf8InCpp String[] dhcpRanges); + + /** + * Stop tethering + * + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the the failure. + */ + void tetherStop(); + + /** + * Get status of tethering + * + * @return true if tethering is enabled, false otherwise. + */ + boolean tetherIsEnabled(); + + /** + * Setup interface for tethering + * + * @param ifName interface name to add + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the the failure. + */ + void tetherInterfaceAdd(in @utf8InCpp String ifName); + + /** + * Reset interface for tethering + * + * @param ifName interface name to remove + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the the failure. + */ + void tetherInterfaceRemove(in @utf8InCpp String ifName); + + /** + * Get the interface list which is stored in netd + * The list contains the interfaces managed by tetherInterfaceAdd/tetherInterfaceRemove + * + * @return ifList interface list result + */ + @utf8InCpp List<String> tetherInterfaceList(); + + /** + * Set dns forwarder server + * + * @param netId the upstream network to forward DNS queries to + * @param dnsAddrs DNS server address to set + * @throws ServiceSpecificException in case of failure, with an error code indicating the + * cause of the the failure. + */ + void tetherDnsSet(int netId, in @utf8InCpp String[] dnsAddrs); + + /** + * Return the DNS list set by tetherDnsSet + * + * @return dnsList dns list result + */ + @utf8InCpp List<String> tetherDnsList(); } diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index a8e74d4c..3f77a767 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -1478,11 +1478,9 @@ TEST_F(BinderTest, BandwidthSetRemoveInterfaceQuota) { TEST_F(BinderTest, BandwidthSetRemoveInterfaceAlert) { long testAlertBytes = 373; - // Add test physical network EXPECT_TRUE(mNetd->networkCreatePhysical(TEST_NETID1, "").isOk()); EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk()); - // Need to have a prior interface quota set to set an alert binder::Status status = mNetd->bandwidthSetInterfaceQuota(sTun.name(), testAlertBytes); status = mNetd->bandwidthSetInterfaceAlert(sTun.name(), testAlertBytes); @@ -1542,3 +1540,128 @@ TEST_F(BinderTest, BandwidthManipulateSpecialApp) { EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); expectBandwidthManipulateSpecialAppRuleDoesNotExist(BANDWIDTH_NICE, uid); } + +namespace { + +int readIntFromPath(const std::string& path) { + std::string result = ""; + EXPECT_TRUE(ReadFileToString(path, &result)); + return std::stoi(result); +} + +int getTetherAcceptIPv6Ra(const std::string& ifName) { + std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/accept_ra", ifName.c_str()); + return readIntFromPath(path); +} + +bool getTetherAcceptIPv6Dad(const std::string& ifName) { + std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/accept_dad", ifName.c_str()); + return readIntFromPath(path); +} + +int getTetherIPv6DadTransmits(const std::string& ifName) { + std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/dad_transmits", ifName.c_str()); + return readIntFromPath(path); +} + +bool getTetherEnableIPv6(const std::string& ifName) { + std::string path = StringPrintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifName.c_str()); + int disableIPv6 = readIntFromPath(path); + return !disableIPv6; +} + +bool interfaceListContains(const std::vector<std::string>& ifList, const std::string& ifName) { + for (const auto& iface : ifList) { + if (iface == ifName) { + return true; + } + } + return false; +} + +void expectTetherInterfaceConfigureForIPv6Router(const std::string& ifName) { + EXPECT_EQ(getTetherAcceptIPv6Ra(ifName), 0); + EXPECT_FALSE(getTetherAcceptIPv6Dad(ifName)); + EXPECT_EQ(getTetherIPv6DadTransmits(ifName), 0); + EXPECT_TRUE(getTetherEnableIPv6(ifName)); +} + +void expectTetherInterfaceConfigureForIPv6Client(const std::string& ifName) { + EXPECT_EQ(getTetherAcceptIPv6Ra(ifName), 2); + EXPECT_TRUE(getTetherAcceptIPv6Dad(ifName)); + EXPECT_EQ(getTetherIPv6DadTransmits(ifName), 1); + EXPECT_FALSE(getTetherEnableIPv6(ifName)); +} + +void expectTetherInterfaceExists(const std::vector<std::string>& ifList, + const std::string& ifName) { + EXPECT_TRUE(interfaceListContains(ifList, ifName)); +} + +void expectTetherInterfaceNotExists(const std::vector<std::string>& ifList, + const std::string& ifName) { + EXPECT_FALSE(interfaceListContains(ifList, ifName)); +} + +void expectTetherDnsListEquals(const std::vector<std::string>& dnsList, + const std::vector<std::string>& testDnsAddrs) { + EXPECT_TRUE(dnsList == testDnsAddrs); +} + +} // namespace + +TEST_F(BinderTest, TetherStartStopStatus) { + std::vector<std::string> noDhcpRange = {}; + static const char dnsdName[] = "dnsmasq"; + + binder::Status status = mNetd->tetherStart(noDhcpRange); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + EXPECT_TRUE(processExists(dnsdName)); + + bool tetherEnabled; + status = mNetd->tetherIsEnabled(&tetherEnabled); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + EXPECT_TRUE(tetherEnabled); + + status = mNetd->tetherStop(); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + EXPECT_FALSE(processExists(dnsdName)); + + status = mNetd->tetherIsEnabled(&tetherEnabled); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + EXPECT_FALSE(tetherEnabled); +} + +TEST_F(BinderTest, TetherInterfaceAddRemoveList) { + // TODO: verify if dnsmasq update interface successfully + + binder::Status status = mNetd->tetherInterfaceAdd(sTun.name()); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectTetherInterfaceConfigureForIPv6Router(sTun.name()); + + std::vector<std::string> ifList; + status = mNetd->tetherInterfaceList(&ifList); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectTetherInterfaceExists(ifList, sTun.name()); + + status = mNetd->tetherInterfaceRemove(sTun.name()); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectTetherInterfaceConfigureForIPv6Client(sTun.name()); + + status = mNetd->tetherInterfaceList(&ifList); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectTetherInterfaceNotExists(ifList, sTun.name()); +} + +TEST_F(BinderTest, TetherDnsSetList) { + // TODO: verify if dnsmasq update dns successfully + std::vector<std::string> testDnsAddrs = {"192.168.1.37", "213.137.100.3"}; + + binder::Status status = mNetd->tetherDnsSet(TEST_NETID1, testDnsAddrs); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + + std::vector<std::string> dnsList; + status = mNetd->tetherDnsList(&dnsList); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectTetherDnsListEquals(dnsList, testDnsAddrs); +} |