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

Commit 05be1c7d authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6203617 from 71910b3a to rvc-release

Change-Id: I73ad0c72a476d5fc06a16fe553eb5bebc94ec81f
parents e8d2c1b0 71910b3a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1261,7 +1261,7 @@ ResolvCacheStatus resolv_cache_lookup(unsigned netid, const void* query, int que
        LOG(INFO) << __func__ << ": NOT IN CACHE (STALE ENTRY " << *lookup << "DISCARDED)";
        res_pquery(e->query, e->querylen);
        _cache_remove_p(cache, lookup);
        return RESOLV_CACHE_NOTFOUND;
        return (flags & ANDROID_RESOLV_NO_CACHE_STORE) ? RESOLV_CACHE_SKIP : RESOLV_CACHE_NOTFOUND;
    }

    *answerlen = e->answerlen;
+8 −35
Original line number Diff line number Diff line
@@ -94,23 +94,11 @@

void res_init(ResState* statp, const struct android_net_context* _Nonnull netcontext,
              android::net::NetworkDnsEventReported* _Nonnull event) {
    memset(statp, 0, sizeof *statp);

    statp->netid = netcontext->dns_netid;
    statp->uid = netcontext->uid;
    statp->pid = netcontext->pid;
    statp->nscount = 1;
    statp->id = arc4random_uniform(65536);
    statp->_mark = netcontext->dns_mark;
    statp->netcontext_flags = netcontext->flags;
    statp->event = event;

    statp->ndots = 1;
    statp->_vcsock = -1;

    for (int ns = 0; ns < MAXNS; ns++) {
        statp->nssocks[ns] = -1;
    }

    // The following dummy initialization is probably useless because
    // it's overwritten later by resolv_populate_res_for_net().
    // TODO: check if it's safe to remove.
@@ -120,28 +108,13 @@ void res_init(ResState* statp, const struct android_net_context* _Nonnull netcon
            .sin.sin_port = htons(NAMESERVER_PORT),
    };
    memcpy(&statp->nsaddrs, &u, sizeof(u));
    statp->nscount = 1;
}

/*
 * This routine is for closing the socket if a virtual circuit is used and
 * the program wants to close it.  This provides support for endhostent()
 * which expects to close the socket.
 *
 * This routine is not expected to be user visible.
 */
void res_nclose(res_state statp) {
    int ns;

    if (statp->_vcsock >= 0) {
        (void) close(statp->_vcsock);
        statp->_vcsock = -1;
        statp->_flags &= ~RES_F_VC;
    }
    for (ns = 0; ns < MAXNS; ns++) {
        if (statp->nssocks[ns] != -1) {
            close(statp->nssocks[ns]);
            statp->nssocks[ns] = -1;
        }
    for (auto& sock : statp->nssocks) {
        sock.reset();
    }
    statp->ndots = 1;
    statp->_mark = netcontext->dns_mark;
    statp->tcp_nssock.reset();
    statp->event = event;
    statp->netcontext_flags = netcontext->flags;
}
+134 −151
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int
            }
            if (resplen < 0) {
                _resolv_cache_query_failed(statp->netid, buf, buflen, flags);
                res_nclose(statp);
                statp->closeSockets();
                return -terrno;
            };

@@ -565,11 +565,11 @@ int res_nsend(res_state statp, const uint8_t* buf, int buflen, uint8_t* ans, int
            if (cache_status == RESOLV_CACHE_NOTFOUND) {
                resolv_cache_add(statp->netid, buf, buflen, ans, resplen);
            }
            res_nclose(statp);
            statp->closeSockets();
            return (resplen);
        }  // for each ns
    }  // for each retry
    res_nclose(statp);
    statp->closeSockets();
    terrno = useTcp ? terrno : gotsomewhere ? ETIMEDOUT : ECONNREFUSED;
    // TODO: Remove errno once callers stop using it
    errno = useTcp ? terrno
@@ -631,25 +631,24 @@ same_ns:
    struct timespec now = evNowTime();

    /* Are we still talking to whom we want to talk to? */
    if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
    if (statp->tcp_nssock >= 0 && (statp->_flags & RES_F_VC) != 0) {
        struct sockaddr_storage peer;
        socklen_t size = sizeof peer;
        unsigned old_mark;
        socklen_t mark_size = sizeof(old_mark);
        if (getpeername(statp->_vcsock, (struct sockaddr*) (void*) &peer, &size) < 0 ||
        if (getpeername(statp->tcp_nssock, (struct sockaddr*)(void*)&peer, &size) < 0 ||
            !sock_eq((struct sockaddr*)(void*)&peer, nsap) ||
            getsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 ||
            getsockopt(statp->tcp_nssock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 ||
            old_mark != statp->_mark) {
            res_nclose(statp);
            statp->_flags &= ~RES_F_VC;
            statp->closeSockets();
        }
    }

    if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
        if (statp->_vcsock >= 0) res_nclose(statp);
    if (statp->tcp_nssock < 0 || (statp->_flags & RES_F_VC) == 0) {
        if (statp->tcp_nssock >= 0) statp->closeSockets();

        statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
        if (statp->_vcsock < 0) {
        statp->tcp_nssock.reset(socket(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0));
        if (statp->tcp_nssock < 0) {
            switch (errno) {
                case EPROTONOSUPPORT:
                case EPFNOSUPPORT:
@@ -662,9 +661,9 @@ same_ns:
                    return -1;
            }
        }
        resolv_tag_socket(statp->_vcsock, statp->uid, statp->pid);
        resolv_tag_socket(statp->tcp_nssock, statp->uid, statp->pid);
        if (statp->_mark != MARK_UNSET) {
            if (setsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &statp->_mark,
            if (setsockopt(statp->tcp_nssock, SOL_SOCKET, SO_MARK, &statp->_mark,
                           sizeof(statp->_mark)) < 0) {
                *terrno = errno;
                PLOG(DEBUG) << __func__ << ": setsockopt: ";
@@ -672,17 +671,17 @@ same_ns:
            }
        }
        errno = 0;
        if (random_bind(statp->_vcsock, nsap->sa_family) < 0) {
        if (random_bind(statp->tcp_nssock, nsap->sa_family) < 0) {
            *terrno = errno;
            dump_error("bind/vc", nsap, nsaplen);
            res_nclose(statp);
            statp->closeSockets();
            return (0);
        }
        if (connect_with_timeout(statp->_vcsock, nsap, (socklen_t) nsaplen,
        if (connect_with_timeout(statp->tcp_nssock, nsap, (socklen_t)nsaplen,
                                 get_timeout(statp, params, ns)) < 0) {
            *terrno = errno;
            dump_error("connect/vc", nsap, nsaplen);
            res_nclose(statp);
            statp->closeSockets();
            /*
             * The way connect_with_timeout() is implemented prevents us from reliably
             * determining whether this was really a timeout or e.g. ECONNREFUSED. Since
@@ -705,10 +704,10 @@ same_ns:
            {.iov_base = &len, .iov_len = INT16SZ},
            {.iov_base = const_cast<uint8_t*>(buf), .iov_len = static_cast<size_t>(buflen)},
    };
    if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
    if (writev(statp->tcp_nssock, iov, 2) != (INT16SZ + buflen)) {
        *terrno = errno;
        PLOG(DEBUG) << __func__ << ": write failed: ";
        res_nclose(statp);
        statp->closeSockets();
        return (0);
    }
    /*
@@ -717,14 +716,14 @@ same_ns:
read_len:
    cp = ans;
    len = INT16SZ;
    while ((n = read(statp->_vcsock, (char*) cp, (size_t) len)) > 0) {
    while ((n = read(statp->tcp_nssock, (char*)cp, (size_t)len)) > 0) {
        cp += n;
        if ((len -= n) == 0) break;
    }
    if (n <= 0) {
        *terrno = errno;
        PLOG(DEBUG) << __func__ << ": read failed: ";
        res_nclose(statp);
        statp->closeSockets();
        /*
         * A long running process might get its TCP
         * connection reset if the remote server was
@@ -736,10 +735,8 @@ read_len:
         */
        if (*terrno == ECONNRESET && !connreset) {
            connreset = 1;
            res_nclose(statp);
            goto same_ns;
        }
        res_nclose(statp);
        return (0);
    }
    uint16_t resplen = ntohs(*reinterpret_cast<const uint16_t*>(ans));
@@ -755,18 +752,18 @@ read_len:
         */
        LOG(DEBUG) << __func__ << ": undersized: " << len;
        *terrno = EMSGSIZE;
        res_nclose(statp);
        statp->closeSockets();
        return (0);
    }
    cp = ans;
    while (len != 0 && (n = read(statp->_vcsock, (char*) cp, (size_t) len)) > 0) {
    while (len != 0 && (n = read(statp->tcp_nssock, (char*)cp, (size_t)len)) > 0) {
        cp += n;
        len -= n;
    }
    if (n <= 0) {
        *terrno = errno;
        PLOG(DEBUG) << __func__ << ": read(vc): ";
        res_nclose(statp);
        statp->closeSockets();
        return (0);
    }

@@ -779,7 +776,7 @@ read_len:
        while (len != 0) {
            char junk[PACKETSZ];

            n = read(statp->_vcsock, junk, (len > sizeof junk) ? sizeof junk : len);
            n = read(statp->tcp_nssock, junk, (len > sizeof junk) ? sizeof junk : len);
            if (n > 0)
                len -= n;
            else
@@ -875,24 +872,39 @@ retry:
    return n;
}

bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const uint8_t* buf,
                         int buflen, uint8_t* ans, int anssiz) {
    const HEADER* hp = (const HEADER*)(const void*)buf;
    HEADER* anhp = (HEADER*)(void*)ans;
    if (hp->id != anhp->id) {
        // response from old query, ignore it.
        LOG(DEBUG) << __func__ << ": old answer:";
        return true;
    }
    if (!res_ourserver_p(statp, (sockaddr*)(void*)&from)) {
        // response from wrong server? ignore it.
        LOG(DEBUG) << __func__ << ": not our server:";
        return true;
    }
    if (!res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) {
        // response contains wrong query? ignore it.
        LOG(DEBUG) << __func__ << ": wrong query name:";
        return true;
    }
    return false;
}

static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen,
                   uint8_t* ans, int anssiz, int* terrno, int ns, int* v_circuit, int* gotsomewhere,
                   time_t* at, int* rcode, int* delay) {
    *at = time(NULL);
    *at = time(nullptr);
    *delay = 0;
    const HEADER* hp = (const HEADER*) (const void*) buf;
    HEADER* anhp = (HEADER*) (void*) ans;
    const struct sockaddr* nsap;
    int nsaplen;
    struct timespec now, timeout, finish, done;
    struct sockaddr_storage from;
    socklen_t fromlen;
    int resplen, n, s;

    nsap = get_nsaddr(statp, (size_t) ns);
    nsaplen = sockaddrSize(nsap);
    const sockaddr* nsap = get_nsaddr(statp, (size_t)ns);
    const int nsaplen = sockaddrSize(nsap);

    if (statp->nssocks[ns] == -1) {
        statp->nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
        statp->nssocks[ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0));
        if (statp->nssocks[ns] < 0) {
            switch (errno) {
                case EPROTONOSUPPORT:
@@ -911,7 +923,7 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int
        if (statp->_mark != MARK_UNSET) {
            if (setsockopt(statp->nssocks[ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
                           sizeof(statp->_mark)) < 0) {
                res_nclose(statp);
                statp->closeSockets();
                return -1;
            }
        }
@@ -921,30 +933,28 @@ static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int
        // a nameserver without timing out.
        if (random_bind(statp->nssocks[ns], nsap->sa_family) < 0) {
            dump_error("bind(dg)", nsap, nsaplen);
            res_nclose(statp);
            statp->closeSockets();
            return (0);
        }
        if (connect(statp->nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
            dump_error("connect(dg)", nsap, nsaplen);
            res_nclose(statp);
            statp->closeSockets();
            return (0);
        }
        LOG(DEBUG) << __func__ << ": new DG socket";
    }
    s = statp->nssocks[ns];
    if (send(s, (const char*) buf, (size_t) buflen, 0) != buflen) {
    if (send(statp->nssocks[ns], (const char*)buf, (size_t)buflen, 0) != buflen) {
        PLOG(DEBUG) << __func__ << ": send: ";
        res_nclose(statp);
        statp->closeSockets();
        return 0;
    }

    timespec timeout = get_timeout(statp, params, ns);
    timespec now = evNowTime();
    timespec finish = evAddTime(now, timeout);
    for (;;) {
        // Wait for reply.
    timeout = get_timeout(statp, params, ns);
    now = evNowTime();
    finish = evAddTime(now, timeout);
retry:
    n = retrying_poll(s, POLLIN, &finish);

        int n = retrying_poll(statp->nssocks[ns], POLLIN, &finish);
        if (n == 0) {
            *rcode = RCODE_TIMEOUT;
            LOG(DEBUG) << __func__ << ": timeout";
@@ -953,99 +963,72 @@ retry:
        }
        if (n < 0) {
            PLOG(DEBUG) << __func__ << ": poll: ";
        res_nclose(statp);
            statp->closeSockets();
            return 0;
        }

        errno = 0;
    fromlen = sizeof(from);
    resplen = recvfrom(s, (char*) ans, (size_t) anssiz, 0, (struct sockaddr*) (void*) &from,
                       &fromlen);
        sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        int resplen = recvfrom(statp->nssocks[ns], (char*)ans, (size_t)anssiz, 0,
                               (sockaddr*)(void*)&from, &fromlen);
        if (resplen <= 0) {
            PLOG(DEBUG) << __func__ << ": recvfrom: ";
        res_nclose(statp);
            statp->closeSockets();
            return 0;
        }
        *gotsomewhere = 1;
        if (resplen < HFIXEDSZ) {
        /*
         * Undersized message.
         */
            // Undersized message.
            LOG(DEBUG) << __func__ << ": undersized: " << resplen;
            *terrno = EMSGSIZE;
        res_nclose(statp);
            statp->closeSockets();
            return 0;
        }
    if (hp->id != anhp->id) {
        /*
         * response from old query, ignore it.
         * XXX - potential security hazard could
         *	 be detected here.
         */
        LOG(DEBUG) << __func__ << ": old answer:";
        res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
        goto retry;
    }
    if (!res_ourserver_p(statp, (struct sockaddr*)(void*)&from)) {
        /*
         * response from wrong server? ignore it.
         * XXX - potential security hazard could
         *	 be detected here.
         */
        LOG(DEBUG) << __func__ << ": not our server:";

        if (ignoreInvalidAnswer(statp, from, buf, buflen, ans, anssiz)) {
            res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
        goto retry;
            continue;
        }

        HEADER* anhp = (HEADER*)(void*)ans;
        if (anhp->rcode == FORMERR && (statp->netcontext_flags & NET_CONTEXT_FLAG_USE_EDNS)) {
        /*
         * Do not retry if the server do not understand EDNS0.
         * The case has to be captured here, as FORMERR packet do not
         * carry query section, hence res_queriesmatch() returns 0.
         */
            //  Do not retry if the server do not understand EDNS0.
            //  The case has to be captured here, as FORMERR packet do not
            //  carry query section, hence res_queriesmatch() returns 0.
            LOG(DEBUG) << __func__ << ": server rejected query with EDNS0:";
            res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
        /* record the error */
            // record the error
            statp->_flags |= RES_F_EDNS0ERR;
        res_nclose(statp);
            statp->closeSockets();
            return 0;
        }
    if (!res_queriesmatch(buf, buf + buflen, ans, ans + anssiz)) {
        /*
         * response contains wrong query? ignore it.
         * XXX - potential security hazard could
         *	 be detected here.
         */
        LOG(DEBUG) << __func__ << ": wrong query name:";
        res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
        goto retry;
    }
    done = evNowTime();

        timespec done = evNowTime();
        *delay = _res_stats_calculate_rtt(&done, &now);
        if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) {
            LOG(DEBUG) << __func__ << ": server rejected query:";
            res_pquery(ans, (resplen > anssiz) ? anssiz : resplen);
        res_nclose(statp);
            statp->closeSockets();
            *rcode = anhp->rcode;
            return 0;
        }
        if (anhp->tc) {
        /*
         * To get the rest of answer,
         * use TCP with same server.
         */
            // To get the rest of answer,
            // use TCP with same server.
            LOG(DEBUG) << __func__ << ": truncated answer";
            *v_circuit = 1;
        res_nclose(statp);
            statp->closeSockets();
            return 1;
        }
    /*
     * All is well, or the error is fatal.  Signal that the
     * next nameserver ought not be tried.
     */
        // All is well, or the error is fatal. Signal that the
        // next nameserver ought not be tried.
        if (resplen > 0) {
            *rcode = anhp->rcode;
        }
        return resplen;
    }
}

static void dump_error(const char* str, const struct sockaddr* address, int alen) {
    char hbuf[NI_MAXHOST];
+27 −17
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#pragma once

#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <net/if.h>
#include <time.h>
#include <string>
@@ -73,6 +74,10 @@
#define RES_TIMEOUT 5000 /* min. milliseconds between retries */
#define RES_DFLRETRY 2    /* Default #/tries. */

// Flags for res_state->_flags
#define RES_F_VC 0x00000001        // socket is TCP
#define RES_F_EDNS0ERR 0x00000004  // EDNS0 caused errors

// Holds either a sockaddr_in or a sockaddr_in6.
union sockaddr_union {
    struct sockaddr sa;
@@ -82,21 +87,31 @@ union sockaddr_union {
constexpr int MAXPACKET = 8 * 1024;

struct ResState {
    void closeSockets() {
        tcp_nssock.reset();
        _flags &= ~RES_F_VC;

        for (auto& sock : nssocks) {
            sock.reset();
        }
    }
    // clang-format off
    unsigned netid;                             // NetId: cache key and socket mark
    uid_t uid;                                  // uid of the app that sent the DNS lookup
    pid_t pid;                                  // pid of the app that sent the DNS lookup
    int nscount;                                // number of name srvers
    uint16_t id;                                // current message id
    std::vector<std::string> search_domains;  // domains to search
    std::vector<std::string> search_domains{};  // domains to search
    sockaddr_union nsaddrs[MAXNS];
    int nssocks[MAXNS];                       // UDP sockets to nameservers
    android::base::unique_fd nssocks[MAXNS];    // UDP sockets to nameservers
    unsigned ndots : 4;                         // threshold for initial abs. query
    unsigned _mark;                             // If non-0 SET_MARK to _mark on all request sockets
    int _vcsock;                              // TCP socket (but why not one per nameserver?)
    uint32_t _flags;                          // See RES_F_* defines below
    android::base::unique_fd tcp_nssock;        // TCP socket (but why not one per nameserver?)
    uint32_t _flags = 0;                        // See RES_F_* defines below
    android::net::NetworkDnsEventReported* event;
    uint32_t netcontext_flags;
    int tc_mode;
    int tc_mode = 0;
    // clang-format on
};

// TODO: remove these legacy aliases
@@ -121,10 +136,6 @@ void _res_stats_set_sample(res_sample* sample, time_t now, int rcode, int rtt);

/* End of stats related definitions */

// Flags for res_state->_flags
#define RES_F_VC 0x00000001        // socket is TCP
#define RES_F_EDNS0ERR 0x00000004  // EDNS0 caused errors

/*
 * Error code extending h_errno codes defined in bionic/libc/include/netdb.h.
 *
@@ -146,7 +157,6 @@ int res_nquerydomain(res_state, const char*, const char*, int, int, uint8_t*, in
int res_nmkquery(int op, const char* qname, int cl, int type, const uint8_t* data, int datalen,
                 uint8_t* buf, int buflen, int netcontext_flags);
int res_nsend(res_state, const uint8_t*, int, uint8_t*, int, int*, uint32_t);
void res_nclose(res_state);
int res_nopt(res_state, int, uint8_t*, int, int);

int getaddrinfo_numeric(const char* hostname, const char* servname, addrinfo hints,
+5 −1
Original line number Diff line number Diff line
@@ -547,6 +547,10 @@ void DNSResponder::setEdns(Edns edns) {
    edns_ = edns;
}

void DNSResponder::setTtl(unsigned ttl) {
    answer_record_ttl_sec_ = ttl;
}

bool DNSResponder::running() const {
    return (udp_socket_.ok()) && (tcp_socket_.ok());
}
@@ -783,7 +787,7 @@ bool DNSResponder::addAnswerRecords(const DNSQuestion& question,
                    .name = {.name = it->first.name},
                    .rtype = it->first.type,
                    .rclass = ns_class::ns_c_in,
                    .ttl = kAnswerRecordTtlSec,  // seconds
                    .ttl = answer_record_ttl_sec_,  // seconds
            };
            if (!fillRdata(it->second, record)) return false;
            answers->push_back(std::move(record));
Loading