func (msg *Message) packDomainName(dname []byte, doCompress bool) (n int) {
	var (
		ok bool
		d  int
	)
	dname = ascii.ToLower(dname)
	msg.dname = string(dname)
	if doCompress {
		ok = msg.compress()
		if ok {
			return 2
		}
	}
	count := byte(0)
	msg.packet = append(msg.packet, 0)
	msg.dnameOff[msg.dname] = msg.off
	for x := 0; x < len(dname); x++ {
		c := dname[x]
		if c == '\\' {
			x++
			if x == len(dname) {
				return n
			}
			c = dname[x]
			if ascii.IsDigit(c) {
				if x+2 >= len(dname) {
					return n
				}
				d, _ = strconv.Atoi(string(dname[x : x+3]))
				c = byte(d)
				if c >= 'A' && c <= 'Z' {
					c += 32
				}
				x += 2
			}
			msg.packet = append(msg.packet, c)
			count++
			continue
		}
		if c == '.' {
			if count == 0 {
				continue
			}
			msg.packet[msg.off] = count
			msg.dname = string(dname[x+1:])
			msg.off += uint16(count + 1)
			n += int(count + 1)
			if doCompress {
				ok = msg.compress()
				if ok {
					n += 2
					return n
				}
			}
			count = 0
			msg.packet = append(msg.packet, 0)
			msg.dnameOff[msg.dname] = msg.off
			if x+1 == len(dname) {
				return n
			}
			continue
		}
		msg.packet = append(msg.packet, c)
		count++
	}
	if count > 0 {
		msg.packet[msg.off] = count
		msg.off += uint16(count + 1)
		n += int(count + 1)
	}
	if len(dname) > 0 {
		msg.packet = append(msg.packet, 0)
		msg.off++
		n++
	}
	return n
}
packDomainName convert string of domain-name into DNS domain-name format.
package dns
import (
	"fmt"
	"log"
	"net"
	"strconv"
	"strings"
	"github.com/shuLhan/share/lib/ascii"
	libbytes "github.com/shuLhan/share/lib/bytes"
	"github.com/shuLhan/share/lib/debug"
	libnet "github.com/shuLhan/share/lib/net"
	"github.com/shuLhan/share/lib/reflect"
)
type Message struct {
	Header     SectionHeader
	Question   SectionQuestion
	Answer     []ResourceRecord
	Authority  []ResourceRecord
	Additional []ResourceRecord
	packet []byte
	off uint16
	dnameOff map[string]uint16
	dname    string
}
func NewMessage() *Message {
	return &Message{
		Header: SectionHeader{
			IsQuery: true,
			IsRD:    true,
			QDCount: 1,
		},
		Question: SectionQuestion{
			Type:  QueryTypeA,
			Class: QueryClassIN,
		},
		dnameOff: make(map[string]uint16),
	}
}
func NewMessageAddress(hname []byte, addresses [][]byte) (msg *Message) {
	if !libnet.IsHostnameValid(hname, false) {
		return nil
	}
	if len(addresses) == 0 {
		return nil
	}
	addr := addresses[0]
	qtype := GetQueryTypeFromAddress(addr)
	if qtype == 0 {
		return nil
	}
	hname = ascii.ToLower(hname)
	rr := ResourceRecord{
		Name:  string(hname),
		Type:  qtype,
		Class: QueryClassIN,
		TTL:   defaultTTL,
		Value: string(addr),
	}
	msg = &Message{
		Header: SectionHeader{
			IsAA:    true,
			QDCount: 1,
			ANCount: 1,
		},
		Question: SectionQuestion{
			Name:  string(hname),
			Type:  qtype,
			Class: QueryClassIN,
		},
		Answer: []ResourceRecord{rr},
	}
	for _, addr := range addresses[1:] {
		qtype = GetQueryTypeFromAddress(addr)
		if qtype == 0 {
			continue
		}
		if qtype != msg.Question.Type {
			continue
		}
		msg.Answer = append(msg.Answer, ResourceRecord{
			Name:  string(hname),
			Type:  qtype,
			Class: QueryClassIN,
			TTL:   defaultTTL,
			Value: string(addr),
		})
		msg.Header.ANCount++
	}
	_, err := msg.Pack()
	if err != nil {
		return nil
	}
	return msg
}
func NewMessageFromRR(rr *ResourceRecord) (msg *Message, err error) {
	msg = &Message{
		Header: SectionHeader{
			IsAA:    true,
			QDCount: 1,
			ANCount: 1,
		},
		Question: SectionQuestion{
			Name:  rr.Name,
			Type:  rr.Type,
			Class: rr.Class,
		},
		Answer: []ResourceRecord{*rr},
	}
	_, err = msg.Pack()
	if err != nil {
		return nil, err
	}
	return msg, nil
}
func (msg *Message) AddAnswer(rr *ResourceRecord) (err error) {
	switch rr.Type {
	case QueryTypeSOA, QueryTypePTR:
		if len(msg.Answer) > 0 {
			msg.Answer[0] = *rr
		} else {
			msg.Answer = append(msg.Answer, *rr)
		}
	default:
		msg.Answer = append(msg.Answer, *rr)
		msg.Header.ANCount++
	}
	_, err = msg.Pack()
	return err
}
func (msg *Message) FilterAnswers(t uint16) (answers []ResourceRecord) {
	for _, rr := range msg.Answer {
		if rr.Type == t {
			answers = append(answers, rr)
		}
	}
	return
}
func (msg *Message) compress() bool {
	off, ok := msg.dnameOff[msg.dname]
	if ok {
		msg.packet = append(msg.packet, maskPointer|byte(off>>8))
		msg.packet = append(msg.packet, byte(off))
		msg.off += 2
		return true
	}
	return false
}