mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-15 03:02:07 +03:00
3f5605c42e
Merge in DNS/adguard-home from 2846-cover-aghnet-vol.1 to master Updates #2846. Squashed commit of the following: commit 368e75b0bacb290f9929b8a5a682b06f2d75df6a Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Fri Jan 21 19:11:59 2022 +0300 aghnet: imp tests commit 8bb3e2a1680fd30294f7c82693891ffb19474c6a Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Fri Jan 21 18:27:06 2022 +0300 aghnet: rm unused test commit 28d8e64880f845810d0af629e5d1f06b9bde5b28 Author: Eugene Burkov <E.Burkov@AdGuard.COM> Date: Fri Jan 21 18:18:22 2022 +0300 aghnet: cover with tests
132 lines
3.0 KiB
Go
132 lines
3.0 KiB
Go
package aghnet
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/log"
|
|
)
|
|
|
|
// IPVersion is a alias for int for documentation purposes. Use it when the
|
|
// integer means IP version.
|
|
type IPVersion = int
|
|
|
|
// IP version constants.
|
|
const (
|
|
IPVersion4 IPVersion = 4
|
|
IPVersion6 IPVersion = 6
|
|
)
|
|
|
|
// NetIface is the interface for network interface methods.
|
|
type NetIface interface {
|
|
Addrs() ([]net.Addr, error)
|
|
}
|
|
|
|
// IfaceIPAddrs returns the interface's IP addresses.
|
|
func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
|
switch ipv {
|
|
case IPVersion4, IPVersion6:
|
|
// Go on.
|
|
default:
|
|
return nil, fmt.Errorf("invalid ip version %d", ipv)
|
|
}
|
|
|
|
addrs, err := iface.Addrs()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, a := range addrs {
|
|
var ip net.IP
|
|
switch a := a.(type) {
|
|
case *net.IPAddr:
|
|
ip = a.IP
|
|
case *net.IPNet:
|
|
ip = a.IP
|
|
default:
|
|
continue
|
|
}
|
|
|
|
// Assume that net.(*Interface).Addrs can only return valid IPv4 and
|
|
// IPv6 addresses. Thus, if it isn't an IPv4 address, it must be an
|
|
// IPv6 one.
|
|
ip4 := ip.To4()
|
|
if ipv == IPVersion4 {
|
|
if ip4 != nil {
|
|
ips = append(ips, ip4)
|
|
}
|
|
} else if ip4 == nil {
|
|
ips = append(ips, ip)
|
|
}
|
|
}
|
|
|
|
return ips, nil
|
|
}
|
|
|
|
// IfaceDNSIPAddrs returns IP addresses of the interface suitable to send to
|
|
// clients as DNS addresses. If err is nil, addrs contains either no addresses
|
|
// or at least two.
|
|
//
|
|
// It makes up to maxAttempts attempts to get the addresses if there are none,
|
|
// each time using the provided backoff. Sometimes an interface needs a few
|
|
// seconds to really initialize.
|
|
//
|
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/2304.
|
|
func IfaceDNSIPAddrs(
|
|
iface NetIface,
|
|
ipv IPVersion,
|
|
maxAttempts int,
|
|
backoff time.Duration,
|
|
) (addrs []net.IP, err error) {
|
|
var n int
|
|
for n = 1; n <= maxAttempts; n++ {
|
|
addrs, err = IfaceIPAddrs(iface, ipv)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("getting ip addrs: %w", err)
|
|
}
|
|
|
|
if len(addrs) > 0 {
|
|
break
|
|
}
|
|
|
|
log.Debug("dhcpv%d: attempt %d: no ip addresses", ipv, n)
|
|
|
|
time.Sleep(backoff)
|
|
}
|
|
|
|
n--
|
|
|
|
switch len(addrs) {
|
|
case 0:
|
|
// Don't return errors in case the users want to try and enable the DHCP
|
|
// server later.
|
|
t := time.Duration(n) * backoff
|
|
log.Error("dhcpv%d: no ip for iface after %d attempts and %s", ipv, n, t)
|
|
|
|
return nil, nil
|
|
case 1:
|
|
// Some Android devices use 8.8.8.8 if there is not a secondary DNS
|
|
// server. Fix that by setting the secondary DNS address to the same
|
|
// address.
|
|
//
|
|
// See https://github.com/AdguardTeam/AdGuardHome/issues/1708.
|
|
log.Debug("dhcpv%d: setting secondary dns ip to itself", ipv)
|
|
addrs = append(addrs, addrs[0])
|
|
default:
|
|
// Go on.
|
|
}
|
|
|
|
log.Debug("dhcpv%d: got addresses %s after %d attempts", ipv, addrs, n)
|
|
|
|
return addrs, nil
|
|
}
|
|
|
|
// interfaceName is a string containing network interface's name. The name is
|
|
// used in file walking methods.
|
|
type interfaceName string
|
|
|
|
// Use interfaceName in the OS-independent code since it's actually only used in
|
|
// several OS-dependent implementations which causes linting issues.
|
|
var _ = interfaceName("")
|