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

Commit 69e6718a authored by Luke Huang's avatar Luke Huang
Browse files

Separate resolv_getaddrinfo from android_getaddrinfofornetcontext

1. Separate resolv_getaddrinfo from android_getaddrinfofornetcontext
   which only do explore_fqdn()
2. cleanup for android_getaddrinfofornetcontext/explore_fqdn

Bug: 135506574
Test: cd system/netd && atest
Change-Id: Ie5c9721f69a9c3dcf5941bd4321d076bb99c313a
parent 061c61f8
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -154,8 +154,7 @@ bool Dns64Configuration::doRfc7050PrefixDiscovery(const android_net_context& net
    // ourselves, which means we also bypass all the special netcontext flag
    // handling and the resolver event logging.
    struct addrinfo* res = nullptr;
    const int status =
            android_getaddrinfofornetcontext(kIPv4OnlyHost, nullptr, &hints, &netcontext, &res);
    const int status = resolv_getaddrinfo(kIPv4OnlyHost, nullptr, &hints, &netcontext, &res);
    ScopedAddrinfo result(res);
    if (status != 0) {
        LOG(WARNING) << "(" << cfg->netId << ", " << cfg->discoveryId << ") plat_prefix/dns("
+1 −1
Original line number Diff line number Diff line
@@ -650,7 +650,7 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
    int32_t rv = 0;
    NetworkDnsEventReported dnsEvent;
    if (queryLimiter.start(uid)) {
        rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, &result);
        rv = resolv_getaddrinfo(mHost, mService, mHints, &mNetContext, &result);
        queryLimiter.finish(uid);
    } else {
        // Note that this error code is currently not passed down to the client.
+120 −119
Original line number Diff line number Diff line
@@ -267,80 +267,67 @@ int getaddrinfo_numeric(const char* hostname, const char* servname, addrinfo hin
    return android_getaddrinfofornetcontext(hostname, servname, &hints, &netcontext, result);
}

int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
                                     const struct addrinfo* hints,
                                     const struct android_net_context* netcontext,
                                     struct addrinfo** res) {
    struct addrinfo sentinel = {};
    struct addrinfo* cur = &sentinel;
    int error = 0;

    // hostname is allowed to be nullptr
    // servname is allowed to be nullptr
    // hints is allowed to be nullptr
    assert(res != nullptr);
    assert(netcontext != nullptr);
namespace {

    struct addrinfo ai = {
            .ai_flags = 0,
            .ai_family = PF_UNSPEC,
            .ai_socktype = ANY,
            .ai_protocol = ANY,
            .ai_addrlen = 0,
            .ai_canonname = nullptr,
            .ai_addr = nullptr,
            .ai_next = nullptr,
    };
int validateHints(const addrinfo* _Nonnull hints) {
    if (!hints) return EAI_BADHINTS;

    do {
        if (hostname == NULL && servname == NULL) {
            error = EAI_NONAME;
            break;
        }
        if (hints) {
            /* error check for hints */
    // error check for hints
    if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) {
                error = EAI_BADHINTS;
                break;
        return EAI_BADHINTS;
    }
    if (hints->ai_flags & ~AI_MASK) {
                error = EAI_BADFLAGS;
                break;
        return EAI_BADFLAGS;
    }

    if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET ||
          hints->ai_family == PF_INET6)) {
                error = EAI_FAMILY;
                break;
        return EAI_FAMILY;
    }

            ai = *hints;
    if (hints->ai_socktype == ANY || hints->ai_protocol == ANY) return 0;

            /*
             * if both socktype/protocol are specified, check if they
             * are meaningful combination.
             */
            if (ai.ai_socktype != ANY && ai.ai_protocol != ANY) {
    // if both socktype/protocol are specified, check if they are meaningful combination.
    for (const Explore& ex : explore_options) {
                    if (ai.ai_family != ex.e_af) continue;
        if (hints->ai_family != ex.e_af) continue;
        if (ex.e_socktype == ANY) continue;
        if (ex.e_protocol == ANY) continue;
                    if (ai.ai_socktype == ex.e_socktype && ai.ai_protocol != ex.e_protocol) {
                        error = EAI_BADHINTS;
                        break;
        if (hints->ai_socktype == ex.e_socktype && hints->ai_protocol != ex.e_protocol) {
            return EAI_BADHINTS;
        }
    }
                if (error) break;

    return 0;
}

}  // namespace

int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
                                     const addrinfo* hints, const android_net_context* netcontext,
                                     addrinfo** res) {
    // hostname is allowed to be nullptr
    // servname is allowed to be nullptr
    // hints is allowed to be nullptr
    assert(res != nullptr);
    assert(netcontext != nullptr);

    addrinfo sentinel = {};
    addrinfo* cur = &sentinel;
    int error = 0;

    do {
        if (hostname == nullptr && servname == nullptr) {
            error = EAI_NONAME;
            break;
        }

        /*
         * Check for special cases:
         * (1) numeric servname is disallowed if socktype/protocol are left unspecified.
         * (2) servname is disallowed for raw and other inet{,6} sockets.
         */
        if (hints && (error = validateHints(hints))) break;
        addrinfo ai = hints ? *hints : addrinfo{};

        // Check for special cases:
        // (1) numeric servname is disallowed if socktype/protocol are left unspecified.
        // (2) servname is disallowed for raw and other inet{,6} sockets.
        if (MATCH_FAMILY(ai.ai_family, PF_INET, 1) || MATCH_FAMILY(ai.ai_family, PF_INET6, 1)) {
            struct addrinfo tmp = ai;
            addrinfo tmp = ai;
            if (tmp.ai_family == PF_UNSPEC) {
                tmp.ai_family = PF_INET6;
            }
@@ -357,7 +344,7 @@ int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
            if (!MATCH(ai.ai_socktype, ex.e_socktype, WILD_SOCKTYPE(ex))) continue;
            if (!MATCH(ai.ai_protocol, ex.e_protocol, WILD_PROTOCOL(ex))) continue;

            struct addrinfo tmp = ai;
            addrinfo tmp = ai;
            if (tmp.ai_family == PF_UNSPEC) tmp.ai_family = ex.e_af;
            if (tmp.ai_socktype == ANY && ex.e_socktype != ANY) tmp.ai_socktype = ex.e_socktype;
            if (tmp.ai_protocol == ANY && ex.e_protocol != ANY) tmp.ai_protocol = ex.e_protocol;
@@ -375,11 +362,8 @@ int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
        }
        if (error) break;

        /*
         * XXX
         * If numeric representation of AF1 can be interpreted as FQDN
         * representation of AF2, we need to think again about the code below.
         */
        // If numeric representation of AF1 can be interpreted as FQDN
        // representation of AF2, we need to think again about the code below.
        if (sentinel.ai_next) break;

        if (hostname == nullptr) {
@@ -391,22 +375,49 @@ int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
            break;
        }

        /*
         * hostname as alphabetical name.
         * We would like to prefer AF_INET6 over AF_INET, so we'll make a outer loop by AFs.
         */
        return resolv_getaddrinfo(hostname, servname, hints, netcontext, res);
    } while (0);

    if (error) {
        freeaddrinfo(sentinel.ai_next);
        *res = nullptr;
    } else {
        *res = sentinel.ai_next;
    }
    return error;
}

int resolv_getaddrinfo(const char* _Nonnull hostname, const char* servname, const addrinfo* hints,
                       const android_net_context* _Nonnull netcontext, addrinfo** _Nonnull res) {
    if (hostname == nullptr && servname == nullptr) return EAI_NONAME;
    if (hostname == nullptr) return EAI_NODATA;

    // hostname is allowed to be nullptr
    // servname is allowed to be nullptr
    // hints is allowed to be nullptr
    assert(res != nullptr);
    assert(netcontext != nullptr);

    int error = EAI_FAIL;
    if (hints && (error = validateHints(hints))) {
        *res = nullptr;
        return error;
    }

    addrinfo ai = hints ? *hints : addrinfo{};
    addrinfo sentinel = {};
    addrinfo* cur = &sentinel;
    // hostname as alphanumeric name.
    // We would like to prefer AF_INET6 over AF_INET, so we'll make a outer loop by AFs.
    for (const Explore& ex : explore_options) {
        // Require exact match for family field
        if (ai.ai_family != ex.e_af) continue;

            if (!MATCH(ai.ai_socktype, ex.e_socktype, WILD_SOCKTYPE(ex))) {
                continue;
            }
            if (!MATCH(ai.ai_protocol, ex.e_protocol, WILD_PROTOCOL(ex))) {
                continue;
            }
        if (!MATCH(ai.ai_socktype, ex.e_socktype, WILD_SOCKTYPE(ex))) continue;

            struct addrinfo tmp = ai;
        if (!MATCH(ai.ai_protocol, ex.e_protocol, WILD_PROTOCOL(ex))) continue;

        addrinfo tmp = ai;
        if (tmp.ai_socktype == ANY && ex.e_socktype != ANY) tmp.ai_socktype = ex.e_socktype;
        if (tmp.ai_protocol == ANY && ex.e_protocol != ANY) tmp.ai_protocol = ex.e_protocol;

@@ -417,55 +428,45 @@ int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
        while (cur->ai_next) cur = cur->ai_next;
    }

        if (sentinel.ai_next) {
            error = 0;
        } else if (error == 0) {
            error = EAI_FAIL;
        }
    } while (0);
    if ((*res = sentinel.ai_next)) return 0;

    if (error) {
    freeaddrinfo(sentinel.ai_next);
    *res = nullptr;
    } else {
        *res = sentinel.ai_next;
    }
    return error;
}

// FQDN hostname, DNS lookup
static int explore_fqdn(const struct addrinfo* pai, const char* hostname, const char* servname,
                        struct addrinfo** res, const struct android_net_context* netcontext) {
    struct addrinfo* result;
    int error = 0;

    assert(pai != NULL);
    /* hostname may be NULL */
    /* servname may be NULL */
    assert(res != NULL);
static int explore_fqdn(const addrinfo* pai, const char* hostname, const char* servname,
                        addrinfo** res, const android_net_context* netcontext) {
    assert(pai != nullptr);
    // hostname may be nullptr
    // servname may be nullptr
    assert(res != nullptr);

    result = NULL;
    addrinfo* result = nullptr;
    int error = 0;

    // If the servname does not match socktype/protocol, ignore it.
    if (get_portmatch(pai, servname) != 0) return 0;
    // If the servname does not match socktype/protocol, return error code.
    if ((error = get_portmatch(pai, servname))) return error;

    if (!files_getaddrinfo(hostname, pai, &result)) {
        error = dns_getaddrinfo(hostname, pai, netcontext, &result);
    }
    if (!error) {
        struct addrinfo* cur;
        for (cur = result; cur; cur = cur->ai_next) {
            GET_PORT(cur, servname);
            /* canonname should be filled already */
        }
        *res = result;
        return 0;
    if (error) {
        freeaddrinfo(result);
        return error;
    }

free:
    for (addrinfo* cur = result; cur; cur = cur->ai_next) {
        // canonname should be filled already
        if ((error = get_port(cur, servname, 0))) {
            freeaddrinfo(result);
            return error;
        }
    }
    *res = result;
    return 0;
}

/*
 * hostname == NULL.
+6 −2
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@

struct addrinfo;

int android_getaddrinfofornetcontext(const char* hostname, const char* servname,
                                     const addrinfo* hints, const android_net_context* netcontext,
                                     addrinfo** res);

// This is the DNS proxy entry point for getaddrinfo().
int android_getaddrinfofornetcontext(const char*, const char*, const addrinfo*,
                                     const android_net_context*, addrinfo**);
int resolv_getaddrinfo(const char* hostname, const char* servname, const addrinfo* hints,
                       const android_net_context* netcontext, addrinfo** res);
+32 −52
Original line number Diff line number Diff line
@@ -112,18 +112,18 @@ class TestBase : public ::testing::Test {
    static constexpr char kBadCharInTheMiddleOfLabelHost[] = "hello.ex^ample.com.";
};

class GetAddrInfoForNetContextTest : public TestBase {};
class ResolvGetAddrInfoTest : public TestBase {};
class GetHostByNameForNetContextTest : public TestBase {};

TEST_F(GetAddrInfoForNetContextTest, InvalidParameters) {
    // Both null "netcontext" and null "res" of android_getaddrinfofornetcontext() are not tested
TEST_F(ResolvGetAddrInfoTest, InvalidParameters) {
    // Both null "netcontext" and null "res" of resolv_getaddrinfo() are not tested
    // here because they are checked by assert() without returning any error number.

    // Invalid hostname and servname.
    // Both hostname and servname are null pointers. Expect error number EAI_NONAME.
    struct addrinfo* result = nullptr;
    int rv = android_getaddrinfofornetcontext(nullptr /*hostname*/, nullptr /*servname*/,
                                              nullptr /*hints*/, &mNetcontext, &result);
    int rv = resolv_getaddrinfo(nullptr /*hostname*/, nullptr /*servname*/, nullptr /*hints*/,
                                &mNetcontext, &result);
    EXPECT_EQ(EAI_NONAME, rv);
    if (result) {
        freeaddrinfo(result);
@@ -178,8 +178,7 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters) {
                .ai_next = config.ai_next,
        };

        rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
                                              &mNetcontext, &result);
        rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext, &result);
        EXPECT_EQ(config.expected_eai_error, rv);

        if (result) {
@@ -189,7 +188,7 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters) {
    }
}

TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_Family) {
TEST_F(ResolvGetAddrInfoTest, InvalidParameters_Family) {
    for (int family = 0; family < AF_MAX; ++family) {
        if (family == AF_UNSPEC || family == AF_INET || family == AF_INET6) {
            continue;  // skip supported family
@@ -201,15 +200,15 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_Family) {
                .ai_family = family,  // unsupported family
        };

        int rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
                                                  &mNetcontext, &result);
        int rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext,
                                    &result);
        EXPECT_EQ(EAI_FAMILY, rv);

        if (result) freeaddrinfo(result);
    }
}

TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_MeaningfulSocktypeAndProtocolCombination) {
TEST_F(ResolvGetAddrInfoTest, InvalidParameters_MeaningfulSocktypeAndProtocolCombination) {
    static const int families[] = {PF_INET, PF_INET6, PF_UNSPEC};
    // Skip to test socket type SOCK_RAW in meaningful combination (explore_options[]) of
    // system\netd\resolv\getaddrinfo.cpp. In explore_options[], the socket type SOCK_RAW always
@@ -248,8 +247,8 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_MeaningfulSocktypeAndProt
                        .ai_socktype = socktype,
                };

                int rv = android_getaddrinfofornetcontext("localhost", nullptr /*servname*/, &hints,
                                                          &mNetcontext, &result);
                int rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext,
                                            &result);
                EXPECT_EQ(EAI_BADHINTS, rv);

                if (result) freeaddrinfo(result);
@@ -258,7 +257,7 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_MeaningfulSocktypeAndProt
    }
}

TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_PortNameAndNumber) {
TEST_F(ResolvGetAddrInfoTest, InvalidParameters_PortNameAndNumber) {
    constexpr char http_portno[] = "80";
    constexpr char invalid_portno[] = "65536";  // out of valid port range from 0 to 65535
    constexpr char http_portname[] = "http";
@@ -280,18 +279,6 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_PortNameAndNumber) {
            {0, AF_INET, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
            {0, AF_INET6, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
            {0, AF_UNSPEC, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
            {0, AF_INET, SOCK_RDM /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET6, SOCK_RDM /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_UNSPEC, SOCK_RDM /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET, SOCK_SEQPACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET6, SOCK_SEQPACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_UNSPEC, SOCK_SEQPACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET, SOCK_DCCP /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET6, SOCK_DCCP /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_UNSPEC, SOCK_DCCP /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET, SOCK_PACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET6, SOCK_PACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_UNSPEC, SOCK_PACKET /*bad*/, http_portno, EAI_SOCKTYPE},
            {0, AF_INET, ANY, invalid_portno /*bad*/, EAI_SERVICE},
            {0, AF_INET, SOCK_STREAM, invalid_portno /*bad*/, EAI_SERVICE},
            {0, AF_INET, SOCK_DGRAM, invalid_portno /*bad*/, EAI_SERVICE},
@@ -332,15 +319,14 @@ TEST_F(GetAddrInfoForNetContextTest, InvalidParameters_PortNameAndNumber) {
        };

        struct addrinfo* result = nullptr;
        int rv = android_getaddrinfofornetcontext("localhost", config.servname, &hints,
                                                  &mNetcontext, &result);
        int rv = resolv_getaddrinfo("localhost", config.servname, &hints, &mNetcontext, &result);
        EXPECT_EQ(config.expected_eai_error, rv);

        if (result) freeaddrinfo(result);
    }
}

TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname_NoData) {
TEST_F(ResolvGetAddrInfoTest, AlphabeticalHostname_NoData) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";
    constexpr char v4_host_name[] = "v4only.example.com.";
@@ -356,7 +342,7 @@ TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname_NoData) {
    // Want AAAA answer but DNS server has A answer only.
    struct addrinfo* result = nullptr;
    const addrinfo hints = {.ai_family = AF_INET6};
    int rv = android_getaddrinfofornetcontext("v4only", nullptr, &hints, &mNetcontext, &result);
    int rv = resolv_getaddrinfo("v4only", nullptr, &hints, &mNetcontext, &result);
    EXPECT_LE(1U, GetNumQueries(dns, v4_host_name));
    EXPECT_EQ(nullptr, result);
    EXPECT_EQ(EAI_NODATA, rv);
@@ -364,7 +350,7 @@ TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname_NoData) {
    if (result) freeaddrinfo(result);
}

TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname) {
TEST_F(ResolvGetAddrInfoTest, AlphabeticalHostname) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";
    constexpr char host_name[] = "sawadee.example.com.";
@@ -394,8 +380,7 @@ TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname) {

        struct addrinfo* result = nullptr;
        const struct addrinfo hints = {.ai_family = config.ai_family};
        int rv =
                android_getaddrinfofornetcontext("sawadee", nullptr, &hints, &mNetcontext, &result);
        int rv = resolv_getaddrinfo("sawadee", nullptr, &hints, &mNetcontext, &result);
        EXPECT_EQ(0, rv);
        EXPECT_TRUE(result != nullptr);
        EXPECT_EQ(1U, GetNumQueries(dns, host_name));
@@ -405,7 +390,7 @@ TEST_F(GetAddrInfoForNetContextTest, AlphabeticalHostname) {
    }
}

TEST_F(GetAddrInfoForNetContextTest, IllegalHostname) {
TEST_F(ResolvGetAddrInfoTest, IllegalHostname) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";

@@ -442,8 +427,7 @@ TEST_F(GetAddrInfoForNetContextTest, IllegalHostname) {

            addrinfo* res = nullptr;
            const addrinfo hints = {.ai_family = family};
            int rv =
                    android_getaddrinfofornetcontext(hostname, nullptr, &hints, &mNetcontext, &res);
            int rv = resolv_getaddrinfo(hostname, nullptr, &hints, &mNetcontext, &res);
            ScopedAddrinfo result(res);
            EXPECT_EQ(nullptr, result);
            EXPECT_EQ(EAI_FAIL, rv);
@@ -451,7 +435,7 @@ TEST_F(GetAddrInfoForNetContextTest, IllegalHostname) {
    }
}

TEST_F(GetAddrInfoForNetContextTest, ServerResponseError) {
TEST_F(ResolvGetAddrInfoTest, ServerResponseError) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";
    constexpr char host_name[] = "hello.example.com.";
@@ -486,8 +470,7 @@ TEST_F(GetAddrInfoForNetContextTest, ServerResponseError) {

        struct addrinfo* result = nullptr;
        const struct addrinfo hints = {.ai_family = AF_UNSPEC};
        int rv =
                android_getaddrinfofornetcontext(host_name, nullptr, &hints, &mNetcontext, &result);
        int rv = resolv_getaddrinfo(host_name, nullptr, &hints, &mNetcontext, &result);
        EXPECT_EQ(config.expected_eai_error, rv);

        if (result) freeaddrinfo(result);
@@ -495,7 +478,7 @@ TEST_F(GetAddrInfoForNetContextTest, ServerResponseError) {
}

// TODO: Add private DNS server timeout test.
TEST_F(GetAddrInfoForNetContextTest, ServerTimeout) {
TEST_F(ResolvGetAddrInfoTest, ServerTimeout) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";
    constexpr char host_name[] = "hello.example.com.";
@@ -510,13 +493,13 @@ TEST_F(GetAddrInfoForNetContextTest, ServerTimeout) {

    struct addrinfo* result = nullptr;
    const struct addrinfo hints = {.ai_family = AF_UNSPEC};
    int rv = android_getaddrinfofornetcontext("hello", nullptr, &hints, &mNetcontext, &result);
    int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result);
    EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv);

    if (result) freeaddrinfo(result);
}

TEST_F(GetAddrInfoForNetContextTest, CnamesNoIpAddress) {
TEST_F(ResolvGetAddrInfoTest, CnamesNoIpAddress) {
    constexpr char ACNAME[] = "acname";  // expect a cname in answer
    constexpr char CNAMES[] = "cnames";  // expect cname chain in answer

@@ -553,14 +536,14 @@ TEST_F(GetAddrInfoForNetContextTest, CnamesNoIpAddress) {
        addrinfo* res = nullptr;
        const addrinfo hints = {.ai_family = config.family};

        int rv = android_getaddrinfofornetcontext(config.name, nullptr, &hints, &mNetcontext, &res);
        int rv = resolv_getaddrinfo(config.name, nullptr, &hints, &mNetcontext, &res);
        ScopedAddrinfo result(res);
        EXPECT_EQ(nullptr, result);
        EXPECT_EQ(EAI_FAIL, rv);
    }
}

TEST_F(GetAddrInfoForNetContextTest, CnamesBrokenChainByIllegalCname) {
TEST_F(ResolvGetAddrInfoTest, CnamesBrokenChainByIllegalCname) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";

@@ -609,8 +592,7 @@ TEST_F(GetAddrInfoForNetContextTest, CnamesBrokenChainByIllegalCname) {

            addrinfo* res = nullptr;
            const addrinfo hints = {.ai_family = family};
            int rv = android_getaddrinfofornetcontext(config.name, nullptr, &hints, &mNetcontext,
                                                      &res);
            int rv = resolv_getaddrinfo(config.name, nullptr, &hints, &mNetcontext, &res);
            ScopedAddrinfo result(res);
            EXPECT_EQ(nullptr, result);
            EXPECT_EQ(EAI_FAIL, rv);
@@ -618,7 +600,7 @@ TEST_F(GetAddrInfoForNetContextTest, CnamesBrokenChainByIllegalCname) {
    }
}

TEST_F(GetAddrInfoForNetContextTest, CnamesInfiniteLoop) {
TEST_F(ResolvGetAddrInfoTest, CnamesInfiniteLoop) {
    constexpr char listen_addr[] = "127.0.0.3";
    constexpr char listen_srv[] = "53";

@@ -637,7 +619,7 @@ TEST_F(GetAddrInfoForNetContextTest, CnamesInfiniteLoop) {
        addrinfo* res = nullptr;
        const addrinfo hints = {.ai_family = family};

        int rv = android_getaddrinfofornetcontext("hello", nullptr, &hints, &mNetcontext, &res);
        int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &res);
        ScopedAddrinfo result(res);
        EXPECT_EQ(nullptr, result);
        EXPECT_EQ(EAI_FAIL, rv);
@@ -922,16 +904,14 @@ TEST_F(GetHostByNameForNetContextTest, CnamesInfiniteLoop) {
    }
}

// Note that local host file function, files_getaddrinfo(), of android_getaddrinfofornetcontext()
// Note that local host file function, files_getaddrinfo(), of resolv_getaddrinfo()
// is not tested because it only returns a boolean (success or failure) without any error number.

// TODO: Simplify the DNS server configuration, DNSResponder and resolv_set_nameservers_for_net, as
//       ResolverTest does.
// TODO: Use the most modern style std::size() to get array size but sizeof(x)/sizeof(x[0]).
// TODO: Use ScopedAddrinfo to handle addrinfo pointers.
// TODO: Add test for android_getaddrinfofornetcontext().
//       - Invalid hostname.
//           - NULL hostname, or numeric hostname.
// TODO: Add test for resolv_getaddrinfo().
//       - DNS response message parsing.
//           - Unexpected type of resource record (RR).
//           - Invalid length CNAME, or QNAME.