ginuerzh/gost · error
connection queue is full
Error message
connection queue is full
What it means
The DNS-over-UDP server emulation in serve() creates a virtual connection and pushes it onto the listener's connChan; if the listener's backlog of unaccepted DNS 'connections' is full (non-blocking send), it rejects the new request with this error. It signals the server is accepting requests faster than the application's ServeDNS handler consumes them.
Solutions
- Ensure a concurrent Accept loop is running and processing connections promptly
- Increase accept queue capacity or spawn more handler goroutines
- Log and drop the request gracefully on this error (client will retry the query)
- Profile the handler behind Accept for blocking calls (network, locks)
Example fix
// before
conn.mq <- mq
select {
case l.connChan <- conn:
default:
return errors.New("connection queue is full")
}
// after
select {
case l.connChan <- conn:
default:
log.Logf("[dns] accept queue full, dropping query from %s", w.RemoteAddr())
return errors.New("connection queue is full") // caller drops; consider resizing queue
} Defensive patterns
Strategy: try-catch
Validate before calling
// cannot be pre-validated; concurrency/backpressure issue at accept time
if queueDepth(l.connChan) >= cap(l.connChan) {
return fmt.Errorf("dns accept queue near capacity: %d/%d", queueDepth(l.connChan), cap(l.connChan))
} Try / catch
if err := serve(w, r); err != nil {
if err.Error() == "connection queue is full" {
// drop query; DNS client will retry — optionally backpressure metric here
return
}
log.Log(err)
} Prevention
- Always run a dedicated Accept loop for the DNS listener before serving
- Keep the ServeDNS/ServeHTTP handler non-blocking; offload heavy work to goroutines
- Monitor queue depth and scale consumers under tunneling load spikes
- Consider resizing the connChan buffer if sustained overflow is observed
When it happens
Trigger: Calling ServeDNS/ServeHTTP for a DNS request when the DNSListener's connChan (capacity-limited accept queue) is already full — i.e., the caller of Accept() is not draining incoming DNS queries fast enough.
Common situations: A DNS tunnel server whose Accept loop is blocked or slow (downstream handler stalled), traffic spikes from DNS tunneling clients, or forgetting to start the Accept loop at all.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/f0b6b9ae81d958f6.
Report an issue: GitHub.
Appendix: source
Thrown at dns.go:229
}()
select {
case err := <-ln.errc:
return nil, err
default:
}
return ln, nil
}
func (l *dnsListener) serve(w dnsResponseWriter, mq []byte) (err error) {
conn := newDNSServerConn(l.addr, w.RemoteAddr())
conn.mq <- mq
select {
case l.connChan <- conn:
default:
return errors.New("connection queue is full")
}
select {
case mr := <-conn.mr:
_, err = w.Write(mr)
case <-conn.cclose:
err = io.EOF
}
return
}
func (l *dnsListener) ServeDNS(w dns.ResponseWriter, m *dns.Msg) {
b, err := m.Pack()
if err != nil {
log.Logf("[dns] %s: %v", l.addr, err)
return
}
if err := l.serve(w, b); err != nil {View on GitHub (pinned to a33fdbf4c9)