mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-20 22:11:50 +03:00
39aeaf8910
Merge in DNS/adguard-home from 4923-gopacket-dhcp-vol.3 to master
Updates #4923.
Squashed commit of the following:
commit 1a09c436e5666a515084cd5e76cfccd67991ae5e
Merge: 95bcf0720 c3f141a0a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Sep 28 19:38:57 2023 +0300
Merge branch 'master' into 4923-gopacket-dhcp-vol.3
commit 95bcf07206434fd451632e819926871ba8c14f08
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Sep 28 13:19:42 2023 +0300
dhcpsvc: fix interface to match legacy version
commit 5da513ce177319f19698c5a8e1d10affaaf5e85c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Sep 28 12:32:21 2023 +0300
dhcpsvc: make it build on 32bit
commit 37a935514b1cebdc817cdcd5ec3562baeafbc42d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Wed Sep 27 19:39:35 2023 +0300
dhcpd: fix v6 as well
commit 03b5454b04c4fdb3fe928d661562883dc3e09d81
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Wed Sep 27 19:34:17 2023 +0300
dhcpsvc: imp code, docs
commit 91a0e451f78fba64578cc541f7ba66579c31d388
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Fri Sep 22 15:25:58 2023 +0300
dhcpsvc: imp filing
commit 57c91e1194caa00a69e62b6655b1b4e38b69b89f
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Fri Sep 22 15:23:02 2023 +0300
dhcpsvc: imp code
commit d86be56efbfc121c9fe2c5ecef992b4523e04d57
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Thu Sep 14 12:24:39 2023 +0300
dhcpsvc: imp code, docs
commit c9ef29057e9e378779d1a7938ad13b6eebda8f50
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Wed Sep 13 17:53:55 2023 +0300
dhcpsvc: add constructor, validations, tests
commit f2533ed64e4ef439603b9cdf9596f8b0c4a87cf1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date: Tue Sep 12 23:05:42 2023 +0500
WIP
98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
package dhcpsvc
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
"math/big"
|
|
"net/netip"
|
|
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
)
|
|
|
|
// ipRange is an inclusive range of IP addresses. A zero range doesn't contain
|
|
// any IP addresses.
|
|
//
|
|
// It is safe for concurrent use.
|
|
type ipRange struct {
|
|
start netip.Addr
|
|
end netip.Addr
|
|
}
|
|
|
|
// maxRangeLen is the maximum IP range length. The bitsets used in servers only
|
|
// accept uints, which can have the size of 32 bit.
|
|
//
|
|
// TODO(a.garipov, e.burkov): Reconsider the value for IPv6.
|
|
const maxRangeLen = math.MaxUint32
|
|
|
|
// newIPRange creates a new IP address range. start must be less than end. The
|
|
// resulting range must not be greater than maxRangeLen.
|
|
func newIPRange(start, end netip.Addr) (r ipRange, err error) {
|
|
defer func() { err = errors.Annotate(err, "invalid ip range: %w") }()
|
|
|
|
switch false {
|
|
case start.Is4() == end.Is4():
|
|
return ipRange{}, fmt.Errorf("%s and %s must be within the same address family", start, end)
|
|
case start.Less(end):
|
|
return ipRange{}, fmt.Errorf("start %s is greater than or equal to end %s", start, end)
|
|
default:
|
|
diff := (&big.Int{}).Sub(
|
|
(&big.Int{}).SetBytes(end.AsSlice()),
|
|
(&big.Int{}).SetBytes(start.AsSlice()),
|
|
)
|
|
|
|
if !diff.IsUint64() || diff.Uint64() > maxRangeLen {
|
|
return ipRange{}, fmt.Errorf("range length must be within %d", uint32(maxRangeLen))
|
|
}
|
|
}
|
|
|
|
return ipRange{
|
|
start: start,
|
|
end: end,
|
|
}, nil
|
|
}
|
|
|
|
// contains returns true if r contains ip.
|
|
func (r ipRange) contains(ip netip.Addr) (ok bool) {
|
|
// Assume that the end was checked to be within the same address family as
|
|
// the start during construction.
|
|
return r.start.Is4() == ip.Is4() && !ip.Less(r.start) && !r.end.Less(ip)
|
|
}
|
|
|
|
// ipPredicate is a function that is called on every IP address in
|
|
// [ipRange.find].
|
|
type ipPredicate func(ip netip.Addr) (ok bool)
|
|
|
|
// find finds the first IP address in r for which p returns true. It returns an
|
|
// empty [netip.Addr] if there are no addresses that satisfy p.
|
|
//
|
|
// TODO(e.burkov): Use.
|
|
func (r ipRange) find(p ipPredicate) (ip netip.Addr) {
|
|
for ip = r.start; !r.end.Less(ip); ip = ip.Next() {
|
|
if p(ip) {
|
|
return ip
|
|
}
|
|
}
|
|
|
|
return netip.Addr{}
|
|
}
|
|
|
|
// offset returns the offset of ip from the beginning of r. It returns 0 and
|
|
// false if ip is not in r.
|
|
func (r ipRange) offset(ip netip.Addr) (offset uint64, ok bool) {
|
|
if !r.contains(ip) {
|
|
return 0, false
|
|
}
|
|
|
|
startData, ipData := r.start.As16(), ip.As16()
|
|
be := binary.BigEndian
|
|
|
|
// Assume that the range length was checked against maxRangeLen during
|
|
// construction.
|
|
return be.Uint64(ipData[8:]) - be.Uint64(startData[8:]), true
|
|
}
|
|
|
|
// String implements the fmt.Stringer interface for *ipRange.
|
|
func (r ipRange) String() (s string) {
|
|
return fmt.Sprintf("%s-%s", r.start, r.end)
|
|
}
|