Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e218d1b3 authored by Luke Huang's avatar Luke Huang
Browse files

Merge 'goog/rvc-dev-plus-aosp' into mainline-prod

Test: m && m com.android.resolv
Test: install resolv apex, DNS works
Bug: 167653798
Change-Id: I5bbc3524952d8b42d371f24d37b37632cbd1f399
parents e3819704 93c4b04d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ cc_library {
    // Link most things statically to minimize our dependence on system ABIs.
    stl: "libc++_static",
    static_libs: [
        "dnsresolver_aidl_interface-ndk_platform",
        "dnsresolver_aidl_interface-unstable-ndk_platform",
        "libbase",
        "libcutils",
        "libnetdutils",
+3 −3
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ constexpr bool requestingUseLocalNameservers(unsigned flags) {
}

bool queryingViaTls(unsigned dns_netid) {
    const auto privateDnsStatus = gPrivateDnsConfiguration.getStatus(dns_netid);
    const auto privateDnsStatus = PrivateDnsConfiguration::getInstance().getStatus(dns_netid);
    switch (privateDnsStatus.mode) {
        case PrivateDnsMode::OPPORTUNISTIC:
            return !privateDnsStatus.validatedServers().empty();
@@ -294,7 +294,7 @@ bool parseQuery(const uint8_t* msg, size_t msgLen, uint16_t* query_id, int* rr_t
// Note: Even if it returns PDM_OFF, it doesn't mean there's no DoT stats in the message
// because Private DNS mode can change at any time.
PrivateDnsModes getPrivateDnsModeForMetrics(uint32_t netId) {
    switch (gPrivateDnsConfiguration.getStatus(netId).mode) {
    switch (PrivateDnsConfiguration::getInstance().getStatus(netId).mode) {
        case PrivateDnsMode::OFF:
            // It can also be due to netId not found.
            return PrivateDnsModes::PDM_OFF;
@@ -308,7 +308,7 @@ PrivateDnsModes getPrivateDnsModeForMetrics(uint32_t netId) {
}

void initDnsEvent(NetworkDnsEventReported* event, const android_net_context& netContext) {
    // The value 0 has the special meaning of unset/unknown in Westworld atoms. So, we set both
    // The value 0 has the special meaning of unset/unknown in Statsd atoms. So, we set both
    // flags to -1 as default value.
    //  1. The hints flag is only used in resolv_getaddrinfo. When user set it to -1 in
    //     resolv_getaddrinfo, the flag will cause validation (validateHints) failure in
+2 −3
Original line number Diff line number Diff line
@@ -17,21 +17,20 @@
#include "DnsResolver.h"

#include <android-base/logging.h>
#include <android-base/properties.h>

#include "DnsProxyListener.h"
#include "DnsResolverService.h"
#include "netd_resolv/resolv.h"
#include "res_debug.h"
#include "util.h"

bool resolv_init(const ResolverNetdCallbacks* callbacks) {
    android::base::InitLogging(/*argv=*/nullptr);
    android::base::SetDefaultTag("libnetd_resolv");
    LOG(INFO) << __func__ << ": Initializing resolver";
    resolv_set_log_severity(android::base::WARNING);

    using android::net::gApiLevel;
    gApiLevel = android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
    gApiLevel = getApiLevel();
    using android::net::gResNetdCallbacks;
    gResNetdCallbacks.check_calling_permission = callbacks->check_calling_permission;
    gResNetdCallbacks.get_network_context = callbacks->get_network_context;
+38 −8
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <BinderUtil.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <netdutils/DumpWriter.h>
@@ -82,8 +83,10 @@ binder_status_t DnsResolverService::start() {
    // NetdNativeService does call disableBackgroundScheduling currently, so it is fine now.
    std::shared_ptr<DnsResolverService> resolverService =
            ::ndk::SharedRefBase::make<DnsResolverService>();
    binder_status_t status =
            AServiceManager_addService(resolverService->asBinder().get(), getServiceName());
    auto binder = resolverService->asBinder();

    if (AIBinder_setRequestingSid) AIBinder_setRequestingSid(binder.get(), true);
    binder_status_t status = AServiceManager_addService(binder.get(), getServiceName());
    if (status != STATUS_OK) {
        return status;
    }
@@ -173,18 +176,45 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
    return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(EX_SECURITY, err.c_str()));
}

namespace {

constexpr char SELINUX_LABEL_SU[] = "u:r:su:s0";

inline bool isRootSecurityContext(const char* sid) {
    // Type su is used for su processes, as well as for adbd and adb shell after performing an adb
    // root command.
    return !strcmp(sid, SELINUX_LABEL_SU);
}

::ndk::ScopedAStatus checkCaCertificatePermission() {
    uid_t uid = AIBinder_getCallingUid();
    if (uid != AID_ROOT) {
        auto err = StringPrintf("UID %d is not authorized to set CA certificate", uid);
        return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(EX_SECURITY, err.c_str()));
    }
    // Check security context if it is supported by platform
    if (!AIBinder_getCallingSid) {
        return ::ndk::ScopedAStatus(AStatus_newOk());
    }
    const char* sid = AIBinder_getCallingSid();
    if (!sid || !isRootSecurityContext(sid)) {
        auto err = StringPrintf("sid %s is not authorized to set CA certificate", sid);
        return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(EX_SECURITY, err.c_str()));
    }
    return ::ndk::ScopedAStatus(AStatus_newOk());
}

}  // namespace

::ndk::ScopedAStatus DnsResolverService::setResolverConfiguration(
        const ResolverParamsParcel& resolverParams) {
    // Locking happens in PrivateDnsConfiguration and res_* functions.
    ENFORCE_INTERNAL_PERMISSIONS();

    // TODO@: Switch to selinux based permission check if AIBinder_getCallingSid and
    //        AIBinder_setRequestingSid can be supported by libbinder_dnk (b/159135973).
    uid_t uid = AIBinder_getCallingUid();
    // CAUTION: caCertificate should NOT be used except for internal testing.
    if (resolverParams.caCertificate.size() != 0 && uid != AID_ROOT) {
        auto err = StringPrintf("UID %d is not authorized to set a non-empty CA certificate", uid);
        return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(EX_SECURITY, err.c_str()));
    if (resolverParams.caCertificate.size() != 0) {
        auto status = checkCaCertificatePermission();
        if (!status.isOk()) return status;
    }

    // TODO: Remove this log after AIDL gen_log supporting more types, b/129732660
+77 −5
Original line number Diff line number Diff line
@@ -77,11 +77,14 @@ bool StatsData::operator==(const StatsData& o) const {
           std::tie(o.serverSockAddr, o.total, o.rcodeCounts, o.latencyUs);
}

int StatsData::averageLatencyMs() const {
    return (total == 0) ? 0 : duration_cast<milliseconds>(latencyUs).count() / total;
}

std::string StatsData::toString() const {
    if (total == 0) return StringPrintf("%s <no data>", serverSockAddr.ip().toString().c_str());

    const auto now = std::chrono::steady_clock::now();
    const int meanLatencyMs = duration_cast<milliseconds>(latencyUs).count() / total;
    const int lastUpdateSec = duration_cast<seconds>(now - lastUpdate).count();
    std::string buf;
    for (const auto& [rcode, counts] : rcodeCounts) {
@@ -90,7 +93,7 @@ std::string StatsData::toString() const {
        }
    }
    return StringPrintf("%s (%d, %dms, [%s], %ds)", serverSockAddr.ip().toString().c_str(), total,
                        meanLatencyMs, buf.c_str(), lastUpdateSec);
                        averageLatencyMs(), buf.c_str(), lastUpdateSec);
}

StatsRecords::StatsRecords(const IPSockAddr& ipSockAddr, size_t size)
@@ -104,6 +107,10 @@ void StatsRecords::push(const Record& record) {
        updateStatsData(mRecords.front(), false);
        mRecords.pop_front();
    }

    // Update the quality factors.
    mSkippedCount = 0;
    updatePenalty(record);
}

void StatsRecords::updateStatsData(const Record& record, const bool add) {
@@ -120,6 +127,41 @@ void StatsRecords::updateStatsData(const Record& record, const bool add) {
    mStatsData.lastUpdate = std::chrono::steady_clock::now();
}

void StatsRecords::updatePenalty(const Record& record) {
    switch (record.rcode) {
        case NS_R_NO_ERROR:
        case NS_R_NXDOMAIN:
        case NS_R_NOTAUTH:
            mPenalty = 0;
            return;
        default:
            // NS_R_TIMEOUT and NS_R_INTERNAL_ERROR are in this case.
            if (mPenalty == 0) {
                mPenalty = 100;
            } else {
                // The evaluated quality drops more quickly when continuous failures happen.
                mPenalty = std::min(mPenalty * 2, kMaxQuality);
            }
            return;
    }
}

double StatsRecords::score() const {
    const int avgRtt = mStatsData.averageLatencyMs();

    // Set the lower bound to -1 in case of "avgRtt + mPenalty < mSkippedCount"
    //   1) when the server doesn't have any stats yet.
    //   2) when the sorting has been disabled while it was enabled before.
    int quality = std::clamp(avgRtt + mPenalty - mSkippedCount, -1, kMaxQuality);

    // Normalization.
    return static_cast<double>(kMaxQuality - quality) * 100 / kMaxQuality;
}

void StatsRecords::incrementSkippedCount() {
    mSkippedCount = std::min(mSkippedCount + 1, kMaxQuality);
}

bool DnsStats::setServers(const std::vector<netdutils::IPSockAddr>& servers, Protocol protocol) {
    if (!ensureNoInvalidIp(servers)) return false;

@@ -147,6 +189,7 @@ bool DnsStats::setServers(const std::vector<netdutils::IPSockAddr>& servers, Pro
bool DnsStats::addStats(const IPSockAddr& ipSockAddr, const DnsQueryEvent& record) {
    if (ipSockAddr.ip() == INVALID_IPADDRESS) return false;

    bool added = false;
    for (auto& [serverSockAddr, statsRecords] : mStats[record.protocol()]) {
        if (serverSockAddr == ipSockAddr) {
            const StatsRecords::Record rec = {
@@ -154,10 +197,36 @@ bool DnsStats::addStats(const IPSockAddr& ipSockAddr, const DnsQueryEvent& recor
                    .latencyUs = microseconds(record.latency_micros()),
            };
            statsRecords.push(rec);
            return true;
            added = true;
        } else {
            statsRecords.incrementSkippedCount();
        }
    }
    return false;

    return added;
}

std::vector<IPSockAddr> DnsStats::getSortedServers(Protocol protocol) const {
    // DoT unsupported. The handshake overhead is expensive, and the connection will hang for a
    // while. Need to figure out if it is worth doing for DoT servers.
    if (protocol == PROTO_DOT) return {};

    auto it = mStats.find(protocol);
    if (it == mStats.end()) return {};

    // Sorting on insertion in decreasing order.
    std::multimap<double, IPSockAddr, std::greater<double>> sortedData;
    for (const auto& [ip, statsRecords] : it->second) {
        sortedData.insert({statsRecords.score(), ip});
    }

    std::vector<IPSockAddr> ret;
    ret.reserve(sortedData.size());
    for (auto& [_, v] : sortedData) {
        ret.push_back(v);  // IPSockAddr is trivially-copyable.
    }

    return ret;
}

std::vector<StatsData> DnsStats::getStats(Protocol protocol) const {
@@ -179,7 +248,10 @@ void DnsStats::dump(DumpWriter& dw) {
            return;
        }
        for (const auto& [_, statsRecords] : statsMap) {
            dw.println("%s", statsRecords.getStatsData().toString().c_str());
            const StatsData& data = statsRecords.getStatsData();
            std::string str = data.toString();
            str += StringPrintf(" score{%.1f}", statsRecords.score());
            dw.println("%s", str.c_str());
        }
    };

Loading