From 502571756400a00445086b5ba412e03fca65e39f Mon Sep 17 00:00:00 2001 From: Stanislav Chzhen Date: Mon, 22 Apr 2024 18:39:22 +0300 Subject: [PATCH] all: imp code; add tests --- internal/client/index.go | 17 ++++++++ internal/client/index_internal_test.go | 56 ++++++++++++++++++++++++++ internal/home/clients.go | 6 ++- internal/querylog/entry.go | 1 + 4 files changed, 79 insertions(+), 1 deletion(-) diff --git a/internal/client/index.go b/internal/client/index.go index a3d19cb884f..fa5c33ad70d 100644 --- a/internal/client/index.go +++ b/internal/client/index.go @@ -215,6 +215,23 @@ func (ci *Index) findByIP(ip netip.Addr) (c *Persistent, found bool) { return nil, false } +// FindByIPWithoutZone finds a persistent client by IP address without zone. It +// strips the IPv6 zone index from the stored IP addresses before comparing, +// because querylog entries don't have it. See TODO on [querylog.logEntry.IP]. +func (ci *Index) FindByIPWithoutZone(ip netip.Addr) (c *Persistent) { + if (ip == netip.Addr{}) { + return nil + } + + for addr, uid := range ci.ipToUID { + if addr.WithZone("") == ip { + return ci.uidToClient[uid] + } + } + + return nil +} + // find finds persistent client by MAC. func (ci *Index) findByMAC(mac net.HardwareAddr) (c *Persistent, found bool) { k := macToKey(mac) diff --git a/internal/client/index_internal_test.go b/internal/client/index_internal_test.go index a03d9a221c1..2c8bec9d5d8 100644 --- a/internal/client/index_internal_test.go +++ b/internal/client/index_internal_test.go @@ -247,3 +247,59 @@ func TestMACToKey(t *testing.T) { _ = macToKey(mac) }) } + +func TestIndex_FindByIPWithoutZone(t *testing.T) { + var ( + ip = netip.MustParseAddr("fe80::a098:7654:32ef:ff1") + ipWithZone = netip.MustParseAddr("fe80::1ff:fe23:4567:890a%eth2") + ) + + var ( + Client = &Persistent{ + Name: "client", + IPs: []netip.Addr{ip}, + } + + ClientWithZone = &Persistent{ + Name: "client_with_zone", + IPs: []netip.Addr{ipWithZone}, + } + ) + + ci := newIDIndex([]*Persistent{ + Client, + ClientWithZone, + }) + + testCases := []struct { + ip netip.Addr + want *Persistent + name string + }{{ + name: "without_zone", + ip: ip, + want: Client, + }, { + name: "with_zone", + ip: ipWithZone, + want: ClientWithZone, + }, { + name: "zero_address", + ip: netip.Addr{}, + want: nil, + }} + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + c := ci.FindByIPWithoutZone(tc.ip.WithZone("")) + + if tc.want == nil { + require.Nil(t, c) + + return + } + + require.Equal(t, tc.want, c) + }) + } +} diff --git a/internal/home/clients.go b/internal/home/clients.go index 5c20497375e..c24d75dfbb8 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -414,7 +414,11 @@ func (clients *clientsContainer) clientOrArtificial( }() cli, ok := clients.find(id) - if ok { + if !ok { + cli = clients.clientIndex.FindByIPWithoutZone(ip) + } + + if cli != nil { return &querylog.Client{ Name: cli.Name, IgnoreQueryLog: cli.IgnoreQueryLog, diff --git a/internal/querylog/entry.go b/internal/querylog/entry.go index c3c800ed131..ed3319b069b 100644 --- a/internal/querylog/entry.go +++ b/internal/querylog/entry.go @@ -31,6 +31,7 @@ type logEntry struct { Answer []byte `json:",omitempty"` OrigAnswer []byte `json:",omitempty"` + // TODO(s.chzhen): Use netip.Addr. IP net.IP `json:"IP"` Result filtering.Result