txthinking/brook · warning

no question

Error message

no question

What it means

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.

Source

Thrown at relay.go:170

		i, err := c.Read(bf[:])
		if err != nil {
			return nil
		}
		if _, err := rc.Write(bf[0:i]); err != nil {
			return nil
		}
	}
	return nil
}

func (s *Relay) UDPHandle(addr *net.UDPAddr, b []byte, l1 *net.UDPConn) error {
	if s.IsDNS {
		m := &dns.Msg{}
		if err := m.Unpack(b); err != nil {
			return err
		}
		if len(m.Question) == 0 {
			return errors.New("no question")
		}
		done, err := DNSGate(addr, m, l1)
		if err != nil {
			return err
		}
		if done {
			return nil
		}
	}
	c, err := s.Pcf.Handle(addr, s.Dstb, b, func(b []byte) (int, error) {
		return l1.WriteToUDP(b, addr)
	}, s.UDPTimeout)
	if err != nil {
		return err
	}
	if c == nil {
		return nil
	}

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Ensure only real DNS queries (with a QD section) are sent to the DNS-mode relay port.
  2. If you need to transport non-query DNS messages, disable IsDNS mode on the relay so packets are forwarded raw without DNS validation.
  3. 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.

Example fix

// before
conn.Write(buildDNSMsgWithNoQuestion()) // relay replies: no question

// after
m := buildDNSMsg()
m.SetQuestion(dns.Fqdn("probe.example.com"), dns.TypeA) // QD=1, relay accepts
Defensive patterns

Strategy: validation

Validate before calling

func isRoutableDNSQuery(b []byte) bool {
    m := &dns.Msg{}
    if m.Unpack(b) != nil {
        return false
    }
    return len(m.Question) > 0
}

Try / catch

if err := relay.UDPHandle(s, addr, d); err != nil && err.Error() == "no question" {
    log.Printf("dropping non-query DNS datagram from %s", addr)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/e8fc88207622da69. Report an issue: GitHub.