ginuerzh/gost · warning

empty question

Error message

empty question

What it means

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.

Source

Thrown at resolver.go:389

		e.SourceNetmask = 32
		e.Address = ip.To4()
	} else {
		e.Family = 2
		e.SourceNetmask = 128
		e.Address = r.srcIP
	}
	opt.Option = append(opt.Option, e)
	m.Extra = append(m.Extra, opt)
}

func (r *resolver) Exchange(ctx context.Context, query []byte) (reply []byte, err error) {
	mq := &dns.Msg{}
	if err = mq.Unpack(query); err != nil {
		return
	}

	if len(mq.Question) == 0 {
		return nil, errors.New("empty question")
	}

	var mr *dns.Msg
	// Only cache for single question.
	if len(mq.Question) == 1 {
		key := newResolverCacheKey(&mq.Question[0])
		mr = r.cache.loadCache(key)
		if mr != nil {
			log.Logf("[dns] exchange message %d (cached): %s", mq.Id, mq.Question[0].String())
			mr.Id = mq.Id
			return mr.Pack()
		}

		defer func() {
			if mr != nil {
				r.cache.storeCache(key, mr, r.TTL())
			}
		}()

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Drop the packet and reply with FORMERR (or nothing) instead of retrying
  2. Fix the client/handler that produces DNS messages without a Question section
  3. Validate incoming DNS messages at the ingress before calling Exchange

Example fix

// before
resp, err := resolver.Exchange(query)
// after
mq := &dns.Msg{}
if err := mq.Unpack(query); err != nil || len(mq.Question) == 0 {
    return dns.Msg{}
}
resp, err := resolver.Exchange(query)
Defensive patterns

Strategy: validation

Validate before calling

mq := &dns.Msg{}
if err := mq.Unpack(query); err != nil {
    return err
}
if len(mq.Question) == 0 {
    return errors.New("refusing to resolve message with no question")
}

Try / catch

resp, err := resolver.Exchange(query)
if err != nil {
    return newFormErrorResponse(query) // respond FORMERR, don't retry
}

Prevention

When it happens

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

Common situations: Buggy or hostile DNS clients sending question-less messages; port-scan probes on the DNS port; a handler stripping the question before forwarding.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/e8a279b6c1a35288. Report an issue: GitHub.