Skip to content

Commit

Permalink
Pull request 2083: AG-27492-client-runtime
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit e4c2abd
Merge: 7411b40 dae304f
Author: Stanislav Chzhen <[email protected]>
Date:   Wed Dec 13 13:15:40 2023 +0300

    Merge branch 'master' into AG-27492-client-runtime

commit 7411b40
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Dec 12 17:51:51 2023 +0300

    all: imp code

commit d5edd02
Merge: 371f5b2 c908eec
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Dec 12 13:45:33 2023 +0300

    Merge branch 'master' into AG-27492-client-runtime

commit 371f5b2
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Dec 12 13:44:38 2023 +0300

    client: imp code

commit 9aefb14
Author: Stanislav Chzhen <[email protected]>
Date:   Fri Dec 8 17:08:07 2023 +0300

    all: imp code

commit 3aa51d1
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Dec 5 19:20:41 2023 +0300

    all: imp docs

commit 71d7187
Author: Stanislav Chzhen <[email protected]>
Date:   Fri Dec 1 17:17:06 2023 +0300

    all: imp code

commit e09f8a0
Author: Stanislav Chzhen <[email protected]>
Date:   Thu Nov 30 14:46:53 2023 +0300

    all: imp log msg

commit ce0a945
Author: Stanislav Chzhen <[email protected]>
Date:   Tue Nov 28 16:21:01 2023 +0300

    all: imp code

commit e84f176
Author: Stanislav Chzhen <[email protected]>
Date:   Wed Nov 22 17:40:18 2023 +0300

    all: add client runtime
  • Loading branch information
schzhn committed Dec 13, 2023
1 parent dae304f commit 9241393
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 76 deletions.
109 changes: 107 additions & 2 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package client
import (
"encoding"
"fmt"

"github.com/AdguardTeam/AdGuardHome/internal/whois"
)

// Source represents the source from which the information about the client has
Expand All @@ -15,8 +17,7 @@ type Source uint8

// Clients information sources. The order determines the priority.
const (
SourceNone Source = iota
SourceWHOIS
SourceWHOIS Source = iota + 1
SourceARP
SourceRDNS
SourceDHCP
Expand Down Expand Up @@ -52,3 +53,107 @@ var _ encoding.TextMarshaler = Source(0)
func (cs Source) MarshalText() (text []byte, err error) {
return []byte(cs.String()), nil
}

// Runtime is a client information from different sources.
type Runtime struct {
// whois is the filtered WHOIS information of a client.
whois *whois.Info

// arp is the ARP information of a client. nil indicates that there is no
// information from the source. Empty non-nil slice indicates that the data
// from the source is present, but empty.
arp []string

// rdns is the RDNS information of a client. nil indicates that there is no
// information from the source. Empty non-nil slice indicates that the data
// from the source is present, but empty.
rdns []string

// dhcp is the DHCP information of a client. nil indicates that there is no
// information from the source. Empty non-nil slice indicates that the data
// from the source is present, but empty.
dhcp []string

// hostsFile is the information from the hosts file. nil indicates that
// there is no information from the source. Empty non-nil slice indicates
// that the data from the source is present, but empty.
hostsFile []string
}

// Info returns a client information from the highest-priority source.
func (r *Runtime) Info() (cs Source, host string) {
info := []string{}

switch {
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
case r.whois != nil:
cs = SourceWHOIS
}

if len(info) == 0 {
return cs, ""
}

// TODO(s.chzhen): Return the full information.
return cs, info[0]
}

// SetInfo sets a host as a client information from the cs.
func (r *Runtime) SetInfo(cs Source, hosts []string) {
if len(hosts) == 1 && hosts[0] == "" {
hosts = []string{}
}

switch cs {
case SourceARP:
r.arp = hosts
case SourceRDNS:
r.rdns = hosts
case SourceDHCP:
r.dhcp = hosts
case SourceHostsFile:
r.hostsFile = hosts
}
}

// WHOIS returns a WHOIS client information.
func (r *Runtime) WHOIS() (info *whois.Info) {
return r.whois
}

// SetWHOIS sets a WHOIS client information. info must be non-nil.
func (r *Runtime) SetWHOIS(info *whois.Info) {
r.whois = info
}

// Unset clears a cs information.
func (r *Runtime) Unset(cs Source) {
switch cs {
case SourceWHOIS:
r.whois = nil
case SourceARP:
r.arp = nil
case SourceRDNS:
r.rdns = nil
case SourceDHCP:
r.dhcp = nil
case SourceHostsFile:
r.hostsFile = nil
}
}

// IsEmpty returns true if there is no information from any source.
func (r *Runtime) IsEmpty() (ok bool) {
return r.whois == nil &&
r.arp == nil &&
r.rdns == nil &&
r.dhcp == nil &&
r.hostsFile == nil
}
16 changes: 0 additions & 16 deletions internal/home/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import (
"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"
"github.com/AdguardTeam/dnsproxy/proxy"
"github.com/AdguardTeam/golibs/stringutil"
)
Expand Down Expand Up @@ -85,17 +83,3 @@ func (c *Client) setSafeSearch(

return nil
}

// RuntimeClient is a client information about which has been obtained using the
// source described in the Source field.
type RuntimeClient struct {
// WHOIS is the filtered WHOIS data of a client.
WHOIS *whois.Info

// Host is the host name of a client.
Host string

// Source is the source from which the information about the client has
// been obtained.
Source client.Source
}
77 changes: 36 additions & 41 deletions internal/home/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ type clientsContainer struct {
list map[string]*Client // name -> client
idIndex map[string]*Client // ID -> client

// ipToRC is the IP address to *RuntimeClient map.
ipToRC map[netip.Addr]*RuntimeClient
// ipToRC maps IP addresses to runtime client information.
ipToRC map[netip.Addr]*client.Runtime

allTags *stringutil.Set

Expand Down Expand Up @@ -103,9 +103,9 @@ func (clients *clientsContainer) Init(
log.Fatal("clients.list != nil")
}

clients.list = make(map[string]*Client)
clients.idIndex = make(map[string]*Client)
clients.ipToRC = map[netip.Addr]*RuntimeClient{}
clients.list = map[string]*Client{}
clients.idIndex = map[string]*Client{}
clients.ipToRC = map[netip.Addr]*client.Runtime{}

clients.allTags = stringutil.NewSet(clientTags...)

Expand Down Expand Up @@ -342,7 +342,7 @@ func (clients *clientsContainer) clientSource(ip netip.Addr) (src client.Source)

rc, ok := clients.ipToRC[ip]
if ok {
src = rc.Source
src, _ = rc.Info()
}

if src < client.SourceDHCP && clients.dhcp.HostByIP(ip) != "" {
Expand Down Expand Up @@ -389,20 +389,22 @@ func (clients *clientsContainer) clientOrArtificial(
}
}()

client, ok := clients.Find(id)
cli, ok := clients.Find(id)
if ok {
return &querylog.Client{
Name: client.Name,
IgnoreQueryLog: client.IgnoreQueryLog,
Name: cli.Name,
IgnoreQueryLog: cli.IgnoreQueryLog,
}, false
}

var rc *RuntimeClient
var rc *client.Runtime
rc, ok = clients.findRuntimeClient(ip)
if ok {
_, host := rc.Info()

return &querylog.Client{
Name: rc.Host,
WHOIS: rc.WHOIS,
Name: host,
WHOIS: rc.WHOIS(),
}, false
}

Expand Down Expand Up @@ -549,7 +551,7 @@ func (clients *clientsContainer) findDHCP(ip netip.Addr) (c *Client, ok bool) {

// runtimeClient returns a runtime client from internal index. Note that it
// doesn't include DHCP clients.
func (clients *clientsContainer) runtimeClient(ip netip.Addr) (rc *RuntimeClient, ok bool) {
func (clients *clientsContainer) runtimeClient(ip netip.Addr) (rc *client.Runtime, ok bool) {
if ip == (netip.Addr{}) {
return nil, false
}
Expand All @@ -563,21 +565,21 @@ 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 > client.SourceDHCP {
return rc, ok
}

func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *client.Runtime, ok bool) {
rc, ok = clients.runtimeClient(ip)
host := clients.dhcp.HostByIP(ip)
if host == "" {
return rc, ok

if host != "" {
if !ok {
rc = &client.Runtime{}
}

rc.SetInfo(client.SourceDHCP, []string{host})

return rc, true
}

return &RuntimeClient{
Host: host,
Source: client.SourceDHCP,
WHOIS: &whois.Info{},
}, true
return rc, ok
}

// check validates the client.
Expand Down Expand Up @@ -768,23 +770,20 @@ func (clients *clientsContainer) setWHOISInfo(ip netip.Addr, wi *whois.Info) {
return
}

// TODO(e.burkov): Consider storing WHOIS information separately and
// potentially get rid of [RuntimeClient].
rc, ok := clients.ipToRC[ip]
if !ok {
// Create a RuntimeClient implicitly so that we don't do this check
// again.
rc = &RuntimeClient{
Source: client.SourceWHOIS,
}
rc = &client.Runtime{}
clients.ipToRC[ip] = rc

log.Debug("clients: set whois info for runtime client with ip %s: %+v", ip, wi)
} else {
log.Debug("clients: set whois info for runtime client %s: %+v", rc.Host, wi)
host, _ := rc.Info()
log.Debug("clients: set whois info for runtime client %s: %+v", host, wi)
}

rc.WHOIS = wi
rc.SetWHOIS(wi)
}

// addHost adds a new IP-hostname pairing. The priorities of the sources are
Expand Down Expand Up @@ -843,18 +842,13 @@ func (clients *clientsContainer) addHostLocked(
}
}

rc = &RuntimeClient{
WHOIS: &whois.Info{},
}
rc = &client.Runtime{}
clients.ipToRC[ip] = rc
} else if src < rc.Source {
return false
}

rc.Host = host
rc.Source = src
rc.SetInfo(src, []string{host})

log.Debug("clients: added %s -> %q [%d]", ip, host, len(clients.ipToRC))
log.Debug("clients: adding client info %s -> %q %q [%d]", ip, src, host, len(clients.ipToRC))

return true
}
Expand All @@ -863,7 +857,8 @@ func (clients *clientsContainer) addHostLocked(
func (clients *clientsContainer) rmHostsBySrc(src client.Source) {
n := 0
for ip, rc := range clients.ipToRC {
if rc.Source == src {
rc.Unset(src)
if rc.IsEmpty() {
delete(clients.ipToRC, ip)
n++
}
Expand Down
Loading

0 comments on commit 9241393

Please sign in to comment.