From b784bb792743f52e9ea5ece68849003573087a8d Mon Sep 17 00:00:00 2001 From: Virgil Date: Fri, 3 Apr 2026 19:49:59 +0000 Subject: [PATCH] feat(dns): add RFC dns.resolve address result Co-Authored-By: Virgil --- service.go | 14 ++++++++++++++ service_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/service.go b/service.go index 3011853..197bdf5 100644 --- a/service.go +++ b/service.go @@ -22,6 +22,10 @@ type ResolveAllResult struct { NS []string `json:"ns"` } +type ResolveAddressResult struct { + Addresses []string `json:"addresses"` +} + type Service struct { mu sync.RWMutex records map[string]NameRecords @@ -73,6 +77,16 @@ func (service *Service) ResolveTXT(name string) ([]string, bool) { return append([]string(nil), record.TXT...), true } +func (service *Service) ResolveAddress(name string) (ResolveAddressResult, bool) { + record, ok := service.findRecord(name) + if !ok { + return ResolveAddressResult{}, false + } + return ResolveAddressResult{ + Addresses: MergeRecords(record.A, record.AAAA), + }, true +} + func (service *Service) ResolveReverse(ip string) ([]string, bool) { service.mu.RLock() defer service.mu.RUnlock() diff --git a/service_test.go b/service_test.go index 334ca4c..b3c5a51 100644 --- a/service_test.go +++ b/service_test.go @@ -62,6 +62,36 @@ func TestServiceResolveTXTUsesWildcard(t *testing.T) { } } +func TestServiceResolveAddressReturnsMergedRecords(t *testing.T) { + service := NewService(ServiceOptions{ + Records: map[string]NameRecords{ + "gateway.charon.lthn": { + A: []string{"10.10.10.10", "10.10.10.10"}, + AAAA: []string{"2600:1f1c:7f0:4f01:0000:0000:0000:0001"}, + }, + }, + }) + + result, ok := service.ResolveAddress("gateway.charon.lthn") + if !ok { + t.Fatal("expected address record to resolve") + } + if len(result.Addresses) != 2 { + t.Fatalf("expected merged unique addresses, got %#v", result.Addresses) + } + if result.Addresses[0] != "10.10.10.10" || result.Addresses[1] != "2600:1f1c:7f0:4f01:0000:0000:0000:0001" { + t.Fatalf("unexpected address order or value: %#v", result.Addresses) + } +} + +func TestServiceResolveAddressFallsBackToFalseWhenMissing(t *testing.T) { + service := NewService(ServiceOptions{}) + + if _, ok := service.ResolveAddress("missing.charon.lthn"); ok { + t.Fatal("expected missing record to return false") + } +} + func TestServiceResolveReverseUsesARecords(t *testing.T) { service := NewService(ServiceOptions{ Records: map[string]NameRecords{ -- 2.45.3