mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-21 20:45:33 +03:00
dhcpsvc: use logger
This commit is contained in:
parent
4779f945ba
commit
f05b9f42e2
4 changed files with 106 additions and 73 deletions
|
@ -6,14 +6,12 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"slices"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
"github.com/AdguardTeam/golibs/mapsutil"
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
|
// DHCPServer is a DHCP server for both IPv4 and IPv6 address families.
|
||||||
|
@ -23,8 +21,6 @@ type DHCPServer struct {
|
||||||
enabled *atomic.Bool
|
enabled *atomic.Bool
|
||||||
|
|
||||||
// logger logs common DHCP events.
|
// logger logs common DHCP events.
|
||||||
//
|
|
||||||
// TODO(e.burkov): Use.
|
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
|
|
||||||
// localTLD is the top-level domain name to use for resolving DHCP clients'
|
// localTLD is the top-level domain name to use for resolving DHCP clients'
|
||||||
|
@ -52,8 +48,7 @@ type DHCPServer struct {
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Use.
|
// TODO(e.burkov): Use.
|
||||||
func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
||||||
l := conf.Logger.With(slogutil.KeyPrefix, "dhcpsvc")
|
l := conf.Logger
|
||||||
|
|
||||||
if !conf.Enabled {
|
if !conf.Enabled {
|
||||||
l.DebugContext(ctx, "disabled")
|
l.DebugContext(ctx, "disabled")
|
||||||
|
|
||||||
|
@ -64,31 +59,24 @@ func New(ctx context.Context, conf *Config) (srv *DHCPServer, err error) {
|
||||||
// TODO(e.burkov): Add validations scoped to the network interfaces set.
|
// TODO(e.burkov): Add validations scoped to the network interfaces set.
|
||||||
ifaces4 := make(netInterfacesV4, 0, len(conf.Interfaces))
|
ifaces4 := make(netInterfacesV4, 0, len(conf.Interfaces))
|
||||||
ifaces6 := make(netInterfacesV6, 0, len(conf.Interfaces))
|
ifaces6 := make(netInterfacesV6, 0, len(conf.Interfaces))
|
||||||
|
|
||||||
ifaceNames := maps.Keys(conf.Interfaces)
|
|
||||||
slices.Sort(ifaceNames)
|
|
||||||
|
|
||||||
var i4 *netInterfaceV4
|
|
||||||
var i6 *netInterfaceV6
|
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
for _, ifaceName := range ifaceNames {
|
mapsutil.SortedRange(conf.Interfaces, func(name string, iface *InterfaceConfig) (cont bool) {
|
||||||
iface := conf.Interfaces[ifaceName]
|
var i4 *netInterfaceV4
|
||||||
|
i4, err = newNetInterfaceV4(ctx, l, name, iface.IPv4)
|
||||||
i4, err = newNetInterfaceV4(ctx, l, ifaceName, iface.IPv4)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, fmt.Errorf("interface %q: ipv4: %w", ifaceName, err))
|
errs = append(errs, fmt.Errorf("interface %q: ipv4: %w", name, err))
|
||||||
} else if i4 != nil {
|
} else if i4 != nil {
|
||||||
ifaces4 = append(ifaces4, i4)
|
ifaces4 = append(ifaces4, i4)
|
||||||
}
|
}
|
||||||
|
|
||||||
i6 = newNetInterfaceV6(ctx, l, ifaceName, iface.IPv6)
|
i6 := newNetInterfaceV6(ctx, l, name, iface.IPv6)
|
||||||
if i6 != nil {
|
if i6 != nil {
|
||||||
ifaces6 = append(ifaces6, i6)
|
ifaces6 = append(ifaces6, i6)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
if err = errors.Join(errs...); err != nil {
|
if err = errors.Join(errs...); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -178,7 +166,7 @@ func (srv *DHCPServer) IPByHost(host string) (ip netip.Addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset implements the [Interface] interface for *DHCPServer.
|
// Reset implements the [Interface] interface for *DHCPServer.
|
||||||
func (srv *DHCPServer) Reset() (err error) {
|
func (srv *DHCPServer) Reset(ctx context.Context) (err error) {
|
||||||
srv.leasesMu.Lock()
|
srv.leasesMu.Lock()
|
||||||
defer srv.leasesMu.Unlock()
|
defer srv.leasesMu.Unlock()
|
||||||
|
|
||||||
|
@ -190,11 +178,13 @@ func (srv *DHCPServer) Reset() (err error) {
|
||||||
}
|
}
|
||||||
srv.leases.clear()
|
srv.leases.clear()
|
||||||
|
|
||||||
|
srv.logger.DebugContext(ctx, "reset leases")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLease implements the [Interface] interface for *DHCPServer.
|
// AddLease implements the [Interface] interface for *DHCPServer.
|
||||||
func (srv *DHCPServer) AddLease(l *Lease) (err error) {
|
func (srv *DHCPServer) AddLease(ctx context.Context, l *Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "adding lease: %w") }()
|
defer func() { err = errors.Annotate(err, "adding lease: %w") }()
|
||||||
|
|
||||||
addr := l.IP
|
addr := l.IP
|
||||||
|
@ -207,13 +197,27 @@ func (srv *DHCPServer) AddLease(l *Lease) (err error) {
|
||||||
srv.leasesMu.Lock()
|
srv.leasesMu.Lock()
|
||||||
defer srv.leasesMu.Unlock()
|
defer srv.leasesMu.Unlock()
|
||||||
|
|
||||||
return srv.leases.add(l, iface)
|
err = srv.leases.add(l, iface)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since there is already an annotation deferred.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.logger.DebugContext(
|
||||||
|
ctx, "added lease",
|
||||||
|
"hostname", l.Hostname,
|
||||||
|
"ip", l.IP,
|
||||||
|
"mac", l.HWAddr,
|
||||||
|
"static", l.IsStatic,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStaticLease implements the [Interface] interface for *DHCPServer.
|
// UpdateStaticLease implements the [Interface] interface for *DHCPServer.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Support moving leases between interfaces.
|
// TODO(e.burkov): Support moving leases between interfaces.
|
||||||
func (srv *DHCPServer) UpdateStaticLease(l *Lease) (err error) {
|
func (srv *DHCPServer) UpdateStaticLease(ctx context.Context, l *Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "updating static lease: %w") }()
|
defer func() { err = errors.Annotate(err, "updating static lease: %w") }()
|
||||||
|
|
||||||
addr := l.IP
|
addr := l.IP
|
||||||
|
@ -226,11 +230,25 @@ func (srv *DHCPServer) UpdateStaticLease(l *Lease) (err error) {
|
||||||
srv.leasesMu.Lock()
|
srv.leasesMu.Lock()
|
||||||
defer srv.leasesMu.Unlock()
|
defer srv.leasesMu.Unlock()
|
||||||
|
|
||||||
return srv.leases.update(l, iface)
|
err = srv.leases.update(l, iface)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since there is already an annotation deferred.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.logger.DebugContext(
|
||||||
|
ctx, "updated lease",
|
||||||
|
"hostname", l.Hostname,
|
||||||
|
"ip", l.IP,
|
||||||
|
"mac", l.HWAddr,
|
||||||
|
"static", l.IsStatic,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveLease implements the [Interface] interface for *DHCPServer.
|
// RemoveLease implements the [Interface] interface for *DHCPServer.
|
||||||
func (srv *DHCPServer) RemoveLease(l *Lease) (err error) {
|
func (srv *DHCPServer) RemoveLease(ctx context.Context, l *Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "removing lease: %w") }()
|
defer func() { err = errors.Annotate(err, "removing lease: %w") }()
|
||||||
|
|
||||||
addr := l.IP
|
addr := l.IP
|
||||||
|
@ -243,7 +261,21 @@ func (srv *DHCPServer) RemoveLease(l *Lease) (err error) {
|
||||||
srv.leasesMu.Lock()
|
srv.leasesMu.Lock()
|
||||||
defer srv.leasesMu.Unlock()
|
defer srv.leasesMu.Unlock()
|
||||||
|
|
||||||
return srv.leases.remove(l, iface)
|
err = srv.leases.remove(l, iface)
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error since there is already an annotation deferred.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
iface.logger.DebugContext(
|
||||||
|
ctx, "removed lease",
|
||||||
|
"hostname", l.Hostname,
|
||||||
|
"ip", l.IP,
|
||||||
|
"mac", l.HWAddr,
|
||||||
|
"static", l.IsStatic,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ifaceForAddr returns the handled network interface for the given IP address,
|
// ifaceForAddr returns the handled network interface for the given IP address,
|
||||||
|
|
|
@ -202,7 +202,7 @@ func TestDHCPServer_AddLease(t *testing.T) {
|
||||||
mac2 := mustParseMAC(t, "06:05:04:03:02:01")
|
mac2 := mustParseMAC(t, "06:05:04:03:02:01")
|
||||||
mac3 := mustParseMAC(t, "02:03:04:05:06:07")
|
mac3 := mustParseMAC(t, "02:03:04:05:06:07")
|
||||||
|
|
||||||
require.NoError(t, srv.AddLease(&dhcpsvc.Lease{
|
require.NoError(t, srv.AddLease(ctx, &dhcpsvc.Lease{
|
||||||
Hostname: host1,
|
Hostname: host1,
|
||||||
IP: ip1,
|
IP: ip1,
|
||||||
HWAddr: mac1,
|
HWAddr: mac1,
|
||||||
|
@ -277,7 +277,7 @@ func TestDHCPServer_AddLease(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.AddLease(tc.lease))
|
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.AddLease(ctx, tc.lease))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ func TestDHCPServer_index(t *testing.T) {
|
||||||
IsStatic: true,
|
IsStatic: true,
|
||||||
}}
|
}}
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
require.NoError(t, srv.AddLease(l))
|
require.NoError(t, srv.AddLease(ctx, l))
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("ip_idx", func(t *testing.T) {
|
t.Run("ip_idx", func(t *testing.T) {
|
||||||
|
@ -408,7 +408,7 @@ func TestDHCPServer_UpdateStaticLease(t *testing.T) {
|
||||||
IsStatic: true,
|
IsStatic: true,
|
||||||
}}
|
}}
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
require.NoError(t, srv.AddLease(l))
|
require.NoError(t, srv.AddLease(ctx, l))
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
@ -478,7 +478,7 @@ func TestDHCPServer_UpdateStaticLease(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.UpdateStaticLease(tc.lease))
|
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.UpdateStaticLease(ctx, tc.lease))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +520,7 @@ func TestDHCPServer_RemoveLease(t *testing.T) {
|
||||||
IsStatic: true,
|
IsStatic: true,
|
||||||
}}
|
}}
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
require.NoError(t, srv.AddLease(l))
|
require.NoError(t, srv.AddLease(ctx, l))
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
@ -571,7 +571,7 @@ func TestDHCPServer_RemoveLease(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.RemoveLease(tc.lease))
|
testutil.AssertErrorMsg(t, tc.wantErrMsg, srv.RemoveLease(ctx, tc.lease))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,12 +612,12 @@ func TestDHCPServer_Reset(t *testing.T) {
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
require.NoError(t, srv.AddLease(l))
|
require.NoError(t, srv.AddLease(ctx, l))
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Len(t, srv.Leases(), len(leases))
|
require.Len(t, srv.Leases(), len(leases))
|
||||||
|
|
||||||
require.NoError(t, srv.Reset())
|
require.NoError(t, srv.Reset(ctx))
|
||||||
|
|
||||||
assert.Empty(t, srv.Leases())
|
assert.Empty(t, srv.Leases())
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ func (c *IPv4Config) validate() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.LeaseDuration <= 0 {
|
if c.LeaseDuration <= 0 {
|
||||||
err = newMustErr("lease duration", "be less than %d", c.LeaseDuration)
|
err = newMustErr("icmp timeout", "be positive", c.LeaseDuration)
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,15 +341,15 @@ func (c *IPv4Config) options(ctx context.Context, l *slog.Logger) (imp, exp laye
|
||||||
slices.SortFunc(imp, compareV4OptionCodes)
|
slices.SortFunc(imp, compareV4OptionCodes)
|
||||||
|
|
||||||
// Set values for explicitly configured options.
|
// Set values for explicitly configured options.
|
||||||
for _, e := range c.Options {
|
for _, o := range c.Options {
|
||||||
i, found := slices.BinarySearchFunc(imp, e, compareV4OptionCodes)
|
i, found := slices.BinarySearchFunc(imp, o, compareV4OptionCodes)
|
||||||
if found {
|
if found {
|
||||||
imp = slices.Delete(imp, i, i+1)
|
imp = slices.Delete(imp, i, i+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
i, found = slices.BinarySearchFunc(exp, e, compareV4OptionCodes)
|
i, found = slices.BinarySearchFunc(exp, o, compareV4OptionCodes)
|
||||||
if e.Length > 0 {
|
if o.Length > 0 {
|
||||||
exp = slices.Insert(exp, i, e)
|
exp = slices.Insert(exp, i, o)
|
||||||
} else if found {
|
} else if found {
|
||||||
exp = slices.Delete(exp, i, i+1)
|
exp = slices.Delete(exp, i, i+1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,36 +62,6 @@ func (c *IPv6Config) validate() (err error) {
|
||||||
return errors.Join(errs...)
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// options returns the implicit and explicit options for the interface. The two
|
|
||||||
// lists are disjoint and the implicit options are initialized with default
|
|
||||||
// values.
|
|
||||||
//
|
|
||||||
// TODO(e.burkov): Add implicit options according to RFC.
|
|
||||||
func (c *IPv6Config) options(ctx context.Context, l *slog.Logger) (imp, exp layers.DHCPv6Options) {
|
|
||||||
// Set default values of host configuration parameters listed in RFC 8415.
|
|
||||||
imp = layers.DHCPv6Options{}
|
|
||||||
slices.SortFunc(imp, compareV6OptionCodes)
|
|
||||||
|
|
||||||
// Set values for explicitly configured options.
|
|
||||||
for _, e := range c.Options {
|
|
||||||
i, found := slices.BinarySearchFunc(imp, e, compareV6OptionCodes)
|
|
||||||
if found {
|
|
||||||
imp = slices.Delete(imp, i, i+1)
|
|
||||||
}
|
|
||||||
|
|
||||||
exp = append(exp, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
l.DebugContext(ctx, "options", "implicit", imp, "explicit", exp)
|
|
||||||
|
|
||||||
return imp, exp
|
|
||||||
}
|
|
||||||
|
|
||||||
// compareV6OptionCodes compares option codes of a and b.
|
|
||||||
func compareV6OptionCodes(a, b layers.DHCPv6Option) (res int) {
|
|
||||||
return int(a.Code) - int(b.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// netInterfaceV6 is a DHCP interface for IPv6 address family.
|
// netInterfaceV6 is a DHCP interface for IPv6 address family.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Add options.
|
// TODO(e.burkov): Add options.
|
||||||
|
@ -142,6 +112,7 @@ func newNetInterfaceV6(
|
||||||
netInterface: netInterface{
|
netInterface: netInterface{
|
||||||
name: name,
|
name: name,
|
||||||
leaseTTL: conf.LeaseDuration,
|
leaseTTL: conf.LeaseDuration,
|
||||||
|
logger: l,
|
||||||
},
|
},
|
||||||
raSLAACOnly: conf.RASLAACOnly,
|
raSLAACOnly: conf.RASLAACOnly,
|
||||||
raAllowSLAAC: conf.RAAllowSLAAC,
|
raAllowSLAAC: conf.RAAllowSLAAC,
|
||||||
|
@ -175,3 +146,33 @@ func (ifaces netInterfacesV6) find(ip netip.Addr) (iface6 *netInterface, ok bool
|
||||||
|
|
||||||
return &ifaces[i].netInterface, true
|
return &ifaces[i].netInterface, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// options returns the implicit and explicit options for the interface. The two
|
||||||
|
// lists are disjoint and the implicit options are initialized with default
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Add implicit options according to RFC.
|
||||||
|
func (c *IPv6Config) options(ctx context.Context, l *slog.Logger) (imp, exp layers.DHCPv6Options) {
|
||||||
|
// Set default values of host configuration parameters listed in RFC 8415.
|
||||||
|
imp = layers.DHCPv6Options{}
|
||||||
|
slices.SortFunc(imp, compareV6OptionCodes)
|
||||||
|
|
||||||
|
// Set values for explicitly configured options.
|
||||||
|
for _, e := range c.Options {
|
||||||
|
i, found := slices.BinarySearchFunc(imp, e, compareV6OptionCodes)
|
||||||
|
if found {
|
||||||
|
imp = slices.Delete(imp, i, i+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
exp = append(exp, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.DebugContext(ctx, "options", "implicit", imp, "explicit", exp)
|
||||||
|
|
||||||
|
return imp, exp
|
||||||
|
}
|
||||||
|
|
||||||
|
// compareV6OptionCodes compares option codes of a and b.
|
||||||
|
func compareV6OptionCodes(a, b layers.DHCPv6Option) (res int) {
|
||||||
|
return int(a.Code) - int(b.Code)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue