mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-10-26 11:27:18 +00:00
aghnet: imp remaining functions
This commit is contained in:
parent
361ec09c19
commit
b48baa52c0
@ -90,8 +90,8 @@ func checkOtherDHCPv4(iface *net.Interface) (ok bool, err error) {
|
||||
return discover4(iface, dstAddr, hostname)
|
||||
}
|
||||
|
||||
// TODO(f.setrakov): continue refactoring, reduce cognitive
|
||||
// complexity.
|
||||
// discover4 sends a DHCPv4 discovery to the specified network interface and
|
||||
// waits for response. iface and dstAddr must not be nil.
|
||||
func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok bool, err error) {
|
||||
var req *dhcpv4.DHCPv4
|
||||
if req, err = dhcpv4.NewDiscovery(iface.HardwareAddr); err != nil {
|
||||
@ -122,17 +122,9 @@ func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok
|
||||
}
|
||||
|
||||
for {
|
||||
if err = c.SetDeadline(time.Now().Add(defaultDiscoverTime)); err != nil {
|
||||
return false, fmt.Errorf("setting deadline: %w", err)
|
||||
}
|
||||
|
||||
var next bool
|
||||
ok, next, err = tryConn4(req, c, iface)
|
||||
ok, next, err = getDHCP4Response(req, c, iface)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv4: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@ -144,9 +136,34 @@ func discover4(iface *net.Interface, dstAddr *net.UDPAddr, hostname string) (ok
|
||||
}
|
||||
}
|
||||
|
||||
// getDHCP4Response reads and validates DHCP response from [net.PacketConn].
|
||||
// req, c and iface must not be nil.
|
||||
func getDHCP4Response(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, next bool, err error) {
|
||||
ok, next, err = tryConn4(req, c, iface)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv4: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
return false, next, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
return ok, false, nil
|
||||
}
|
||||
|
||||
// tryConn4 reads and validates DHCPv4 response packet if it matches
|
||||
// the original request. req and c must not be nil.
|
||||
//
|
||||
// TODO(a.garipov): Refactor further. Inspect error handling, remove parameter
|
||||
// next, address the TODO, merge with tryConn6, etc.
|
||||
func tryConn4(req *dhcpv4.DHCPv4, c net.PacketConn, iface *net.Interface) (ok, next bool, err error) {
|
||||
if err = c.SetDeadline(time.Now().Add(defaultDiscoverTime)); err != nil {
|
||||
return false, false, fmt.Errorf("setting deadline: %w", err)
|
||||
}
|
||||
// TODO: replicate dhclient's behavior of retrying several times with
|
||||
// progressively longer timeouts.
|
||||
log.Tracef("dhcpv4: waiting %v for an answer", defaultDiscoverTime)
|
||||
@ -223,8 +240,8 @@ func checkOtherDHCPv6(iface *net.Interface) (ok bool, err error) {
|
||||
return discover6(iface, udpAddr, dstAddr)
|
||||
}
|
||||
|
||||
// TODO(f.setrakov): continue refactoring, reduce cognitive
|
||||
// complexity.
|
||||
// discover6 sends a DHCPv6 discovery to the specified network interface and
|
||||
// waits for response. iface, updAddr and dstAddr must not be nil.
|
||||
func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, err error) {
|
||||
req, err := dhcpv6.NewSolicit(iface.HardwareAddr)
|
||||
if err != nil {
|
||||
@ -245,12 +262,8 @@ func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, er
|
||||
|
||||
for {
|
||||
var next bool
|
||||
ok, next, err = tryConn6(req, c)
|
||||
ok, next, err = getDHCP6Response(req, c)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv6: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@ -262,6 +275,28 @@ func discover6(iface *net.Interface, udpAddr, dstAddr *net.UDPAddr) (ok bool, er
|
||||
}
|
||||
}
|
||||
|
||||
// getDHCP6Response reads and validates DHCP response from [net.PacketConn].
|
||||
// req and c must not be nil.
|
||||
func getDHCP6Response(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) {
|
||||
ok, next, err = tryConn6(req, c)
|
||||
if next {
|
||||
if err != nil {
|
||||
log.Debug("dhcpv6: trying a connection: %s", err)
|
||||
}
|
||||
|
||||
return false, next, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
return ok, false, nil
|
||||
}
|
||||
|
||||
// tryConn6 reads and validates DHCPv6 response packet if it matches
|
||||
// the original request. req and c must not be nil.
|
||||
//
|
||||
// TODO(a.garipov): See the comment on tryConn4. Sigh…
|
||||
func tryConn6(req *dhcpv6.Message, c net.PacketConn) (ok, next bool, err error) {
|
||||
// TODO: replicate dhclient's behavior of retrying several times with
|
||||
|
||||
@ -23,10 +23,7 @@ type NetIface interface {
|
||||
Addrs() ([]net.Addr, error)
|
||||
}
|
||||
|
||||
// IfaceIPAddrs returns the interface's IP addresses.
|
||||
//
|
||||
// TODO(f.setrakov): continue refactoring, reduce cognitive
|
||||
// complexity.
|
||||
// IfaceIPAddrs returns the interface's IP addresses. iface must noot be nil.
|
||||
func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
switch ipv {
|
||||
case IPVersion4, IPVersion6:
|
||||
@ -41,25 +38,7 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
}
|
||||
|
||||
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 {
|
||||
if ip := ipFromAddr(a, ipv); ip != nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
}
|
||||
@ -67,6 +46,30 @@ func IfaceIPAddrs(iface NetIface, ipv IPVersion) (ips []net.IP, err error) {
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
// ipFromAddr converts addr to IP.
|
||||
func ipFromAddr(addr net.Addr, ipv IPVersion) (ip net.IP) {
|
||||
switch addr := addr.(type) {
|
||||
case *net.IPAddr:
|
||||
ip = addr.IP
|
||||
case *net.IPNet:
|
||||
ip = addr.IP
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return ip4
|
||||
} else if ip4 == nil {
|
||||
return ip
|
||||
}
|
||||
|
||||
return 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.
|
||||
|
||||
@ -136,7 +136,7 @@ func (iface NetInterface) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// NetInterfaceFrom converts a [net.Interface] to [NetInterface], populating
|
||||
// name, MAC address, flags, MTU, IP addresses, and subnets. iface must not be
|
||||
// name, MAC address, flags, MTU, IP addresses, and subnets. iface must not be
|
||||
// nil.
|
||||
func NetInterfaceFrom(iface *net.Interface) (niface *NetInterface, err error) {
|
||||
niface = &NetInterface{
|
||||
@ -146,51 +146,50 @@ func NetInterfaceFrom(iface *net.Interface) (niface *NetInterface, err error) {
|
||||
MTU: iface.MTU,
|
||||
}
|
||||
|
||||
var addrs []net.Addr
|
||||
addrs, err = iface.Addrs()
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get addresses for interface %s: %w", iface.Name, err)
|
||||
return nil, fmt.Errorf("getting addresses for interface %q: %w", iface.Name, err)
|
||||
}
|
||||
|
||||
if err = populateAddrs(niface, iface.Name, addrs); err != nil {
|
||||
return nil, err
|
||||
for i, addr := range addrs {
|
||||
if err = populateAddrs(addr, niface); err != nil {
|
||||
return nil, fmt.Errorf("populating from addrs[%d]: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return niface, nil
|
||||
}
|
||||
|
||||
// populateAddrs fills [*NetInterface] IP addresses and subnets from [[]net.Addr].
|
||||
func populateAddrs(niface *NetInterface, ifaceName string, addrs []net.Addr) (err error) {
|
||||
for _, addr := range addrs {
|
||||
var n *net.IPNet
|
||||
n, err = ipNetFromAddr(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip, ok := netip.AddrFromSlice(n.IP)
|
||||
if !ok {
|
||||
return fmt.Errorf("bad address %s", n.IP)
|
||||
}
|
||||
|
||||
ip = ip.Unmap()
|
||||
|
||||
// Skip link-local IPv4 addresses
|
||||
if isLinkLocalV4(ip) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
ip = ip.WithZone(ifaceName)
|
||||
}
|
||||
|
||||
ones, _ := n.Mask.Size()
|
||||
p := netip.PrefixFrom(ip, ones)
|
||||
|
||||
niface.Addresses = append(niface.Addresses, ip)
|
||||
niface.Subnets = append(niface.Subnets, p)
|
||||
// populateAddrs fills [*NetInterface] IP addresses and subnets. niface
|
||||
// must not be nil.
|
||||
func populateAddrs(addr net.Addr, niface *NetInterface) (err error) {
|
||||
n, err := ipNetFromAddr(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip, ok := netip.AddrFromSlice(n.IP)
|
||||
if !ok {
|
||||
return fmt.Errorf("bad address %s", n.IP)
|
||||
}
|
||||
|
||||
ip = ip.Unmap()
|
||||
|
||||
// Skip link-local IPv4 addresses
|
||||
if isLinkLocalV4(ip) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ip.IsLinkLocalUnicast() {
|
||||
ip = ip.WithZone(niface.Name)
|
||||
}
|
||||
|
||||
ones, _ := n.Mask.Size()
|
||||
p := netip.PrefixFrom(ip, ones)
|
||||
|
||||
niface.Addresses = append(niface.Addresses, ip)
|
||||
niface.Subnets = append(niface.Subnets, p)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user