Skip to content

Commit

Permalink
Merge branch 'AdguardTeam:master' into feature/filters-list-per-client
Browse files Browse the repository at this point in the history
  • Loading branch information
hoang-rio authored Jul 11, 2024
2 parents 2e535ee + 42c7cd6 commit a700d34
Show file tree
Hide file tree
Showing 28 changed files with 295 additions and 157 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
go 1.22.5

require (
github.com/AdguardTeam/dnsproxy v0.71.2
github.com/AdguardTeam/golibs v0.24.0
github.com/AdguardTeam/dnsproxy v0.72.0
github.com/AdguardTeam/golibs v0.24.1
github.com/AdguardTeam/urlfilter v0.19.0
github.com/NYTimes/gziphandler v1.1.1
github.com/ameshkov/dnscrypt/v2 v2.3.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/AdguardTeam/dnsproxy v0.71.2 h1:dFG2wga4GDdj1eI3rU2wqjQ6QGQm9MjLRb5ZzyH3Vgg=
github.com/AdguardTeam/dnsproxy v0.71.2/go.mod h1:huI5zyWhlimHBhg0jt2CMinXzsEHymI+WlvxIfmfEGA=
github.com/AdguardTeam/golibs v0.24.0 h1:qAnOq7BQtwSVo7Co9q703/n+nZ2Ap6smkugU9G9MomY=
github.com/AdguardTeam/golibs v0.24.0/go.mod h1:9/vJcYznW7RlmCT/Qzi8XNZGj+ZbWfHZJmEXKnRpCAU=
github.com/AdguardTeam/dnsproxy v0.72.0 h1:Psn7uCMVR/dCx8Te2Iy05bWWRNArSBF9j38VXNtt6+4=
github.com/AdguardTeam/dnsproxy v0.72.0/go.mod h1:5ehzbfInAu07not4beAM+FlFPqntw18T1sQCK/kIQR8=
github.com/AdguardTeam/golibs v0.24.1 h1:/ulkfm65wi33p72ybxiOt3lSdP0nr1GggSoaT4sHbns=
github.com/AdguardTeam/golibs v0.24.1/go.mod h1:9/vJcYznW7RlmCT/Qzi8XNZGj+ZbWfHZJmEXKnRpCAU=
github.com/AdguardTeam/urlfilter v0.19.0 h1:q7eH13+yNETlpD/VD3u5rLQOripcUdEktqZFy+KiQLk=
github.com/AdguardTeam/urlfilter v0.19.0/go.mod h1:+N54ZvxqXYLnXuvpaUhK2exDQW+djZBRSb6F6j0rkBY=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
Expand Down
2 changes: 1 addition & 1 deletion internal/aghos/syslog.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package aghos

// ConfigureSyslog reroutes standard logger output to syslog.
func ConfigureSyslog(serviceName string) error {
func ConfigureSyslog(serviceName string) (err error) {
return configureSyslog(serviceName)
}
6 changes: 5 additions & 1 deletion internal/aghos/syslog_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import (
"github.com/AdguardTeam/golibs/log"
)

func configureSyslog(serviceName string) error {
// configureSyslog sets standard log output to syslog.
func configureSyslog(serviceName string) (err error) {
w, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_USER, serviceName)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}

log.SetOutput(w)

return nil
}
21 changes: 14 additions & 7 deletions internal/aghos/syslog_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,30 @@ func (w *eventLogWriter) Write(b []byte) (int, error) {
return len(b), w.el.Info(1, string(b))
}

func configureSyslog(serviceName string) error {
// Note that the eventlog src is the same as the service name
// Otherwise, we will get "the description for event id cannot be found" warning in every log record
// configureSyslog sets standard log output to event log.
func configureSyslog(serviceName string) (err error) {
// Note that the eventlog src is the same as the service name, otherwise we
// will get "the description for event id cannot be found" warning in every
// log record.

// Continue if we receive "registry key already exists" or if we get
// ERROR_ACCESS_DENIED so that we can log without administrative permissions
// for pre-existing eventlog sources.
if err := eventlog.InstallAsEventCreate(serviceName, eventlog.Info|eventlog.Warning|eventlog.Error); err != nil {
if !strings.Contains(err.Error(), "registry key already exists") && err != windows.ERROR_ACCESS_DENIED {
return err
}
err = eventlog.InstallAsEventCreate(serviceName, eventlog.Info|eventlog.Warning|eventlog.Error)
if err != nil &&
!strings.Contains(err.Error(), "registry key already exists") &&
err != windows.ERROR_ACCESS_DENIED {
// Don't wrap the error, because it's informative enough as is.
return err
}

el, err := eventlog.Open(serviceName)
if err != nil {
// Don't wrap the error, because it's informative enough as is.
return err
}

log.SetOutput(&eventLogWriter{el: el})

return nil
}
3 changes: 3 additions & 0 deletions internal/dhcpsvc/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ func (srv *DHCPServer) dbLoad(ctx context.Context) (err error) {

return nil
}
defer func() {
err = errors.WithDeferred(err, file.Close())
}()

dl := &dataLeases{}
err = json.NewDecoder(file).Decode(dl)
Expand Down
2 changes: 1 addition & 1 deletion internal/dhcpsvc/dhcpsvc.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type Interface interface {
IPByHost(host string) (ip netip.Addr)

// Leases returns all the active DHCP leases. The returned slice should be
// a clone.
// a clone. The order of leases is undefined.
//
// TODO(e.burkov): Consider implementing iterating methods with appropriate
// signatures instead of cloning the whole list.
Expand Down
64 changes: 49 additions & 15 deletions internal/dhcpsvc/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,102 @@ package dhcpsvc
import (
"fmt"
"log/slog"
"slices"
"net"
"time"
)

// netInterface is a common part of any network interface within the DHCP
// server.
// macKey contains hardware address as byte array of 6, 8, or 20 bytes.
//
// TODO(e.burkov): Move to aghnet or even to netutil.
type macKey any

// macToKey converts mac into macKey, which is used as the key for the lease
// maps. mac must be a valid hardware address of length 6, 8, or 20 bytes, see
// [netutil.ValidateMAC].
func macToKey(mac net.HardwareAddr) (key macKey) {
switch len(mac) {
case 6:
return [6]byte(mac)
case 8:
return [8]byte(mac)
case 20:
return [20]byte(mac)
default:
panic(fmt.Errorf("invalid mac address %#v", mac))
}
}

// netInterface is a common part of any interface within the DHCP server.
//
// TODO(e.burkov): Add other methods as [DHCPServer] evolves.
type netInterface struct {
// logger logs the events related to the network interface.
logger *slog.Logger

// leases is the set of DHCP leases assigned to this interface.
leases map[macKey]*Lease

// name is the name of the network interface.
name string

// leases is a set of leases sorted by hardware address.
leases []*Lease

// leaseTTL is the default Time-To-Live value for leases.
leaseTTL time.Duration
}

// newNetInterface creates a new netInterface with the given name, leaseTTL, and
// logger.
func newNetInterface(name string, l *slog.Logger, leaseTTL time.Duration) (iface *netInterface) {
return &netInterface{
logger: l,
leases: map[macKey]*Lease{},
name: name,
leaseTTL: leaseTTL,
}
}

// reset clears all the slices in iface for reuse.
func (iface *netInterface) reset() {
iface.leases = iface.leases[:0]
clear(iface.leases)
}

// insertLease inserts the given lease into iface. It returns an error if the
// addLease inserts the given lease into iface. It returns an error if the
// lease can't be inserted.
func (iface *netInterface) insertLease(l *Lease) (err error) {
i, found := slices.BinarySearchFunc(iface.leases, l, compareLeaseMAC)
func (iface *netInterface) addLease(l *Lease) (err error) {
mk := macToKey(l.HWAddr)
_, found := iface.leases[mk]
if found {
return fmt.Errorf("lease for mac %s already exists", l.HWAddr)
}

iface.leases = slices.Insert(iface.leases, i, l)
iface.leases[mk] = l

return nil
}

// updateLease replaces an existing lease within iface with the given one. It
// returns an error if there is no lease with such hardware address.
func (iface *netInterface) updateLease(l *Lease) (prev *Lease, err error) {
i, found := slices.BinarySearchFunc(iface.leases, l, compareLeaseMAC)
mk := macToKey(l.HWAddr)
prev, found := iface.leases[mk]
if !found {
return nil, fmt.Errorf("no lease for mac %s", l.HWAddr)
}

prev, iface.leases[i] = iface.leases[i], l
iface.leases[mk] = l

return prev, nil
}

// removeLease removes an existing lease from iface. It returns an error if
// there is no lease equal to l.
func (iface *netInterface) removeLease(l *Lease) (err error) {
i, found := slices.BinarySearchFunc(iface.leases, l, compareLeaseMAC)
mk := macToKey(l.HWAddr)
_, found := iface.leases[mk]
if !found {
return fmt.Errorf("no lease for mac %s", l.HWAddr)
}

iface.leases = slices.Delete(iface.leases, i, i+1)
delete(iface.leases, mk)

return nil
}
6 changes: 0 additions & 6 deletions internal/dhcpsvc/lease.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dhcpsvc

import (
"bytes"
"net"
"net/netip"
"slices"
Expand Down Expand Up @@ -45,8 +44,3 @@ func (l *Lease) Clone() (clone *Lease) {
IsStatic: l.IsStatic,
}
}

// compareLeaseMAC compares two [Lease]s by hardware address.
func compareLeaseMAC(a, b *Lease) (res int) {
return bytes.Compare(a.HWAddr, b.HWAddr)
}
2 changes: 1 addition & 1 deletion internal/dhcpsvc/leaseindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (idx *leaseIndex) add(l *Lease, iface *netInterface) (err error) {
return fmt.Errorf("lease for hostname %s already exists", l.Hostname)
}

err = iface.insertLease(l)
err = iface.addLease(l)
if err != nil {
return err
}
Expand Down
85 changes: 49 additions & 36 deletions internal/dhcpsvc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ type DHCPServer struct {
leases *leaseIndex

// interfaces4 is the set of IPv4 interfaces sorted by interface name.
interfaces4 netInterfacesV4
interfaces4 dhcpInterfacesV4

// interfaces6 is the set of IPv6 interfaces sorted by interface name.
interfaces6 netInterfacesV6
interfaces6 dhcpInterfacesV6

// icmpTimeout is the timeout for checking another DHCP server's presence.
icmpTimeout time.Duration
Expand All @@ -63,28 +63,9 @@ func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
return nil, nil
}

// TODO(e.burkov): Add validations scoped to the network interfaces set.
ifaces4 := make(netInterfacesV4, 0, len(conf.Interfaces))
ifaces6 := make(netInterfacesV6, 0, len(conf.Interfaces))
var errs []error

mapsutil.SortedRange(conf.Interfaces, func(name string, iface *InterfaceConfig) (cont bool) {
var i4 *netInterfaceV4
i4, err = newNetInterfaceV4(ctx, l, name, iface.IPv4)
if err != nil {
errs = append(errs, fmt.Errorf("interface %q: ipv4: %w", name, err))
} else if i4 != nil {
ifaces4 = append(ifaces4, i4)
}

i6 := newNetInterfaceV6(ctx, l, name, iface.IPv6)
if i6 != nil {
ifaces6 = append(ifaces6, i6)
}

return true
})
if err = errors.Join(errs...); err != nil {
ifaces4, ifaces6, err := newInterfaces(ctx, l, conf.Interfaces)
if err != nil {
// Don't wrap the error since it's informative enough as is.
return nil, err
}

Expand Down Expand Up @@ -112,6 +93,43 @@ func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
return srv, nil
}

// newInterfaces creates interfaces for the given map of interface names to
// their configurations.
func newInterfaces(
ctx context.Context,
l *slog.Logger,
ifaces map[string]*InterfaceConfig,
) (v4 dhcpInterfacesV4, v6 dhcpInterfacesV6, err error) {
defer func() { err = errors.Annotate(err, "creating interfaces: %w") }()

// TODO(e.burkov): Add validations scoped to the network interfaces set.
v4 = make(dhcpInterfacesV4, 0, len(ifaces))
v6 = make(dhcpInterfacesV6, 0, len(ifaces))

var errs []error
mapsutil.SortedRange(ifaces, func(name string, iface *InterfaceConfig) (cont bool) {
var i4 *dhcpInterfaceV4
i4, err = newDHCPInterfaceV4(ctx, l, name, iface.IPv4)
if err != nil {
errs = append(errs, fmt.Errorf("interface %q: ipv4: %w", name, err))
} else if i4 != nil {
v4 = append(v4, i4)
}

i6 := newDHCPInterfaceV6(ctx, l, name, iface.IPv6)
if i6 != nil {
v6 = append(v6, i6)
}

return true
})
if err = errors.Join(errs...); err != nil {
return nil, nil, err
}

return v4, v6, nil
}

// type check
//
// TODO(e.burkov): Uncomment when the [Interface] interface is implemented.
Expand All @@ -127,16 +145,11 @@ func (srv *DHCPServer) Leases() (leases []*Lease) {
srv.leasesMu.RLock()
defer srv.leasesMu.RUnlock()

for _, iface := range srv.interfaces4 {
for _, lease := range iface.leases {
leases = append(leases, lease.Clone())
}
}
for _, iface := range srv.interfaces6 {
for _, lease := range iface.leases {
leases = append(leases, lease.Clone())
}
}
srv.leases.rangeLeases(func(l *Lease) (cont bool) {
leases = append(leases, l.Clone())

return true
})

return leases
}
Expand Down Expand Up @@ -200,10 +213,10 @@ func (srv *DHCPServer) Reset(ctx context.Context) (err error) {
// expects the DHCPServer.leasesMu to be locked.
func (srv *DHCPServer) resetLeases() {
for _, iface := range srv.interfaces4 {
iface.reset()
iface.common.reset()
}
for _, iface := range srv.interfaces6 {
iface.reset()
iface.common.reset()
}
srv.leases.clear()
}
Expand Down
Loading

0 comments on commit a700d34

Please sign in to comment.