Pull request 1978: 4923 gopacket dhcp vol.2

Merge in DNS/adguard-home from 4923-gopacket-dhcp-vol.2 to master

Updates #4923.

Squashed commit of the following:

commit d0ef7d44af9790ed55401f6f65c7149f4c3658f7
Merge: f92b4c72d a4fdc3e8e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Aug 30 13:43:41 2023 +0300

    Merge branch 'master' into 4923-gopacket-dhcp-vol.2

commit f92b4c72de03ceacb9b8890b7cf4307688795ce5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Aug 28 12:33:29 2023 +0300

    dhcpd: imp code

commit 63f0fce99a0343af2670943770cfef4694ae93ed
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Aug 24 15:01:34 2023 +0300

    all: imp dhcpd code

commit 563b43b4b5ab6c9c9046c7f09008ea3ef344f4e9
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 28 17:03:55 2023 +0300

    dhcpd: imp indexing

commit 340d3efa90ac4d34ba3d18702692de0fbc0247be
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Jul 28 16:22:43 2023 +0300

    all: adapt current code
This commit is contained in:
Eugene Burkov
2023-08-30 14:02:12 +03:00
parent a4fdc3e8ed
commit a325c9b6bb
18 changed files with 502 additions and 394 deletions

View File

@@ -12,7 +12,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
@@ -35,7 +34,7 @@ type DHCP interface {
// HostByIP returns the hostname of the DHCP client with the given IP
// address. The address will be netip.Addr{} if there is no such client,
// due to an assumption that a DHCP client must always have an IP address.
// due to an assumption that a DHCP client must always have a hostname.
HostByIP(ip netip.Addr) (host string)
// MACByIP returns the MAC address for the given IP address leased. It
@@ -56,8 +55,8 @@ type clientsContainer struct {
allTags *stringutil.Set
// dhcpServer is used for looking up clients IP addresses by MAC addresses
dhcpServer dhcpd.Interface
// dhcp is the DHCP service implementation.
dhcp DHCP
// dnsServer is used for checking clients IP status access list status
dnsServer *dnsforward.Server
@@ -94,7 +93,7 @@ type clientsContainer struct {
// Note: this function must be called only once
func (clients *clientsContainer) Init(
objects []*clientObject,
dhcpServer dhcpd.Interface,
dhcpServer DHCP,
etcHosts *aghnet.HostsContainer,
arpDB arpdb.Interface,
filteringConf *filtering.Config,
@@ -109,7 +108,9 @@ func (clients *clientsContainer) Init(
clients.allTags = stringutil.NewSet(clientTags...)
clients.dhcpServer = dhcpServer
// TODO(e.burkov): Use [dhcpsvc] implementation when it's ready.
clients.dhcp = dhcpServer
clients.etcHosts = etcHosts
clients.arpDB = arpDB
err = clients.addFromConfig(objects, filteringConf)
@@ -125,11 +126,6 @@ func (clients *clientsContainer) Init(
return nil
}
if clients.dhcpServer != nil {
clients.dhcpServer.SetOnLeaseChanged(clients.onDHCPLeaseChanged)
clients.onDHCPLeaseChanged(dhcpd.LeaseChangedAdded)
}
if clients.etcHosts != nil {
go clients.handleHostsUpdates()
}
@@ -310,40 +306,6 @@ func (clients *clientsContainer) periodicUpdate() {
}
}
// onDHCPLeaseChanged is a callback for the DHCP server. It updates the list of
// runtime clients using the DHCP server's leases.
//
// TODO(e.burkov): Remove when switched to dhcpsvc.
func (clients *clientsContainer) onDHCPLeaseChanged(flags int) {
if clients.dhcpServer == nil || !config.Clients.Sources.DHCP {
return
}
clients.lock.Lock()
defer clients.lock.Unlock()
clients.rmHostsBySrc(ClientSourceDHCP)
if flags == dhcpd.LeaseChangedRemovedAll {
return
}
leases := clients.dhcpServer.Leases(dhcpd.LeasesAll)
n := 0
for _, l := range leases {
if l.Hostname == "" {
continue
}
ok := clients.addHostLocked(l.IP, l.Hostname, ClientSourceDHCP)
if ok {
n++
}
}
log.Debug("clients: added %d client aliases from dhcp", n)
}
// clientSource checks if client with this IP address already exists and returns
// the source which updated it last. It returns [ClientSourceNone] if the
// client doesn't exist.
@@ -358,10 +320,14 @@ func (clients *clientsContainer) clientSource(ip netip.Addr) (src clientSource)
rc, ok := clients.ipToRC[ip]
if ok {
return rc.Source
src = rc.Source
}
return ClientSourceNone
if src < ClientSourceDHCP && clients.dhcp.HostByIP(ip) != "" {
src = ClientSourceDHCP
}
return src
}
// findMultiple is a wrapper around Find to make it a valid client finder for
@@ -522,17 +488,14 @@ func (clients *clientsContainer) findLocked(id string) (c *Client, ok bool) {
}
}
if clients.dhcpServer != nil {
return clients.findDHCP(ip)
}
return nil, false
// TODO(e.burkov): Iterate through clients.list only once.
return clients.findDHCP(ip)
}
// findDHCP searches for a client by its MAC, if the DHCP server is active and
// there is such client. clients.lock is expected to be locked.
func (clients *clientsContainer) findDHCP(ip netip.Addr) (c *Client, ok bool) {
foundMAC := clients.dhcpServer.FindMACbyIP(ip)
foundMAC := clients.dhcp.MACByIP(ip)
if foundMAC == nil {
return nil, false
}
@@ -553,8 +516,9 @@ func (clients *clientsContainer) findDHCP(ip netip.Addr) (c *Client, ok bool) {
return nil, false
}
// findRuntimeClient finds a runtime client by their IP.
func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *RuntimeClient, 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) {
if ip == (netip.Addr{}) {
return nil, false
}
@@ -567,6 +531,24 @@ func (clients *clientsContainer) findRuntimeClient(ip netip.Addr) (rc *RuntimeCl
return rc, ok
}
// 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 {
return rc, ok
}
host := clients.dhcp.HostByIP(ip)
if host == "" {
return rc, ok
}
return &RuntimeClient{
Host: host,
Source: ClientSourceDHCP,
WHOIS: &whois.Info{},
}, true
}
// check validates the client.
func (clients *clientsContainer) check(c *Client) (err error) {
switch {
@@ -824,10 +806,15 @@ func (clients *clientsContainer) addHostLocked(
) (ok bool) {
rc, ok := clients.ipToRC[ip]
if !ok {
if src < ClientSourceDHCP {
if clients.dhcp.HostByIP(ip) != "" {
return false
}
}
rc = &RuntimeClient{
WHOIS: &whois.Info{},
}
clients.ipToRC[ip] = rc
} else if src < rc.Source {
return false

View File

@@ -8,21 +8,44 @@ import (
"time"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testDHCP struct {
OnLeases func() (leases []*dhcpsvc.Lease)
OnHostBy func(ip netip.Addr) (host string)
OnMACBy func(ip netip.Addr) (mac net.HardwareAddr)
}
// Lease implements the [DHCP] interface for testDHCP.
func (t *testDHCP) Leases() (leases []*dhcpsvc.Lease) { return t.OnLeases() }
// HostByIP implements the [DHCP] interface for testDHCP.
func (t *testDHCP) HostByIP(ip netip.Addr) (host string) { return t.OnHostBy(ip) }
// MACByIP implements the [DHCP] interface for testDHCP.
func (t *testDHCP) MACByIP(ip netip.Addr) (mac net.HardwareAddr) { return t.OnMACBy(ip) }
// newClientsContainer is a helper that creates a new clients container for
// tests.
func newClientsContainer(t *testing.T) (c *clientsContainer) {
t.Helper()
c = &clientsContainer{
testing: true,
}
err := c.Init(nil, nil, nil, nil, &filtering.Config{})
require.NoError(t, err)
dhcp := &testDHCP{
OnLeases: func() (leases []*dhcpsvc.Lease) { panic("not implemented") },
OnHostBy: func(ip netip.Addr) (host string) { return "" },
OnMACBy: func(ip netip.Addr) (mac net.HardwareAddr) { return nil },
}
require.NoError(t, c.Init(nil, dhcp, nil, nil, &filtering.Config{}))
return c
}
@@ -288,7 +311,7 @@ func TestClientsAddExisting(t *testing.T) {
dhcpServer, err := dhcpd.Create(config)
require.NoError(t, err)
clients.dhcpServer = dhcpServer
clients.dhcp = dhcpServer
err = dhcpServer.AddStaticLease(&dhcpd.Lease{
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},

View File

@@ -123,6 +123,17 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http
data.RuntimeClients = append(data.RuntimeClients, cj)
}
for _, l := range clients.dhcp.Leases() {
cj := runtimeClientJSON{
Name: l.Hostname,
Source: ClientSourceDHCP,
IP: l.IP,
WHOIS: &whois.Info{},
}
data.RuntimeClients = append(data.RuntimeClients, cj)
}
data.Tags = clientTags
aghhttp.WriteJSONResponseOK(w, r, data)

View File

@@ -14,7 +14,6 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/client"
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
@@ -123,7 +122,7 @@ func initDNSServer(
filters *filtering.DNSFilter,
sts stats.Interface,
qlog querylog.QueryLog,
dhcpSrv dhcpd.Interface,
dhcpSrv dnsforward.DHCP,
anonymizer *aghnet.IPMut,
httpReg aghhttp.RegisterFunc,
tlsConf *tlsConfigSettings,

View File

@@ -7,6 +7,6 @@ import (
)
func TestMain(m *testing.M) {
testutil.DiscardLogOutput(m)
initCmdLineOpts()
testutil.DiscardLogOutput(m)
}