From eb6ac8617b6e69ac5c9255ffc1025e75e67aee34 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Tue, 27 Jan 2026 14:04:46 +0700 Subject: [PATCH] fix(dns): handle empty and invalid IP addresses gracefully Add guard checks to prevent panics when processing client info with empty IP addresses. Replace netip.MustParseAddr with ParseAddr to handle invalid IP addresses gracefully instead of panicking. Add test to verify queryFromSelf handles IP addresses safely. --- cmd/cli/dns_proxy.go | 14 ++++++++++++-- cmd/cli/dns_proxy_test.go | 10 ++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/cmd/cli/dns_proxy.go b/cmd/cli/dns_proxy.go index 718417a..965a069 100644 --- a/cmd/cli/dns_proxy.go +++ b/cmd/cli/dns_proxy.go @@ -1158,7 +1158,12 @@ func (p *prog) getClientInfo(remoteIP string, msg *dns.Msg) *ctrld.ClientInfo { } else { ci.Hostname = p.ciTable.LookupHostname(ci.IP, ci.Mac) } - ci.Self = p.queryFromSelf(ci.IP) + + if ci.IP == "" { + p.Debug().Msgf("client info entry with empty IP address: %v", ci) + } else { + ci.Self = p.queryFromSelf(ci.IP) + } // If this is a query from self, but ci.IP is not loopback IP, // try using hostname mapping for lookback IP if presents. if ci.Self { @@ -1275,7 +1280,12 @@ func (p *prog) queryFromSelf(ip string) bool { if val, ok := p.queryFromSelfMap.Load(ip); ok { return val.(bool) } - netIP := netip.MustParseAddr(ip) + netIP, err := netip.ParseAddr(ip) + if err != nil { + p.Debug().Err(err).Msgf("could not parse IP: %q", ip) + return false + } + regularIPs, loopbackIPs, err := netmon.LocalAddresses() if err != nil { p.Warn().Err(err).Msg("Could not get local addresses") diff --git a/cmd/cli/dns_proxy_test.go b/cmd/cli/dns_proxy_test.go index 6f5f7f0..5095552 100644 --- a/cmd/cli/dns_proxy_test.go +++ b/cmd/cli/dns_proxy_test.go @@ -794,6 +794,16 @@ func Test_handleRecovery_Integration(t *testing.T) { } } +func Test_prog_queryFromSelf(t *testing.T) { + p := newTestProg(t) + require.NotPanics(t, func() { + p.queryFromSelf("") + }) + require.NotPanics(t, func() { + p.queryFromSelf("foo") + }) +} + // newTestProg creates a properly initialized *prog for testing. func newTestProg(t *testing.T) *prog { p := &prog{cfg: testhelper.SampleConfig(t)}