mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-15 18:08:30 -07:00
dhcpsvc: generalize
This commit is contained in:
parent
e4c2cae73a
commit
310ed67b9b
@ -36,10 +36,10 @@ type DHCPServer struct {
|
||||
leaseByName map[string]*Lease
|
||||
|
||||
// interfaces4 is the set of IPv4 interfaces sorted by interface name.
|
||||
interfaces4 []*netInterfaceV4
|
||||
interfaces4 netInterfacesV4
|
||||
|
||||
// interfaces6 is the set of IPv6 interfaces sorted by interface name.
|
||||
interfaces6 []*netInterfaceV6
|
||||
interfaces6 netInterfacesV6
|
||||
|
||||
// icmpTimeout is the timeout for checking another DHCP server's presence.
|
||||
icmpTimeout time.Duration
|
||||
@ -55,8 +55,9 @@ func New(conf *Config) (srv *DHCPServer, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ifaces4 := make([]*netInterfaceV4, 0, len(conf.Interfaces))
|
||||
ifaces6 := make([]*netInterfaceV6, 0, len(conf.Interfaces))
|
||||
// TODO(e.burkov): Add validations scoped to the network interfaces set.
|
||||
ifaces4 := make(netInterfacesV4, 0, len(conf.Interfaces))
|
||||
ifaces6 := make(netInterfacesV6, 0, len(conf.Interfaces))
|
||||
|
||||
ifaceNames := maps.Keys(conf.Interfaces)
|
||||
slices.Sort(ifaceNames)
|
||||
@ -181,9 +182,18 @@ func (srv *DHCPServer) Reset() (err error) {
|
||||
|
||||
// AddLease implements the [Interface] interface for *DHCPServer.
|
||||
func (srv *DHCPServer) AddLease(l *Lease) (err error) {
|
||||
iface, err := srv.netInterfaceForLease(l)
|
||||
if err != nil {
|
||||
return err
|
||||
var ok bool
|
||||
var iface *netInterface
|
||||
|
||||
addr := l.IP
|
||||
|
||||
if addr.Is4() {
|
||||
iface, ok = srv.interfaces4.find(addr)
|
||||
} else {
|
||||
iface, ok = srv.interfaces6.find(addr)
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("no interface for IP address %s", addr)
|
||||
}
|
||||
|
||||
srv.leasesMu.Lock()
|
||||
@ -199,45 +209,3 @@ func (srv *DHCPServer) AddLease(l *Lease) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// netInterfaceForLease returns the iface responsible for l, if any. l must
|
||||
// have a valid IP address.
|
||||
func (srv *DHCPServer) netInterfaceForLease(l *Lease) (iface *netInterface, err error) {
|
||||
if addr := l.IP; addr.Is4() {
|
||||
var iface4 *netInterfaceV4
|
||||
iface4, err = netInterfaceForAddr(srv.interfaces4, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iface = &iface4.netInterface
|
||||
} else {
|
||||
var iface6 *netInterfaceV6
|
||||
iface6, err = netInterfaceForAddr(srv.interfaces6, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
iface = &iface6.netInterface
|
||||
}
|
||||
|
||||
return iface, nil
|
||||
}
|
||||
|
||||
// netInterface is a network interface.
|
||||
type netInterfaceAny interface {
|
||||
contains(addr netip.Addr) (ok bool)
|
||||
}
|
||||
|
||||
// netInterfaceForAddr returns the first network interface from ifaces that
|
||||
// contains addr. It returns an error if there is no such interface in ifaces.
|
||||
func netInterfaceForAddr[I netInterfaceAny](ifaces []I, addr netip.Addr) (iface I, err error) {
|
||||
i := slices.IndexFunc(ifaces, func(iface I) (ok bool) {
|
||||
return iface.contains(addr)
|
||||
})
|
||||
if i < 0 {
|
||||
return iface, fmt.Errorf("no interface for IP address %s", addr)
|
||||
}
|
||||
|
||||
return ifaces[i], nil
|
||||
}
|
||||
|
@ -320,10 +320,18 @@ func newNetInterfaceV4(name string, conf *IPv4Config) (i *netInterfaceV4, err er
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ netInterfaceAny = (*netInterfaceV4)(nil)
|
||||
// netInterfacesV4 is a slice of network interfaces of IPv4 address family.
|
||||
type netInterfacesV4 []*netInterfaceV4
|
||||
|
||||
// contains returns true if ip is within the address space allocated for i.
|
||||
//
|
||||
// TODO(e.burkov): Make this a method of [netInterface].
|
||||
func (i *netInterfaceV4) contains(ip netip.Addr) (ok bool) { return i.subnet.Contains(ip) }
|
||||
// find returns the first network interface within ifaces containing ip. It
|
||||
// returns false if there is no such interface.
|
||||
func (ifaces netInterfacesV4) find(ip netip.Addr) (iface4 *netInterface, ok bool) {
|
||||
i := slices.IndexFunc(ifaces, func(iface *netInterfaceV4) bool {
|
||||
return iface.subnet.Contains(ip)
|
||||
})
|
||||
if i < 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &ifaces[i].netInterface, true
|
||||
}
|
||||
|
@ -134,16 +134,18 @@ func newNetInterfaceV6(name string, conf *IPv6Config) (i *netInterfaceV6) {
|
||||
return i
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ netInterfaceAny = (*netInterfaceV4)(nil)
|
||||
// netInterfacesV4 is a slice of network interfaces of IPv4 address family.
|
||||
type netInterfacesV6 []*netInterfaceV6
|
||||
|
||||
// contains returns true if ip is within the address space allocated for i.
|
||||
//
|
||||
// TODO(e.burkov): DHCPv6 inherits the weird behavior of legacy implementation
|
||||
// where the allocated range constrained by the first address and the first
|
||||
// address with last byte set to 0xff. Proper prefixes should be used instead.
|
||||
//
|
||||
// TODO(e.burkov): Make this a method of [netInterface].
|
||||
func (i *netInterfaceV6) contains(ip netip.Addr) (ok bool) {
|
||||
return !i.rangeStart.Less(ip) && netip.PrefixFrom(i.rangeStart, 120).Contains(ip)
|
||||
// find returns the first network interface within ifaces containing ip. It
|
||||
// returns false if there is no such interface.
|
||||
func (ifaces netInterfacesV6) find(ip netip.Addr) (iface6 *netInterface, ok bool) {
|
||||
i := slices.IndexFunc(ifaces, func(iface *netInterfaceV6) bool {
|
||||
return !iface.rangeStart.Less(ip) && netip.PrefixFrom(iface.rangeStart, 120).Contains(ip)
|
||||
})
|
||||
if i < 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &ifaces[i].netInterface, true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user