From 2a1cc62001caccbbb875e03da90b671c9ac5ec16 Mon Sep 17 00:00:00 2001 From: Guy Nesher Date: Wed, 22 Apr 2026 20:42:14 +0300 Subject: [PATCH] fix: guard QueryCert against panic on short/empty QNAME (#1635) * fix: guard QueryCert against panic on short/empty QNAME QueryCert slices data[:len(data)-1] to strip a trailing dot, which panics when data is empty (slice bounds [:-1]). Add a length check to return early for inputs shorter than a minimal valid "x." form. While miekg/dns currently rejects wire-format packets that would produce an empty QNAME, the Nebula code should not rely on library behavior for crash safety. Made-with: Cursor * fix merge conflicts --------- Co-authored-by: JackDoan --- dns_server.go | 3 +++ dns_server_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/dns_server.go b/dns_server.go index 8af88b52..5b12b922 100644 --- a/dns_server.go +++ b/dns_server.go @@ -241,6 +241,9 @@ func (d *dnsServer) Query(q uint16, data string) (netip.Addr, bool) { } func (d *dnsServer) QueryCert(data string) string { + if len(data) < 2 { + return "" + } ip, err := netip.ParseAddr(data[:len(data)-1]) if err != nil { return "" diff --git a/dns_server_test.go b/dns_server_test.go index ef8a5a64..e09d3fa9 100644 --- a/dns_server_test.go +++ b/dns_server_test.go @@ -16,6 +16,19 @@ import ( "github.com/stretchr/testify/require" ) +type stubDNSWriter struct{} + +func (stubDNSWriter) LocalAddr() net.Addr { return &net.UDPAddr{} } +func (stubDNSWriter) RemoteAddr() net.Addr { + return &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 5353} +} +func (stubDNSWriter) Write([]byte) (int, error) { return 0, nil } +func (stubDNSWriter) WriteMsg(*dns.Msg) error { return nil } +func (stubDNSWriter) Close() error { return nil } +func (stubDNSWriter) TsigStatus() error { return nil } +func (stubDNSWriter) TsigTimersOnly(bool) {} +func (stubDNSWriter) Hijack() {} + func TestParsequery(t *testing.T) { l := logrus.New() hostMap := &HostMap{} @@ -70,6 +83,19 @@ func TestParsequery(t *testing.T) { ds.parseQuery(m, nil) assert.Empty(t, m.Answer) assert.Equal(t, dns.RcodeNameError, m.Rcode) + + // short lookups should not fail + m = &dns.Msg{} + m.Question = []dns.Question{{Name: "", Qtype: dns.TypeTXT, Qclass: dns.ClassINET}} + ds.parseQuery(m, stubDNSWriter{}) + assert.Empty(t, m.Answer) + assert.Equal(t, dns.RcodeNameError, m.Rcode) + + m = &dns.Msg{} + m.Question = []dns.Question{{Name: ".", Qtype: dns.TypeTXT, Qclass: dns.ClassINET}} + ds.parseQuery(m, stubDNSWriter{}) + assert.Empty(t, m.Answer) + assert.Equal(t, dns.RcodeNameError, m.Rcode) } func Test_getDnsServerAddr(t *testing.T) {