Pull request: dhcpd: refactor validations
Updates #3107. Updates #3127. Squashed commit of the following: commit ad64472566ecd1b0864212cd2644a57439aceb85 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Thu May 13 14:45:21 2021 +0300 dhcpd: refactor validations
This commit is contained in:
parent
1b789b5f81
commit
c890f5c152
|
@ -19,6 +19,7 @@ and this project adheres to
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- DHCP leases validation ([#3107], [#3127]).
|
||||||
- Local PTR request recursion in Docker containers ([#3064]).
|
- Local PTR request recursion in Docker containers ([#3064]).
|
||||||
- Ignoring client-specific filtering settings when filtering is disabled in
|
- Ignoring client-specific filtering settings when filtering is disabled in
|
||||||
general settings ([#2875]).
|
general settings ([#2875]).
|
||||||
|
@ -26,7 +27,9 @@ and this project adheres to
|
||||||
|
|
||||||
[#2875]: https://github.com/AdguardTeam/AdGuardHome/issues/2875
|
[#2875]: https://github.com/AdguardTeam/AdGuardHome/issues/2875
|
||||||
[#3064]: https://github.com/AdguardTeam/AdGuardHome/issues/3064
|
[#3064]: https://github.com/AdguardTeam/AdGuardHome/issues/3064
|
||||||
|
[#3107]: https://github.com/AdguardTeam/AdGuardHome/issues/3107
|
||||||
[#3115]: https://github.com/AdguardTeam/AdGuardHome/issues/3115
|
[#3115]: https://github.com/AdguardTeam/AdGuardHome/issues/3115
|
||||||
|
[#3127]: https://github.com/AdguardTeam/AdGuardHome/issues/3127
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,42 +73,26 @@ func normalizeHostname(hostname string) (norm string, err error) {
|
||||||
return norm, nil
|
return norm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validHostnameForClient accepts the hostname sent by the client and returns
|
// validHostnameForClient accepts the hostname sent by the client and its IP and
|
||||||
// either a normalized version of that hostname or a new hostname generated from
|
// returns either a normalized version of that hostname, or a new hostname
|
||||||
// the client's IP address. If this new hostname is different from the provided
|
// generated from the IP address, or an empty string.
|
||||||
// previous hostname, additional uniqueness check is performed.
|
func (s *v4Server) validHostnameForClient(cliHostname string, ip net.IP) (hostname string) {
|
||||||
//
|
hostname, err := normalizeHostname(cliHostname)
|
||||||
// hostname is always a non-empty valid hostname. If err is not nil, it
|
if err != nil {
|
||||||
// describes the issues encountered when normalizing cliHostname.
|
log.Info("dhcpv4: %s", err)
|
||||||
func (s *v4Server) validHostnameForClient(
|
|
||||||
cliHostname string,
|
|
||||||
prevHostname string,
|
|
||||||
ip net.IP,
|
|
||||||
) (hostname string, err error) {
|
|
||||||
hostname, err = normalizeHostname(cliHostname)
|
|
||||||
if err == nil && hostname != "" {
|
|
||||||
err = aghnet.ValidateDomainName(hostname)
|
|
||||||
if err != nil {
|
|
||||||
// Go on and assign a hostname made from the IP below,
|
|
||||||
// returning the error that we've got.
|
|
||||||
hostname = ""
|
|
||||||
} else if hostname != prevHostname && s.leaseHosts.Has(hostname) {
|
|
||||||
// Go on and assign a unique hostname made from the IP
|
|
||||||
// below, returning the error about uniqueness.
|
|
||||||
err = agherr.Error("hostname exists")
|
|
||||||
hostname = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostname == "" {
|
if hostname == "" {
|
||||||
hostname = aghnet.GenerateHostname(ip)
|
hostname = aghnet.GenerateHostname(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostname != cliHostname {
|
err = aghnet.ValidateDomainName(hostname)
|
||||||
log.Info("dhcpv4: normalized hostname %q into %q", cliHostname, hostname)
|
if err != nil {
|
||||||
|
log.Info("dhcpv4: %s", err)
|
||||||
|
hostname = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return hostname, err
|
return hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetLeases - reset leases
|
// ResetLeases - reset leases
|
||||||
|
@ -124,15 +108,7 @@ func (s *v4Server) ResetLeases(leases []*Lease) {
|
||||||
s.leases = nil
|
s.leases = nil
|
||||||
|
|
||||||
for _, l := range leases {
|
for _, l := range leases {
|
||||||
l.Hostname, err = s.validHostnameForClient(l.Hostname, l.Hostname, l.IP)
|
l.Hostname = s.validHostnameForClient(l.Hostname, l.IP)
|
||||||
if err != nil {
|
|
||||||
log.Info(
|
|
||||||
"dhcpv4: warning: previous hostname %q is invalid: %s",
|
|
||||||
l.Hostname,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.addLease(l)
|
err = s.addLease(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO(a.garipov): Wrap and bubble up the error.
|
// TODO(a.garipov): Wrap and bubble up the error.
|
||||||
|
@ -287,6 +263,15 @@ func (s *v4Server) rmDynamicLease(lease *Lease) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.rmLeaseByIndex(i)
|
s.rmLeaseByIndex(i)
|
||||||
|
if i == len(s.leases) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
l = s.leases[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.Hostname == lease.Hostname {
|
||||||
|
l.Hostname = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,22 +337,25 @@ func (s *v4Server) AddStaticLease(l Lease) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostname string
|
if l.Hostname != "" {
|
||||||
hostname, err = normalizeHostname(l.Hostname)
|
var hostname string
|
||||||
if err != nil {
|
hostname, err = normalizeHostname(l.Hostname)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
err = aghnet.ValidateDomainName(hostname)
|
err = aghnet.ValidateDomainName(hostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("validating hostname: %w", err)
|
return fmt.Errorf("validating hostname: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.leaseHosts.Has(hostname) {
|
// Don't check for hostname uniqueness, since we try to emulate
|
||||||
return agherr.Error("hostname exists")
|
// dnsmasq here, which means that rmDynamicLease below will
|
||||||
}
|
// simply empty the hostname of the dynamic lease if there even
|
||||||
|
// is one.
|
||||||
|
|
||||||
l.Hostname = hostname
|
l.Hostname = hostname
|
||||||
|
}
|
||||||
|
|
||||||
// Perform the following actions in an anonymous function to make sure
|
// Perform the following actions in an anonymous function to make sure
|
||||||
// that the lock gets unlocked before the notification step.
|
// that the lock gets unlocked before the notification step.
|
||||||
|
@ -553,7 +541,10 @@ func (s *v4Server) commitLease(l *Lease) {
|
||||||
defer s.leasesLock.Unlock()
|
defer s.leasesLock.Unlock()
|
||||||
|
|
||||||
s.conf.notify(LeaseChangedDBStore)
|
s.conf.notify(LeaseChangedDBStore)
|
||||||
s.leaseHosts.Add(l.Hostname)
|
|
||||||
|
if l.Hostname != "" {
|
||||||
|
s.leaseHosts.Add(l.Hostname)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
s.conf.notify(LeaseChangedAdded)
|
s.conf.notify(LeaseChangedAdded)
|
||||||
|
@ -647,7 +638,7 @@ func (o *optFQDN) ToBytes() []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// processDiscover is the handler for the DHCP Request request.
|
// processRequest is the handler for the DHCP Request request.
|
||||||
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needsReply bool) {
|
||||||
mac := req.ClientHWAddr
|
mac := req.ClientHWAddr
|
||||||
err := aghnet.ValidateHardwareAddress(mac)
|
err := aghnet.ValidateHardwareAddress(mac)
|
||||||
|
@ -662,13 +653,13 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needs
|
||||||
|
|
||||||
sid := req.ServerIdentifier()
|
sid := req.ServerIdentifier()
|
||||||
if len(sid) != 0 && !sid.Equal(s.conf.dnsIPAddrs[0]) {
|
if len(sid) != 0 && !sid.Equal(s.conf.dnsIPAddrs[0]) {
|
||||||
log.Debug("dhcpv4: bad OptionServerIdentifier in request message for %s", mac)
|
log.Debug("dhcpv4: bad OptionServerIdentifier in req msg for %s", mac)
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ip4 := reqIP.To4(); ip4 == nil {
|
if ip4 := reqIP.To4(); ip4 == nil {
|
||||||
log.Debug("dhcpv4: bad OptionRequestedIPAddress in request message for %s", mac)
|
log.Debug("dhcpv4: bad OptionRequestedIPAddress in req msg for %s", mac)
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -685,15 +676,17 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needs
|
||||||
|
|
||||||
if l.IP.Equal(reqIP) {
|
if l.IP.Equal(reqIP) {
|
||||||
lease = l
|
lease = l
|
||||||
} else {
|
|
||||||
log.Debug(
|
return
|
||||||
`dhcpv4: mismatched OptionRequestedIPAddress `+
|
|
||||||
`in request message for %s`,
|
|
||||||
mac,
|
|
||||||
)
|
|
||||||
mismatch = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug(
|
||||||
|
`dhcpv4: mismatched OptionRequestedIPAddress in req msg for %s`,
|
||||||
|
mac,
|
||||||
|
)
|
||||||
|
|
||||||
|
mismatch = true
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -709,13 +702,12 @@ func (s *v4Server) processRequest(req, resp *dhcpv4.DHCPv4) (lease *Lease, needs
|
||||||
|
|
||||||
if !lease.IsStatic() {
|
if !lease.IsStatic() {
|
||||||
cliHostname := req.HostName()
|
cliHostname := req.HostName()
|
||||||
lease.Hostname, err = s.validHostnameForClient(cliHostname, lease.Hostname, reqIP)
|
hostname := s.validHostnameForClient(cliHostname, reqIP)
|
||||||
if err != nil {
|
if hostname != lease.Hostname && s.leaseHosts.Has(hostname) {
|
||||||
log.Info(
|
log.Info("dhcpv4: hostname %q already exists", hostname)
|
||||||
"dhcpv4: warning: client hostname %q is invalid: %s",
|
lease.Hostname = ""
|
||||||
cliHostname,
|
} else {
|
||||||
err,
|
lease.Hostname = hostname
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.commitLease(lease)
|
s.commitLease(lease)
|
||||||
|
|
Loading…
Reference in New Issue