diff --git a/internal/arpdb/arpdb.go b/internal/arpdb/arpdb.go index ebb11011..66b1ae1e 100644 --- a/internal/arpdb/arpdb.go +++ b/internal/arpdb/arpdb.go @@ -77,8 +77,8 @@ func (n Neighbor) Clone() (clone Neighbor) { } } -// validatedHostname returns valid hostname. Otherwise returns empty string and -// logs the error if hostname is not valid. +// validatedHostname returns h if it's a valid hostname, or an empty string +// otherwise, logging the validation error. func validatedHostname(h string) (host string) { err := netutil.ValidateHostname(h) if err != nil { diff --git a/internal/client/client.go b/internal/client/client.go index 6cfcec79..6b81b9b8 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -3,3 +3,52 @@ // // TODO(a.garipov): Expand. package client + +import ( + "encoding" + "fmt" +) + +// Source represents the source from which the information about the client has +// been obtained. +type Source uint8 + +// Clients information sources. The order determines the priority. +const ( + SourceNone Source = iota + SourceWHOIS + SourceARP + SourceRDNS + SourceDHCP + SourceHostsFile + SourcePersistent +) + +// type check +var _ fmt.Stringer = Source(0) + +// String returns a human-readable name of cs. +func (cs Source) String() (s string) { + switch cs { + case SourceWHOIS: + return "WHOIS" + case SourceARP: + return "ARP" + case SourceRDNS: + return "rDNS" + case SourceDHCP: + return "DHCP" + case SourceHostsFile: + return "etc/hosts" + default: + return "" + } +} + +// type check +var _ encoding.TextMarshaler = Source(0) + +// MarshalText implements encoding.TextMarshaler for the Source. +func (cs Source) MarshalText() (text []byte, err error) { + return []byte(cs.String()), nil +} diff --git a/internal/home/client.go b/internal/home/client.go index c0d39dad..751bde6d 100644 --- a/internal/home/client.go +++ b/internal/home/client.go @@ -1,10 +1,10 @@ package home import ( - "encoding" "fmt" "time" + "github.com/AdguardTeam/AdGuardHome/internal/client" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/filtering/safesearch" "github.com/AdguardTeam/AdGuardHome/internal/whois" @@ -83,50 +83,6 @@ func (c *Client) setSafeSearch( return nil } -// clientSource represents the source from which the information about the -// client has been obtained. -type clientSource uint - -// Clients information sources. The order determines the priority. -const ( - ClientSourceNone clientSource = iota - ClientSourceWHOIS - ClientSourceARP - ClientSourceRDNS - ClientSourceDHCP - ClientSourceHostsFile - ClientSourcePersistent -) - -// type check -var _ fmt.Stringer = clientSource(0) - -// String returns a human-readable name of cs. -func (cs clientSource) String() (s string) { - switch cs { - case ClientSourceWHOIS: - return "WHOIS" - case ClientSourceARP: - return "ARP" - case ClientSourceRDNS: - return "rDNS" - case ClientSourceDHCP: - return "DHCP" - case ClientSourceHostsFile: - return "etc/hosts" - default: - return "" - } -} - -// type check -var _ encoding.TextMarshaler = clientSource(0) - -// MarshalText implements encoding.TextMarshaler for the clientSource. -func (cs clientSource) MarshalText() (text []byte, err error) { - return []byte(cs.String()), nil -} - // RuntimeClient is a client information about which has been obtained using the // source described in the Source field. type RuntimeClient struct { @@ -138,5 +94,5 @@ type RuntimeClient struct { // Source is the source from which the information about the client has // been obtained. - Source clientSource + Source client.Source } diff --git a/internal/home/clients.go b/internal/home/clients.go index 6a0ab9fd..68e0b7d1 100644 --- a/internal/home/clients.go +++ b/internal/home/clients.go @@ -307,15 +307,15 @@ func (clients *clientsContainer) periodicUpdate() { } // clientSource checks if client with this IP address already exists and returns -// the source which updated it last. It returns [ClientSourceNone] if the +// the source which updated it last. It returns [client.SourceNone] if the // client doesn't exist. -func (clients *clientsContainer) clientSource(ip netip.Addr) (src clientSource) { +func (clients *clientsContainer) clientSource(ip netip.Addr) (src client.Source) { clients.lock.Lock() defer clients.lock.Unlock() _, ok := clients.findLocked(ip.String()) if ok { - return ClientSourcePersistent + return client.SourcePersistent } rc, ok := clients.ipToRC[ip] @@ -323,8 +323,8 @@ func (clients *clientsContainer) clientSource(ip netip.Addr) (src clientSource) src = rc.Source } - if src < ClientSourceDHCP && clients.dhcp.HostByIP(ip) != "" { - src = ClientSourceDHCP + if src < client.SourceDHCP && clients.dhcp.HostByIP(ip) != "" { + src = client.SourceDHCP } return src @@ -533,7 +533,7 @@ func (clients *clientsContainer) runtimeClient(ip netip.Addr) (rc *RuntimeClient // findRuntimeClient finds a runtime client by their IP. func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *RuntimeClient, ok bool) { - if rc, ok = clients.runtimeClient(ip); ok && rc.Source > ClientSourceDHCP { + if rc, ok = clients.runtimeClient(ip); ok && rc.Source > client.SourceDHCP { return rc, ok } @@ -544,7 +544,7 @@ func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *RuntimeCl return &RuntimeClient{ Host: host, - Source: ClientSourceDHCP, + Source: client.SourceDHCP, WHOIS: &whois.Info{}, }, true } @@ -744,7 +744,7 @@ func (clients *clientsContainer) setWHOISInfo(ip netip.Addr, wi *whois.Info) { // Create a RuntimeClient implicitly so that we don't do this check // again. rc = &RuntimeClient{ - Source: ClientSourceWHOIS, + Source: client.SourceWHOIS, } clients.ipToRC[ip] = rc @@ -763,7 +763,7 @@ func (clients *clientsContainer) setWHOISInfo(ip netip.Addr, wi *whois.Info) { func (clients *clientsContainer) addHost( ip netip.Addr, host string, - src clientSource, + src client.Source, ) (ok bool) { clients.lock.Lock() defer clients.lock.Unlock() @@ -786,7 +786,7 @@ func (clients *clientsContainer) UpdateAddress(ip netip.Addr, host string, info defer clients.lock.Unlock() if host != "" { - ok := clients.addHostLocked(ip, host, ClientSourceRDNS) + ok := clients.addHostLocked(ip, host, client.SourceRDNS) if !ok { log.Debug("clients: host for client %q already set with higher priority source", ip) } @@ -802,11 +802,11 @@ func (clients *clientsContainer) UpdateAddress(ip netip.Addr, host string, info func (clients *clientsContainer) addHostLocked( ip netip.Addr, host string, - src clientSource, + src client.Source, ) (ok bool) { rc, ok := clients.ipToRC[ip] if !ok { - if src < ClientSourceDHCP { + if src < client.SourceDHCP { if clients.dhcp.HostByIP(ip) != "" { return false } @@ -829,7 +829,7 @@ func (clients *clientsContainer) addHostLocked( } // rmHostsBySrc removes all entries that match the specified source. -func (clients *clientsContainer) rmHostsBySrc(src clientSource) { +func (clients *clientsContainer) rmHostsBySrc(src client.Source) { n := 0 for ip, rc := range clients.ipToRC { if rc.Source == src { @@ -847,7 +847,7 @@ func (clients *clientsContainer) addFromHostsFile(hosts aghnet.Hosts) { clients.lock.Lock() defer clients.lock.Unlock() - clients.rmHostsBySrc(ClientSourceHostsFile) + clients.rmHostsBySrc(client.SourceHostsFile) n := 0 for addr, rec := range hosts { @@ -855,7 +855,7 @@ func (clients *clientsContainer) addFromHostsFile(hosts aghnet.Hosts) { // hostname for the IP address. // // TODO(e.burkov): Consider using all the names from all the records. - clients.addHostLocked(addr, rec[0].Names[0], ClientSourceHostsFile) + clients.addHostLocked(addr, rec[0].Names[0], client.SourceHostsFile) n++ } @@ -883,11 +883,11 @@ func (clients *clientsContainer) addFromSystemARP() { clients.lock.Lock() defer clients.lock.Unlock() - clients.rmHostsBySrc(ClientSourceARP) + clients.rmHostsBySrc(client.SourceARP) added := 0 for _, n := range ns { - if clients.addHostLocked(n.IP, n.Name, ClientSourceARP) { + if clients.addHostLocked(n.IP, n.Name, client.SourceARP) { added++ } } diff --git a/internal/home/clients_internal_test.go b/internal/home/clients_internal_test.go index 5c92a896..b8ef598f 100644 --- a/internal/home/clients_internal_test.go +++ b/internal/home/clients_internal_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/AdguardTeam/AdGuardHome/internal/client" "github.com/AdguardTeam/AdGuardHome/internal/dhcpd" "github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc" "github.com/AdguardTeam/AdGuardHome/internal/filtering" @@ -99,9 +100,9 @@ func TestClients(t *testing.T) { assert.Equal(t, "client2", c.Name) - assert.Equal(t, clients.clientSource(cliNoneIP), ClientSourceNone) - assert.Equal(t, clients.clientSource(cli1IP), ClientSourcePersistent) - assert.Equal(t, clients.clientSource(cli2IP), ClientSourcePersistent) + assert.Equal(t, clients.clientSource(cliNoneIP), client.SourceNone) + assert.Equal(t, clients.clientSource(cli1IP), client.SourcePersistent) + assert.Equal(t, clients.clientSource(cli2IP), client.SourcePersistent) }) t.Run("add_fail_name", func(t *testing.T) { @@ -148,8 +149,8 @@ func TestClients(t *testing.T) { }) require.NoError(t, err) - assert.Equal(t, clients.clientSource(cliOldIP), ClientSourceNone) - assert.Equal(t, clients.clientSource(cliNewIP), ClientSourcePersistent) + assert.Equal(t, clients.clientSource(cliOldIP), client.SourceNone) + assert.Equal(t, clients.clientSource(cliNewIP), client.SourcePersistent) prev, ok = clients.list["client1"] require.True(t, ok) @@ -181,7 +182,7 @@ func TestClients(t *testing.T) { ok := clients.Del("client1-renamed") require.True(t, ok) - assert.Equal(t, clients.clientSource(netip.MustParseAddr("1.1.1.2")), ClientSourceNone) + assert.Equal(t, clients.clientSource(netip.MustParseAddr("1.1.1.2")), client.SourceNone) }) t.Run("del_fail", func(t *testing.T) { @@ -191,32 +192,32 @@ func TestClients(t *testing.T) { t.Run("addhost_success", func(t *testing.T) { ip := netip.MustParseAddr("1.1.1.1") - ok := clients.addHost(ip, "host", ClientSourceARP) + ok := clients.addHost(ip, "host", client.SourceARP) assert.True(t, ok) - ok = clients.addHost(ip, "host2", ClientSourceARP) + ok = clients.addHost(ip, "host2", client.SourceARP) assert.True(t, ok) - ok = clients.addHost(ip, "host3", ClientSourceHostsFile) + ok = clients.addHost(ip, "host3", client.SourceHostsFile) assert.True(t, ok) - assert.Equal(t, clients.clientSource(ip), ClientSourceHostsFile) + assert.Equal(t, clients.clientSource(ip), client.SourceHostsFile) }) t.Run("dhcp_replaces_arp", func(t *testing.T) { ip := netip.MustParseAddr("1.2.3.4") - ok := clients.addHost(ip, "from_arp", ClientSourceARP) + ok := clients.addHost(ip, "from_arp", client.SourceARP) assert.True(t, ok) - assert.Equal(t, clients.clientSource(ip), ClientSourceARP) + assert.Equal(t, clients.clientSource(ip), client.SourceARP) - ok = clients.addHost(ip, "from_dhcp", ClientSourceDHCP) + ok = clients.addHost(ip, "from_dhcp", client.SourceDHCP) assert.True(t, ok) - assert.Equal(t, clients.clientSource(ip), ClientSourceDHCP) + assert.Equal(t, clients.clientSource(ip), client.SourceDHCP) }) t.Run("addhost_fail", func(t *testing.T) { ip := netip.MustParseAddr("1.1.1.1") - ok := clients.addHost(ip, "host1", ClientSourceRDNS) + ok := clients.addHost(ip, "host1", client.SourceRDNS) assert.False(t, ok) }) } @@ -239,7 +240,7 @@ func TestClientsWHOIS(t *testing.T) { t.Run("existing_auto-client", func(t *testing.T) { ip := netip.MustParseAddr("1.1.1.1") - ok := clients.addHost(ip, "host", ClientSourceRDNS) + ok := clients.addHost(ip, "host", client.SourceRDNS) assert.True(t, ok) clients.setWHOISInfo(ip, whois) @@ -282,7 +283,7 @@ func TestClientsAddExisting(t *testing.T) { assert.True(t, ok) // Now add an auto-client with the same IP. - ok = clients.addHost(ip, "test", ClientSourceRDNS) + ok = clients.addHost(ip, "test", client.SourceRDNS) assert.True(t, ok) }) diff --git a/internal/home/clientshttp.go b/internal/home/clientshttp.go index 6b49881c..62a46e78 100644 --- a/internal/home/clientshttp.go +++ b/internal/home/clientshttp.go @@ -8,6 +8,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/aghalg" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp" + "github.com/AdguardTeam/AdGuardHome/internal/client" "github.com/AdguardTeam/AdGuardHome/internal/filtering" "github.com/AdguardTeam/AdGuardHome/internal/schedule" "github.com/AdguardTeam/AdGuardHome/internal/whois" @@ -88,9 +89,9 @@ func (j *clientJSON) copySettings( type runtimeClientJSON struct { WHOIS *whois.Info `json:"whois_info"` - IP netip.Addr `json:"ip"` - Name string `json:"name"` - Source clientSource `json:"source"` + IP netip.Addr `json:"ip"` + Name string `json:"name"` + Source client.Source `json:"source"` } type clientListJSON struct { @@ -126,7 +127,7 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http for _, l := range clients.dhcp.Leases() { cj := runtimeClientJSON{ Name: l.Hostname, - Source: ClientSourceDHCP, + Source: client.SourceDHCP, IP: l.IP, WHOIS: &whois.Info{}, }