{"record":{"id":"e8fc88207622da69","repo":"txthinking/brook","slug":"no-question","errorCode":null,"errorMessage":"no question","messagePattern":"no question","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"relay.go","lineNumber":170,"sourceCode":"\t\ti, err := c.Read(bf[:])\n\t\tif err != nil {\n\t\t\treturn nil\n\t\t}\n\t\tif _, err := rc.Write(bf[0:i]); err != nil {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *Relay) UDPHandle(addr *net.UDPAddr, b []byte, l1 *net.UDPConn) error {\n\tif s.IsDNS {\n\t\tm := &dns.Msg{}\n\t\tif err := m.Unpack(b); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(m.Question) == 0 {\n\t\t\treturn errors.New(\"no question\")\n\t\t}\n\t\tdone, err := DNSGate(addr, m, l1)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif done {\n\t\t\treturn nil\n\t\t}\n\t}\n\tc, err := s.Pcf.Handle(addr, s.Dstb, b, func(b []byte) (int, error) {\n\t\treturn l1.WriteToUDP(b, addr)\n\t}, s.UDPTimeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif c == nil {\n\t\treturn nil\n\t}","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/txthinking/brook/blob/5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8/relay.go#L152-L188","documentation":"When the relay is in DNS mode (IsDNS), UDPHandle unpacks the incoming UDP payload as a DNS message and requires at least one Question entry. A DNS message with zero questions cannot be routed by DNSGate, so the relay rejects it with \"no question\" instead of forwarding it.","triggerScenarios":"Relay.UDPHandle receives a UDP packet whose bytes unpack into a valid dns.Msg but with len(m.Question) == 0 — e.g. non-query DNS traffic (NOTIFY without question in some encodings, empty EDNS keepalive probes) or a payload that happens to parse as a header-only DNS message.","commonSituations":"Misconfigured clients pointing arbitrary UDP traffic at a DNS-mode relay port; malformed or minimal DNS probes; tools sending zero-question DNS datagrams for liveness checks.","solutions":["Ensure only real DNS queries (with a QD section) are sent to the DNS-mode relay port.","If you need to transport non-query DNS messages, disable IsDNS mode on the relay so packets are forwarded raw without DNS validation.","Inspect the offending client packet; if it's a health check, switch it to a proper query like a type-A lookup for a probe domain."],"exampleFix":"// before\nconn.Write(buildDNSMsgWithNoQuestion()) // relay replies: no question\n\n// after\nm := buildDNSMsg()\nm.SetQuestion(dns.Fqdn(\"probe.example.com\"), dns.TypeA) // QD=1, relay accepts","handlingStrategy":"validation","validationCode":"func isRoutableDNSQuery(b []byte) bool {\n    m := &dns.Msg{}\n    if m.Unpack(b) != nil {\n        return false\n    }\n    return len(m.Question) > 0\n}","typeGuard":null,"tryCatchPattern":"if err := relay.UDPHandle(s, addr, d); err != nil && err.Error() == \"no question\" {\n    log.Printf(\"dropping non-query DNS datagram from %s\", addr)\n}","preventionTips":["Only point genuine DNS resolvers/clients at a relay with IsDNS enabled.","Send health-check traffic as real queries (e.g. type-A for a probe domain).","Turn off IsDNS if you must forward arbitrary UDP payloads."],"tags":["network","dns","udp","validation"],"backgroundTag":"empty-required-field","analyzedSha":"5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8","analyzedAt":"2026-09-06T04:35:00.432Z","contentChangedAt":"2026-09-06T04:35:00.432Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}