/** * Copyright (c) 2016, 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. */ #define LOG_TAG "Netd" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Controllers.h" #include "Fwmark.h" #include "InterfaceController.h" #include "NetdNativeService.h" #include "OemNetdListener.h" #include "Permission.h" #include "Process.h" #include "RouteController.h" #include "SockDiag.h" #include "UidRanges.h" #include "android/net/BnNetd.h" #include "binder_utils/BinderUtil.h" #include "binder_utils/NetdPermissions.h" #include "netid_client.h" // NETID_UNSET using android::base::StringPrintf; using android::base::WriteStringToFile; using android::net::TetherStatsParcel; using android::net::UidRangeParcel; using android::net::netd::aidl::NativeUidRangeConfig; using android::netdutils::DumpWriter; using android::netdutils::getIfaceNames; using android::netdutils::ScopedIndent; using android::os::ParcelFileDescriptor; namespace android { namespace net { namespace { const char OPT_SHORT[] = "--short"; #define ENFORCE_ANY_PERMISSION(...) \ do { \ binder::Status status = checkAnyPermission({__VA_ARGS__}); \ if (!status.isOk()) { \ return status; \ } \ } while (0) #define NETD_LOCKING_RPC(lock, ... /* permissions */) \ ENFORCE_ANY_PERMISSION(__VA_ARGS__); \ std::lock_guard _lock(lock); #define NETD_BIG_LOCK_RPC(... /* permissions */) NETD_LOCKING_RPC(gBigNetdLock, __VA_ARGS__) #define RETURN_BINDER_STATUS_IF_NOT_OK(logEntry, res) \ do { \ if (!isOk((res))) { \ logErrorStatus((logEntry), (res)); \ return asBinderStatus((res)); \ } \ } while (0) #define ENFORCE_NETWORK_STACK_PERMISSIONS() \ ENFORCE_ANY_PERMISSION(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK) void logErrorStatus(netdutils::LogEntry& logEntry, const netdutils::Status& status) { gLog.log(logEntry.returns(status.code()).withAutomaticDuration()); } binder::Status asBinderStatus(const netdutils::Status& status) { if (isOk(status)) { return binder::Status::ok(); } return binder::Status::fromServiceSpecificError(status.code(), status.msg().c_str()); } template binder::Status asBinderStatus(const base::Result result) { if (result.ok()) return binder::Status::ok(); return binder::Status::fromServiceSpecificError(result.error().code(), result.error().message().c_str()); } bool contains(const Vector& words, const String16& word) { for (const auto& w : words) { if (w == word) return true; } return false; } } // namespace NetdNativeService::NetdNativeService() { // register log callback to BnNetd::logFunc BnNetd::logFunc = [](const auto& log) { binderCallLogFn(log, [](const std::string& msg) { gLog.info("%s", msg.c_str()); }); }; } status_t NetdNativeService::start() { IPCThreadState::self()->disableBackgroundScheduling(true); const status_t ret = BinderService::publish(); if (ret != android::OK) { return ret; } sp ps(ProcessState::self()); ps->startThreadPool(); ps->giveThreadPoolName(); return android::OK; } status_t NetdNativeService::dump(int fd, const Vector &args) { const binder::Status dump_permission = checkAnyPermission({PERM_DUMP}); if (!dump_permission.isOk()) { const String8 msg(dump_permission.toString8()); write(fd, msg.c_str(), msg.size()); return PERMISSION_DENIED; } // This method does not grab any locks. If individual classes need locking // their dump() methods MUST handle locking appropriately. DumpWriter dw(fd); if (!args.isEmpty() && args[0] == TcpSocketMonitor::DUMP_KEYWORD) { dw.blankline(); gCtls->tcpSocketMonitor.dump(dw); dw.blankline(); return NO_ERROR; } process::dump(dw); dw.blankline(); gCtls->netCtrl.dump(dw); dw.blankline(); gCtls->xfrmCtrl.dump(dw); dw.blankline(); gCtls->tetherCtrl.dump(dw); dw.blankline(); { ScopedIndent indentLog(dw); if (contains(args, String16(OPT_SHORT))) { dw.println("Log: "); } else { dw.println("Log:"); ScopedIndent indentLogEntries(dw); gLog.forEachEntry([&dw](const std::string& entry) mutable { dw.println(entry); }); } dw.blankline(); } { ScopedIndent indentLog(dw); if (contains(args, String16(OPT_SHORT))) { dw.println("UnsolicitedLog: "); } else { dw.println("UnsolicitedLog:"); ScopedIndent indentLogEntries(dw); gUnsolicitedLog.forEachEntry( [&dw](const std::string& entry) mutable { dw.println(entry); }); } dw.blankline(); } return NO_ERROR; } binder::Status NetdNativeService::isAlive(bool *alive) { NETD_BIG_LOCK_RPC(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); *alive = true; return binder::Status::ok(); } binder::Status NetdNativeService::firewallReplaceUidChain(const std::string&, bool, const std::vector&, bool*) { DEPRECATED; } binder::Status NetdNativeService::bandwidthEnableDataSaver(bool enable, bool *ret) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int err = gCtls->bandwidthCtrl.enableDataSaver(enable); *ret = (err == 0); return binder::Status::ok(); } binder::Status NetdNativeService::bandwidthSetInterfaceQuota(const std::string& ifName, int64_t bytes) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->bandwidthCtrl.setInterfaceQuota(ifName, bytes); return statusFromErrcode(res); } binder::Status NetdNativeService::bandwidthRemoveInterfaceQuota(const std::string& ifName) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->bandwidthCtrl.removeInterfaceQuota(ifName); return statusFromErrcode(res); } binder::Status NetdNativeService::bandwidthSetInterfaceAlert(const std::string& ifName, int64_t bytes) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->bandwidthCtrl.setInterfaceAlert(ifName, bytes); return statusFromErrcode(res); } binder::Status NetdNativeService::bandwidthRemoveInterfaceAlert(const std::string& ifName) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->bandwidthCtrl.removeInterfaceAlert(ifName); return statusFromErrcode(res); } binder::Status NetdNativeService::bandwidthSetGlobalAlert(int64_t bytes) { NETD_LOCKING_RPC(gCtls->bandwidthCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->bandwidthCtrl.setGlobalAlert(bytes); return statusFromErrcode(res); } binder::Status NetdNativeService::bandwidthAddNaughtyApp(int32_t) { DEPRECATED; } binder::Status NetdNativeService::bandwidthRemoveNaughtyApp(int32_t) { DEPRECATED; } binder::Status NetdNativeService::bandwidthAddNiceApp(int32_t) { DEPRECATED; } binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t) { DEPRECATED; } // TODO: Remove this function when there are no users. Currently, it is still used by DNS resolver // tests. binder::Status NetdNativeService::networkCreatePhysical(int32_t netId, int32_t permission) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.createPhysicalNetwork(netId, convertPermission(permission), false /* local */); return statusFromErrcode(ret); } // TODO: Remove this function when there are no users. Currently, it is still used by DNS resolver // tests. binder::Status NetdNativeService::networkCreateVpn(int32_t netId, bool secure) { ENFORCE_NETWORK_STACK_PERMISSIONS(); // The value of vpnType does not matter here, because it is not used in AOSP and is only // implemented by OEMs. Also, the RPC is going to deprecate. Just pick a value defined in INetd // as default. int ret = gCtls->netCtrl.createVirtualNetwork(netId, secure, NativeVpnType::LEGACY, false /* excludeLocalRoutes */); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkCreate(const NativeNetworkConfig& config) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = -EINVAL; if (config.networkType == NativeNetworkType::PHYSICAL) { ret = gCtls->netCtrl.createPhysicalNetwork( config.netId, convertPermission(config.permission), false /* isLocalNetwork */); } else if (config.networkType == NativeNetworkType::PHYSICAL_LOCAL) { ret = gCtls->netCtrl.createPhysicalNetwork( config.netId, convertPermission(config.permission), true /* isLocalNetwork */); } else if (config.networkType == NativeNetworkType::VIRTUAL) { ret = gCtls->netCtrl.createVirtualNetwork(config.netId, config.secure, config.vpnType, config.excludeLocalRoutes); } return statusFromErrcode(ret); } binder::Status NetdNativeService::networkDestroy(int32_t netId) { ENFORCE_NETWORK_STACK_PERMISSIONS(); // NetworkController::destroyNetwork is thread-safe. const int ret = gCtls->netCtrl.destroyNetwork(netId); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkAddInterface(int32_t netId, const std::string& iface) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.addInterfaceToNetwork(netId, iface.c_str()); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkRemoveInterface(int32_t netId, const std::string& iface) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.removeInterfaceFromNetwork(netId, iface.c_str()); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkAddUidRanges( int32_t netId, const std::vector& uidRangeArray) { // NetworkController::addUsersToNetwork is thread-safe. ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray), UidRanges::SUB_PRIORITY_HIGHEST); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkRemoveUidRanges( int32_t netId, const std::vector& uidRangeArray) { // NetworkController::removeUsersFromNetwork is thread-safe. ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray), UidRanges::SUB_PRIORITY_HIGHEST); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkAddUidRangesParcel(const NativeUidRangeConfig& config) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.addUsersToNetwork(config.netId, UidRanges(config.uidRanges), config.subPriority); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkRemoveUidRangesParcel(const NativeUidRangeConfig& config) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int ret = gCtls->netCtrl.removeUsersFromNetwork(config.netId, UidRanges(config.uidRanges), config.subPriority); return statusFromErrcode(ret); } binder::Status NetdNativeService::networkRejectNonSecureVpn( bool add, const std::vector& uidRangeArray) { // TODO: elsewhere RouteController is only used from the tethering and network controllers, so // it should be possible to use the same lock as NetworkController. However, every call through // the CommandListener "network" command will need to hold this lock too, not just the ones that // read/modify network internal state (that is sufficient for ::dump() because it doesn't // look at routes, but it's not enough here). NETD_BIG_LOCK_RPC(PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); UidRanges uidRanges(uidRangeArray); int err; if (add) { err = RouteController::addUsersToRejectNonSecureNetworkRule(uidRanges); } else { err = RouteController::removeUsersFromRejectNonSecureNetworkRule(uidRanges); } return statusFromErrcode(err); } binder::Status NetdNativeService::socketDestroy(const std::vector& uids, const std::vector& skipUids) { ENFORCE_NETWORK_STACK_PERMISSIONS(); SockDiag sd; if (!sd.open()) { return binder::Status::fromServiceSpecificError(EIO, String8("Could not open SOCK_DIAG socket")); } UidRanges uidRanges(uids); int err = sd.destroySockets(uidRanges, std::set(skipUids.begin(), skipUids.end()), true /* excludeLoopback */); if (err) { return binder::Status::fromServiceSpecificError(-err, String8::format("destroySockets: %s", strerror(-err))); } return binder::Status::ok(); } binder::Status NetdNativeService::tetherApplyDnsInterfaces(bool *ret) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); *ret = gCtls->tetherCtrl.applyDnsInterfaces(); return binder::Status::ok(); } namespace { constexpr const int UNUSED_IFINDEX = 0; void tetherAddStatsByInterface(TetherController::TetherStats* tetherStatsParcel, const TetherController::TetherStats& tetherStats) { if (tetherStatsParcel->extIface == tetherStats.extIface) { tetherStatsParcel->rxBytes += tetherStats.rxBytes; tetherStatsParcel->rxPackets += tetherStats.rxPackets; tetherStatsParcel->txBytes += tetherStats.txBytes; tetherStatsParcel->txPackets += tetherStats.txPackets; } } TetherStatsParcel toTetherStatsParcel(const TetherController::TetherStats& stats) { TetherStatsParcel result; result.iface = stats.extIface; result.rxBytes = stats.rxBytes; result.rxPackets = stats.rxPackets; result.txBytes = stats.txBytes; result.txPackets = stats.txPackets; result.ifIndex = UNUSED_IFINDEX; return result; } void setTetherStatsParcelVecByInterface(std::vector* tetherStatsVec, const TetherController::TetherStatsList& statsList) { std::map statsMap; for (const auto& stats : statsList) { auto iter = statsMap.find(stats.extIface); if (iter != statsMap.end()) { tetherAddStatsByInterface(&(iter->second), stats); } else { statsMap.insert( std::pair(stats.extIface, stats)); } } for (auto iter = statsMap.begin(); iter != statsMap.end(); iter++) { tetherStatsVec->push_back(toTetherStatsParcel(iter->second)); } } std::vector tetherStatsParcelVecToStringVec(std::vector* tVec) { std::vector result; for (const auto& t : *tVec) { result.push_back(StringPrintf("%s:%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64, t.iface.c_str(), t.rxBytes, t.rxPackets, t.txBytes, t.txPackets)); } return result; } } // namespace binder::Status NetdNativeService::tetherGetStats( std::vector* tetherStatsParcelVec) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); const auto& statsList = gCtls->tetherCtrl.getTetherStats(); if (!isOk(statsList)) { return asBinderStatus(statsList); } setTetherStatsParcelVecByInterface(tetherStatsParcelVec, statsList.value()); auto statsResults = tetherStatsParcelVecToStringVec(tetherStatsParcelVec); return binder::Status::ok(); } binder::Status NetdNativeService::interfaceAddAddress(const std::string &ifName, const std::string &addrString, int prefixLength) { ENFORCE_NETWORK_STACK_PERMISSIONS(); const int err = InterfaceController::addAddress( ifName.c_str(), addrString.c_str(), prefixLength); if (err != 0) { return binder::Status::fromServiceSpecificError(-err, String8::format("InterfaceController error: %s", strerror(-err))); } return binder::Status::ok(); } binder::Status NetdNativeService::interfaceDelAddress(const std::string &ifName, const std::string &addrString, int prefixLength) { ENFORCE_NETWORK_STACK_PERMISSIONS(); const int err = InterfaceController::delAddress( ifName.c_str(), addrString.c_str(), prefixLength); if (err != 0) { return binder::Status::fromServiceSpecificError(-err, String8::format("InterfaceController error: %s", strerror(-err))); } return binder::Status::ok(); } namespace { std::tuple getPathComponents(int32_t ipversion, int32_t category) { const char* ipversionStr = nullptr; switch (ipversion) { case INetd::IPV4: ipversionStr = "ipv4"; break; case INetd::IPV6: ipversionStr = "ipv6"; break; default: return {binder::Status::fromServiceSpecificError(EAFNOSUPPORT, "Bad IP version"), nullptr, nullptr}; } const char* whichStr = nullptr; switch (category) { case INetd::CONF: whichStr = "conf"; break; case INetd::NEIGH: whichStr = "neigh"; break; default: return {binder::Status::fromServiceSpecificError(EINVAL, "Bad category"), nullptr, nullptr}; } return {binder::Status::ok(), ipversionStr, whichStr}; } } // namespace binder::Status NetdNativeService::getProcSysNet(int32_t ipversion, int32_t which, const std::string& ifname, const std::string& parameter, std::string* value) { ENFORCE_NETWORK_STACK_PERMISSIONS(); const auto pathParts = getPathComponents(ipversion, which); const auto& pathStatus = std::get<0>(pathParts); if (!pathStatus.isOk()) { return pathStatus; } const int err = InterfaceController::getParameter(std::get<1>(pathParts), std::get<2>(pathParts), ifname.c_str(), parameter.c_str(), value); return statusFromErrcode(err); } binder::Status NetdNativeService::setProcSysNet(int32_t ipversion, int32_t which, const std::string& ifname, const std::string& parameter, const std::string& value) { ENFORCE_NETWORK_STACK_PERMISSIONS(); const auto pathParts = getPathComponents(ipversion, which); const auto& pathStatus = std::get<0>(pathParts); if (!pathStatus.isOk()) { return pathStatus; } const int err = InterfaceController::setParameter(std::get<1>(pathParts), std::get<2>(pathParts), ifname.c_str(), parameter.c_str(), value.c_str()); return statusFromErrcode(err); } binder::Status NetdNativeService::ipSecSetEncapSocketOwner(const ParcelFileDescriptor& socket, int newUid) { ENFORCE_NETWORK_STACK_PERMISSIONS(); uid_t callerUid = IPCThreadState::self()->getCallingUid(); return asBinderStatus( gCtls->xfrmCtrl.ipSecSetEncapSocketOwner(socket.get(), newUid, callerUid)); } binder::Status NetdNativeService::ipSecAllocateSpi( int32_t transformId, const std::string& sourceAddress, const std::string& destinationAddress, int32_t inSpi, int32_t* outSpi) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecAllocateSpi( transformId, sourceAddress, destinationAddress, inSpi, outSpi)); } binder::Status NetdNativeService::ipSecAddSecurityAssociation( int32_t transformId, int32_t mode, const std::string& sourceAddress, const std::string& destinationAddress, int32_t underlyingNetId, int32_t spi, int32_t markValue, int32_t markMask, const std::string& authAlgo, const std::vector& authKey, int32_t authTruncBits, const std::string& cryptAlgo, const std::vector& cryptKey, int32_t cryptTruncBits, const std::string& aeadAlgo, const std::vector& aeadKey, int32_t aeadIcvBits, int32_t encapType, int32_t encapLocalPort, int32_t encapRemotePort, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecAddSecurityAssociation( transformId, mode, sourceAddress, destinationAddress, underlyingNetId, spi, markValue, markMask, authAlgo, authKey, authTruncBits, cryptAlgo, cryptKey, cryptTruncBits, aeadAlgo, aeadKey, aeadIcvBits, encapType, encapLocalPort, encapRemotePort, interfaceId)); } binder::Status NetdNativeService::ipSecDeleteSecurityAssociation( int32_t transformId, const std::string& sourceAddress, const std::string& destinationAddress, int32_t spi, int32_t markValue, int32_t markMask, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecDeleteSecurityAssociation( transformId, sourceAddress, destinationAddress, spi, markValue, markMask, interfaceId)); } binder::Status NetdNativeService::ipSecApplyTransportModeTransform( const ParcelFileDescriptor& socket, int32_t transformId, int32_t direction, const std::string& sourceAddress, const std::string& destinationAddress, int32_t spi) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecApplyTransportModeTransform( socket.get(), transformId, direction, sourceAddress, destinationAddress, spi)); } binder::Status NetdNativeService::ipSecRemoveTransportModeTransform( const ParcelFileDescriptor& socket) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecRemoveTransportModeTransform(socket.get())); } binder::Status NetdNativeService::ipSecAddSecurityPolicy(int32_t transformId, int32_t selAddrFamily, int32_t direction, const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi, int32_t markValue, int32_t markMask, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecAddSecurityPolicy( transformId, selAddrFamily, direction, tmplSrcAddress, tmplDstAddress, spi, markValue, markMask, interfaceId)); } binder::Status NetdNativeService::ipSecUpdateSecurityPolicy( int32_t transformId, int32_t selAddrFamily, int32_t direction, const std::string& tmplSrcAddress, const std::string& tmplDstAddress, int32_t spi, int32_t markValue, int32_t markMask, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecUpdateSecurityPolicy( transformId, selAddrFamily, direction, tmplSrcAddress, tmplDstAddress, spi, markValue, markMask, interfaceId)); } binder::Status NetdNativeService::ipSecDeleteSecurityPolicy(int32_t transformId, int32_t selAddrFamily, int32_t direction, int32_t markValue, int32_t markMask, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecDeleteSecurityPolicy( transformId, selAddrFamily, direction, markValue, markMask, interfaceId)); } binder::Status NetdNativeService::ipSecAddTunnelInterface(const std::string& deviceName, const std::string& localAddress, const std::string& remoteAddress, int32_t iKey, int32_t oKey, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecAddTunnelInterface( deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, false)); } binder::Status NetdNativeService::ipSecUpdateTunnelInterface(const std::string& deviceName, const std::string& localAddress, const std::string& remoteAddress, int32_t iKey, int32_t oKey, int32_t interfaceId) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecAddTunnelInterface( deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, true)); } binder::Status NetdNativeService::ipSecRemoveTunnelInterface(const std::string& deviceName) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecRemoveTunnelInterface(deviceName)); } binder::Status NetdNativeService::ipSecMigrate(const IpSecMigrateInfoParcel& migrateInfo) { // Necessary locking done in IpSecService and kernel ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->xfrmCtrl.ipSecMigrate( migrateInfo.requestId, migrateInfo.selAddrFamily, migrateInfo.direction, migrateInfo.oldSourceAddress, migrateInfo.oldDestinationAddress, migrateInfo.newSourceAddress, migrateInfo.newDestinationAddress, migrateInfo.interfaceId)); } binder::Status NetdNativeService::setIPv6AddrGenMode(const std::string& ifName, int32_t mode) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(InterfaceController::setIPv6AddrGenMode(ifName, mode)); } binder::Status NetdNativeService::wakeupAddInterface(const std::string& ifName, const std::string& prefix, int32_t mark, int32_t mask) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->wakeupCtrl.addInterface(ifName, prefix, mark, mask)); } binder::Status NetdNativeService::wakeupDelInterface(const std::string& ifName, const std::string& prefix, int32_t mark, int32_t mask) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return asBinderStatus(gCtls->wakeupCtrl.delInterface(ifName, prefix, mark, mask)); } binder::Status NetdNativeService::trafficSwapActiveStatsMap() { DEPRECATED; } binder::Status NetdNativeService::idletimerAddInterface(const std::string& ifName, int32_t timeout, const std::string& classLabel) { NETD_LOCKING_RPC(gCtls->idletimerCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->idletimerCtrl.addInterfaceIdletimer(ifName.c_str(), timeout, classLabel.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::idletimerRemoveInterface(const std::string& ifName, int32_t timeout, const std::string& classLabel) { NETD_LOCKING_RPC(gCtls->idletimerCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->idletimerCtrl.removeInterfaceIdletimer(ifName.c_str(), timeout, classLabel.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::strictUidCleartextPenalty(int32_t uid, int32_t policyPenalty) { NETD_LOCKING_RPC(gCtls->strictCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); StrictPenalty penalty; switch (policyPenalty) { case INetd::PENALTY_POLICY_REJECT: penalty = REJECT; break; case INetd::PENALTY_POLICY_LOG: penalty = LOG; break; case INetd::PENALTY_POLICY_ACCEPT: penalty = ACCEPT; break; default: return statusFromErrcode(-EINVAL); break; } int res = gCtls->strictCtrl.setUidCleartextPenalty((uid_t) uid, penalty); return statusFromErrcode(res); } binder::Status NetdNativeService::clatdStart(const std::string& /* ifName */, const std::string& /* nat64Prefix */, std::string* /* v6Addr */) { DEPRECATED; } binder::Status NetdNativeService::clatdStop(const std::string& /* ifName */) { DEPRECATED; } binder::Status NetdNativeService::ipfwdEnabled(bool* status) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); *status = (gCtls->tetherCtrl.getIpfwdRequesterList().size() > 0) ? true : false; return binder::Status::ok(); } binder::Status NetdNativeService::ipfwdGetRequesterList(std::vector* requesterList) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); for (const auto& requester : gCtls->tetherCtrl.getIpfwdRequesterList()) { requesterList->push_back(requester); } return binder::Status::ok(); } binder::Status NetdNativeService::ipfwdEnableForwarding(const std::string& requester) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = (gCtls->tetherCtrl.enableForwarding(requester.c_str())) ? 0 : -EREMOTEIO; return statusFromErrcode(res); } binder::Status NetdNativeService::ipfwdDisableForwarding(const std::string& requester) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = (gCtls->tetherCtrl.disableForwarding(requester.c_str())) ? 0 : -EREMOTEIO; return statusFromErrcode(res); } binder::Status NetdNativeService::ipfwdAddInterfaceForward(const std::string& fromIface, const std::string& toIface) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int res = RouteController::enableTethering(fromIface.c_str(), toIface.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::ipfwdRemoveInterfaceForward(const std::string& fromIface, const std::string& toIface) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int res = RouteController::disableTethering(fromIface.c_str(), toIface.c_str()); return statusFromErrcode(res); } namespace { std::string addCurlyBrackets(const std::string& s) { return "{" + s + "}"; } } // namespace binder::Status NetdNativeService::interfaceGetList(std::vector* interfaceListResult) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); const auto& ifaceList = getIfaceNames(); interfaceListResult->clear(); interfaceListResult->reserve(ifaceList.value().size()); interfaceListResult->insert(end(*interfaceListResult), begin(ifaceList.value()), end(ifaceList.value())); return binder::Status::ok(); } std::string interfaceConfigurationParcelToString(const InterfaceConfigurationParcel& cfg) { std::vector result{cfg.ifName, cfg.hwAddr, cfg.ipv4Addr, std::to_string(cfg.prefixLength)}; result.insert(end(result), begin(cfg.flags), end(cfg.flags)); return addCurlyBrackets(base::Join(result, ", ")); } binder::Status NetdNativeService::interfaceGetCfg( const std::string& ifName, InterfaceConfigurationParcel* interfaceGetCfgResult) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).arg(ifName); const auto& cfgRes = InterfaceController::getCfg(ifName); RETURN_BINDER_STATUS_IF_NOT_OK(entry, cfgRes); *interfaceGetCfgResult = cfgRes.value(); gLog.log(entry.returns(interfaceConfigurationParcelToString(*interfaceGetCfgResult)) .withAutomaticDuration()); return binder::Status::ok(); } binder::Status NetdNativeService::interfaceSetCfg(const InterfaceConfigurationParcel& cfg) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); auto entry = gLog.newEntry() .prettyFunction(__PRETTY_FUNCTION__) .arg(interfaceConfigurationParcelToString(cfg)); const auto& res = InterfaceController::setCfg(cfg); RETURN_BINDER_STATUS_IF_NOT_OK(entry, res); gLog.log(entry.withAutomaticDuration()); return binder::Status::ok(); } binder::Status NetdNativeService::interfaceSetIPv6PrivacyExtensions(const std::string& ifName, bool enable) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = InterfaceController::setIPv6PrivacyExtensions(ifName.c_str(), enable); return statusFromErrcode(res); } binder::Status NetdNativeService::interfaceClearAddrs(const std::string& ifName) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = InterfaceController::clearAddrs(ifName.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::interfaceSetEnableIPv6(const std::string& ifName, bool enable) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = InterfaceController::setEnableIPv6(ifName.c_str(), enable); return statusFromErrcode(res); } binder::Status NetdNativeService::interfaceSetMtu(const std::string& ifName, int32_t mtuValue) { NETD_LOCKING_RPC(InterfaceController::mutex, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); std::string mtu = std::to_string(mtuValue); int res = InterfaceController::setMtu(ifName.c_str(), mtu.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherStart(const std::vector& dhcpRanges) { TetherConfigParcel config; config.usingLegacyDnsProxy = true; config.dhcpRanges = dhcpRanges; return tetherStartWithConfiguration(config); } binder::Status NetdNativeService::tetherStartWithConfiguration(const TetherConfigParcel& config) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); if (config.dhcpRanges.size() % 2 == 1) { return statusFromErrcode(-EINVAL); } // TODO: Pass TetherConfigParcel directly. int res = gCtls->tetherCtrl.startTethering(config.usingLegacyDnsProxy, config.dhcpRanges); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherStop() { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.stopTethering(); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherIsEnabled(bool* enabled) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); *enabled = gCtls->tetherCtrl.isTetheringStarted(); return binder::Status::ok(); } binder::Status NetdNativeService::tetherInterfaceAdd(const std::string& ifName) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.tetherInterface(ifName.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherInterfaceRemove(const std::string& ifName) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.untetherInterface(ifName.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherInterfaceList(std::vector* ifList) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); for (const auto& ifname : gCtls->tetherCtrl.getTetheredInterfaceList()) { ifList->push_back(ifname); } return binder::Status::ok(); } binder::Status NetdNativeService::tetherDnsSet(int32_t netId, const std::vector& dnsAddrs) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.setDnsForwarders(netId, dnsAddrs); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherDnsList(std::vector* dnsList) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); for (const auto& fwdr : gCtls->tetherCtrl.getDnsForwarders()) { dnsList->push_back(fwdr); } return binder::Status::ok(); } binder::Status NetdNativeService::networkAddRouteParcel(int32_t netId, const RouteInfoParcel& route) { // Public methods of NetworkController are thread-safe. ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = false; uid_t uid = 0; // UID is only meaningful for legacy routes. // convert Parcel to parameters int res = gCtls->netCtrl.addRoute(netId, route.ifName.c_str(), route.destination.c_str(), route.nextHop.empty() ? nullptr : route.nextHop.c_str(), legacy, uid, route.mtu); return statusFromErrcode(res); } binder::Status NetdNativeService::networkUpdateRouteParcel(int32_t netId, const RouteInfoParcel& route) { // Public methods of NetworkController are thread-safe. ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = false; uid_t uid = 0; // UID is only meaningful for legacy routes. // convert Parcel to parameters int res = gCtls->netCtrl.updateRoute(netId, route.ifName.c_str(), route.destination.c_str(), route.nextHop.empty() ? nullptr : route.nextHop.c_str(), legacy, uid, route.mtu); return statusFromErrcode(res); } binder::Status NetdNativeService::networkRemoveRouteParcel(int32_t netId, const RouteInfoParcel& route) { return networkRemoveRoute(netId, route.ifName, route.destination, route.nextHop); } binder::Status NetdNativeService::networkAddRoute(int32_t netId, const std::string& ifName, const std::string& destination, const std::string& nextHop) { // Public methods of NetworkController are thread-safe. ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = false; uid_t uid = 0; // UID is only meaningful for legacy routes. int res = gCtls->netCtrl.addRoute(netId, ifName.c_str(), destination.c_str(), nextHop.empty() ? nullptr : nextHop.c_str(), legacy, uid, 0); return statusFromErrcode(res); } binder::Status NetdNativeService::networkRemoveRoute(int32_t netId, const std::string& ifName, const std::string& destination, const std::string& nextHop) { ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = false; uid_t uid = 0; // UID is only meaningful for legacy routes. int res = gCtls->netCtrl.removeRoute(netId, ifName.c_str(), destination.c_str(), nextHop.empty() ? nullptr : nextHop.c_str(), legacy, uid); return statusFromErrcode(res); } binder::Status NetdNativeService::networkAddLegacyRoute(int32_t netId, const std::string& ifName, const std::string& destination, const std::string& nextHop, int32_t uid) { ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = true; int res = gCtls->netCtrl.addRoute(netId, ifName.c_str(), destination.c_str(), nextHop.empty() ? nullptr : nextHop.c_str(), legacy, (uid_t)uid, 0); return statusFromErrcode(res); } binder::Status NetdNativeService::networkRemoveLegacyRoute(int32_t netId, const std::string& ifName, const std::string& destination, const std::string& nextHop, int32_t uid) { ENFORCE_NETWORK_STACK_PERMISSIONS(); bool legacy = true; int res = gCtls->netCtrl.removeRoute(netId, ifName.c_str(), destination.c_str(), nextHop.empty() ? nullptr : nextHop.c_str(), legacy, (uid_t) uid); return statusFromErrcode(res); } binder::Status NetdNativeService::networkGetDefault(int32_t* netId) { ENFORCE_NETWORK_STACK_PERMISSIONS(); *netId = gCtls->netCtrl.getDefaultNetwork(); return binder::Status::ok(); } binder::Status NetdNativeService::networkSetDefault(int32_t netId) { ENFORCE_NETWORK_STACK_PERMISSIONS(); int res = gCtls->netCtrl.setDefaultNetwork(netId); return statusFromErrcode(res); } binder::Status NetdNativeService::networkClearDefault() { ENFORCE_NETWORK_STACK_PERMISSIONS(); unsigned netId = NETID_UNSET; int res = gCtls->netCtrl.setDefaultNetwork(netId); return statusFromErrcode(res); } std::vector NetdNativeService::intsToUids(const std::vector& intUids) { return {begin(intUids), end(intUids)}; } Permission NetdNativeService::convertPermission(int32_t permission) { switch (permission) { case INetd::PERMISSION_NETWORK: return Permission::PERMISSION_NETWORK; case INetd::PERMISSION_SYSTEM: return Permission::PERMISSION_SYSTEM; default: return Permission::PERMISSION_NONE; } } binder::Status NetdNativeService::networkSetPermissionForNetwork(int32_t netId, int32_t permission) { ENFORCE_NETWORK_STACK_PERMISSIONS(); std::vector netIds = {(unsigned) netId}; int res = gCtls->netCtrl.setPermissionForNetworks(convertPermission(permission), netIds); return statusFromErrcode(res); } binder::Status NetdNativeService::networkSetPermissionForUser(int32_t permission, const std::vector& uids) { ENFORCE_NETWORK_STACK_PERMISSIONS(); gCtls->netCtrl.setPermissionForUsers(convertPermission(permission), intsToUids(uids)); return binder::Status::ok(); } binder::Status NetdNativeService::networkClearPermissionForUser(const std::vector& uids) { ENFORCE_NETWORK_STACK_PERMISSIONS(); Permission permission = Permission::PERMISSION_NONE; gCtls->netCtrl.setPermissionForUsers(permission, intsToUids(uids)); return binder::Status::ok(); } binder::Status NetdNativeService::networkSetProtectAllow(int32_t uid) { ENFORCE_NETWORK_STACK_PERMISSIONS(); gCtls->netCtrl.allowProtect((uid_t)uid, NETID_UNSET); return binder::Status::ok(); } binder::Status NetdNativeService::networkSetProtectDeny(int32_t uid) { ENFORCE_NETWORK_STACK_PERMISSIONS(); gCtls->netCtrl.denyProtect((uid_t)uid, NETID_UNSET); return binder::Status::ok(); } binder::Status NetdNativeService::networkCanProtect(int32_t uid, bool* ret) { ENFORCE_NETWORK_STACK_PERMISSIONS(); *ret = gCtls->netCtrl.canProtect((uid_t)uid, NETID_UNSET); return binder::Status::ok(); } binder::Status NetdNativeService::trafficSetNetPermForUids(int32_t, const std::vector&) { DEPRECATED; } binder::Status NetdNativeService::firewallSetFirewallType(int32_t firewallType) { NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); auto type = static_cast(firewallType); int res = gCtls->firewallCtrl.setFirewallType(type); return statusFromErrcode(res); } binder::Status NetdNativeService::firewallSetInterfaceRule(const std::string& ifName, int32_t firewallRule) { NETD_LOCKING_RPC(gCtls->firewallCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); auto rule = static_cast(firewallRule); int res = gCtls->firewallCtrl.setInterfaceRule(ifName.c_str(), rule); return statusFromErrcode(res); } binder::Status NetdNativeService::firewallSetUidRule(int32_t, int32_t, int32_t) { DEPRECATED; } binder::Status NetdNativeService::firewallEnableChildChain(int32_t, bool) { DEPRECATED; } binder::Status NetdNativeService::firewallAddUidInterfaceRules(const std::string&, const std::vector&) { DEPRECATED; } binder::Status NetdNativeService::firewallRemoveUidInterfaceRules(const std::vector&) { DEPRECATED; } binder::Status NetdNativeService::tetherAddForward(const std::string& intIface, const std::string& extIface) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.enableNat(intIface.c_str(), extIface.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::tetherRemoveForward(const std::string& intIface, const std::string& extIface) { NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK); int res = gCtls->tetherCtrl.disableNat(intIface.c_str(), extIface.c_str()); return statusFromErrcode(res); } binder::Status NetdNativeService::setTcpRWmemorySize(const std::string& rmemValues, const std::string& wmemValues) { ENFORCE_NETWORK_STACK_PERMISSIONS(); if (!WriteStringToFile(rmemValues, TCP_RMEM_PROC_FILE)) { int ret = -errno; return statusFromErrcode(ret); } if (!WriteStringToFile(wmemValues, TCP_WMEM_PROC_FILE)) { int ret = -errno; return statusFromErrcode(ret); } return binder::Status::ok(); } binder::Status NetdNativeService::registerUnsolicitedEventListener( const android::sp& listener) { ENFORCE_NETWORK_STACK_PERMISSIONS(); gCtls->eventReporter.registerUnsolEventListener(listener); return binder::Status::ok(); } binder::Status NetdNativeService::getOemNetd(android::sp* listener) { ENFORCE_NETWORK_STACK_PERMISSIONS(); *listener = com::android::internal::net::OemNetdListener::getListener(); return binder::Status::ok(); } binder::Status NetdNativeService::getFwmarkForNetwork(int32_t netId, MarkMaskParcel* markMask) { ENFORCE_NETWORK_STACK_PERMISSIONS(); Fwmark fwmark; fwmark.netId = netId; markMask->mask = FWMARK_NET_ID_MASK; markMask->mark = fwmark.intValue; return binder::Status::ok(); } binder::Status NetdNativeService::tetherOffloadRuleAdd(const TetherOffloadRuleParcel& /* rule */) { DEPRECATED; } binder::Status NetdNativeService::tetherOffloadRuleRemove( const TetherOffloadRuleParcel& /* rule */) { DEPRECATED; } binder::Status NetdNativeService::tetherOffloadGetStats( std::vector* /* tetherStatsParcelVec */) { DEPRECATED; } binder::Status NetdNativeService::tetherOffloadSetInterfaceQuota(int /* ifIndex */, int64_t /* quotaBytes */) { DEPRECATED; } binder::Status NetdNativeService::tetherOffloadGetAndClearStats( int /* ifIndex */, android::net::TetherStatsParcel* /* tetherStats */) { DEPRECATED; } binder::Status NetdNativeService::setNetworkAllowlist( const std::vector& rangeConfigs) { ENFORCE_NETWORK_STACK_PERMISSIONS(); return statusFromErrcode(gCtls->netCtrl.setNetworkAllowlist(rangeConfigs)); } } // namespace net } // namespace android