// 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.

// DNS client: see RFC 1035.
// Has to be linked into package net for Dial.

// TODO(rsc):
//	Could potentially handle many outstanding lookups faster.
//	Random UDP source port (net.Dial should do that for us).
//	Random request IDs.

package net

import (
	
	
	
	
	
	
	
	
	
	
	

	
)

const (
	// to be used as a useTCP parameter to exchange
	useTCPOnly  = true
	useUDPOrTCP = false

	// Maximum DNS packet size.
	// Value taken from https://dnsflagday.net/2020/.
	maxDNSPacketSize = 1232
)

var (
	errLameReferral              = errors.New("lame referral")
	errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message")
	errCannotMarshalDNSMessage   = errors.New("cannot marshal DNS message")
	errServerMisbehaving         = errors.New("server misbehaving")
	errInvalidDNSResponse        = errors.New("invalid DNS response")
	errNoAnswerFromDNSServer     = errors.New("no answer from DNS server")

	// errServerTemporarilyMisbehaving is like errServerMisbehaving, except
	// that when it gets translated to a DNSError, the IsTemporary field
	// gets set to true.
	errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"}
)

// netedns0 controls whether we send an EDNS0 additional header.
var netedns0 = godebug.New("netedns0")

func newRequest( dnsmessage.Question,  bool) ( uint16, ,  []byte,  error) {
	 = uint16(randInt())
	 := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: , RecursionDesired: true, AuthenticData: })
	if  := .StartQuestions();  != nil {
		return 0, nil, nil, 
	}
	if  := .Question();  != nil {
		return 0, nil, nil, 
	}

	if netedns0.Value() == "0" {
		netedns0.IncNonDefault()
	} else {
		// Accept packets up to maxDNSPacketSize.  RFC 6891.
		if  := .StartAdditionals();  != nil {
			return 0, nil, nil, 
		}
		var  dnsmessage.ResourceHeader
		if  := .SetEDNS0(maxDNSPacketSize, dnsmessage.RCodeSuccess, false);  != nil {
			return 0, nil, nil, 
		}
		if  := .OPTResource(, dnsmessage.OPTResource{});  != nil {
			return 0, nil, nil, 
		}
	}

	,  = .Finish()
	if  != nil {
		return 0, nil, nil, 
	}
	 = [2:]
	 := len() - 2
	[0] = byte( >> 8)
	[1] = byte()
	return , , , nil
}

func checkResponse( uint16,  dnsmessage.Question,  dnsmessage.Header,  dnsmessage.Question) bool {
	if !.Response {
		return false
	}
	if  != .ID {
		return false
	}
	if .Type != .Type || .Class != .Class || !equalASCIIName(.Name, .Name) {
		return false
	}
	return true
}

func dnsPacketRoundTrip( Conn,  uint16,  dnsmessage.Question,  []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
	if ,  := .Write();  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, 
	}

	 = make([]byte, maxDNSPacketSize)
	for {
		,  := .Read()
		if  != nil {
			return dnsmessage.Parser{}, dnsmessage.Header{}, 
		}
		var  dnsmessage.Parser
		// Ignore invalid responses as they may be malicious
		// forgery attempts. Instead continue waiting until
		// timeout. See golang.org/issue/13281.
		,  := .Start([:])
		if  != nil {
			continue
		}
		,  := .Question()
		if  != nil || !checkResponse(, , , ) {
			continue
		}
		return , , nil
	}
}

func dnsStreamRoundTrip( Conn,  uint16,  dnsmessage.Question,  []byte) (dnsmessage.Parser, dnsmessage.Header, error) {
	if ,  := .Write();  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, 
	}

	 = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
	if ,  := io.ReadFull(, [:2]);  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, 
	}
	 := int([0])<<8 | int([1])
	if  > len() {
		 = make([]byte, )
	}
	,  := io.ReadFull(, [:])
	if  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, 
	}
	var  dnsmessage.Parser
	,  := .Start([:])
	if  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
	}
	,  := .Question()
	if  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage
	}
	if !checkResponse(, , , ) {
		return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
	}
	return , , nil
}

// exchange sends a query on the connection and hopes for a response.
func ( *Resolver) ( context.Context,  string,  dnsmessage.Question,  time.Duration, ,  bool) (dnsmessage.Parser, dnsmessage.Header, error) {
	.Class = dnsmessage.ClassINET
	, , ,  := newRequest(, )
	if  != nil {
		return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage
	}
	var  []string
	if  {
		 = []string{"tcp"}
	} else {
		 = []string{"udp", "tcp"}
	}
	for ,  := range  {
		,  := context.WithDeadline(, time.Now().Add())
		defer ()

		,  := .dial(, , )
		if  != nil {
			return dnsmessage.Parser{}, dnsmessage.Header{}, 
		}
		if ,  := .Deadline();  && !.IsZero() {
			.SetDeadline()
		}
		var  dnsmessage.Parser
		var  dnsmessage.Header
		if ,  := .(PacketConn);  {
			, ,  = dnsPacketRoundTrip(, , , )
		} else {
			, ,  = dnsStreamRoundTrip(, , , )
		}
		.Close()
		if  != nil {
			return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr()
		}
		if  := .SkipQuestion();  != dnsmessage.ErrSectionDone {
			return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse
		}
		// RFC 5966 indicates that when a client receives a UDP response with
		// the TC flag set, it should take the TC flag as an indication that it
		// should retry over TCP instead.
		// The case when the TC flag is set in a TCP response is not well specified,
		// so this implements the glibc resolver behavior, returning the existing
		// dns response instead of returning a "errNoAnswerFromDNSServer" error.
		// See go.dev/issue/64896
		if .Truncated &&  == "udp" {
			continue
		}
		return , , nil
	}
	return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer
}

// checkHeader performs basic sanity checks on the header.
func checkHeader( *dnsmessage.Parser,  dnsmessage.Header) error {
	,  := extractExtendedRCode(*, )

	if  == dnsmessage.RCodeNameError {
		return errNoSuchHost
	}

	,  := .AnswerHeader()
	if  != nil &&  != dnsmessage.ErrSectionDone {
		return errCannotUnmarshalDNSMessage
	}

	// libresolv continues to the next server when it receives
	// an invalid referral response. See golang.org/issue/15434.
	if  == dnsmessage.RCodeSuccess && !.Authoritative && !.RecursionAvailable &&  == dnsmessage.ErrSectionDone && ! {
		return errLameReferral
	}

	if  != dnsmessage.RCodeSuccess &&  != dnsmessage.RCodeNameError {
		// None of the error codes make sense
		// for the query we sent. If we didn't get
		// a name error and we didn't get success,
		// the server is behaving incorrectly or
		// having temporary trouble.
		if  == dnsmessage.RCodeServerFailure {
			return errServerTemporarilyMisbehaving
		}
		return errServerMisbehaving
	}

	return nil
}

func skipToAnswer( *dnsmessage.Parser,  dnsmessage.Type) error {
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			return errNoSuchHost
		}
		if  != nil {
			return errCannotUnmarshalDNSMessage
		}
		if .Type ==  {
			return nil
		}
		if  := .SkipAnswer();  != nil {
			return errCannotUnmarshalDNSMessage
		}
	}
}

// extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0))
// If an OPT record is not found, the RCode from the hdr is returned.
// Another return value indicates whether an additional resource was found.
func extractExtendedRCode( dnsmessage.Parser,  dnsmessage.Header) (dnsmessage.RCode, bool) {
	.SkipAllAnswers()
	.SkipAllAuthorities()
	 := false
	for {
		,  := .AdditionalHeader()
		if  != nil {
			return .RCode, 
		}
		 = true
		if .Type == dnsmessage.TypeOPT {
			return .ExtendedRCode(.RCode), 
		}
		if  := .SkipAdditional();  != nil {
			return .RCode, 
		}
	}
}

// Do a lookup for a single name, which must be rooted
// (otherwise answer will not find the answers).
func ( *Resolver) ( context.Context,  *dnsConfig,  string,  dnsmessage.Type) (dnsmessage.Parser, string, error) {
	var  error
	 := .serverOffset()
	 := uint32(len(.servers))

	,  := dnsmessage.NewName()
	if  != nil {
		return dnsmessage.Parser{}, "", &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: }
	}
	 := dnsmessage.Question{
		Name:  ,
		Type:  ,
		Class: dnsmessage.ClassINET,
	}

	for  := 0;  < .attempts; ++ {
		for  := uint32(0);  < ; ++ {
			 := .servers[(+)%]

			, ,  := .exchange(, , , .timeout, .useTCP, .trustAD)
			if  != nil {
				 := newDNSError(, , )
				// Set IsTemporary for socket-level errors. Note that this flag
				// may also be used to indicate a SERVFAIL response.
				if ,  := .(*OpError);  {
					.IsTemporary = true
				}
				 = 
				continue
			}

			if  := checkHeader(&, );  != nil {
				if  == errNoSuchHost {
					// The name does not exist, so trying
					// another server won't help.
					return , , newDNSError(errNoSuchHost, , )
				}
				 = newDNSError(, , )
				continue
			}

			if  := skipToAnswer(&, );  != nil {
				if  == errNoSuchHost {
					// The name does not exist, so trying
					// another server won't help.
					return , , newDNSError(errNoSuchHost, , )
				}
				 = newDNSError(, , )
				continue
			}

			return , , nil
		}
	}
	return dnsmessage.Parser{}, "", 
}

// A resolverConfig represents a DNS stub resolver configuration.
type resolverConfig struct {
	initOnce sync.Once // guards init of resolverConfig

	// ch is used as a semaphore that only allows one lookup at a
	// time to recheck resolv.conf.
	ch          chan struct{} // guards lastChecked and modTime
	lastChecked time.Time     // last time resolv.conf was checked

	dnsConfig atomic.Pointer[dnsConfig] // parsed resolv.conf structure used in lookups
}

var resolvConf resolverConfig

func getSystemDNSConfig() *dnsConfig {
	resolvConf.tryUpdate("/etc/resolv.conf")
	return resolvConf.dnsConfig.Load()
}

// init initializes conf and is only called via conf.initOnce.
func ( *resolverConfig) () {
	// Set dnsConfig and lastChecked so we don't parse
	// resolv.conf twice the first time.
	.dnsConfig.Store(dnsReadConfig("/etc/resolv.conf"))
	.lastChecked = time.Now()

	// Prepare ch so that only one update of resolverConfig may
	// run at once.
	.ch = make(chan struct{}, 1)
}

// tryUpdate tries to update conf with the named resolv.conf file.
// The name variable only exists for testing. It is otherwise always
// "/etc/resolv.conf".
func ( *resolverConfig) ( string) {
	.initOnce.Do(.init)

	if .dnsConfig.Load().noReload {
		return
	}

	// Ensure only one update at a time checks resolv.conf.
	if !.tryAcquireSema() {
		return
	}
	defer .releaseSema()

	 := time.Now()
	if .lastChecked.After(.Add(-5 * time.Second)) {
		return
	}
	.lastChecked = 

	switch runtime.GOOS {
	case "windows":
		// There's no file on disk, so don't bother checking
		// and failing.
		//
		// The Windows implementation of dnsReadConfig (called
		// below) ignores the name.
	default:
		var  time.Time
		if ,  := os.Stat();  == nil {
			 = .ModTime()
		}
		if .Equal(.dnsConfig.Load().mtime) {
			return
		}
	}

	 := dnsReadConfig()
	.dnsConfig.Store()
}

func ( *resolverConfig) () bool {
	select {
	case .ch <- struct{}{}:
		return true
	default:
		return false
	}
}

func ( *resolverConfig) () {
	<-.ch
}

func ( *Resolver) ( context.Context,  string,  dnsmessage.Type,  *dnsConfig) (dnsmessage.Parser, string, error) {
	if !isDomainName() {
		// We used to use "invalid domain name" as the error,
		// but that is a detail of the specific lookup mechanism.
		// Other lookups might allow broader name syntax
		// (for example Multicast DNS allows UTF-8; see RFC 6762).
		// For consistency with libc resolvers, report no such host.
		return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, , "")
	}

	if  == nil {
		 = getSystemDNSConfig()
	}

	var (
		      dnsmessage.Parser
		 string
		    error
	)
	for ,  := range .nameList() {
		, ,  = .tryOneName(, , , )
		if  == nil {
			break
		}
		if ,  := .(Error);  && .Temporary() && .strictErrors() {
			// If we hit a temporary error with StrictErrors enabled,
			// stop immediately instead of trying more names.
			break
		}
	}
	if  == nil {
		return , , nil
	}
	if ,  := .(*DNSError);  {
		// Show original name passed to lookup, not suffixed one.
		// In general we might have tried many suffixes; showing
		// just one is misleading. See also golang.org/issue/6324.
		.Name = 
	}
	return dnsmessage.Parser{}, "", 
}

// avoidDNS reports whether this is a hostname for which we should not
// use DNS. Currently this includes only .onion, per RFC 7686. See
// golang.org/issue/13705. Does not cover .local names (RFC 6762),
// see golang.org/issue/16739.
func avoidDNS( string) bool {
	if  == "" {
		return true
	}
	if [len()-1] == '.' {
		 = [:len()-1]
	}
	return stringsHasSuffixFold(, ".onion")
}

// nameList returns a list of names for sequential DNS queries.
func ( *dnsConfig) ( string) []string {
	// Check name length (see isDomainName).
	 := len()
	 :=  > 0 && [-1] == '.'
	if  > 254 ||  == 254 && ! {
		return nil
	}

	// If name is rooted (trailing dot), try only that name.
	if  {
		if avoidDNS() {
			return nil
		}
		return []string{}
	}

	 := bytealg.CountString(, '.') >= .ndots
	 += "."
	++

	// Build list of search choices.
	 := make([]string, 0, 1+len(.search))
	// If name has enough dots, try unsuffixed first.
	if  && !avoidDNS() {
		 = append(, )
	}
	// Try suffixes that are not too long (see isDomainName).
	for ,  := range .search {
		 :=  + 
		if !avoidDNS() && len() <= 254 {
			 = append(, )
		}
	}
	// Try unsuffixed, if not tried first above.
	if ! && !avoidDNS() {
		 = append(, )
	}
	return 
}

// hostLookupOrder specifies the order of LookupHost lookup strategies.
// It is basically a simplified representation of nsswitch.conf.
// "files" means /etc/hosts.
type hostLookupOrder int

const (
	// hostLookupCgo means defer to cgo.
	hostLookupCgo      hostLookupOrder = iota
	hostLookupFilesDNS                 // files first
	hostLookupDNSFiles                 // dns first
	hostLookupFiles                    // only files
	hostLookupDNS                      // only DNS
)

var lookupOrderName = map[hostLookupOrder]string{
	hostLookupCgo:      "cgo",
	hostLookupFilesDNS: "files,dns",
	hostLookupDNSFiles: "dns,files",
	hostLookupFiles:    "files",
	hostLookupDNS:      "dns",
}

func ( hostLookupOrder) () string {
	if ,  := lookupOrderName[];  {
		return 
	}
	return "hostLookupOrder=" + itoa.Itoa(int()) + "??"
}

func ( *Resolver) ( context.Context,  string,  hostLookupOrder,  *dnsConfig) ( []string,  error) {
	if  == hostLookupFilesDNS ||  == hostLookupFiles {
		// Use entries from /etc/hosts if they match.
		, _ = lookupStaticHost()
		if len() > 0 {
			return
		}

		if  == hostLookupFiles {
			return nil, newDNSError(errNoSuchHost, , "")
		}
	}
	, ,  := .goLookupIPCNAMEOrder(, "ip", , , )
	if  != nil {
		return
	}
	 = make([]string, 0, len())
	for ,  := range  {
		 = append(, .String())
	}
	return
}

// lookup entries from /etc/hosts
func goLookupIPFiles( string) ( []IPAddr,  string) {
	,  := lookupStaticHost()
	for ,  := range  {
		,  := splitHostZone()
		if  := ParseIP();  != nil {
			 := IPAddr{IP: , Zone: }
			 = append(, )
		}
	}
	sortByRFC6724()
	return , 
}

// goLookupIP is the native Go implementation of LookupIP.
// The libc versions are in cgo_*.go.
func ( *Resolver) ( context.Context, ,  string,  hostLookupOrder,  *dnsConfig) ( []IPAddr,  error) {
	, _,  = .goLookupIPCNAMEOrder(, , , , )
	return
}

func ( *Resolver) ( context.Context, ,  string,  hostLookupOrder,  *dnsConfig) ( []IPAddr,  dnsmessage.Name,  error) {
	if  == hostLookupFilesDNS ||  == hostLookupFiles {
		var  string
		,  = goLookupIPFiles()

		if len() > 0 {
			var  error
			,  = dnsmessage.NewName()
			if  != nil {
				return nil, dnsmessage.Name{}, 
			}
			return , , nil
		}

		if  == hostLookupFiles {
			return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, , "")
		}
	}

	if !isDomainName() {
		// See comment in func lookup above about use of errNoSuchHost.
		return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, , "")
	}
	type  struct {
		      dnsmessage.Parser
		 string
		error
	}

	if  == nil {
		 = getSystemDNSConfig()
	}

	 := make(chan , 1)
	 := []dnsmessage.Type{dnsmessage.TypeA, dnsmessage.TypeAAAA}
	if  == "CNAME" {
		 = append(, dnsmessage.TypeCNAME)
	}
	switch ipVersion() {
	case '4':
		 = []dnsmessage.Type{dnsmessage.TypeA}
	case '6':
		 = []dnsmessage.Type{dnsmessage.TypeAAAA}
	}
	var  func( string,  dnsmessage.Type)
	var  func( string,  dnsmessage.Type) 
	if .singleRequest {
		 = func( string,  dnsmessage.Type) {}
		 = func( string,  dnsmessage.Type)  {
			dnsWaitGroup.Add(1)
			defer dnsWaitGroup.Done()
			, ,  := .tryOneName(, , , )
			return {, , }
		}
	} else {
		 = func( string,  dnsmessage.Type) {
			dnsWaitGroup.Add(1)
			go func( dnsmessage.Type) {
				, ,  := .tryOneName(, , , )
				 <- {, , }
				dnsWaitGroup.Done()
			}()
		}
		 = func( string,  dnsmessage.Type)  {
			return <-
		}
	}
	var  error
	for ,  := range .nameList() {
		for ,  := range  {
			(, )
		}
		 := false
		for ,  := range  {
			 := (, )
			if . != nil {
				if ,  := ..(Error);  && .Temporary() && .strictErrors() {
					// This error will abort the nameList loop.
					 = true
					 = .
				} else if  == nil ||  == +"." {
					// Prefer error for original name.
					 = .
				}
				continue
			}

			// Presotto says it's okay to assume that servers listed in
			// /etc/resolv.conf are recursive resolvers.
			//
			// We asked for recursion, so it should have included all the
			// answers we need in this one packet.
			//
			// Further, RFC 1034 section 4.3.1 says that "the recursive
			// response to a query will be... The answer to the query,
			// possibly preface by one or more CNAME RRs that specify
			// aliases encountered on the way to an answer."
			//
			// Therefore, we should be able to assume that we can ignore
			// CNAMEs and that the A and AAAA records we requested are
			// for the canonical name.

		:
			for {
				,  := ..AnswerHeader()
				if  != nil &&  != dnsmessage.ErrSectionDone {
					 = &DNSError{
						Err:    errCannotUnmarshalDNSMessage.Error(),
						Name:   ,
						Server: .,
					}
				}
				if  != nil {
					break
				}
				switch .Type {
				case dnsmessage.TypeA:
					,  := ..AResource()
					if  != nil {
						 = &DNSError{
							Err:    errCannotUnmarshalDNSMessage.Error(),
							Name:   ,
							Server: .,
						}
						break 
					}
					 = append(, IPAddr{IP: IP(.A[:])})
					if .Length == 0 && .Name.Length != 0 {
						 = .Name
					}

				case dnsmessage.TypeAAAA:
					,  := ..AAAAResource()
					if  != nil {
						 = &DNSError{
							Err:    errCannotUnmarshalDNSMessage.Error(),
							Name:   ,
							Server: .,
						}
						break 
					}
					 = append(, IPAddr{IP: IP(.AAAA[:])})
					if .Length == 0 && .Name.Length != 0 {
						 = .Name
					}

				case dnsmessage.TypeCNAME:
					,  := ..CNAMEResource()
					if  != nil {
						 = &DNSError{
							Err:    errCannotUnmarshalDNSMessage.Error(),
							Name:   ,
							Server: .,
						}
						break 
					}
					if .Length == 0 && .CNAME.Length > 0 {
						 = .CNAME
					}

				default:
					if  := ..SkipAnswer();  != nil {
						 = &DNSError{
							Err:    errCannotUnmarshalDNSMessage.Error(),
							Name:   ,
							Server: .,
						}
						break 
					}
					continue
				}
			}
		}
		if  {
			// If either family hit an error with StrictErrors enabled,
			// discard all addresses. This ensures that network flakiness
			// cannot turn a dualstack hostname IPv4/IPv6-only.
			 = nil
			break
		}
		if len() > 0 ||  == "CNAME" && .Length > 0 {
			break
		}
	}
	if ,  := .(*DNSError);  {
		// Show original name passed to lookup, not suffixed one.
		// In general we might have tried many suffixes; showing
		// just one is misleading. See also golang.org/issue/6324.
		.Name = 
	}
	sortByRFC6724()
	if len() == 0 && !( == "CNAME" && .Length > 0) {
		if  == hostLookupDNSFiles {
			var  string
			,  = goLookupIPFiles()
			if len() > 0 {
				var  error
				,  = dnsmessage.NewName()
				if  != nil {
					return nil, dnsmessage.Name{}, 
				}
				return , , nil
			}
		}
		if  != nil {
			return nil, dnsmessage.Name{}, 
		}
	}
	return , , nil
}

// goLookupCNAME is the native Go (non-cgo) implementation of LookupCNAME.
func ( *Resolver) ( context.Context,  string,  hostLookupOrder,  *dnsConfig) (string, error) {
	, ,  := .goLookupIPCNAMEOrder(, "CNAME", , , )
	return .String(), 
}

// goLookupPTR is the native Go implementation of LookupAddr.
func ( *Resolver) ( context.Context,  string,  hostLookupOrder,  *dnsConfig) ([]string, error) {
	if  == hostLookupFiles ||  == hostLookupFilesDNS {
		 := lookupStaticAddr()
		if len() > 0 {
			return , nil
		}

		if  == hostLookupFiles {
			return nil, newDNSError(errNoSuchHost, , "")
		}
	}

	,  := reverseaddr()
	if  != nil {
		return nil, 
	}
	, ,  := .lookup(, , dnsmessage.TypePTR, )
	if  != nil {
		var  *DNSError
		if errors.As(, &) && .IsNotFound {
			if  == hostLookupDNSFiles {
				 := lookupStaticAddr()
				if len() > 0 {
					return , nil
				}
			}
		}
		return nil, 
	}
	var  []string
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			break
		}
		if  != nil {
			return nil, &DNSError{
				Err:    errCannotUnmarshalDNSMessage.Error(),
				Name:   ,
				Server: ,
			}
		}
		if .Type != dnsmessage.TypePTR {
			 := .SkipAnswer()
			if  != nil {
				return nil, &DNSError{
					Err:    errCannotUnmarshalDNSMessage.Error(),
					Name:   ,
					Server: ,
				}
			}
			continue
		}
		,  := .PTRResource()
		if  != nil {
			return nil, &DNSError{
				Err:    errCannotUnmarshalDNSMessage.Error(),
				Name:   ,
				Server: ,
			}
		}
		 = append(, .PTR.String())

	}

	return , nil
}