diff --git a/internal/client/client.go b/internal/client/client.go index 17858a69133..732a4582fdb 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -7,6 +7,7 @@ package client import ( "encoding" "fmt" + "strings" "github.com/AdguardTeam/AdGuardHome/internal/whois" ) @@ -57,73 +58,74 @@ func (cs Source) MarshalText() (text []byte, err error) { // Runtime is a client information from different sources. type Runtime struct { - // WHOIS is the filtered WHOIS data of a client. + // WHOIS is the filtered WHOIS information of a client. WHOIS *whois.Info - // ARP is the ARP data of a client. - ARP string + // arp is the ARP information of a client. + arp []string - // RDNS is the RDNS data of a client. - RDNS string + // rdns is the RDNS information of a client. + rdns []string - // DHCP is the DHCP data of a client. - DHCP string + // dhcp is the DHCP information of a client. + dhcp []string - // HostsFile is the data from the hosts file. - HostsFile string + // hostsFile is the information from the hosts file. + hostsFile []string } // Info returns client information with highest priority. func (r *Runtime) Info() (cs Source, host string) { - if r == nil { - return SourceNone, "" - } + info := []string{} switch { - case r.HostsFile != "": - return SourceHostsFile, r.HostsFile - case r.DHCP != "": - return SourceDHCP, r.DHCP - case r.RDNS != "": - return SourceRDNS, r.RDNS - case r.ARP != "": - return SourceARP, r.ARP + case r.hostsFile != nil: + cs, info = SourceHostsFile, r.hostsFile + case r.dhcp != nil: + cs, info = SourceDHCP, r.dhcp + case r.rdns != nil: + cs, info = SourceRDNS, r.rdns + case r.arp != nil: + cs, info = SourceARP, r.arp } - return SourceNone, "" + return cs, strings.Join(info, " ") } -// SetInfo sets client information. -func (r *Runtime) SetInfo(cs Source, host string) { - if host == "" { - host = "–" - } - +// SetInfo sets client information. info must be non-nil. +func (r *Runtime) SetInfo(cs Source, info []string) { switch cs { case SourceARP: - r.ARP = host + r.arp = info case SourceRDNS: - r.RDNS = host + r.rdns = info case SourceDHCP: - r.DHCP = host + r.dhcp = info case SourceHostsFile: - r.HostsFile = host + r.hostsFile = info } } -// IsSet returns true if a cs data is present. -func (r *Runtime) IsSet(cs Source) (ok bool) { +// Clear clears a cs information. +func (r *Runtime) Clear(cs Source) { switch cs { case SourceWHOIS: - return r.WHOIS != nil + r.WHOIS = nil case SourceARP: - return r.ARP != "" + r.arp = nil case SourceRDNS: - return r.RDNS != "" + r.rdns = nil case SourceDHCP: - return r.DHCP != "" + r.dhcp = nil case SourceHostsFile: - return r.HostsFile != "" + r.hostsFile = nil + } +} + +// IsEmpty returns true if there is no information from any source. +func (r *Runtime) IsEmpty() (ok bool) { + if r.WHOIS == nil && r.arp == nil && r.rdns == nil && r.dhcp == nil && r.hostsFile == nil { + return true } return false diff --git a/internal/home/clients.go b/internal/home/clients.go index eee7c6ceab6..2a1a3d282e6 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -563,20 +563,27 @@ func (clients *clientsContainer) runtimeClient(ip netip.Addr) (rc *client.Runtim // findRuntimeClient finds a runtime client by their IP. func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *client.Runtime, ok bool) { rc, ok = clients.runtimeClient(ip) - src, _ := rc.Info() - if src > client.SourceDHCP { - return rc, ok + if ok { + src, _ := rc.Info() + if src > client.SourceDHCP { + return rc, ok + } } host := clients.dhcp.HostByIP(ip) - if host == "" { - return rc, ok + if !ok && host == "" { + return nil, false } - return &client.Runtime{ - DHCP: host, - WHOIS: &whois.Info{}, - }, true + if !ok { + rc = &client.Runtime{ + WHOIS: &whois.Info{}, + } + } + + rc.SetInfo(client.SourceDHCP, []string{host}) + + return rc, true } // check validates the client. @@ -847,7 +854,7 @@ func (clients *clientsContainer) addHostLocked( clients.ipToRC[ip] = rc } - rc.SetInfo(src, host) + rc.SetInfo(src, []string{host}) log.Debug("clients: added %s -> %q [%d]", ip, host, len(clients.ipToRC)) @@ -858,7 +865,8 @@ func (clients *clientsContainer) addHostLocked( func (clients *clientsContainer) rmHostsBySrc(src client.Source) { n := 0 for ip, rc := range clients.ipToRC { - if rc.IsSet(src) { + rc.Clear(src) + if rc.IsEmpty() { delete(clients.ipToRC, ip) n++ }