{"record":{"id":"e8a279b6c1a35288","repo":"ginuerzh/gost","slug":"empty-question","errorCode":null,"errorMessage":"empty question","messagePattern":"empty question","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"resolver.go","lineNumber":389,"sourceCode":"\t\te.SourceNetmask = 32\n\t\te.Address = ip.To4()\n\t} else {\n\t\te.Family = 2\n\t\te.SourceNetmask = 128\n\t\te.Address = r.srcIP\n\t}\n\topt.Option = append(opt.Option, e)\n\tm.Extra = append(m.Extra, opt)\n}\n\nfunc (r *resolver) Exchange(ctx context.Context, query []byte) (reply []byte, err error) {\n\tmq := &dns.Msg{}\n\tif err = mq.Unpack(query); err != nil {\n\t\treturn\n\t}\n\n\tif len(mq.Question) == 0 {\n\t\treturn nil, errors.New(\"empty question\")\n\t}\n\n\tvar mr *dns.Msg\n\t// Only cache for single question.\n\tif len(mq.Question) == 1 {\n\t\tkey := newResolverCacheKey(&mq.Question[0])\n\t\tmr = r.cache.loadCache(key)\n\t\tif mr != nil {\n\t\t\tlog.Logf(\"[dns] exchange message %d (cached): %s\", mq.Id, mq.Question[0].String())\n\t\t\tmr.Id = mq.Id\n\t\t\treturn mr.Pack()\n\t\t}\n\n\t\tdefer func() {\n\t\t\tif mr != nil {\n\t\t\t\tr.cache.storeCache(key, mr, r.TTL())\n\t\t\t}\n\t\t}()","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/resolver.go#L371-L407","documentation":"Exchange unpacks a raw DNS query and requires at least one question section to know what to resolve. A well-formed but questionless DNS message (or one whose questions were lost in an upstream transform) cannot be answered, so the error is returned.","triggerScenarios":"Calling Exchange with a query that Unpacks successfully but has len(mq.Question) == 0 — e.g. an empty QUERY opcode packet or a malformed client request.","commonSituations":"Buggy or hostile DNS clients sending question-less messages; port-scan probes on the DNS port; a handler stripping the question before forwarding.","solutions":["Drop the packet and reply with FORMERR (or nothing) instead of retrying","Fix the client/handler that produces DNS messages without a Question section","Validate incoming DNS messages at the ingress before calling Exchange"],"exampleFix":"// before\nresp, err := resolver.Exchange(query)\n// after\nmq := &dns.Msg{}\nif err := mq.Unpack(query); err != nil || len(mq.Question) == 0 {\n    return dns.Msg{}\n}\nresp, err := resolver.Exchange(query)","handlingStrategy":"validation","validationCode":"mq := &dns.Msg{}\nif err := mq.Unpack(query); err != nil {\n    return err\n}\nif len(mq.Question) == 0 {\n    return errors.New(\"refusing to resolve message with no question\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := resolver.Exchange(query)\nif err != nil {\n    return newFormErrorResponse(query) // respond FORMERR, don't retry\n}","preventionTips":["Validate DNS messages before forwarding them upstream","Reply FORMERR to question-less queries","Log sources of malformed queries to identify buggy clients"],"tags":["dns","resolver","validation"],"backgroundTag":"empty-dns-question","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}