Core: Propagate TSIG status in DoQ transport (#7947)

This PR nsure DoQ writer preserves and returns TSIG verification status, preventing authentication bypass on DNS-over-QUIC.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang
2026-03-20 13:08:19 -07:00
committed by GitHub
parent 68a8f46129
commit e8db7e155e
3 changed files with 22 additions and 1 deletions

View File

@@ -14,6 +14,7 @@ type DoQWriter struct {
remoteAddr net.Addr remoteAddr net.Addr
stream *quic.Stream stream *quic.Stream
Msg *dns.Msg Msg *dns.Msg
tsigStatus error
} }
func (w *DoQWriter) Write(b []byte) (int, error) { func (w *DoQWriter) Write(b []byte) (int, error) {
@@ -61,7 +62,7 @@ func AddPrefix(b []byte) (m []byte) {
// These methods implement the dns.ResponseWriter interface from Go DNS. // These methods implement the dns.ResponseWriter interface from Go DNS.
func (w *DoQWriter) TsigStatus() error { return nil } func (w *DoQWriter) TsigStatus() error { return w.tsigStatus }
func (w *DoQWriter) TsigTimersOnly(b bool) {} func (w *DoQWriter) TsigTimersOnly(b bool) {}
func (w *DoQWriter) Hijack() {} func (w *DoQWriter) Hijack() {}
func (w *DoQWriter) LocalAddr() net.Addr { return w.localAddr } func (w *DoQWriter) LocalAddr() net.Addr { return w.localAddr }

View File

@@ -224,6 +224,14 @@ func (s *ServerQUIC) serveQUICStream(stream *quic.Stream, conn *quic.Conn) {
Msg: req, Msg: req,
} }
if tsig := req.IsTsig(); tsig != nil {
if s.tsigSecret == nil {
w.tsigStatus = dns.ErrSecret
} else if _, ok := s.tsigSecret[tsig.Hdr.Name]; !ok {
w.tsigStatus = dns.ErrSecret
}
}
dnsCtx := context.WithValue(stream.Context(), Key{}, s.Server) dnsCtx := context.WithValue(stream.Context(), Key{}, s.Server)
dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0) dnsCtx = context.WithValue(dnsCtx, LoopKey{}, 0)
s.ServeDNS(dnsCtx, w, req) s.ServeDNS(dnsCtx, w, req)

View File

@@ -439,3 +439,15 @@ func TestAcquireQUICWorkerReturnsFalseOnCancelledContext(t *testing.T) {
t.Fatal("expected acquireQUICWorker to return false when context is cancelled") t.Fatal("expected acquireQUICWorker to return false when context is cancelled")
} }
} }
func TestDoQWriterTsigStatusReturnsStoredStatus(t *testing.T) {
want := errors.New("bad tsig")
w := &DoQWriter{
tsigStatus: want,
}
if got := w.TsigStatus(); got != want {
t.Fatalf("TsigStatus() = %v, want %v", got, want)
}
}