Files
ctrld/doq.go
2022-12-13 01:27:48 +07:00

76 lines
1.6 KiB
Go

package ctrld
import (
"context"
"crypto/tls"
"io"
"net"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/miekg/dns"
)
type doqResolver struct {
uc *UpstreamConfig
}
func (r *doqResolver) Resolve(ctx context.Context, msg *dns.Msg) (*dns.Msg, error) {
endpoint := r.uc.Endpoint
tlsConfig := &tls.Config{NextProtos: []string{"doq"}}
if r.uc.BootstrapIP != "" {
tlsConfig.ServerName = r.uc.Domain
_, port, _ := net.SplitHostPort(endpoint)
endpoint = net.JoinHostPort(r.uc.BootstrapIP, port)
}
return resolve(ctx, msg, endpoint, tlsConfig)
}
func resolve(ctx context.Context, msg *dns.Msg, endpoint string, tlsConfig *tls.Config) (*dns.Msg, error) {
session, err := quic.DialAddr(endpoint, tlsConfig, nil)
if err != nil {
return nil, err
}
defer session.CloseWithError(quic.ApplicationErrorCode(quic.NoError), "")
msgBytes, err := msg.Pack()
if err != nil {
return nil, err
}
stream, err := session.OpenStream()
if err != nil {
return nil, err
}
deadline, ok := ctx.Deadline()
if !ok {
deadline = time.Now().Add(5 * time.Second)
}
_ = stream.SetDeadline(deadline)
var msgLen = uint16(len(msgBytes))
var msgLenBytes = []byte{byte(msgLen >> 8), byte(msgLen & 0xFF)}
if _, err := stream.Write(msgLenBytes); err != nil {
return nil, err
}
if _, err := stream.Write(msgBytes); err != nil {
return nil, err
}
buf, err := io.ReadAll(stream)
if err != nil {
return nil, err
}
_ = stream.Close()
answer := new(dns.Msg)
if err := answer.Unpack(buf[2:]); err != nil {
return nil, err
}
answer.SetReply(msg)
return answer, nil
}