{"record":{"id":"5785eb90ad55f78e","repo":"v2rayA/v2rayA","slug":"dns-upstream-invalid-response-w","errorCode":null,"errorMessage":"dns upstream: invalid response: %w","messagePattern":"dns upstream: invalid response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/dns/upstream_stub.go","lineNumber":161,"sourceCode":"\t\t\t\tlog.Printf(\"[dns upstream] TCP fallback error (attempt %d): %s %s → %s: %v\", attempt+1,\n\t\t\t\t\tdns.Type(uint16(query.QType)).String(), query.Name, upstream.Addr, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tbreak\n\t}\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"dns upstream: exchange failed: %w\", err)\n\t}\n\n\tif resp == nil {\n\t\treturn nil, nil\n\t}\n\n\tif err := ValidateResponse(resp); err != nil {\n\t\treturn nil, fmt.Errorf(\"dns upstream: invalid response: %w\", err)\n\t}\n\tif err := ValidateQuestionMatch(resp, query.Name, query.QType); err != nil {\n\t\treturn nil, fmt.Errorf(\"dns upstream: question mismatch: %w\", err)\n\t}\n\n\tvar ttl uint32\n\tif len(resp.Answer) > 0 {\n\t\tttl = resp.Answer[0].Header().Ttl\n\t\tfor _, rr := range resp.Answer[1:] {\n\t\t\tif rr.Header().Ttl < ttl {\n\t\t\t\tttl = rr.Header().Ttl\n\t\t\t}\n\t\t}\n\t}\n\n\tdnsResp := &DnsResponse{\n\t\tQuery:      *query,\n\t\tRawMsg:     resp,","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/core/dns/upstream_stub.go#L143-L179","documentation":"exchangeDirect validates the DNS message received from a direct upstream with ValidateResponse and wraps any failure as \"dns upstream: invalid response: %w\". The reply arrived and parsed as DNS, but it is not an acceptable response — e.g. it is not a response to a query (QR bit unset), is malformed, or carries an unexpected opcode. This guards against spoofed or broken upstreams.","triggerScenarios":"Calling UpstreamManager.Exchange on a direct upstream whose reply fails ValidateResponse: responses with QR=0, malformed flags/sections, or otherwise structurally invalid messages returned by the server or injected by a middlebox (captive portals, ISP hijackers).","commonSituations":"Captive portal or hotel/airport Wi-Fi intercepting port 53 and returning an HTML/redirect page or junk packet; a middlebox rewriting DNS payloads; a misconfigured upstream replying with queries instead of responses; spoofed answers on untrusted networks.","solutions":["Inspect resp.Rcode/flags via the log output or capture with tcpdump to see what the upstream actually returned.","Switch to a trusted upstream (1.1.1.1, 8.8.8.8) or an encrypted one (DoH/DoT) to bypass port-53 interception.","Complete captive-portal authentication or leave the intercepting network.","Mark the failing upstream unhealthy in config and let a fallback upstream serve queries.","Check whether a local firewall/NAT device is rewriting UDP/53 payloads."],"exampleFix":"// before\nupstream addr: \"192.168.1.1:53\" // router hijacked by ISP, returns junk\n// after\nupstream addr: \"1.1.1.1:53\" // or enable DoH upstream to avoid interception","handlingStrategy":"retry","validationCode":"// Sanity-check the upstream before use: a valid reply should parse and be a response\nq := new(dns.Msg)\nq.SetQuestion(dns.Fqdn(\"example.com.\"), dns.TypeA)\nc := new(dns.Client)\nr, _, err := c.Exchange(q, upstream.Addr)\nif err != nil || r == nil || !r.Response || r.Rcode == dns.RcodeFormatError {\n    return fmt.Errorf(\"upstream %s returns invalid responses\", upstream.Addr)\n}","typeGuard":"func isInvalidResponseErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"dns upstream: invalid response\")\n}","tryCatchPattern":"resp, err := mgr.Exchange(upstream, query)\nif err != nil {\n    var target *dns.Msg\n    if strings.Contains(err.Error(), \"invalid response\") {\n        log.Printf(\"upstream %s returned invalid reply, failing over: %v\", upstream.Addr, err)\n        resp, err = mgr.Exchange(fallbackUpstream, query)\n    }\n    _ = target\n    if err != nil { return err }\n}","preventionTips":["Avoid plain UDP/53 on untrusted networks (hotels, captive portals) — use DoH/DoT upstreams.","Complete portal authentication before relying on DNS.","Monitor upstream health and rotate away from resolvers that repeatedly fail validation.","Pin well-known, DNSSEC-capable resolvers instead of router-provided DNS."],"tags":["dns","upstream","validation","spoofing","captive-portal"],"backgroundTag":"invalid-dns-response","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}