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

Commit b1aa65a7 authored by chenbruce's avatar chenbruce
Browse files

Add setupUdpSocket() and use it in send_dg()

When implementing mDNS .local resolution, it would have the exact
same code to setup a udp socket as send_dg(). Factor it into a
common helper function.

Bug: 140857615
Test: cd packages/modules/DnsResolver && atest
Change-Id: Id2a5945b85ea306ddbcc6ee84aa876ac0b7709fc
parent 76620646
Loading
Loading
Loading
Loading
+42 −31
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ using android::netdutils::Stopwatch;
static int send_vc(res_state statp, res_params* params, const uint8_t* buf, int buflen,
                   uint8_t* ans, int anssiz, int* terrno, size_t ns, time_t* at, int* rcode,
                   int* delay);
static int setupUdpSocket(ResState* statp, const sockaddr* sockap, size_t addrIndex, int* terrno);
static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen,
                   uint8_t* ans, int anssiz, int* terrno, size_t* ns, int* v_circuit,
                   int* gotsomewhere, time_t* at, int* rcode, int* delay);
@@ -997,58 +998,68 @@ bool ignoreInvalidAnswer(res_state statp, const sockaddr_storage& from, const ui
    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, size_t* ns, int* v_circuit,
                   int* gotsomewhere, time_t* at, int* rcode, int* delay) {
    // It should never happen, but just in case.
    if (*ns >= statp->nsaddrs.size()) {
        LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns;
        *terrno = EINVAL;
        return -1;
    }

    *at = time(nullptr);
    *delay = 0;
    const sockaddr_storage ss = statp->nsaddrs[*ns];
    const sockaddr* nsap = reinterpret_cast<const sockaddr*>(&ss);
    const int nsaplen = sockaddrSize(nsap);
// return 1 when setup udp socket success.
// return 0 when timeout , bind error, network error(ex: Protocol not supported ...).
// return -1 when create socket fail, set socket option fail.
static int setupUdpSocket(ResState* statp, const sockaddr* sockap, size_t addrIndex, int* terrno) {
    statp->udpsocks[addrIndex].reset(socket(sockap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0));

    if (statp->udpsocks[*ns] == -1) {
        statp->udpsocks[*ns].reset(socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0));
        if (statp->udpsocks[*ns] < 0) {
    if (statp->udpsocks[addrIndex] < 0) {
        *terrno = errno;
            PLOG(DEBUG) << __func__ << ": socket(dg): ";
        PLOG(ERROR) << __func__ << ": socket: ";
        switch (errno) {
            case EPROTONOSUPPORT:
            case EPFNOSUPPORT:
            case EAFNOSUPPORT:
                    return (0);
                return 0;
            default:
                    return (-1);
                return -1;
        }
    }

    const uid_t uid = statp->enforce_dns_uid ? AID_DNS : statp->uid;
        resolv_tag_socket(statp->udpsocks[*ns], uid, statp->pid);
    resolv_tag_socket(statp->udpsocks[addrIndex], uid, statp->pid);
    if (statp->_mark != MARK_UNSET) {
            if (setsockopt(statp->udpsocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
        if (setsockopt(statp->udpsocks[addrIndex], SOL_SOCKET, SO_MARK, &(statp->_mark),
                       sizeof(statp->_mark)) < 0) {
            *terrno = errno;
            statp->closeSockets();
            return -1;
        }
    }

    if (random_bind(statp->udpsocks[addrIndex], sockap->sa_family) < 0) {
        *terrno = errno;
        dump_error("bind", sockap);
        statp->closeSockets();
        return 0;
    }
    return 1;
}

static int send_dg(res_state statp, res_params* params, const uint8_t* buf, int buflen,
                   uint8_t* ans, int anssiz, int* terrno, size_t* ns, int* v_circuit,
                   int* gotsomewhere, time_t* at, int* rcode, int* delay) {
    // It should never happen, but just in case.
    if (*ns >= statp->nsaddrs.size()) {
        LOG(ERROR) << __func__ << ": Out-of-bound indexing: " << ns;
        *terrno = EINVAL;
        return -1;
    }

    *at = time(nullptr);
    *delay = 0;
    const sockaddr_storage ss = statp->nsaddrs[*ns];
    const sockaddr* nsap = reinterpret_cast<const sockaddr*>(&ss);

    if (statp->udpsocks[*ns] == -1) {
        int result = setupUdpSocket(statp, nsap, *ns, terrno);
        if (result <= 0) return result;

        // Use a "connected" datagram socket to receive an ECONNREFUSED error
        // on the next socket operation when the server responds with an
        // ICMP port-unreachable error. This way we can detect the absence of
        // a nameserver without timing out.
        if (random_bind(statp->udpsocks[*ns], nsap->sa_family) < 0) {
            *terrno = errno;
            dump_error("bind(dg)", nsap);
            statp->closeSockets();
            return (0);
        }
        if (connect(statp->udpsocks[*ns], nsap, (socklen_t)nsaplen) < 0) {
        if (connect(statp->udpsocks[*ns], nsap, sockaddrSize(nsap)) < 0) {
            *terrno = errno;
            dump_error("connect(dg)", nsap);
            statp->closeSockets();