Files
abrown38andClaude Opus 5.5 42e2013cb2 Names beside inside addresses
Reverse lookups (internal/names, POST /names) put a name beside each
inside address in connections, the log, quota usage, the dashboard's
quotas and the statistics' devices and blocked sources, in the web UI
and hc (--no-names to leave them out). Only inside addresses are looked
up: an inside zone's networks, and private ones outside the external
zones'. Names are cached (names.cache, 10m) and never stored;
names.resolver picks the DNS server.

Also: hc stats top devices listed each device twice; the dashboard's
quotas named the rule's ID twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:58:35 +01:00

58 lines
1.6 KiB
Go

package names
import (
"context"
"errors"
"net"
"net/netip"
"sync/atomic"
"testing"
"time"
)
func TestNames(t *testing.T) {
var calls atomic.Int32
slow := make(chan struct{})
r := NewFunc(func(ctx context.Context, addr string) ([]string, error) {
calls.Add(1)
switch addr {
case "10.0.0.1":
return []string{"nas.example.net."}, nil
case "10.0.0.2":
return nil, &net.DNSError{Err: "no such host", Name: addr, IsNotFound: true}
case "10.0.0.3":
return nil, errors.New("server failure")
case "10.0.0.4":
<-slow
return []string{"slow.example.net."}, nil
}
return nil, nil
}, time.Hour)
a := netip.MustParseAddr
all := []netip.Addr{a("10.0.0.1"), a("10.0.0.2"), a("10.0.0.3"), a("10.0.0.4")}
got := r.Names(context.Background(), all, 200*time.Millisecond)
if len(got) != 1 || got[a("10.0.0.1")] != "nas.example.net" {
t.Fatalf("first call: %v", got)
}
// The slow lookup finishes later and is there next time; the others
// come from the cache, the failure too until it is retried.
close(slow)
time.Sleep(50 * time.Millisecond)
got = r.Names(context.Background(), all, 200*time.Millisecond)
if len(got) != 2 || got[a("10.0.0.4")] != "slow.example.net" {
t.Fatalf("second call: %v", got)
}
if n := calls.Load(); n != 4 {
t.Fatalf("%d lookups, want 4 (cached)", n)
}
// A failure is tried again after retry, a missing name after ttl.
now := time.Now().Add(2 * time.Minute)
r.now = func() time.Time { return now }
r.Names(context.Background(), all, 200*time.Millisecond)
if n := calls.Load(); n != 5 {
t.Fatalf("%d lookups, want 5 (the failure again)", n)
}
}