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

Commit 84f5fa8b authored by Ken Chen's avatar Ken Chen
Browse files

Remove unicast-response bit from .local resolution

RFC 6762 section 6.7 says that the Multicast DNS responder MUST send a
UDP response directly back to the querier, via unicast, to the query
packet's source IP address and port if the source UDP port in a received
Multicast DNS query is not 5353. Section 5.4 also mentions "...New
questions created by local clients afterwards should be treated as
normal 'QM' questions and SHOULD NOT have the unicast-response bit set
on the first question of the series."

DNS resolver works as a one-shot Multicast DNS querier, which send
queries from random ports. The unicast-response bit is not necessary to
be set.

Setting the unicast-response bit may also cause malfunction on .local
fallback queries. Currently, the bit is not cleared while .local
resolution is fallbacked from Multicast to Unicast DNS queries. DNS
server may send a no error response without Answer RR, or a failure.

One way to fix this is clearing the unicast-response bit before
fallback. However, it needs to parse packet bytes in res_nsend() because
the query packet is made before the res_nsend() but the fallback
decision is made in res_nsend(). Besides, it can cause problems in
cache. The query class is counted in cache key hashing. The answer
obtained by fallback queries is hashed (without unicast-response bit)
and stored in cache. But subsequent .local queries cannot match the
record because their unicast-response bit is initially set.

To avoid adding more complexity, the unnecessary unicast-response bit
should be removed.

Bug: 227147672
Test: atest
Test: Ping test.local on openWRT with fallback and without fallback.
Change-Id: Ib703a7537f638669fdc1d9c6927800e5c901786a
parent f3c42075
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -1439,11 +1439,6 @@ static int dns_getaddrinfo(const char* name, const addrinfo* pai,

    setMdnsFlag(name, res.netid, &(res.flags));

    if (isMdnsResolution(res.flags)) {
        q.qclass |= C_UNICAST;
        q2.qclass |= C_UNICAST;
    }

    int he;
    if (res_searchN(name, &q, &res, &he) < 0) {
        // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA.
+1 −2
Original line number Diff line number Diff line
@@ -633,8 +633,7 @@ static int dns_gethtbyname(ResState* res, const char* name, int addr_type, getna
    auto buf = std::make_unique<querybuf>();

    int he;
    const unsigned qclass = isMdnsResolution(res->flags) ? C_IN | C_UNICAST : C_IN;
    n = res_nsearch(res, name, qclass, type, {buf->buf, (int)sizeof(buf->buf)}, &he);
    n = res_nsearch(res, name, C_IN, type, {buf->buf, (int)sizeof(buf->buf)}, &he);
    if (n < 0) {
        LOG(DEBUG) << __func__ << ": res_nsearch failed (" << n << ")";
        // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA.
+1 −3
Original line number Diff line number Diff line
@@ -260,7 +260,6 @@ static time_t _time_now(void) {
#define DNS_TYPE_ALL "\00\0377" /* big-endian decimal 255 */

#define DNS_CLASS_IN "\00\01" /* big-endian decimal 1 */
#define MDNS_CLASS_UNICAST_IN "\200\01" /* big-endian decimal 32769 */

struct DnsPacket {
    const uint8_t* base;
@@ -375,8 +374,7 @@ static int _dnsPacket_checkQR(DnsPacket* packet) {
        return 0;
    }
    /* CLASS must be IN */
    if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN) &&
        !_dnsPacket_checkBytes(packet, 2, MDNS_CLASS_UNICAST_IN)) {
    if (!_dnsPacket_checkBytes(packet, 2, DNS_CLASS_IN)) {
        LOG(INFO) << __func__ << ": unsupported CLASS";
        return 0;
    }
+0 −2
Original line number Diff line number Diff line
@@ -89,8 +89,6 @@ union sockaddr_union {
};
constexpr int MAXPACKET = 8 * 1024;

const unsigned C_UNICAST = 0x8000;  // unicast-response bit for MDNS

struct ResState {
    ResState(const android_net_context* netcontext, android::net::NetworkDnsEventReported* dnsEvent)
        : netid(netcontext->dns_netid),
+1 −3
Original line number Diff line number Diff line
@@ -978,10 +978,8 @@ bool DNSResponder::makeResponse(DNSHeader* header, int protocol, char* response,

bool DNSResponder::makeResponseFromAddressOrHostname(DNSHeader* header, char* response,
                                                     size_t* response_len) const {
    const unsigned unicast_bit = 0x8000;  // unicast-response bit for MDNS
    for (const DNSQuestion& question : header->questions) {
        if (question.qclass != ns_class::ns_c_in && question.qclass != ns_class::ns_c_any &&
            question.qclass != (unicast_bit | ns_class::ns_c_in)) {
        if (question.qclass != ns_class::ns_c_in && question.qclass != ns_class::ns_c_any) {
            LOG(INFO) << "unsupported question class " << question.qclass;
            return makeErrorResponse(header, ns_rcode::ns_r_notimpl, response, response_len);
        }