summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Huang <huangluke@google.com>2018-08-21 17:17:19 +0800
committerLuke Huang <huangluke@google.com>2018-09-26 09:00:03 +0000
commitb5733d781fb375cef99971eaa91962a1e71db5d2 (patch)
tree0699a97d5cc9b4141d36bd5b33f38e0d50fecc5d
parenta4387187be6f8f4a7bc2465d1f782fab0648efd5 (diff)
downloadnetd-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.cpp72
-rw-r--r--server/NetdNativeService.h8
-rw-r--r--server/TetherController.cpp58
-rw-r--r--server/TetherController.h4
-rw-r--r--server/binder/android/net/INetd.aidl69
-rw-r--r--tests/binder_test.cpp127
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);
+}