Pull request 2070: 4923 gopacket DHCP vol.4
Merge in DNS/adguard-home from 4923-gopacket-dhcp-vol.4 to master
Updates #4923.
Squashed commit of the following:
commit 4b87258c70ac98b2abb1ac95f7e916e244b3cd08
Merge: 61458864f 9b91a8740
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Nov 16 14:05:34 2023 +0300
Merge branch 'master' into 4923-gopacket-dhcp-vol.4
commit 61458864f3df7a027e65060a5f0fb516cc7911a7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Wed Nov 15 18:48:40 2023 +0300
all: imp code
commit 506a0ab81e76beebb900f86580577563b471e4e2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Tue Nov 14 15:59:56 2023 +0300
all: cleanup moving lease
commit 8d218b732662ac4308ed09d28c1bf9f65906d47c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Mon Nov 13 18:13:39 2023 +0300
all: rm old leases type
This commit is contained in:
parent
9b91a87406
commit
8bb1aad739
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -49,16 +50,16 @@ type ServerConfig struct {
|
||||||
// DHCPServer - DHCP server interface
|
// DHCPServer - DHCP server interface
|
||||||
type DHCPServer interface {
|
type DHCPServer interface {
|
||||||
// ResetLeases resets leases.
|
// ResetLeases resets leases.
|
||||||
ResetLeases(leases []*Lease) (err error)
|
ResetLeases(leases []*dhcpsvc.Lease) (err error)
|
||||||
// GetLeases returns deep clones of the current leases.
|
// GetLeases returns deep clones of the current leases.
|
||||||
GetLeases(flags GetLeasesFlags) (leases []*Lease)
|
GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease)
|
||||||
// AddStaticLease - add a static lease
|
// AddStaticLease - add a static lease
|
||||||
AddStaticLease(l *Lease) (err error)
|
AddStaticLease(l *dhcpsvc.Lease) (err error)
|
||||||
// RemoveStaticLease - remove a static lease
|
// RemoveStaticLease - remove a static lease
|
||||||
RemoveStaticLease(l *Lease) (err error)
|
RemoveStaticLease(l *dhcpsvc.Lease) (err error)
|
||||||
|
|
||||||
// UpdateStaticLease updates IP, hostname of the lease.
|
// UpdateStaticLease updates IP, hostname of the lease.
|
||||||
UpdateStaticLease(l *Lease) (err error)
|
UpdateStaticLease(l *dhcpsvc.Lease) (err error)
|
||||||
|
|
||||||
// FindMACbyIP returns a MAC address by the IP address of its lease, if
|
// FindMACbyIP returns a MAC address by the IP address of its lease, if
|
||||||
// there is one.
|
// there is one.
|
||||||
|
@ -81,7 +82,7 @@ type DHCPServer interface {
|
||||||
Start() (err error)
|
Start() (err error)
|
||||||
// Stop - stop server
|
// Stop - stop server
|
||||||
Stop() (err error)
|
Stop() (err error)
|
||||||
getLeasesRef() []*Lease
|
getLeasesRef() []*dhcpsvc.Lease
|
||||||
}
|
}
|
||||||
|
|
||||||
// V4ServerConf - server configuration
|
// V4ServerConf - server configuration
|
||||||
|
|
|
@ -5,9 +5,13 @@ package dhcpd
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/google/renameio/v2/maybe"
|
"github.com/google/renameio/v2/maybe"
|
||||||
|
@ -28,7 +32,60 @@ type dataLeases struct {
|
||||||
Version int `json:"version"`
|
Version int `json:"version"`
|
||||||
|
|
||||||
// Leases is the list containing stored DHCP leases.
|
// Leases is the list containing stored DHCP leases.
|
||||||
Leases []*Lease `json:"leases"`
|
Leases []*dbLease `json:"leases"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbLease is the structure of stored lease.
|
||||||
|
type dbLease struct {
|
||||||
|
Expiry string `json:"expires"`
|
||||||
|
IP netip.Addr `json:"ip"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
HWAddr string `json:"mac"`
|
||||||
|
IsStatic bool `json:"static"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromLease converts *dhcpsvc.Lease to *dbLease.
|
||||||
|
func fromLease(l *dhcpsvc.Lease) (dl *dbLease) {
|
||||||
|
var expiryStr string
|
||||||
|
if !l.IsStatic {
|
||||||
|
// The front-end is waiting for RFC 3999 format of the time value. It
|
||||||
|
// also shouldn't got an Expiry field for static leases.
|
||||||
|
//
|
||||||
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/2692.
|
||||||
|
expiryStr = l.Expiry.Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dbLease{
|
||||||
|
Expiry: expiryStr,
|
||||||
|
Hostname: l.Hostname,
|
||||||
|
HWAddr: l.HWAddr.String(),
|
||||||
|
IP: l.IP,
|
||||||
|
IsStatic: l.IsStatic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toLease converts *dbLease to *dhcpsvc.Lease.
|
||||||
|
func (dl *dbLease) toLease() (l *dhcpsvc.Lease, err error) {
|
||||||
|
mac, err := net.ParseMAC(dl.HWAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing hardware address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expiry := time.Time{}
|
||||||
|
if !dl.IsStatic {
|
||||||
|
expiry, err = time.Parse(time.RFC3339, dl.Expiry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing expiry time: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dhcpsvc.Lease{
|
||||||
|
Expiry: expiry,
|
||||||
|
IP: dl.IP,
|
||||||
|
Hostname: dl.Hostname,
|
||||||
|
HWAddr: mac,
|
||||||
|
IsStatic: dl.IsStatic,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbLoad loads stored leases.
|
// dbLoad loads stored leases.
|
||||||
|
@ -49,15 +106,22 @@ func (s *server) dbLoad() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
leases := dl.Leases
|
leases := dl.Leases
|
||||||
|
leases4 := []*dhcpsvc.Lease{}
|
||||||
leases4 := []*Lease{}
|
leases6 := []*dhcpsvc.Lease{}
|
||||||
leases6 := []*Lease{}
|
|
||||||
|
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
if l.IP.Is4() {
|
var lease *dhcpsvc.Lease
|
||||||
leases4 = append(leases4, l)
|
lease, err = l.toLease()
|
||||||
|
if err != nil {
|
||||||
|
log.Info("dhcp: invalid lease: %s", err)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if lease.IP.Is4() {
|
||||||
|
leases4 = append(leases4, lease)
|
||||||
} else {
|
} else {
|
||||||
leases6 = append(leases6, l)
|
leases6 = append(leases6, lease)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +137,12 @@ func (s *server) dbLoad() (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("dhcp: loaded leases v4:%d v6:%d total-read:%d from DB",
|
log.Info(
|
||||||
len(leases4), len(leases6), len(leases))
|
"dhcp: loaded leases v4:%d v6:%d total-read:%d from DB",
|
||||||
|
len(leases4),
|
||||||
|
len(leases6),
|
||||||
|
len(leases),
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -83,24 +151,26 @@ func (s *server) dbLoad() (err error) {
|
||||||
func (s *server) dbStore() (err error) {
|
func (s *server) dbStore() (err error) {
|
||||||
// Use an empty slice here as opposed to nil so that it doesn't write
|
// Use an empty slice here as opposed to nil so that it doesn't write
|
||||||
// "null" into the database file if leases are empty.
|
// "null" into the database file if leases are empty.
|
||||||
leases := []*Lease{}
|
leases := []*dbLease{}
|
||||||
|
|
||||||
leases4 := s.srv4.getLeasesRef()
|
for _, l := range s.srv4.getLeasesRef() {
|
||||||
leases = append(leases, leases4...)
|
leases = append(leases, fromLease(l))
|
||||||
|
}
|
||||||
|
|
||||||
if s.srv6 != nil {
|
if s.srv6 != nil {
|
||||||
leases6 := s.srv6.getLeasesRef()
|
for _, l := range s.srv6.getLeasesRef() {
|
||||||
leases = append(leases, leases6...)
|
leases = append(leases, fromLease(l))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeDB(s.conf.dbFilePath, leases)
|
return writeDB(s.conf.dbFilePath, leases)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeDB writes leases to file at path.
|
// writeDB writes leases to file at path.
|
||||||
func writeDB(path string, leases []*Lease) (err error) {
|
func writeDB(path string, leases []*dbLease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "writing db: %w") }()
|
defer func() { err = errors.Annotate(err, "writing db: %w") }()
|
||||||
|
|
||||||
slices.SortFunc(leases, func(a, b *Lease) (res int) {
|
slices.SortFunc(leases, func(a, b *dbLease) (res int) {
|
||||||
return strings.Compare(a.Hostname, b.Hostname)
|
return strings.Compare(a.Hostname, b.Hostname)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
package dhcpd
|
package dhcpd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
@ -12,7 +11,6 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/timeutil"
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -29,105 +27,6 @@ const (
|
||||||
defaultBackoff time.Duration = 500 * time.Millisecond
|
defaultBackoff time.Duration = 500 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lease contains the necessary information about a DHCP lease. It's used as is
|
|
||||||
// in the database, so don't change it until it's absolutely necessary, see
|
|
||||||
// [dataVersion].
|
|
||||||
//
|
|
||||||
// TODO(e.burkov): Unexport it and use [dhcpsvc.Lease].
|
|
||||||
type Lease struct {
|
|
||||||
// Expiry is the expiration time of the lease.
|
|
||||||
Expiry time.Time `json:"expires"`
|
|
||||||
|
|
||||||
// Hostname of the client.
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
|
|
||||||
// HWAddr is the physical hardware address (MAC address).
|
|
||||||
HWAddr net.HardwareAddr `json:"mac"`
|
|
||||||
|
|
||||||
// IP is the IP address leased to the client.
|
|
||||||
IP netip.Addr `json:"ip"`
|
|
||||||
|
|
||||||
// IsStatic defines if the lease is static.
|
|
||||||
IsStatic bool `json:"static"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a deep copy of l.
|
|
||||||
func (l *Lease) Clone() (clone *Lease) {
|
|
||||||
if l == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Lease{
|
|
||||||
Expiry: l.Expiry,
|
|
||||||
Hostname: l.Hostname,
|
|
||||||
HWAddr: slices.Clone(l.HWAddr),
|
|
||||||
IP: l.IP,
|
|
||||||
IsStatic: l.IsStatic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsBlocklisted returns true if the lease is blocklisted.
|
|
||||||
//
|
|
||||||
// TODO(a.garipov): Just make it a boolean field.
|
|
||||||
func (l *Lease) IsBlocklisted() (ok bool) {
|
|
||||||
if len(l.HWAddr) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, b := range l.HWAddr {
|
|
||||||
if b != 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface for Lease.
|
|
||||||
func (l Lease) MarshalJSON() ([]byte, error) {
|
|
||||||
var expiryStr string
|
|
||||||
if !l.IsStatic {
|
|
||||||
// The front-end is waiting for RFC 3999 format of the time
|
|
||||||
// value. It also shouldn't got an Expiry field for static
|
|
||||||
// leases.
|
|
||||||
//
|
|
||||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/2692.
|
|
||||||
expiryStr = l.Expiry.Format(time.RFC3339)
|
|
||||||
}
|
|
||||||
|
|
||||||
type lease Lease
|
|
||||||
return json.Marshal(&struct {
|
|
||||||
HWAddr string `json:"mac"`
|
|
||||||
Expiry string `json:"expires,omitempty"`
|
|
||||||
lease
|
|
||||||
}{
|
|
||||||
HWAddr: l.HWAddr.String(),
|
|
||||||
Expiry: expiryStr,
|
|
||||||
lease: lease(l),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Unmarshaler interface for *Lease.
|
|
||||||
func (l *Lease) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
type lease Lease
|
|
||||||
aux := struct {
|
|
||||||
*lease
|
|
||||||
HWAddr string `json:"mac"`
|
|
||||||
}{
|
|
||||||
lease: (*lease)(l),
|
|
||||||
}
|
|
||||||
if err = json.Unmarshal(data, &aux); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
l.HWAddr, err = net.ParseMAC(aux.HWAddr)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("couldn't parse MAC address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnLeaseChangedT is a callback for lease changes.
|
// OnLeaseChangedT is a callback for lease changes.
|
||||||
type OnLeaseChangedT func(flags int)
|
type OnLeaseChangedT func(flags int)
|
||||||
|
|
||||||
|
@ -370,19 +269,7 @@ func (s *server) Stop() (err error) {
|
||||||
|
|
||||||
// Leases returns the list of active DHCP leases.
|
// Leases returns the list of active DHCP leases.
|
||||||
func (s *server) Leases() (leases []*dhcpsvc.Lease) {
|
func (s *server) Leases() (leases []*dhcpsvc.Lease) {
|
||||||
ls := append(s.srv4.GetLeases(LeasesAll), s.srv6.GetLeases(LeasesAll)...)
|
return append(s.srv4.GetLeases(LeasesAll), s.srv6.GetLeases(LeasesAll)...)
|
||||||
leases = make([]*dhcpsvc.Lease, len(ls))
|
|
||||||
for i, l := range ls {
|
|
||||||
leases[i] = &dhcpsvc.Lease{
|
|
||||||
Expiry: l.Expiry,
|
|
||||||
Hostname: l.Hostname,
|
|
||||||
HWAddr: l.HWAddr,
|
|
||||||
IP: l.IP,
|
|
||||||
IsStatic: l.IsStatic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return leases
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MACByIP returns a MAC address by the IP address of its lease, if there is
|
// MACByIP returns a MAC address by the IP address of its lease, if there is
|
||||||
|
@ -414,6 +301,6 @@ func (s *server) IPByHost(host string) (ip netip.Addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddStaticLease - add static v4 lease
|
// AddStaticLease - add static v4 lease
|
||||||
func (s *server) AddStaticLease(l *Lease) error {
|
func (s *server) AddStaticLease(l *dhcpsvc.Lease) error {
|
||||||
return s.srv4.AddStaticLease(l)
|
return s.srv4.AddStaticLease(l)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -44,7 +45,7 @@ func TestDB(t *testing.T) {
|
||||||
s.srv6, err = v6Create(V6ServerConf{})
|
s.srv6, err = v6Create(V6ServerConf{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
leases := []*Lease{{
|
leases := []*dhcpsvc.Lease{{
|
||||||
Expiry: time.Now().Add(time.Hour),
|
Expiry: time.Now().Add(time.Hour),
|
||||||
Hostname: "static-1.local",
|
Hostname: "static-1.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
|
|
|
@ -93,13 +93,13 @@ func leasesToStatic(leases []*dhcpsvc.Lease) (static []*leaseStatic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// toLease converts leaseStatic to Lease or returns error.
|
// toLease converts leaseStatic to Lease or returns error.
|
||||||
func (l *leaseStatic) toLease() (lease *Lease, err error) {
|
func (l *leaseStatic) toLease() (lease *dhcpsvc.Lease, err error) {
|
||||||
addr, err := net.ParseMAC(l.HWAddr)
|
addr, err := net.ParseMAC(l.HWAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't parse MAC address: %w", err)
|
return nil, fmt.Errorf("couldn't parse MAC address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Lease{
|
return &dhcpsvc.Lease{
|
||||||
HWAddr: addr,
|
HWAddr: addr,
|
||||||
IP: l.IP,
|
IP: l.IP,
|
||||||
Hostname: l.Hostname,
|
Hostname: l.Hostname,
|
||||||
|
@ -593,7 +593,7 @@ func setOtherDHCPResult(ifaceName string, result *dhcpSearchResult) {
|
||||||
|
|
||||||
// parseLease parses a lease from r. If there is no error returns DHCPServer
|
// parseLease parses a lease from r. If there is no error returns DHCPServer
|
||||||
// and *Lease. r must be non-nil.
|
// and *Lease. r must be non-nil.
|
||||||
func (s *server) parseLease(r io.Reader) (srv DHCPServer, lease *Lease, err error) {
|
func (s *server) parseLease(r io.Reader) (srv DHCPServer, lease *dhcpsvc.Lease, err error) {
|
||||||
l := &leaseStatic{}
|
l := &leaseStatic{}
|
||||||
err = json.NewDecoder(r).Decode(l)
|
err = json.NewDecoder(r).Decode(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package dhcpd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
@ -25,9 +26,9 @@ const (
|
||||||
dbFilename = "leases.db"
|
dbFilename = "leases.db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// leaseJSON is the structure of stored lease.
|
// leaseJSON is the structure of stored lease in a legacy database.
|
||||||
//
|
//
|
||||||
// Deprecated: Use [Lease].
|
// Deprecated: Use [dbLease].
|
||||||
type leaseJSON struct {
|
type leaseJSON struct {
|
||||||
HWAddr []byte `json:"mac"`
|
HWAddr []byte `json:"mac"`
|
||||||
IP []byte `json:"ip"`
|
IP []byte `json:"ip"`
|
||||||
|
@ -35,13 +36,28 @@ type leaseJSON struct {
|
||||||
Expiry int64 `json:"exp"`
|
Expiry int64 `json:"exp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeIP(ip net.IP) net.IP {
|
// readOldDB reads the old database from the given path.
|
||||||
ip4 := ip.To4()
|
func readOldDB(path string) (leases []*leaseJSON, err error) {
|
||||||
if ip4 != nil {
|
// #nosec G304 -- Trust this path, since it's taken from the old file name
|
||||||
return ip4
|
// relative to the working directory and should generally be considered
|
||||||
|
// safe.
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
// Nothing to migrate.
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
// Don't wrap the error since it's informative enough as is.
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() { err = errors.WithDeferred(err, file.Close()) }()
|
||||||
|
|
||||||
|
leases = []*leaseJSON{}
|
||||||
|
err = json.NewDecoder(file).Decode(&leases)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decoding old db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ip
|
return leases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrateDB migrates stored leases if necessary.
|
// migrateDB migrates stored leases if necessary.
|
||||||
|
@ -51,59 +67,50 @@ func migrateDB(conf *ServerConfig) (err error) {
|
||||||
oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename)
|
oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename)
|
||||||
dataDirPath := filepath.Join(conf.DataDir, dataFilename)
|
dataDirPath := filepath.Join(conf.DataDir, dataFilename)
|
||||||
|
|
||||||
// #nosec G304 -- Trust this path, since it's taken from the old file name
|
oldLeases, err := readOldDB(oldLeasesPath)
|
||||||
// relative to the working directory and should generally be considered
|
if err != nil {
|
||||||
// safe.
|
// Don't wrap the error since it's informative enough as is.
|
||||||
file, err := os.Open(oldLeasesPath)
|
return err
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
} else if oldLeases == nil {
|
||||||
// Nothing to migrate.
|
// Nothing to migrate.
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
|
||||||
// Don't wrap the error since it's informative enough as is.
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ljs := []leaseJSON{}
|
leases := make([]*dbLease, 0, len(oldLeases))
|
||||||
err = json.NewDecoder(file).Decode(&ljs)
|
for _, l := range oldLeases {
|
||||||
if err != nil {
|
l.IP = normalizeIP(l.IP)
|
||||||
// Don't wrap the error since it's informative enough as is.
|
ip, ok := netip.AddrFromSlice(l.IP)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
// Don't wrap the error since it's informative enough as is.
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
leases := []*Lease{}
|
|
||||||
|
|
||||||
for _, lj := range ljs {
|
|
||||||
lj.IP = normalizeIP(lj.IP)
|
|
||||||
|
|
||||||
ip, ok := netip.AddrFromSlice(lj.IP)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Info("dhcp: invalid IP: %s", lj.IP)
|
log.Info("dhcp: invalid IP: %s", l.IP)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lease := &Lease{
|
leases = append(leases, &dbLease{
|
||||||
Expiry: time.Unix(lj.Expiry, 0),
|
Expiry: time.Unix(l.Expiry, 0).Format(time.RFC3339),
|
||||||
Hostname: lj.Hostname,
|
Hostname: l.Hostname,
|
||||||
HWAddr: lj.HWAddr,
|
HWAddr: net.HardwareAddr(l.HWAddr).String(),
|
||||||
IP: ip,
|
IP: ip,
|
||||||
IsStatic: lj.Expiry == leaseExpireStatic,
|
IsStatic: l.Expiry == leaseExpireStatic,
|
||||||
}
|
})
|
||||||
|
|
||||||
leases = append(leases, lease)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writeDB(dataDirPath, leases)
|
err = writeDB(dataDirPath, leases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't wrap the error since it's informative enough as is.
|
// Don't wrap the error since an annotation deferred already.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.Remove(oldLeasesPath)
|
return os.Remove(oldLeasesPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalizeIP converts the given IP address to IPv4 if it's IPv4-mapped IPv6,
|
||||||
|
// or leaves it as is otherwise.
|
||||||
|
func normalizeIP(ip net.IP) (normalized net.IP) {
|
||||||
|
normalized = ip.To4()
|
||||||
|
if normalized != nil {
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package dhcpd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -27,16 +26,16 @@ func TestMigrateDB(t *testing.T) {
|
||||||
err := os.WriteFile(oldLeasesPath, []byte(testData), 0o644)
|
err := os.WriteFile(oldLeasesPath, []byte(testData), 0o644)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
wantLeases := []*Lease{{
|
wantLeases := []*dbLease{{
|
||||||
Expiry: time.Time{},
|
Expiry: time.Unix(1, 0).Format(time.RFC3339),
|
||||||
Hostname: "test1",
|
Hostname: "test1",
|
||||||
HWAddr: net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66},
|
HWAddr: "11:22:33:44:55:66",
|
||||||
IP: netip.MustParseAddr("1.2.3.4"),
|
IP: netip.MustParseAddr("1.2.3.4"),
|
||||||
IsStatic: true,
|
IsStatic: true,
|
||||||
}, {
|
}, {
|
||||||
Expiry: time.Unix(1231231231, 0),
|
Expiry: time.Unix(1231231231, 0).Format(time.RFC3339),
|
||||||
Hostname: "test2",
|
Hostname: "test2",
|
||||||
HWAddr: net.HardwareAddr{0x66, 0x55, 0x44, 0x33, 0x22, 0x11},
|
HWAddr: "66:55:44:33:22:11",
|
||||||
IP: netip.MustParseAddr("4.3.2.1"),
|
IP: netip.MustParseAddr("4.3.2.1"),
|
||||||
IsStatic: false,
|
IsStatic: false,
|
||||||
}}
|
}}
|
||||||
|
@ -62,12 +61,12 @@ func TestMigrateDB(t *testing.T) {
|
||||||
|
|
||||||
leases := dl.Leases
|
leases := dl.Leases
|
||||||
|
|
||||||
for i, wl := range wantLeases {
|
for i, wantLease := range wantLeases {
|
||||||
assert.Equal(t, wl.Hostname, leases[i].Hostname)
|
assert.Equal(t, wantLease.Hostname, leases[i].Hostname)
|
||||||
assert.Equal(t, wl.HWAddr, leases[i].HWAddr)
|
assert.Equal(t, wantLease.HWAddr, leases[i].HWAddr)
|
||||||
assert.Equal(t, wl.IP, leases[i].IP)
|
assert.Equal(t, wantLease.IP, leases[i].IP)
|
||||||
assert.Equal(t, wl.IsStatic, leases[i].IsStatic)
|
assert.Equal(t, wantLease.IsStatic, leases[i].IsStatic)
|
||||||
|
|
||||||
require.True(t, wl.Expiry.Equal(leases[i].Expiry))
|
require.Equal(t, wantLease.Expiry, leases[i].Expiry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ package dhcpd
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type winServer struct{}
|
type winServer struct{}
|
||||||
|
@ -14,19 +16,19 @@ type winServer struct{}
|
||||||
// type check
|
// type check
|
||||||
var _ DHCPServer = winServer{}
|
var _ DHCPServer = winServer{}
|
||||||
|
|
||||||
func (winServer) ResetLeases(_ []*Lease) (err error) { return nil }
|
func (winServer) ResetLeases(_ []*dhcpsvc.Lease) (err error) { return nil }
|
||||||
func (winServer) GetLeases(_ GetLeasesFlags) (leases []*Lease) { return nil }
|
func (winServer) GetLeases(_ GetLeasesFlags) (leases []*dhcpsvc.Lease) { return nil }
|
||||||
func (winServer) getLeasesRef() []*Lease { return nil }
|
func (winServer) getLeasesRef() []*dhcpsvc.Lease { return nil }
|
||||||
func (winServer) AddStaticLease(_ *Lease) (err error) { return nil }
|
func (winServer) AddStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||||
func (winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
|
func (winServer) RemoveStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||||
func (winServer) UpdateStaticLease(_ *Lease) (err error) { return nil }
|
func (winServer) UpdateStaticLease(_ *dhcpsvc.Lease) (err error) { return nil }
|
||||||
func (winServer) FindMACbyIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
func (winServer) FindMACbyIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||||
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
|
||||||
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
|
||||||
func (winServer) Start() (err error) { return nil }
|
func (winServer) Start() (err error) { return nil }
|
||||||
func (winServer) Stop() (err error) { return nil }
|
func (winServer) Stop() (err error) { return nil }
|
||||||
func (winServer) HostByIP(_ netip.Addr) (host string) { return "" }
|
func (winServer) HostByIP(_ netip.Addr) (host string) { return "" }
|
||||||
func (winServer) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
func (winServer) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
||||||
|
|
||||||
func v4Create(_ *V4ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
func v4Create(_ *V4ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
||||||
func v6Create(_ V6ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
func v6Create(_ V6ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
@ -38,7 +39,7 @@ type v4Server struct {
|
||||||
// have intersections with [implicitOpts].
|
// have intersections with [implicitOpts].
|
||||||
explicitOpts dhcpv4.Options
|
explicitOpts dhcpv4.Options
|
||||||
|
|
||||||
// leasesLock protects leases, leaseHosts, and leasedOffsets.
|
// leasesLock protects leases, hostsIndex, ipIndex, and leasedOffsets.
|
||||||
leasesLock sync.Mutex
|
leasesLock sync.Mutex
|
||||||
|
|
||||||
// leasedOffsets contains offsets from conf.ipRange.start that have been
|
// leasedOffsets contains offsets from conf.ipRange.start that have been
|
||||||
|
@ -46,13 +47,13 @@ type v4Server struct {
|
||||||
leasedOffsets *bitSet
|
leasedOffsets *bitSet
|
||||||
|
|
||||||
// leases contains all dynamic and static leases.
|
// leases contains all dynamic and static leases.
|
||||||
leases []*Lease
|
leases []*dhcpsvc.Lease
|
||||||
|
|
||||||
// hostsIndex is the set of all hostnames of all known DHCP clients.
|
// hostsIndex is the set of all hostnames of all known DHCP clients.
|
||||||
hostsIndex map[string]*Lease
|
hostsIndex map[string]*dhcpsvc.Lease
|
||||||
|
|
||||||
// ipIndex is an index of leases by their IP addresses.
|
// ipIndex is an index of leases by their IP addresses.
|
||||||
ipIndex map[netip.Addr]*Lease
|
ipIndex map[netip.Addr]*dhcpsvc.Lease
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *v4Server) enabled() (ok bool) {
|
func (s *v4Server) enabled() (ok bool) {
|
||||||
|
@ -141,7 +142,7 @@ func (s *v4Server) IPByHost(host string) (ip netip.Addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetLeases resets leases.
|
// ResetLeases resets leases.
|
||||||
func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
|
func (s *v4Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
||||||
|
|
||||||
if s.conf == nil {
|
if s.conf == nil {
|
||||||
|
@ -152,8 +153,8 @@ func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
s.leasedOffsets = newBitSet()
|
s.leasedOffsets = newBitSet()
|
||||||
s.hostsIndex = make(map[string]*Lease, len(leases))
|
s.hostsIndex = make(map[string]*dhcpsvc.Lease, len(leases))
|
||||||
s.ipIndex = make(map[netip.Addr]*Lease, len(leases))
|
s.ipIndex = make(map[netip.Addr]*dhcpsvc.Lease, len(leases))
|
||||||
s.leases = nil
|
s.leases = nil
|
||||||
|
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
|
@ -173,14 +174,14 @@ func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLeasesRef returns the actual leases slice. For internal use only.
|
// getLeasesRef returns the actual leases slice. For internal use only.
|
||||||
func (s *v4Server) getLeasesRef() []*Lease {
|
func (s *v4Server) getLeasesRef() []*dhcpsvc.Lease {
|
||||||
return s.leases
|
return s.leases
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBlocklisted returns true if this lease holds a blocklisted IP.
|
// isBlocklisted returns true if this lease holds a blocklisted IP.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Make a method of *Lease?
|
// TODO(a.garipov): Make a method of *Lease?
|
||||||
func (s *v4Server) isBlocklisted(l *Lease) (ok bool) {
|
func (s *v4Server) isBlocklisted(l *dhcpsvc.Lease) (ok bool) {
|
||||||
if len(l.HWAddr) == 0 {
|
if len(l.HWAddr) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -196,11 +197,11 @@ func (s *v4Server) isBlocklisted(l *Lease) (ok bool) {
|
||||||
|
|
||||||
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
||||||
// use.
|
// use.
|
||||||
func (s *v4Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
func (s *v4Server) GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease) {
|
||||||
// The function shouldn't return nil, because zero-length slice behaves
|
// The function shouldn't return nil, because zero-length slice behaves
|
||||||
// differently in cases like marshalling. Our front-end also requires
|
// differently in cases like marshalling. Our front-end also requires
|
||||||
// a non-nil value in the response.
|
// a non-nil value in the response.
|
||||||
leases = []*Lease{}
|
leases = []*dhcpsvc.Lease{}
|
||||||
|
|
||||||
getDynamic := flags&LeasesDynamic != 0
|
getDynamic := flags&LeasesDynamic != 0
|
||||||
getStatic := flags&LeasesStatic != 0
|
getStatic := flags&LeasesStatic != 0
|
||||||
|
@ -248,7 +249,7 @@ func (s *v4Server) FindMACbyIP(ip netip.Addr) (mac net.HardwareAddr) {
|
||||||
const defaultHwAddrLen = 6
|
const defaultHwAddrLen = 6
|
||||||
|
|
||||||
// Add the specified IP to the black list for a time period
|
// Add the specified IP to the black list for a time period
|
||||||
func (s *v4Server) blocklistLease(l *Lease) {
|
func (s *v4Server) blocklistLease(l *dhcpsvc.Lease) {
|
||||||
l.HWAddr = make(net.HardwareAddr, defaultHwAddrLen)
|
l.HWAddr = make(net.HardwareAddr, defaultHwAddrLen)
|
||||||
l.Hostname = ""
|
l.Hostname = ""
|
||||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||||
|
@ -284,7 +285,7 @@ func (s *v4Server) rmLeaseByIndex(i int) {
|
||||||
// Return error if a static lease is found
|
// Return error if a static lease is found
|
||||||
//
|
//
|
||||||
// TODO(s.chzhen): Refactor the code.
|
// TODO(s.chzhen): Refactor the code.
|
||||||
func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
func (s *v4Server) rmDynamicLease(lease *dhcpsvc.Lease) (err error) {
|
||||||
for i, l := range s.leases {
|
for i, l := range s.leases {
|
||||||
isStatic := l.IsStatic
|
isStatic := l.IsStatic
|
||||||
|
|
||||||
|
@ -320,7 +321,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// addLease adds a dynamic or static lease.
|
// addLease adds a dynamic or static lease.
|
||||||
func (s *v4Server) addLease(l *Lease) (err error) {
|
func (s *v4Server) addLease(l *dhcpsvc.Lease) (err error) {
|
||||||
r := s.conf.ipRange
|
r := s.conf.ipRange
|
||||||
leaseIP := net.IP(l.IP.AsSlice())
|
leaseIP := net.IP(l.IP.AsSlice())
|
||||||
offset, inOffset := r.offset(leaseIP)
|
offset, inOffset := r.offset(leaseIP)
|
||||||
|
@ -352,7 +353,7 @@ func (s *v4Server) addLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// rmLease removes a lease with the same properties.
|
// rmLease removes a lease with the same properties.
|
||||||
func (s *v4Server) rmLease(lease *Lease) (err error) {
|
func (s *v4Server) rmLease(lease *dhcpsvc.Lease) (err error) {
|
||||||
if len(s.leases) == 0 {
|
if len(s.leases) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -378,7 +379,7 @@ const ErrUnconfigured errors.Error = "server is unconfigured"
|
||||||
|
|
||||||
// AddStaticLease implements the DHCPServer interface for *v4Server. It is
|
// AddStaticLease implements the DHCPServer interface for *v4Server. It is
|
||||||
// safe for concurrent use.
|
// safe for concurrent use.
|
||||||
func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
func (s *v4Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv4: adding static lease: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv4: adding static lease: %w") }()
|
||||||
|
|
||||||
if s.conf == nil {
|
if s.conf == nil {
|
||||||
|
@ -435,7 +436,7 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStaticLease updates IP, hostname of the static lease.
|
// UpdateStaticLease updates IP, hostname of the static lease.
|
||||||
func (s *v4Server) UpdateStaticLease(l *Lease) (err error) {
|
func (s *v4Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Annotate(err, "dhcpv4: updating static lease: %w")
|
err = errors.Annotate(err, "dhcpv4: updating static lease: %w")
|
||||||
|
@ -474,7 +475,7 @@ func (s *v4Server) UpdateStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateStaticLease returns an error if the static lease is invalid.
|
// validateStaticLease returns an error if the static lease is invalid.
|
||||||
func (s *v4Server) validateStaticLease(l *Lease) (err error) {
|
func (s *v4Server) validateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
hostname, err := normalizeHostname(l.Hostname)
|
hostname, err := normalizeHostname(l.Hostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't wrap the error, because it's informative enough as is.
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
|
@ -511,7 +512,7 @@ func (s *v4Server) validateStaticLease(l *Lease) (err error) {
|
||||||
|
|
||||||
// updateStaticLease safe removes dynamic lease with the same properties and
|
// updateStaticLease safe removes dynamic lease with the same properties and
|
||||||
// then adds a static lease l.
|
// then adds a static lease l.
|
||||||
func (s *v4Server) updateStaticLease(l *Lease) (err error) {
|
func (s *v4Server) updateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
|
@ -529,7 +530,7 @@ func (s *v4Server) updateStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
||||||
func (s *v4Server) RemoveStaticLease(l *Lease) (err error) {
|
func (s *v4Server) RemoveStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
|
||||||
|
|
||||||
if s.conf == nil {
|
if s.conf == nil {
|
||||||
|
@ -606,7 +607,7 @@ func (s *v4Server) addrAvailable(target net.IP) (avail bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// findLease finds a lease by its MAC-address.
|
// findLease finds a lease by its MAC-address.
|
||||||
func (s *v4Server) findLease(mac net.HardwareAddr) (l *Lease) {
|
func (s *v4Server) findLease(mac net.HardwareAddr) (l *dhcpsvc.Lease) {
|
||||||
for _, l = range s.leases {
|
for _, l = range s.leases {
|
||||||
if bytes.Equal(mac, l.HWAddr) {
|
if bytes.Equal(mac, l.HWAddr) {
|
||||||
return l
|
return l
|
||||||
|
@ -646,8 +647,8 @@ func (s *v4Server) findExpiredLease() int {
|
||||||
|
|
||||||
// reserveLease reserves a lease for a client by its MAC-address. It returns
|
// reserveLease reserves a lease for a client by its MAC-address. It returns
|
||||||
// nil if it couldn't allocate a new lease.
|
// nil if it couldn't allocate a new lease.
|
||||||
func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) {
|
func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err error) {
|
||||||
l = &Lease{HWAddr: slices.Clone(mac)}
|
l = &dhcpsvc.Lease{HWAddr: slices.Clone(mac)}
|
||||||
|
|
||||||
nextIP := s.nextIP()
|
nextIP := s.nextIP()
|
||||||
if nextIP == nil {
|
if nextIP == nil {
|
||||||
|
@ -679,7 +680,7 @@ func (s *v4Server) reserveLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||||
// commitLease refreshes l's values. It takes the desired hostname into account
|
// commitLease refreshes l's values. It takes the desired hostname into account
|
||||||
// when setting it into the lease, but generates a unique one if the provided
|
// when setting it into the lease, but generates a unique one if the provided
|
||||||
// can't be used.
|
// can't be used.
|
||||||
func (s *v4Server) commitLease(l *Lease, hostname string) {
|
func (s *v4Server) commitLease(l *dhcpsvc.Lease, hostname string) {
|
||||||
prev := l.Hostname
|
prev := l.Hostname
|
||||||
hostname = s.validHostnameForClient(hostname, l.IP)
|
hostname = s.validHostnameForClient(hostname, l.IP)
|
||||||
|
|
||||||
|
@ -709,7 +710,7 @@ func (s *v4Server) commitLease(l *Lease, hostname string) {
|
||||||
|
|
||||||
// allocateLease allocates a new lease for the MAC address. If there are no IP
|
// allocateLease allocates a new lease for the MAC address. If there are no IP
|
||||||
// addresses left, both l and err are nil.
|
// addresses left, both l and err are nil.
|
||||||
func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *Lease, err error) {
|
func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *dhcpsvc.Lease, err error) {
|
||||||
for {
|
for {
|
||||||
l, err = s.reserveLease(mac)
|
l, err = s.reserveLease(mac)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -728,7 +729,7 @@ func (s *v4Server) allocateLease(mac net.HardwareAddr) (l *Lease, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDiscover is the handler for the DHCP Discover request.
|
// handleDiscover is the handler for the DHCP Discover request.
|
||||||
func (s *v4Server) handleDiscover(req, resp *dhcpv4.DHCPv4) (l *Lease, err error) {
|
func (s *v4Server) handleDiscover(req, resp *dhcpv4.DHCPv4) (l *dhcpsvc.Lease, err error) {
|
||||||
mac := req.ClientHWAddr
|
mac := req.ClientHWAddr
|
||||||
|
|
||||||
defer s.conf.notify(LeaseChangedDBStore)
|
defer s.conf.notify(LeaseChangedDBStore)
|
||||||
|
@ -787,7 +788,7 @@ func OptionFQDN(fqdn string) (opt dhcpv4.Option) {
|
||||||
// checkLease checks if the pair of mac and ip is already leased. The mismatch
|
// checkLease checks if the pair of mac and ip is already leased. The mismatch
|
||||||
// is true when the existing lease has the same hardware address but differs in
|
// is true when the existing lease has the same hardware address but differs in
|
||||||
// its IP address.
|
// its IP address.
|
||||||
func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (lease *Lease, mismatch bool) {
|
func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (l *dhcpsvc.Lease, mismatch bool) {
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
|
@ -798,7 +799,7 @@ func (s *v4Server) checkLease(mac net.HardwareAddr, ip net.IP) (lease *Lease, mi
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range s.leases {
|
for _, l = range s.leases {
|
||||||
if !bytes.Equal(l.HWAddr, mac) {
|
if !bytes.Equal(l.HWAddr, mac) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -823,7 +824,7 @@ func (s *v4Server) handleSelecting(
|
||||||
req *dhcpv4.DHCPv4,
|
req *dhcpv4.DHCPv4,
|
||||||
reqIP net.IP,
|
reqIP net.IP,
|
||||||
sid net.IP,
|
sid net.IP,
|
||||||
) (l *Lease, needsReply bool) {
|
) (l *dhcpsvc.Lease, needsReply bool) {
|
||||||
// Client inserts the address of the selected server in server identifier,
|
// Client inserts the address of the selected server in server identifier,
|
||||||
// ciaddr MUST be zero.
|
// ciaddr MUST be zero.
|
||||||
mac := req.ClientHWAddr
|
mac := req.ClientHWAddr
|
||||||
|
@ -857,7 +858,10 @@ func (s *v4Server) handleSelecting(
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleInitReboot handles the DHCPREQUEST generated during INIT-REBOOT state.
|
// handleInitReboot handles the DHCPREQUEST generated during INIT-REBOOT state.
|
||||||
func (s *v4Server) handleInitReboot(req *dhcpv4.DHCPv4, reqIP net.IP) (l *Lease, needsReply bool) {
|
func (s *v4Server) handleInitReboot(
|
||||||
|
req *dhcpv4.DHCPv4,
|
||||||
|
reqIP net.IP,
|
||||||
|
) (l *dhcpsvc.Lease, needsReply bool) {
|
||||||
mac := req.ClientHWAddr
|
mac := req.ClientHWAddr
|
||||||
|
|
||||||
ip4 := reqIP.To4()
|
ip4 := reqIP.To4()
|
||||||
|
@ -899,7 +903,7 @@ func (s *v4Server) handleInitReboot(req *dhcpv4.DHCPv4, reqIP net.IP) (l *Lease,
|
||||||
|
|
||||||
// handleRenew handles the DHCPREQUEST generated during RENEWING or REBINDING
|
// handleRenew handles the DHCPREQUEST generated during RENEWING or REBINDING
|
||||||
// state.
|
// state.
|
||||||
func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *Lease, needsReply bool) {
|
func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *dhcpsvc.Lease, needsReply bool) {
|
||||||
mac := req.ClientHWAddr
|
mac := req.ClientHWAddr
|
||||||
|
|
||||||
// ciaddr MUST be filled in with client's IP address.
|
// ciaddr MUST be filled in with client's IP address.
|
||||||
|
@ -926,7 +930,7 @@ func (s *v4Server) handleRenew(req *dhcpv4.DHCPv4) (l *Lease, needsReply bool) {
|
||||||
|
|
||||||
// handleByRequestType handles the DHCPREQUEST according to the state during
|
// handleByRequestType handles the DHCPREQUEST according to the state during
|
||||||
// which it's generated by client.
|
// which it's generated by client.
|
||||||
func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *dhcpsvc.Lease, needsReply bool) {
|
||||||
reqIP, sid := req.RequestedIPAddress(), req.ServerIdentifier()
|
reqIP, sid := req.RequestedIPAddress(), req.ServerIdentifier()
|
||||||
|
|
||||||
if sid != nil && !sid.IsUnspecified() {
|
if sid != nil && !sid.IsUnspecified() {
|
||||||
|
@ -950,7 +954,7 @@ func (s *v4Server) handleByRequestType(req *dhcpv4.DHCPv4) (lease *Lease, needsR
|
||||||
// handleRequest is the handler for a DHCPREQUEST message.
|
// handleRequest is the handler for a DHCPREQUEST message.
|
||||||
//
|
//
|
||||||
// See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.2.
|
// See https://datatracker.ietf.org/doc/html/rfc2131#section-4.3.2.
|
||||||
func (s *v4Server) handleRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
func (s *v4Server) handleRequest(req, resp *dhcpv4.DHCPv4) (lease *dhcpsvc.Lease, needsReply bool) {
|
||||||
lease, needsReply = s.handleByRequestType(req)
|
lease, needsReply = s.handleByRequestType(req)
|
||||||
if lease == nil {
|
if lease == nil {
|
||||||
return nil, needsReply
|
return nil, needsReply
|
||||||
|
@ -1043,7 +1047,7 @@ func (s *v4Server) handleDecline(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// findLeaseForIP returns a lease for provided ip and mac.
|
// findLeaseForIP returns a lease for provided ip and mac.
|
||||||
func (s *v4Server) findLeaseForIP(ip net.IP, mac net.HardwareAddr) (l *Lease) {
|
func (s *v4Server) findLeaseForIP(ip net.IP, mac net.HardwareAddr) (l *dhcpsvc.Lease) {
|
||||||
netIP, ok := netip.AddrFromSlice(ip)
|
netIP, ok := netip.AddrFromSlice(ip)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Info("dhcpv4: invalid IP: %s", ip)
|
log.Info("dhcpv4: invalid IP: %s", ip)
|
||||||
|
@ -1106,7 +1110,11 @@ func (s *v4Server) handleRelease(req, resp *dhcpv4.DHCPv4) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// messageHandler describes a DHCPv4 message handler function.
|
// messageHandler describes a DHCPv4 message handler function.
|
||||||
type messageHandler func(s *v4Server, req, resp *dhcpv4.DHCPv4) (rCode int, l *Lease, err error)
|
type messageHandler func(
|
||||||
|
s *v4Server,
|
||||||
|
req *dhcpv4.DHCPv4,
|
||||||
|
resp *dhcpv4.DHCPv4,
|
||||||
|
) (rCode int, l *dhcpsvc.Lease, err error)
|
||||||
|
|
||||||
// messageHandlers is a map of handlers for various messages with message types
|
// messageHandlers is a map of handlers for various messages with message types
|
||||||
// keys.
|
// keys.
|
||||||
|
@ -1115,7 +1123,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||||
s *v4Server,
|
s *v4Server,
|
||||||
req *dhcpv4.DHCPv4,
|
req *dhcpv4.DHCPv4,
|
||||||
resp *dhcpv4.DHCPv4,
|
resp *dhcpv4.DHCPv4,
|
||||||
) (rCode int, l *Lease, err error) {
|
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||||
l, err = s.handleDiscover(req, resp)
|
l, err = s.handleDiscover(req, resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("handling discover: %s", err)
|
return 0, nil, fmt.Errorf("handling discover: %s", err)
|
||||||
|
@ -1131,7 +1139,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||||
s *v4Server,
|
s *v4Server,
|
||||||
req *dhcpv4.DHCPv4,
|
req *dhcpv4.DHCPv4,
|
||||||
resp *dhcpv4.DHCPv4,
|
resp *dhcpv4.DHCPv4,
|
||||||
) (rCode int, l *Lease, err error) {
|
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||||
var toReply bool
|
var toReply bool
|
||||||
l, toReply = s.handleRequest(req, resp)
|
l, toReply = s.handleRequest(req, resp)
|
||||||
if l == nil {
|
if l == nil {
|
||||||
|
@ -1149,7 +1157,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||||
s *v4Server,
|
s *v4Server,
|
||||||
req *dhcpv4.DHCPv4,
|
req *dhcpv4.DHCPv4,
|
||||||
resp *dhcpv4.DHCPv4,
|
resp *dhcpv4.DHCPv4,
|
||||||
) (rCode int, l *Lease, err error) {
|
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||||
err = s.handleDecline(req, resp)
|
err = s.handleDecline(req, resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("handling decline: %s", err)
|
return 0, nil, fmt.Errorf("handling decline: %s", err)
|
||||||
|
@ -1161,7 +1169,7 @@ var messageHandlers = map[dhcpv4.MessageType]messageHandler{
|
||||||
s *v4Server,
|
s *v4Server,
|
||||||
req *dhcpv4.DHCPv4,
|
req *dhcpv4.DHCPv4,
|
||||||
resp *dhcpv4.DHCPv4,
|
resp *dhcpv4.DHCPv4,
|
||||||
) (rCode int, l *Lease, err error) {
|
) (rCode int, l *dhcpsvc.Lease, err error) {
|
||||||
err = s.handleRelease(req, resp)
|
err = s.handleRelease(req, resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("handling release: %s", err)
|
return 0, nil, fmt.Errorf("handling release: %s", err)
|
||||||
|
@ -1402,8 +1410,8 @@ func (s *v4Server) Stop() (err error) {
|
||||||
// Create DHCPv4 server
|
// Create DHCPv4 server
|
||||||
func v4Create(conf *V4ServerConf) (srv *v4Server, err error) {
|
func v4Create(conf *V4ServerConf) (srv *v4Server, err error) {
|
||||||
s := &v4Server{
|
s := &v4Server{
|
||||||
hostsIndex: map[string]*Lease{},
|
hostsIndex: map[string]*dhcpsvc.Lease{},
|
||||||
ipIndex: map[netip.Addr]*Lease{},
|
ipIndex: map[netip.Addr]*dhcpsvc.Lease{},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = conf.Validate()
|
err = conf.Validate()
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/AdguardTeam/golibs/stringutil"
|
"github.com/AdguardTeam/golibs/stringutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
|
@ -67,7 +68,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||||
s := defaultSrv(t)
|
s := defaultSrv(t)
|
||||||
|
|
||||||
t.Run("add_static", func(t *testing.T) {
|
t.Run("add_static", func(t *testing.T) {
|
||||||
err := s.AddStaticLease(&Lease{
|
err := s.AddStaticLease(&dhcpsvc.Lease{
|
||||||
Hostname: staticName,
|
Hostname: staticName,
|
||||||
HWAddr: staticMAC,
|
HWAddr: staticMAC,
|
||||||
IP: staticIP,
|
IP: staticIP,
|
||||||
|
@ -76,7 +77,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("same_name", func(t *testing.T) {
|
t.Run("same_name", func(t *testing.T) {
|
||||||
err = s.AddStaticLease(&Lease{
|
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||||
Hostname: staticName,
|
Hostname: staticName,
|
||||||
HWAddr: anotherMAC,
|
HWAddr: anotherMAC,
|
||||||
IP: anotherIP,
|
IP: anotherIP,
|
||||||
|
@ -90,7 +91,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||||
"dynamic leases for " + anotherIP.String() +
|
"dynamic leases for " + anotherIP.String() +
|
||||||
" (" + staticMAC.String() + "): static lease already exists"
|
" (" + staticMAC.String() + "): static lease already exists"
|
||||||
|
|
||||||
err = s.AddStaticLease(&Lease{
|
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||||
Hostname: anotherName,
|
Hostname: anotherName,
|
||||||
HWAddr: staticMAC,
|
HWAddr: staticMAC,
|
||||||
IP: anotherIP,
|
IP: anotherIP,
|
||||||
|
@ -104,7 +105,7 @@ func TestV4Server_leasing(t *testing.T) {
|
||||||
"dynamic leases for " + staticIP.String() +
|
"dynamic leases for " + staticIP.String() +
|
||||||
" (" + anotherMAC.String() + "): static lease already exists"
|
" (" + anotherMAC.String() + "): static lease already exists"
|
||||||
|
|
||||||
err = s.AddStaticLease(&Lease{
|
err = s.AddStaticLease(&dhcpsvc.Lease{
|
||||||
Hostname: anotherName,
|
Hostname: anotherName,
|
||||||
HWAddr: anotherMAC,
|
HWAddr: anotherMAC,
|
||||||
IP: staticIP,
|
IP: staticIP,
|
||||||
|
@ -208,11 +209,11 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
require.Empty(t, ls)
|
require.Empty(t, ls)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
lease *Lease
|
lease *dhcpsvc.Lease
|
||||||
name string
|
name string
|
||||||
wantErrMsg string
|
wantErrMsg string
|
||||||
}{{
|
}{{
|
||||||
lease: &Lease{
|
lease: &dhcpsvc.Lease{
|
||||||
Hostname: "success.local",
|
Hostname: "success.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -220,7 +221,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
name: "success",
|
name: "success",
|
||||||
wantErrMsg: "",
|
wantErrMsg: "",
|
||||||
}, {
|
}, {
|
||||||
lease: &Lease{
|
lease: &dhcpsvc.Lease{
|
||||||
Hostname: "probably-router.local",
|
Hostname: "probably-router.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: DefaultGatewayIP,
|
IP: DefaultGatewayIP,
|
||||||
|
@ -229,7 +230,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
wantErrMsg: "dhcpv4: adding static lease: " +
|
wantErrMsg: "dhcpv4: adding static lease: " +
|
||||||
`can't assign the gateway IP "192.168.10.1" to the lease`,
|
`can't assign the gateway IP "192.168.10.1" to the lease`,
|
||||||
}, {
|
}, {
|
||||||
lease: &Lease{
|
lease: &dhcpsvc.Lease{
|
||||||
Hostname: "ip6.local",
|
Hostname: "ip6.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("ffff::1"),
|
IP: netip.MustParseAddr("ffff::1"),
|
||||||
|
@ -238,7 +239,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
wantErrMsg: `dhcpv4: adding static lease: ` +
|
wantErrMsg: `dhcpv4: adding static lease: ` +
|
||||||
`invalid IP "ffff::1": only IPv4 is supported`,
|
`invalid IP "ffff::1": only IPv4 is supported`,
|
||||||
}, {
|
}, {
|
||||||
lease: &Lease{
|
lease: &dhcpsvc.Lease{
|
||||||
Hostname: "bad-mac.local",
|
Hostname: "bad-mac.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -247,7 +248,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
wantErrMsg: `dhcpv4: adding static lease: bad mac address "aa:aa": ` +
|
wantErrMsg: `dhcpv4: adding static lease: bad mac address "aa:aa": ` +
|
||||||
`bad mac address length 2, allowed: [6 8 20]`,
|
`bad mac address length 2, allowed: [6 8 20]`,
|
||||||
}, {
|
}, {
|
||||||
lease: &Lease{
|
lease: &dhcpsvc.Lease{
|
||||||
Hostname: "bad-lbl-.local",
|
Hostname: "bad-lbl-.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -266,7 +267,7 @@ func TestV4Server_AddRemove_static(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.RemoveStaticLease(&Lease{
|
err = s.RemoveStaticLease(&dhcpsvc.Lease{
|
||||||
IP: tc.lease.IP,
|
IP: tc.lease.IP,
|
||||||
HWAddr: tc.lease.HWAddr,
|
HWAddr: tc.lease.HWAddr,
|
||||||
})
|
})
|
||||||
|
@ -289,7 +290,7 @@ func TestV4_AddReplace(t *testing.T) {
|
||||||
s, ok := sIface.(*v4Server)
|
s, ok := sIface.(*v4Server)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
dynLeases := []Lease{{
|
dynLeases := []dhcpsvc.Lease{{
|
||||||
Hostname: "dynamic-1.local",
|
Hostname: "dynamic-1.local",
|
||||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -304,7 +305,7 @@ func TestV4_AddReplace(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stLeases := []*Lease{{
|
stLeases := []*dhcpsvc.Lease{{
|
||||||
Hostname: "static-1.local",
|
Hostname: "static-1.local",
|
||||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -513,7 +514,7 @@ func TestV4StaticLease_Get(t *testing.T) {
|
||||||
s.conf.dnsIPAddrs = []netip.Addr{dnsAddr}
|
s.conf.dnsIPAddrs = []netip.Addr{dnsAddr}
|
||||||
s.implicitOpts.Update(dhcpv4.OptDNS(dnsAddr.AsSlice()))
|
s.implicitOpts.Update(dhcpv4.OptDNS(dnsAddr.AsSlice()))
|
||||||
|
|
||||||
l := &Lease{
|
l := &dhcpsvc.Lease{
|
||||||
Hostname: "static-1.local",
|
Hostname: "static-1.local",
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: netip.MustParseAddr("192.168.10.150"),
|
IP: netip.MustParseAddr("192.168.10.150"),
|
||||||
|
@ -779,7 +780,7 @@ func TestV4Server_FindMACbyIP(t *testing.T) {
|
||||||
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
||||||
|
|
||||||
s := &v4Server{
|
s := &v4Server{
|
||||||
leases: []*Lease{{
|
leases: []*dhcpsvc.Lease{{
|
||||||
Hostname: staticName,
|
Hostname: staticName,
|
||||||
HWAddr: staticMAC,
|
HWAddr: staticMAC,
|
||||||
IP: staticIP,
|
IP: staticIP,
|
||||||
|
@ -791,11 +792,11 @@ func TestV4Server_FindMACbyIP(t *testing.T) {
|
||||||
IP: anotherIP,
|
IP: anotherIP,
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
s.ipIndex = map[netip.Addr]*Lease{
|
s.ipIndex = map[netip.Addr]*dhcpsvc.Lease{
|
||||||
staticIP: s.leases[0],
|
staticIP: s.leases[0],
|
||||||
anotherIP: s.leases[1],
|
anotherIP: s.leases[1],
|
||||||
}
|
}
|
||||||
s.hostsIndex = map[string]*Lease{
|
s.hostsIndex = map[string]*dhcpsvc.Lease{
|
||||||
staticName: s.leases[0],
|
staticName: s.leases[0],
|
||||||
anotherName: s.leases[1],
|
anotherName: s.leases[1],
|
||||||
}
|
}
|
||||||
|
@ -845,7 +846,7 @@ func TestV4Server_handleDecline(t *testing.T) {
|
||||||
s4, ok := s.(*v4Server)
|
s4, ok := s.(*v4Server)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
s4.leases = []*Lease{{
|
s4.leases = []*dhcpsvc.Lease{{
|
||||||
Hostname: dynamicName,
|
Hostname: dynamicName,
|
||||||
HWAddr: dynamicMAC,
|
HWAddr: dynamicMAC,
|
||||||
IP: dynamicIP,
|
IP: dynamicIP,
|
||||||
|
@ -887,7 +888,7 @@ func TestV4Server_handleRelease(t *testing.T) {
|
||||||
s4, ok := s.(*v4Server)
|
s4, ok := s.(*v4Server)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
s4.leases = []*Lease{{
|
s4.leases = []*dhcpsvc.Lease{{
|
||||||
Hostname: dynamicName,
|
Hostname: dynamicName,
|
||||||
HWAddr: dynamicMAC,
|
HWAddr: dynamicMAC,
|
||||||
IP: dynamicIP,
|
IP: dynamicIP,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
@ -31,7 +32,7 @@ type v6Server struct {
|
||||||
sid dhcpv6.DUID
|
sid dhcpv6.DUID
|
||||||
srv *server6.Server
|
srv *server6.Server
|
||||||
|
|
||||||
leases []*Lease
|
leases []*dhcpsvc.Lease
|
||||||
leasesLock sync.Mutex
|
leasesLock sync.Mutex
|
||||||
ipAddrs [256]byte
|
ipAddrs [256]byte
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,7 @@ func (s *v6Server) IPByHost(host string) (ip netip.Addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetLeases resets leases.
|
// ResetLeases resets leases.
|
||||||
func (s *v6Server) ResetLeases(leases []*Lease) (err error) {
|
func (s *v6Server) ResetLeases(leases []*dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||||
|
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
|
@ -111,12 +112,14 @@ func (s *v6Server) ResetLeases(leases []*Lease) (err error) {
|
||||||
|
|
||||||
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
// GetLeases returns the list of current DHCP leases. It is safe for concurrent
|
||||||
// use.
|
// use.
|
||||||
func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*dhcpsvc.Lease) {
|
||||||
// The function shouldn't return nil value because zero-length slice
|
// The function shouldn't return nil value because zero-length slice
|
||||||
// behaves differently in cases like marshalling. Our front-end also
|
// behaves differently in cases like marshalling. Our front-end also
|
||||||
// requires non-nil value in the response.
|
// requires non-nil value in the response.
|
||||||
leases = []*Lease{}
|
leases = []*dhcpsvc.Lease{}
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
for _, l := range s.leases {
|
for _, l := range s.leases {
|
||||||
if l.IsStatic {
|
if l.IsStatic {
|
||||||
if (flags & LeasesStatic) != 0 {
|
if (flags & LeasesStatic) != 0 {
|
||||||
|
@ -128,12 +131,12 @@ func (s *v6Server) GetLeases(flags GetLeasesFlags) (leases []*Lease) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.leasesLock.Unlock()
|
|
||||||
return leases
|
return leases
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLeasesRef returns the actual leases slice. For internal use only.
|
// getLeasesRef returns the actual leases slice. For internal use only.
|
||||||
func (s *v6Server) getLeasesRef() []*Lease {
|
func (s *v6Server) getLeasesRef() []*dhcpsvc.Lease {
|
||||||
return s.leases
|
return s.leases
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +177,7 @@ func (s *v6Server) leaseRemoveSwapByIndex(i int) {
|
||||||
|
|
||||||
// Remove a dynamic lease with the same properties
|
// Remove a dynamic lease with the same properties
|
||||||
// Return error if a static lease is found
|
// Return error if a static lease is found
|
||||||
func (s *v6Server) rmDynamicLease(lease *Lease) (err error) {
|
func (s *v6Server) rmDynamicLease(lease *dhcpsvc.Lease) (err error) {
|
||||||
for i := 0; i < len(s.leases); i++ {
|
for i := 0; i < len(s.leases); i++ {
|
||||||
l := s.leases[i]
|
l := s.leases[i]
|
||||||
|
|
||||||
|
@ -204,7 +207,7 @@ func (s *v6Server) rmDynamicLease(lease *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddStaticLease adds a static lease. It is safe for concurrent use.
|
// AddStaticLease adds a static lease. It is safe for concurrent use.
|
||||||
func (s *v6Server) AddStaticLease(l *Lease) (err error) {
|
func (s *v6Server) AddStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||||
|
|
||||||
if !l.IP.Is6() {
|
if !l.IP.Is6() {
|
||||||
|
@ -236,7 +239,7 @@ func (s *v6Server) AddStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStaticLease updates IP, hostname of the static lease.
|
// UpdateStaticLease updates IP, hostname of the static lease.
|
||||||
func (s *v6Server) UpdateStaticLease(l *Lease) (err error) {
|
func (s *v6Server) UpdateStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Annotate(err, "dhcpv6: updating static lease: %w")
|
err = errors.Annotate(err, "dhcpv6: updating static lease: %w")
|
||||||
|
@ -267,7 +270,7 @@ func (s *v6Server) UpdateStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
// RemoveStaticLease removes a static lease. It is safe for concurrent use.
|
||||||
func (s *v6Server) RemoveStaticLease(l *Lease) (err error) {
|
func (s *v6Server) RemoveStaticLease(l *dhcpsvc.Lease) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
|
||||||
|
|
||||||
if !l.IP.Is6() {
|
if !l.IP.Is6() {
|
||||||
|
@ -292,7 +295,7 @@ func (s *v6Server) RemoveStaticLease(l *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a lease
|
// Add a lease
|
||||||
func (s *v6Server) addLease(l *Lease) {
|
func (s *v6Server) addLease(l *dhcpsvc.Lease) {
|
||||||
s.leases = append(s.leases, l)
|
s.leases = append(s.leases, l)
|
||||||
ip := l.IP.As16()
|
ip := l.IP.As16()
|
||||||
s.ipAddrs[ip[15]] = 1
|
s.ipAddrs[ip[15]] = 1
|
||||||
|
@ -300,7 +303,7 @@ func (s *v6Server) addLease(l *Lease) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a lease with the same properties
|
// Remove a lease with the same properties
|
||||||
func (s *v6Server) rmLease(lease *Lease) (err error) {
|
func (s *v6Server) rmLease(lease *dhcpsvc.Lease) (err error) {
|
||||||
for i, l := range s.leases {
|
for i, l := range s.leases {
|
||||||
if l.IP == lease.IP {
|
if l.IP == lease.IP {
|
||||||
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
|
if !bytes.Equal(l.HWAddr, lease.HWAddr) ||
|
||||||
|
@ -318,7 +321,7 @@ func (s *v6Server) rmLease(lease *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find lease by MAC.
|
// Find lease by MAC.
|
||||||
func (s *v6Server) findLease(mac net.HardwareAddr) (lease *Lease) {
|
func (s *v6Server) findLease(mac net.HardwareAddr) (lease *dhcpsvc.Lease) {
|
||||||
for i := range s.leases {
|
for i := range s.leases {
|
||||||
if bytes.Equal(mac, s.leases[i].HWAddr) {
|
if bytes.Equal(mac, s.leases[i].HWAddr) {
|
||||||
return s.leases[i]
|
return s.leases[i]
|
||||||
|
@ -356,8 +359,8 @@ func (s *v6Server) findFreeIP() net.IP {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve lease for MAC
|
// Reserve lease for MAC
|
||||||
func (s *v6Server) reserveLease(mac net.HardwareAddr) *Lease {
|
func (s *v6Server) reserveLease(mac net.HardwareAddr) *dhcpsvc.Lease {
|
||||||
l := Lease{
|
l := dhcpsvc.Lease{
|
||||||
HWAddr: make([]byte, len(mac)),
|
HWAddr: make([]byte, len(mac)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +393,7 @@ func (s *v6Server) reserveLease(mac net.HardwareAddr) *Lease {
|
||||||
return &l
|
return &l
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *v6Server) commitDynamicLease(l *Lease) {
|
func (s *v6Server) commitDynamicLease(l *dhcpsvc.Lease) {
|
||||||
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
l.Expiry = time.Now().Add(s.conf.leaseTime)
|
||||||
|
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
|
@ -438,7 +441,7 @@ func (s *v6Server) checkSID(msg *dhcpv6.Message) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// . IAAddress must be equal to the lease's IP
|
// . IAAddress must be equal to the lease's IP
|
||||||
func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *Lease) error {
|
func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *dhcpsvc.Lease) error {
|
||||||
switch msg.Type() {
|
switch msg.Type() {
|
||||||
case dhcpv6.MessageTypeRequest,
|
case dhcpv6.MessageTypeRequest,
|
||||||
dhcpv6.MessageTypeConfirm,
|
dhcpv6.MessageTypeConfirm,
|
||||||
|
@ -464,7 +467,7 @@ func (s *v6Server) checkIA(msg *dhcpv6.Message, lease *Lease) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store lease in DB (if necessary) and return lease life time
|
// Store lease in DB (if necessary) and return lease life time
|
||||||
func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *Lease) time.Duration {
|
func (s *v6Server) commitLease(msg *dhcpv6.Message, lease *dhcpsvc.Lease) time.Duration {
|
||||||
lifetime := s.conf.leaseTime
|
lifetime := s.conf.leaseTime
|
||||||
|
|
||||||
switch msg.Type() {
|
switch msg.Type() {
|
||||||
|
@ -506,7 +509,7 @@ func (s *v6Server) process(msg *dhcpv6.Message, req, resp dhcpv6.DHCPv6) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var lease *Lease
|
var lease *dhcpsvc.Lease
|
||||||
func() {
|
func() {
|
||||||
s.leasesLock.Lock()
|
s.leasesLock.Lock()
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/dhcpsvc"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||||
"github.com/insomniacslk/dhcp/iana"
|
"github.com/insomniacslk/dhcp/iana"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -28,7 +29,7 @@ func TestV6_AddRemove_static(t *testing.T) {
|
||||||
require.Empty(t, s.GetLeases(LeasesStatic))
|
require.Empty(t, s.GetLeases(LeasesStatic))
|
||||||
|
|
||||||
// Add static lease.
|
// Add static lease.
|
||||||
l := &Lease{
|
l := &dhcpsvc.Lease{
|
||||||
IP: netip.MustParseAddr("2001::1"),
|
IP: netip.MustParseAddr("2001::1"),
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ func TestV6_AddRemove_static(t *testing.T) {
|
||||||
assert.True(t, ls[0].IsStatic)
|
assert.True(t, ls[0].IsStatic)
|
||||||
|
|
||||||
// Try to remove non-existent static lease.
|
// Try to remove non-existent static lease.
|
||||||
err = s.RemoveStaticLease(&Lease{
|
err = s.RemoveStaticLease(&dhcpsvc.Lease{
|
||||||
IP: netip.MustParseAddr("2001::2"),
|
IP: netip.MustParseAddr("2001::2"),
|
||||||
HWAddr: l.HWAddr,
|
HWAddr: l.HWAddr,
|
||||||
})
|
})
|
||||||
|
@ -72,7 +73,7 @@ func TestV6_AddReplace(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
// Add dynamic leases.
|
// Add dynamic leases.
|
||||||
dynLeases := []*Lease{{
|
dynLeases := []*dhcpsvc.Lease{{
|
||||||
IP: netip.MustParseAddr("2001::1"),
|
IP: netip.MustParseAddr("2001::1"),
|
||||||
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0x11, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
}, {
|
}, {
|
||||||
|
@ -84,7 +85,7 @@ func TestV6_AddReplace(t *testing.T) {
|
||||||
s.addLease(l)
|
s.addLease(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
stLeases := []*Lease{{
|
stLeases := []*dhcpsvc.Lease{{
|
||||||
IP: netip.MustParseAddr("2001::1"),
|
IP: netip.MustParseAddr("2001::1"),
|
||||||
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0x33, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
}, {
|
}, {
|
||||||
|
@ -126,7 +127,7 @@ func TestV6GetLease(t *testing.T) {
|
||||||
LinkLayerAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
LinkLayerAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
}
|
}
|
||||||
|
|
||||||
l := &Lease{
|
l := &dhcpsvc.Lease{
|
||||||
IP: netip.MustParseAddr("2001::1"),
|
IP: netip.MustParseAddr("2001::1"),
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
}
|
}
|
||||||
|
@ -324,7 +325,7 @@ func TestV6_FindMACbyIP(t *testing.T) {
|
||||||
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
anotherMAC := net.HardwareAddr{0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB}
|
||||||
|
|
||||||
s := &v6Server{
|
s := &v6Server{
|
||||||
leases: []*Lease{{
|
leases: []*dhcpsvc.Lease{{
|
||||||
Hostname: staticName,
|
Hostname: staticName,
|
||||||
HWAddr: staticMAC,
|
HWAddr: staticMAC,
|
||||||
IP: staticIP,
|
IP: staticIP,
|
||||||
|
@ -337,7 +338,7 @@ func TestV6_FindMACbyIP(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
s.leases = []*Lease{{
|
s.leases = []*dhcpsvc.Lease{{
|
||||||
Hostname: staticName,
|
Hostname: staticName,
|
||||||
HWAddr: staticMAC,
|
HWAddr: staticMAC,
|
||||||
IP: staticIP,
|
IP: staticIP,
|
||||||
|
|
|
@ -43,7 +43,7 @@ func (conf *Config) Validate() (err error) {
|
||||||
case !conf.Enabled:
|
case !conf.Enabled:
|
||||||
return nil
|
return nil
|
||||||
case conf.ICMPTimeout < 0:
|
case conf.ICMPTimeout < 0:
|
||||||
return fmt.Errorf("icmp timeout %s must be non-negative", conf.ICMPTimeout)
|
return newMustErr("icmp timeout", "be non-negative", conf.ICMPTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = netutil.ValidateDomainName(conf.LocalDomainName)
|
err = netutil.ValidateDomainName(conf.LocalDomainName)
|
||||||
|
@ -68,9 +68,9 @@ func (conf *Config) Validate() (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mustBeErr returns an error that indicates that valName must be as must
|
// newMustErr returns an error that indicates that valName must be as must
|
||||||
// describes.
|
// describes.
|
||||||
func mustBeErr(valName, must string, val fmt.Stringer) (err error) {
|
func newMustErr(valName, must string, val fmt.Stringer) (err error) {
|
||||||
return fmt.Errorf("%s %s must %s", valName, val, must)
|
return fmt.Errorf("%s %s must %s", valName, val, must)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lease is a DHCP lease.
|
// Lease is a DHCP lease.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Consider it to [agh], since it also may be needed in
|
// TODO(e.burkov): Consider moving it to [agh], since it also may be needed in
|
||||||
// [websvc]. Also think of implementing iterating methods with appropriate
|
// [websvc].
|
||||||
// signatures.
|
|
||||||
type Lease struct {
|
type Lease struct {
|
||||||
// IP is the IP address leased to the client.
|
// IP is the IP address leased to the client.
|
||||||
IP netip.Addr
|
IP netip.Addr
|
||||||
|
@ -34,6 +34,21 @@ type Lease struct {
|
||||||
IsStatic bool
|
IsStatic bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of l.
|
||||||
|
func (l *Lease) Clone() (clone *Lease) {
|
||||||
|
if l == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Lease{
|
||||||
|
Expiry: l.Expiry,
|
||||||
|
Hostname: l.Hostname,
|
||||||
|
HWAddr: slices.Clone(l.HWAddr),
|
||||||
|
IP: l.IP,
|
||||||
|
IsStatic: l.IsStatic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Interface interface {
|
type Interface interface {
|
||||||
agh.ServiceWithConfig[*Config]
|
agh.ServiceWithConfig[*Config]
|
||||||
|
|
||||||
|
@ -57,6 +72,9 @@ type Interface interface {
|
||||||
IPByHost(host string) (ip netip.Addr)
|
IPByHost(host string) (ip netip.Addr)
|
||||||
|
|
||||||
// Leases returns all the active DHCP leases.
|
// Leases returns all the active DHCP leases.
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Consider implementing iterating methods with appropriate
|
||||||
|
// signatures instead of cloning the whole list.
|
||||||
Leases() (ls []*Lease)
|
Leases() (ls []*Lease)
|
||||||
|
|
||||||
// AddLease adds a new DHCP lease. It returns an error if the lease is
|
// AddLease adds a new DHCP lease. It returns an error if the lease is
|
||||||
|
@ -91,6 +109,9 @@ func (Empty) Shutdown(_ context.Context) (err error) { return nil }
|
||||||
// Config implements the [ServiceWithConfig] interface for Empty.
|
// Config implements the [ServiceWithConfig] interface for Empty.
|
||||||
func (Empty) Config() (conf *Config) { return nil }
|
func (Empty) Config() (conf *Config) { return nil }
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ Interface = Empty{}
|
||||||
|
|
||||||
// Enabled implements the [Interface] interface for Empty.
|
// Enabled implements the [Interface] interface for Empty.
|
||||||
func (Empty) Enabled() (ok bool) { return false }
|
func (Empty) Enabled() (ok bool) { return false }
|
||||||
|
|
||||||
|
@ -103,9 +124,6 @@ func (Empty) MACByIP(_ netip.Addr) (mac net.HardwareAddr) { return nil }
|
||||||
// IPByHost implements the [Interface] interface for Empty.
|
// IPByHost implements the [Interface] interface for Empty.
|
||||||
func (Empty) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
func (Empty) IPByHost(_ string) (ip netip.Addr) { return netip.Addr{} }
|
||||||
|
|
||||||
// type check
|
|
||||||
var _ Interface = Empty{}
|
|
||||||
|
|
||||||
// Leases implements the [Interface] interface for Empty.
|
// Leases implements the [Interface] interface for Empty.
|
||||||
func (Empty) Leases() (leases []*Lease) { return nil }
|
func (Empty) Leases() (leases []*Lease) { return nil }
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ type DHCPServer struct {
|
||||||
// interfaces6 is the set of IPv6 interfaces sorted by interface name.
|
// interfaces6 is the set of IPv6 interfaces sorted by interface name.
|
||||||
interfaces6 []*iface6
|
interfaces6 []*iface6
|
||||||
|
|
||||||
|
// leases is the set of active DHCP leases.
|
||||||
|
leases []*Lease
|
||||||
|
|
||||||
// icmpTimeout is the timeout for checking another DHCP server's presence.
|
// icmpTimeout is the timeout for checking another DHCP server's presence.
|
||||||
icmpTimeout time.Duration
|
icmpTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
@ -75,3 +78,23 @@ func New(conf *Config) (srv *DHCPServer, err error) {
|
||||||
icmpTimeout: conf.ICMPTimeout,
|
icmpTimeout: conf.ICMPTimeout,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// type check
|
||||||
|
//
|
||||||
|
// TODO(e.burkov): Uncomment when the [Interface] interface is implemented.
|
||||||
|
// var _ Interface = (*DHCPServer)(nil)
|
||||||
|
|
||||||
|
// Enabled implements the [Interface] interface for *DHCPServer.
|
||||||
|
func (srv *DHCPServer) Enabled() (ok bool) {
|
||||||
|
return srv.enabled.Load()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leases implements the [Interface] interface for *DHCPServer.
|
||||||
|
func (srv *DHCPServer) Leases() (leases []*Lease) {
|
||||||
|
leases = make([]*Lease, 0, len(srv.leases))
|
||||||
|
for _, lease := range srv.leases {
|
||||||
|
leases = append(leases, lease.Clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
return leases
|
||||||
|
}
|
||||||
|
|
|
@ -45,15 +45,15 @@ func (conf *IPv4Config) validate() (err error) {
|
||||||
case !conf.Enabled:
|
case !conf.Enabled:
|
||||||
return nil
|
return nil
|
||||||
case !conf.GatewayIP.Is4():
|
case !conf.GatewayIP.Is4():
|
||||||
return mustBeErr("gateway ip", "be a valid ipv4", conf.GatewayIP)
|
return newMustErr("gateway ip", "be a valid ipv4", conf.GatewayIP)
|
||||||
case !conf.SubnetMask.Is4():
|
case !conf.SubnetMask.Is4():
|
||||||
return mustBeErr("subnet mask", "be a valid ipv4 cidr mask", conf.SubnetMask)
|
return newMustErr("subnet mask", "be a valid ipv4 cidr mask", conf.SubnetMask)
|
||||||
case !conf.RangeStart.Is4():
|
case !conf.RangeStart.Is4():
|
||||||
return mustBeErr("range start", "be a valid ipv4", conf.RangeStart)
|
return newMustErr("range start", "be a valid ipv4", conf.RangeStart)
|
||||||
case !conf.RangeEnd.Is4():
|
case !conf.RangeEnd.Is4():
|
||||||
return mustBeErr("range end", "be a valid ipv4", conf.RangeEnd)
|
return newMustErr("range end", "be a valid ipv4", conf.RangeEnd)
|
||||||
case conf.LeaseDuration <= 0:
|
case conf.LeaseDuration <= 0:
|
||||||
return mustBeErr("lease duration", "be less than %d", conf.LeaseDuration)
|
return newMustErr("lease duration", "be less than %d", conf.LeaseDuration)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,7 +314,7 @@ func TestClientsAddExisting(t *testing.T) {
|
||||||
|
|
||||||
clients.dhcp = dhcpServer
|
clients.dhcp = dhcpServer
|
||||||
|
|
||||||
err = dhcpServer.AddStaticLease(&dhcpd.Lease{
|
err = dhcpServer.AddStaticLease(&dhcpsvc.Lease{
|
||||||
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
|
||||||
IP: ip,
|
IP: ip,
|
||||||
Hostname: "testhost",
|
Hostname: "testhost",
|
||||||
|
|
Loading…
Reference in New Issue