{"record":{"id":"57f2a2e8bf27992a","repo":"XX-net/XX-Net","slug":"received-response-without-question","errorCode":null,"errorMessage":"received response without question","messagePattern":"received response without question","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"code/default/smart_router/local/dns_query.py","lineNumber":234,"sourceCode":"            try:\n                try:\n                    response, server = sock.recvfrom(8192)\n                    server, port = server\n                except Exception as e:\n                    # xlog.exception(\"sock.recvfrom except:%r\", e)\n                    continue\n\n                if not response:\n                    continue\n\n                try:\n                    p = DNSRecord.parse(response)\n                except Exception as e:\n                    xlog.exception(\"dns client parse response fail:%r\", e)\n                    continue\n\n                if len(p.questions) == 0:\n                    xlog.warn(\"received response without question\")\n                    continue\n\n                id = p.header.id\n\n                if id not in self.waiters:\n                    continue\n\n                que = self.waiters[id]\n                org_domain = que.domain\n                domain = str(p.questions[0].qname)\n                xlog.debug(\"DNS local query received %s from:%s domain:%s org:%s\", len(p.rr), server, domain, org_domain)\n                ips = []\n                for r in p.rr:\n                    ip = utils.to_bytes(str(r.rdata))\n                    ips.append(ip)\n\n                if ips:\n                    que.put(ips)","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/XX-net/XX-Net/blob/cfa5bc17b67676e467f37ec50766127e0ab5f0aa/code/default/smart_router/local/dns_query.py#L216-L252","documentation":"The UDP DNS receive worker parsed a DNS response whose question section is empty. RFC-compliant responses echo the original question; an empty question section indicates a broken/misbehaving upstream server, a spoofed packet, or a truncated response. The packet is discarded and the loop continues.","triggerScenarios":"A captive portal or middlebox replying with malformed DNS packets; a DNS server returning a response with QDCOUNT=0; packet corruption or interception on hostile networks; a non-DNS service replying on port 53.","commonSituations":"Hotel/airport captive portals, ISP DNS hijacking, firewall/security appliances that mangle DNS, misconfigured local dnsmasq instances.","solutions":["Inspect the upstream DNS server with 'dig @server domain' to confirm it returns well-formed responses","Switch to a different upstream DNS server (public resolvers like 8.8.8.8)","Use DNS-over-TLS/DNS-over-HTTPS (DnsOverTlsQuery/DnsOverHttpsQuery in this module) to bypass UDP mangling","If behind a captive portal, complete portal authentication first"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"# worker already continues; at the caller level treat query timeout as signal to switch transports:\nips = udp_client.query(domain, timeout=3)\nif not ips:\n    ips = tcp_client.query(domain)  # or DoT/DoH","preventionTips":["Prefer encrypted DNS (DoT/DoH) on networks known to mangle UDP DNS","Monitor this warning rate — a spike indicates captive portal or DNS interception","Complete captive-portal auth before relying on DNS"],"tags":["dns","udp","malformed-response","packet-parsing"],"backgroundTag":"malformed-dns-response","analyzedSha":"cfa5bc17b67676e467f37ec50766127e0ab5f0aa","analyzedAt":"2026-08-27T19:28:28.225Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}