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

Commit e51091d1 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Support DNS64 synthesis using externally-discovered prefixes.

Currently, the DNS resolver supports DNS64 synthesis only for
prefixes that it discovered itself, and not for NAT64 prefixes
discovered via other means (e.g., RA).

Add a way to set a NAT64 prefix that was discovered by other
means. This new IPC is mutually exclusive with the existing
prefix discovery mechansisms:

- Setting the prefix has no effect if prefix discovery is
  started.
- Starting (or stopping) prefix discovery clears the prefix.
- Setting the prefix does not result in any NAT64 prefix update
  callback.

It is the responsibility of the caller (ConnectivityService,
Nat464Xlat) to ensure that prefix discovery is stopped before
setting the prefix.

This does not add any significant complexity to the connectivity
code, and it ensures that the behaviour of the existing IPCs
(startPrefix64Discovery and stopPrefix64Discovery) are unchanged.
This is necessary to ensure that DNS64 synthesis continues to
work on Q devices.

Disallowing concurrent use of prefix discovery and externally-set
prefixes also simplifies the implementation because it allows
reuse of most of the data structures and teardown code in
Dns64Configuration. The externally-set prefix is represented by a
Dns64Configuration with a special discovery ID of kNoDiscoveryId
(== 0), which cannot be used by any discovery attempt. That way,
if discovery is started, then stopped, and then the prefix is
set, if a stale discovery thread then completes, it will be
ignored because the thread's ID cannot be kNoDiscoveryId.

Bug: 153694684
Bug: 156914456
Test: new tests in resolv_integration_test
Change-Id: I7c63fb62b70635a1b5cc7a21d60f091ba2705d72
parent 468ac8ae
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -119,7 +119,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",
+45 −6
Original line number Diff line number Diff line
@@ -214,10 +214,15 @@ bool Dns64Configuration::shouldContinueDiscovery(const Dns64Config& cfg) {
}

void Dns64Configuration::removeDns64Config(unsigned netId) REQUIRES(mMutex) {
    IPPrefix prefix = getPrefix64Locked(netId);
    mDns64Configs.erase(netId);
    if (!prefix.isUninitialized()) {
        reportNat64PrefixStatus(netId, PREFIX_REMOVED, prefix);
    const auto& iter = mDns64Configs.find(netId);
    if (iter == mDns64Configs.end()) return;

    Dns64Config cfg = iter->second;
    mDns64Configs.erase(iter);

    // Only report a prefix removed event if the prefix was discovered, not if it was set.
    if (cfg.isFromPrefixDiscovery() && !cfg.prefix64.isUninitialized()) {
        reportNat64PrefixStatus(netId, PREFIX_REMOVED, cfg.prefix64);
    }
}

@@ -229,9 +234,43 @@ void Dns64Configuration::recordDns64Config(const Dns64Config& cfg) {
    mDns64Configs.emplace(std::make_pair(cfg.netId, cfg));

    reportNat64PrefixStatus(cfg.netId, PREFIX_ADDED, cfg.prefix64);
}

int Dns64Configuration::setPrefix64(unsigned netId, const IPPrefix* pfx) {
    if (pfx->isUninitialized() || pfx->family() != AF_INET6 || pfx->length() != 96) {
        return -EINVAL;
    }

    std::lock_guard guard(mMutex);

    // This method may only be called if prefix discovery has been stopped or was never started.
    auto iter = mDns64Configs.find(netId);
    if (iter != mDns64Configs.end()) {
        if (iter->second.isFromPrefixDiscovery()) {
            return -EEXIST;
        } else {
            mDns64Configs.erase(iter);
        }
    }

    Dns64Config cfg(kNoDiscoveryId, netId);
    cfg.prefix64 = *pfx;
    mDns64Configs.emplace(std::make_pair(netId, cfg));

    return 0;
}

int Dns64Configuration::clearPrefix64(unsigned netId) {
    std::lock_guard guard(mMutex);

    const auto& iter = mDns64Configs.find(netId);
    if (iter == mDns64Configs.end() || iter->second.isFromPrefixDiscovery()) {
        return -ENOENT;
    }

    mDns64Configs.erase(iter);

    // TODO: consider extending INetdEventListener to report the DNS64 prefix
    // up to ConnectivityService to potentially include this in LinkProperties.
    return 0;
}

}  // namespace net
+12 −1
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ class Dns64Configuration {
    void stopPrefixDiscovery(unsigned netId);
    netdutils::IPPrefix getPrefix64(unsigned netId) const;

    int setPrefix64(unsigned netId, const netdutils::IPPrefix* pfx);
    int clearPrefix64(unsigned netId);

    void dump(netdutils::DumpWriter& dw, unsigned netId);

  private:
@@ -89,16 +92,24 @@ class Dns64Configuration {
        Dns64Config(unsigned pseudoRandomId, unsigned network)
            : discoveryId(pseudoRandomId), netId(network) {}

        // ID of the discovery operation, or kNoDiscoveryId if no discovery was performed (i.e., the
        // prefix was discovered and passed in via setPrefix64).
        const unsigned int discoveryId;
        const unsigned int netId;
        netdutils::IPPrefix prefix64{};

        bool isFromPrefixDiscovery() const { return discoveryId != kNoDiscoveryId; }
    };

    static constexpr int kNoDiscoveryId = 0;

    enum { PREFIX_REMOVED, PREFIX_ADDED };

    static bool doRfc7050PrefixDiscovery(const android_net_context& netcontext, Dns64Config* cfg);

    unsigned getNextId() REQUIRES(mMutex) { return mNextId++; }
    // Picks the next discovery ID. Never returns kNoDiscoveryId.
    unsigned getNextId() REQUIRES(mMutex) { return ++mNextId ? mNextId : ++mNextId; }

    netdutils::IPPrefix getPrefix64Locked(unsigned netId) const REQUIRES(mMutex);
    bool isDiscoveryInProgress(const Dns64Config& cfg) const REQUIRES(mMutex);
    bool reportNat64PrefixStatus(unsigned netId, bool added, const netdutils::IPPrefix& pfx)
+16 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ using aidl::android::net::ResolverParamsParcel;
using android::base::Join;
using android::base::StringPrintf;
using android::netdutils::DumpWriter;
using android::netdutils::IPPrefix;

namespace android {
namespace net {
@@ -240,6 +241,21 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
    return statusFromErrcode(res);
}

::ndk::ScopedAStatus DnsResolverService::setPrefix64(int netId, const std::string& stringPrefix) {
    ENFORCE_NETWORK_STACK_PERMISSIONS();

    if (stringPrefix.empty()) {
        return statusFromErrcode(gDnsResolv->resolverCtrl.clearPrefix64(netId));
    }

    IPPrefix prefix;
    if (!IPPrefix::forString(stringPrefix, &prefix)) {
        return statusFromErrcode(-EINVAL);
    }

    return statusFromErrcode(gDnsResolv->resolverCtrl.setPrefix64(netId, &prefix));
}

::ndk::ScopedAStatus DnsResolverService::setLogSeverity(int32_t logSeverity) {
    ENFORCE_NETWORK_STACK_PERMISSIONS();

+2 −1
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ class DnsResolverService : public aidl::android::net::BnDnsResolver {
    ::ndk::ScopedAStatus startPrefix64Discovery(int32_t netId) override;
    ::ndk::ScopedAStatus stopPrefix64Discovery(int32_t netId) override;
    // (internal use only)
    ::ndk::ScopedAStatus getPrefix64(int netId, std::string* stringPrefix) override;
    ::ndk::ScopedAStatus getPrefix64(int32_t netId, std::string* stringPrefix) override;
    ::ndk::ScopedAStatus setPrefix64(int32_t netId, const std::string& stringPrefix) override;

    // Debug log command
    ::ndk::ScopedAStatus setLogSeverity(int32_t logSeverity) override;
Loading