mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-20 14:01:50 +03:00
6fd0a624ca
Updates #4923.
Squashed commit of the following:
commit 0f90eb3596fcbca0d87cb4eb857d45aea26f3854
Merge: 38b3165b6 bd99e3e09
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Mon Feb 19 20:11:38 2024 +0300
Merge branch 'master' into 4923-gopacket-dhcp-vol.7
commit 38b3165b696c9a3f69484d8e4c2c847340ed9363
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Mon Feb 19 14:52:01 2024 +0300
dhcpsvc: imp docs
commit 0a078920a20de9fb2d864c90d2311800c6f3bc3f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Mon Feb 19 14:48:19 2024 +0300
dhcpsvc: imp code
commit 30691f0d989c48b2f0dff8079952615dbfbdaea1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Feb 15 19:57:41 2024 +0300
dhcpsvc: imp code, dry
commit 20f5ef80fb2d1cad869883da3684a01e5b8b3315
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Feb 15 15:57:09 2024 +0300
dhcpsvc: finish leases methods
126 lines
3.3 KiB
Go
126 lines
3.3 KiB
Go
package dhcpsvc
|
|
|
|
import (
|
|
"fmt"
|
|
"net/netip"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
// leaseIndex is the set of leases indexed by their identifiers for quick
|
|
// lookup.
|
|
type leaseIndex struct {
|
|
// byAddr is a lookup shortcut for leases by their IP addresses.
|
|
byAddr map[netip.Addr]*Lease
|
|
|
|
// byName is a lookup shortcut for leases by their hostnames.
|
|
//
|
|
// TODO(e.burkov): Use a slice of leases with the same hostname?
|
|
byName map[string]*Lease
|
|
}
|
|
|
|
// newLeaseIndex returns a new index for [Lease]s.
|
|
func newLeaseIndex() *leaseIndex {
|
|
return &leaseIndex{
|
|
byAddr: map[netip.Addr]*Lease{},
|
|
byName: map[string]*Lease{},
|
|
}
|
|
}
|
|
|
|
// leaseByAddr returns a lease by its IP address.
|
|
func (idx *leaseIndex) leaseByAddr(addr netip.Addr) (l *Lease, ok bool) {
|
|
l, ok = idx.byAddr[addr]
|
|
|
|
return l, ok
|
|
}
|
|
|
|
// leaseByName returns a lease by its hostname.
|
|
func (idx *leaseIndex) leaseByName(name string) (l *Lease, ok bool) {
|
|
// TODO(e.burkov): Probably, use a case-insensitive comparison and store in
|
|
// slice. This would require a benchmark.
|
|
l, ok = idx.byName[strings.ToLower(name)]
|
|
|
|
return l, ok
|
|
}
|
|
|
|
// clear removes all leases from idx.
|
|
func (idx *leaseIndex) clear() {
|
|
clear(idx.byAddr)
|
|
clear(idx.byName)
|
|
}
|
|
|
|
// add adds l into idx and into iface. l must be valid, iface should be
|
|
// responsible for l's IP. It returns an error if l duplicates at least a
|
|
// single value of another lease.
|
|
func (idx *leaseIndex) add(l *Lease, iface *netInterface) (err error) {
|
|
loweredName := strings.ToLower(l.Hostname)
|
|
|
|
if _, ok := idx.byAddr[l.IP]; ok {
|
|
return fmt.Errorf("lease for ip %s already exists", l.IP)
|
|
} else if _, ok = idx.byName[loweredName]; ok {
|
|
return fmt.Errorf("lease for hostname %s already exists", l.Hostname)
|
|
}
|
|
|
|
err = iface.insertLease(l)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
idx.byAddr[l.IP] = l
|
|
idx.byName[loweredName] = l
|
|
|
|
return nil
|
|
}
|
|
|
|
// remove removes l from idx and from iface. l must be valid, iface should
|
|
// contain the same lease or the lease itself. It returns an error if the lease
|
|
// not found.
|
|
func (idx *leaseIndex) remove(l *Lease, iface *netInterface) (err error) {
|
|
loweredName := strings.ToLower(l.Hostname)
|
|
|
|
if _, ok := idx.byAddr[l.IP]; !ok {
|
|
return fmt.Errorf("no lease for ip %s", l.IP)
|
|
} else if _, ok = idx.byName[loweredName]; !ok {
|
|
return fmt.Errorf("no lease for hostname %s", l.Hostname)
|
|
}
|
|
|
|
err = iface.removeLease(l)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
delete(idx.byAddr, l.IP)
|
|
delete(idx.byName, loweredName)
|
|
|
|
return nil
|
|
}
|
|
|
|
// update updates l in idx and in iface. l must be valid, iface should be
|
|
// responsible for l's IP. It returns an error if l duplicates at least a
|
|
// single value of another lease, except for the updated lease itself.
|
|
func (idx *leaseIndex) update(l *Lease, iface *netInterface) (err error) {
|
|
loweredName := strings.ToLower(l.Hostname)
|
|
|
|
existing, ok := idx.byAddr[l.IP]
|
|
if ok && !slices.Equal(l.HWAddr, existing.HWAddr) {
|
|
return fmt.Errorf("lease for ip %s already exists", l.IP)
|
|
}
|
|
|
|
existing, ok = idx.byName[loweredName]
|
|
if ok && !slices.Equal(l.HWAddr, existing.HWAddr) {
|
|
return fmt.Errorf("lease for hostname %s already exists", l.Hostname)
|
|
}
|
|
|
|
prev, err := iface.updateLease(l)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
delete(idx.byAddr, prev.IP)
|
|
delete(idx.byName, strings.ToLower(prev.Hostname))
|
|
|
|
idx.byAddr[l.IP] = l
|
|
idx.byName[loweredName] = l
|
|
|
|
return nil
|
|
}
|