// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package ice

import (
	
	

	
	
)

// The conditions of invalidation written below are defined in
// https://tools.ietf.org/html/rfc8445#section-5.1.1.1
// It is partial because the link-local check is done later in various gather local
// candidate methods which conditionally accept IPv6 based on usage of mDNS or not.
func isSupportedIPv6Partial( net.IP) bool {
	if len() != net.IPv6len ||
		// Deprecated IPv4-compatible IPv6 addresses [RFC4291] and IPv6 site-
		//   local unicast addresses [RFC3879] MUST NOT be included in the
		//   address candidates.
		isZeros([0:12]) || // !(IPv4-compatible IPv6)
		[0] == 0xfe && [1]&0xc0 == 0xc0 { // !(IPv6 site-local unicast)
		return false
	}

	return true
}

func isZeros( net.IP) bool {
	for  := 0;  < len(); ++ {
		if [] != 0 {
			return false
		}
	}

	return true
}

//nolint:gocognit,cyclop
func localInterfaces(
	 transport.Net,
	 func(string) ( bool),
	 func(net.IP) ( bool),
	 []NetworkType,
	 bool,
) ([]*transport.Interface, []netip.Addr, error) {
	 := []netip.Addr{}
	,  := .Interfaces()
	if  != nil {
		return nil, , 
	}

	 := make([]*transport.Interface, 0, len())

	var ,  bool
	if len() == 0 {
		 = true
		 = true
	} else {
		for ,  := range  {
			if .IsIPv4() {
				 = true
			}

			if .IsIPv6() {
				 = true
			}
		}
	}

	for ,  := range  {
		if .Flags&net.FlagUp == 0 {
			continue // Interface down
		}
		if (.Flags&net.FlagLoopback != 0) && ! {
			continue // Loopback interface
		}

		if  != nil && !(.Name) {
			continue
		}

		,  := .Addrs()
		if  != nil {
			continue
		}

		 := false
		for ,  := range  {
			, , ,  := parseAddrFromIface(, .Name)
			if  != nil || (.IsLoopback() && !) {
				continue
			}
			if .Is6() {
				if ! {
					continue
				} else if !isSupportedIPv6Partial(.AsSlice()) {
					continue
				}
			} else if ! {
				continue
			}

			if  != nil && !(.AsSlice()) {
				continue
			}

			 = true
			 = append(, )
		}

		if  {
			 := 
			 = append(, )
		}
	}

	return , , nil
}

//nolint:cyclop
func listenUDPInPortRange(
	 transport.Net,
	 logging.LeveledLogger,
	,  int,
	 string,
	 *net.UDPAddr,
) (transport.UDPConn, error) {
	if (.Port != 0) || (( == 0) && ( == 0)) {
		return .ListenUDP(, )
	}

	if  == 0 {
		 = 1024 // Start at 1024 which is non-privileged
	}

	if  == 0 {
		 = 0xFFFF
	}

	if  >  {
		return nil, ErrPort
	}

	 := globalMathRandomGenerator.Intn(-+1) + 
	 := 
	for {
		 := &net.UDPAddr{
			IP:   .IP,
			Zone: .Zone,
			Port: ,
		}

		,  := .ListenUDP(, )
		if  == nil {
			return ,  //nolint:nilerr
		}
		.Debugf("Failed to listen %s: %v", .String(), )
		++
		if  >  {
			 = 
		}
		if  ==  {
			break
		}
	}

	return nil, ErrPort
}