func (cl *DoHClient) Write(packet []byte) (n int, err error) {
	n, err = cl.w.Write(packet)
	if err != nil {
		cl.responded <- false
		return
	}
	cl.responded <- true
	return
}
Write the raw DNS response message to active connection.
This method is only used by server to write the response of query to
client.
package dns
import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)
type DoHClient struct {
	addr    *url.URL
	headers http.Header
	req     *http.Request
	query   url.Values
	conn    *http.Client
	w http.ResponseWriter
	responded chan bool
}
func NewDoHClient(nameserver string, allowInsecure bool) (*DoHClient, error) {
	nsURL, err := url.Parse(nameserver)
	if err != nil {
		return nil, err
	}
	if nsURL.Scheme != "https" {
		err = fmt.Errorf("DoH name server must be HTTPS")
		return nil, err
	}
	tr := &http.Transport{
		MaxIdleConns:    1,
		IdleConnTimeout: 30 * time.Second,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: allowInsecure,
		},
	}
	cl := &DoHClient{
		addr: nsURL,
		headers: http.Header{
			"accept": []string{
				"application/dns-message",
			},
		},
		query: nsURL.Query(),
		conn: &http.Client{
			Transport: tr,
			Timeout:   clientTimeout,
		},
	}
	cl.req = &http.Request{
		Method:     http.MethodGet,
		URL:        nsURL,
		Proto:      "HTTP/2",
		ProtoMajor: 2,
		ProtoMinor: 0,
		Header:     cl.headers,
		Body:       nil,
		Host:       nsURL.Hostname(),
	}
	return cl, nil
}
func (cl *DoHClient) Close() error {
	cl.conn.Transport.(*http.Transport).CloseIdleConnections()
	return nil
}
func (cl *DoHClient) Lookup(
	allowRecursion bool, qtype, qclass uint16, qname string,
) (
	*Message, error,
) {
	if len(qname) == 0 {
		return nil, nil
	}
	if qtype == 0 {
		qtype = QueryTypeA
	}
	if qclass == 0 {
		qclass = QueryClassIN
	}
	msg := NewMessage()
	msg.Header.IsRD = allowRecursion
	msg.Question.Type = qtype
	msg.Question.Class = qclass
	msg.Question.Name = qname
	_, err := msg.Pack()
	if err != nil {
		return nil, err
	}
	res, err := cl.Get(msg)
	if err != nil {
		return nil, err
	}
	return res, err
}
func (cl *DoHClient) Post(msg *Message) (*Message, error) {
	cl.req.Method = http.MethodPost
	cl.req.Body = ioutil.NopCloser(bytes.NewReader(msg.packet))
	cl.req.URL.RawQuery = ""
	httpRes, err := cl.conn.Do(cl.req)
	if err != nil {
		cl.req.Body.Close()
		return nil, err
	}
	cl.req.Body.Close()
	res := NewMessage()
	res.packet, err = ioutil.ReadAll(httpRes.Body)
	httpRes.Body.Close()
	if err != nil {
		return nil, err
	}
	err = res.Unpack()
	return res, err
}
func (cl *DoHClient) Get(msg *Message) (*Message, error) {
	q := base64.RawURLEncoding.EncodeToString(msg.packet)
	cl.query.Set("dns", q)
	cl.req.Method = http.MethodGet
	cl.req.Body = nil
	cl.req.URL.RawQuery = cl.query.Encode()
	httpRes, err := cl.conn.Do(cl.req)
	if err != nil {
		return nil, err
	}
	res := NewMessage()
	res.packet, err = ioutil.ReadAll(httpRes.Body)
	httpRes.Body.Close()
	if err != nil {
		return nil, err
	}
	if httpRes.StatusCode != 200 {
		err = fmt.Errorf("%s", string(res.packet))
		return nil, err
	}
	if len(res.packet) > 20 {
		err = res.Unpack()
		if err != nil {
			return nil, err
		}
	}
	return res, err
}
func (cl *DoHClient) Query(msg *Message) (*Message, error) {
	return cl.Get(msg)
}
func (cl *DoHClient) RemoteAddr() string {
	return cl.addr.String()
}
func (cl *DoHClient) SetRemoteAddr(addr string) (err error) {
	cl.addr, err = url.Parse(addr)
	if err != nil {
		return
	}
	cl.query = cl.addr.Query()
	return
}
func (cl *DoHClient) SetTimeout(t time.Duration) {
	cl.conn.Timeout = t
}