// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	
	
	
	
	_  // for go:linkname

	
)

// provided by runtime
//
//go:linkname runtime_rand runtime.rand
func runtime_rand() uint64

func randInt() int {
	return int(uint(runtime_rand()) >> 1) // clear sign bit
}

func randIntn( int) int {
	return randInt() % 
}

// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
// address addr suitable for rDNS (PTR) record lookup or an error if it fails
// to parse the IP address.
func reverseaddr( string) ( string,  error) {
	 := ParseIP()
	if  == nil {
		return "", &DNSError{Err: "unrecognized address", Name: }
	}
	if .To4() != nil {
		return itoa.Uitoa(uint([15])) + "." + itoa.Uitoa(uint([14])) + "." + itoa.Uitoa(uint([13])) + "." + itoa.Uitoa(uint([12])) + ".in-addr.arpa.", nil
	}
	// Must be IPv6
	 := make([]byte, 0, len()*4+len("ip6.arpa."))
	// Add it, in reverse, to the buffer
	for  := len() - 1;  >= 0; -- {
		 := []
		 = append(, hexDigit[&0xF],
			'.',
			hexDigit[>>4],
			'.')
	}
	// Append "ip6.arpa." and return (buf already has the final .)
	 = append(, "ip6.arpa."...)
	return string(), nil
}

func equalASCIIName(,  dnsmessage.Name) bool {
	if .Length != .Length {
		return false
	}
	for  := 0;  < int(.Length); ++ {
		 := .Data[]
		 := .Data[]
		if 'A' <=  &&  <= 'Z' {
			 += 0x20
		}
		if 'A' <=  &&  <= 'Z' {
			 += 0x20
		}
		if  !=  {
			return false
		}
	}
	return true
}

// isDomainName checks if a string is a presentation-format domain name
// (currently restricted to hostname-compatible "preferred name" LDH labels and
// SRV-like "underscore labels"; see golang.org/issue/12421).
//
// isDomainName should be an internal detail,
// but widely used packages access it using linkname.
// Notable members of the hall of shame include:
//   - github.com/sagernet/sing
//
// Do not remove or change the type signature.
// See go.dev/issue/67401.
//
//go:linkname isDomainName
func isDomainName( string) bool {
	// The root domain name is valid. See golang.org/issue/45715.
	if  == "." {
		return true
	}

	// See RFC 1035, RFC 3696.
	// Presentation format has dots before every label except the first, and the
	// terminal empty label is optional here because we assume fully-qualified
	// (absolute) input. We must therefore reserve space for the first and last
	// labels' length octets in wire format, where they are necessary and the
	// maximum total length is 255.
	// So our _effective_ maximum is 253, but 254 is not rejected if the last
	// character is a dot.
	 := len()
	if  == 0 ||  > 254 ||  == 254 && [-1] != '.' {
		return false
	}

	 := byte('.')
	 := false // true once we've seen a letter or hyphen
	 := 0
	for  := 0;  < len(); ++ {
		 := []
		switch {
		default:
			return false
		case 'a' <=  &&  <= 'z' || 'A' <=  &&  <= 'Z' ||  == '_':
			 = true
			++
		case '0' <=  &&  <= '9':
			// fine
			++
		case  == '-':
			// Byte before dash cannot be dot.
			if  == '.' {
				return false
			}
			++
			 = true
		case  == '.':
			// Byte before dot cannot be dot, dash.
			if  == '.' ||  == '-' {
				return false
			}
			if  > 63 ||  == 0 {
				return false
			}
			 = 0
		}
		 = 
	}
	if  == '-' ||  > 63 {
		return false
	}

	return 
}

// absDomainName returns an absolute domain name which ends with a
// trailing dot to match pure Go reverse resolver and all other lookup
// routines.
// See golang.org/issue/12189.
// But we don't want to add dots for local names from /etc/hosts.
// It's hard to tell so we settle on the heuristic that names without dots
// (like "localhost" or "myhost") do not get trailing dots, but any other
// names do.
func absDomainName( string) string {
	if bytealg.IndexByteString(, '.') != -1 && [len()-1] != '.' {
		 += "."
	}
	return 
}

// An SRV represents a single DNS SRV record.
type SRV struct {
	Target   string
	Port     uint16
	Priority uint16
	Weight   uint16
}

// byPriorityWeight sorts SRV records by ascending priority and weight.
type byPriorityWeight []*SRV

// shuffleByWeight shuffles SRV records by weight using the algorithm
// described in RFC 2782.
func ( byPriorityWeight) () {
	 := 0
	for ,  := range  {
		 += int(.Weight)
	}
	for  > 0 && len() > 1 {
		 := 0
		 := randIntn()
		for  := range  {
			 += int([].Weight)
			if  >  {
				if  > 0 {
					[0], [] = [], [0]
				}
				break
			}
		}
		 -= int([0].Weight)
		 = [1:]
	}
}

// sort reorders SRV records as specified in RFC 2782.
func ( byPriorityWeight) () {
	slices.SortFunc(, func(,  *SRV) int {
		if  := cmp.Compare(.Priority, .Priority);  != 0 {
			return 
		}
		return cmp.Compare(.Weight, .Weight)
	})
	 := 0
	for  := 1;  < len(); ++ {
		if [].Priority != [].Priority {
			[:].shuffleByWeight()
			 = 
		}
	}
	[:].shuffleByWeight()
}

// An MX represents a single DNS MX record.
type MX struct {
	Host string
	Pref uint16
}

// byPref sorts MX records by preference
type byPref []*MX

// sort reorders MX records as specified in RFC 5321.
func ( byPref) () {
	for  := range  {
		 := randIntn( + 1)
		[], [] = [], []
	}
	slices.SortFunc(, func(,  *MX) int {
		return cmp.Compare(.Pref, .Pref)
	})
}

// An NS represents a single DNS NS record.
type NS struct {
	Host string
}