Pull request: * dhcpd: send secondary dns as well

Merge in DNS/adguard-home from 1708-secondary-dns to master

Updates #1708.

Squashed commit of the following:

commit 4529452e31131763f00c9c834cc95638f1a3d142
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Nov 9 18:12:57 2020 +0300

    * dhcpd: send secondary dns as well
This commit is contained in:
Ainar Garipov
2020-11-09 19:27:04 +03:00
parent 1e583315a8
commit 3cc5bf210d
5 changed files with 152 additions and 85 deletions

View File

@@ -26,12 +26,16 @@ func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
return false, fmt.Errorf("couldn't find interface by name %s: %w", ifaceName, err)
}
// get ipv4 address of an interface
ifaceIPNet := getIfaceIPv4(*iface)
ifaceIPNet, err := ifaceIPv4Addrs(iface)
if err != nil {
return false, fmt.Errorf("getting ipv4 addrs for iface %s: %w", ifaceName, err)
}
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("couldn't find IPv4 address of interface %s %+v", ifaceName, iface)
return false, fmt.Errorf("interface %s has no ipv4 addresses", ifaceName)
}
// TODO(a.garipov): Find out what this is about. Perhaps this
// information is outdated or at least incomplete.
if runtime.GOOS == "darwin" {
return false, fmt.Errorf("can't find DHCP server: not supported on macOS")
}
@@ -82,46 +86,66 @@ func CheckIfOtherDHCPServersPresentV4(ifaceName string) (bool, error) {
}
for {
// wait for answer
log.Tracef("Waiting %v for an answer", defaultDiscoverTime)
// TODO: replicate dhclient's behaviour of retrying several times with progressively bigger timeouts
b := make([]byte, 1500)
_ = c.SetReadDeadline(time.Now().Add(defaultDiscoverTime))
n, _, err := c.ReadFrom(b)
if isTimeout(err) {
// timed out -- no DHCP servers
log.Debug("DHCPv4: didn't receive DHCP response")
return false, nil
}
if err != nil {
return false, fmt.Errorf("couldn't receive packet: %w", err)
}
log.Tracef("Received packet (%v bytes)", n)
response, err := dhcpv4.FromBytes(b[:n])
if err != nil {
log.Debug("DHCPv4: dhcpv4.FromBytes: %s", err)
ok, next, err := tryConn(req, c, iface)
if next {
continue
}
log.Debug("DHCPv4: received message from server: %s", response.Summary())
if !(response.OpCode == dhcpv4.OpcodeBootReply &&
response.HWType == iana.HWTypeEthernet &&
bytes.Equal(response.ClientHWAddr, iface.HardwareAddr) &&
bytes.Equal(response.TransactionID[:], req.TransactionID[:]) &&
response.Options.Has(dhcpv4.OptionDHCPMessageType)) {
log.Debug("DHCPv4: received message from server doesn't match our request")
continue
if ok {
return true, nil
}
if err != nil {
log.Debug("%s", err)
}
log.Tracef("The packet is from an active DHCP server")
// that's a DHCP server there
return true, nil
}
}
// TODO(a.garipov): Refactor further. Inspect error handling, remove the next
// parameter, address the TODO, etc.
func tryConn(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, next bool, err error) {
// TODO: replicate dhclient's behavior of retrying several times with
// progressively longer timeouts.
log.Tracef("waiting %v for an answer", defaultDiscoverTime)
b := make([]byte, 1500)
_ = c.SetReadDeadline(time.Now().Add(defaultDiscoverTime))
n, _, err := c.ReadFrom(b)
if err != nil {
if isTimeout(err) {
log.Debug("dhcpv4: didn't receive dhcp response")
return false, false, nil
}
return false, false, fmt.Errorf("receiving packet: %w", err)
}
log.Tracef("received packet, %d bytes", n)
response, err := dhcpv4.FromBytes(b[:n])
if err != nil {
log.Debug("dhcpv4: encoding: %s", err)
return false, true, err
}
log.Debug("dhcpv4: received message from server: %s", response.Summary())
if !(response.OpCode == dhcpv4.OpcodeBootReply &&
response.HWType == iana.HWTypeEthernet &&
bytes.Equal(response.ClientHWAddr, iface.HardwareAddr) &&
bytes.Equal(response.TransactionID[:], req.TransactionID[:]) &&
response.Options.Has(dhcpv4.OptionDHCPMessageType)) {
log.Debug("dhcpv4: received message from server doesn't match our request")
return false, true, nil
}
log.Tracef("the packet is from an active dhcp server")
return true, false, nil
}
// CheckIfOtherDHCPServersPresentV6 sends a DHCP request to the specified network interface,
// and waits for a response for a period defined by defaultDiscoverTime
func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
@@ -130,9 +154,12 @@ func CheckIfOtherDHCPServersPresentV6(ifaceName string) (bool, error) {
return false, fmt.Errorf("dhcpv6: net.InterfaceByName: %s: %w", ifaceName, err)
}
ifaceIPNet := getIfaceIPv6(*iface)
ifaceIPNet, err := ifaceIPv6Addrs(iface)
if err != nil {
return false, fmt.Errorf("getting ipv6 addrs for iface %s: %w", ifaceName, err)
}
if len(ifaceIPNet) == 0 {
return false, fmt.Errorf("dhcpv6: couldn't find IPv6 address of interface %s %+v", ifaceName, iface)
return false, fmt.Errorf("interface %s has no ipv6 addresses", ifaceName)
}
srcIP := ifaceIPNet[0]