Sam
81da49093d
All checks were successful
continuous-integration/drone/push Build is passing
Instead of copying the opts struct every time it gets passed around, it should be created once and passed through reference. This should reduce memory utilization, unfortunately I cannot test it since this program runs so fast pprof won't report anything useful. I think I found all of them 🙂 Co-authored-by: Sam Therapy <sam@samtherapy.net> Reviewed-on: #132 Reviewed-by: grumbulon <grumbulon@grumbulon.xyz>
102 lines
2.4 KiB
Go
102 lines
2.4 KiB
Go
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package resolvers
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"git.froth.zone/sam/awl/pkg/util"
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// QUICResolver is for DNS-over-QUIC queries.
|
|
type QUICResolver struct {
|
|
opts *util.Options
|
|
}
|
|
|
|
var _ Resolver = (*QUICResolver)(nil)
|
|
|
|
// LookUp performs a DNS query.
|
|
func (resolver *QUICResolver) LookUp(msg *dns.Msg) (util.Response, error) {
|
|
var resp util.Response
|
|
|
|
tls := &tls.Config{
|
|
//nolint:gosec // This is intentional if the user requests it
|
|
InsecureSkipVerify: resolver.opts.TLSNoVerify,
|
|
ServerName: resolver.opts.TLSHost,
|
|
MinVersion: tls.VersionTLS12,
|
|
NextProtos: []string{"doq"},
|
|
}
|
|
|
|
conf := new(quic.Config)
|
|
conf.HandshakeIdleTimeout = resolver.opts.Request.Timeout
|
|
|
|
resolver.opts.Logger.Debug("quic: making query")
|
|
|
|
connection, err := quic.DialAddr(resolver.opts.Request.Server, tls, conf)
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: dial: %w", err)
|
|
}
|
|
|
|
resolver.opts.Logger.Debug("quic: packing query")
|
|
|
|
// Compress request to over-the-wire
|
|
buf, err := msg.Pack()
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: pack: %w", err)
|
|
}
|
|
|
|
t := time.Now()
|
|
|
|
resolver.opts.Logger.Debug("quic: creating stream")
|
|
|
|
stream, err := connection.OpenStream()
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: quic stream creation: %w", err)
|
|
}
|
|
|
|
resolver.opts.Logger.Debug("quic: writing to stream")
|
|
|
|
_, err = stream.Write(buf)
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: quic stream write: %w", err)
|
|
}
|
|
|
|
resolver.opts.Logger.Debug("quic: reading stream")
|
|
|
|
fullRes, err := io.ReadAll(stream)
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: quic stream read: %w", err)
|
|
}
|
|
|
|
resp.RTT = time.Since(t)
|
|
|
|
resolver.opts.Logger.Debug("quic: closing connection")
|
|
// Close with error: no error
|
|
err = connection.CloseWithError(0, "")
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: quic connection close: %w", err)
|
|
}
|
|
|
|
resolver.opts.Logger.Debug("quic: closing stream")
|
|
|
|
err = stream.Close()
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: quic stream close: %w", err)
|
|
}
|
|
|
|
resp.DNS = &dns.Msg{}
|
|
|
|
resolver.opts.Logger.Debug("quic: unpacking response")
|
|
|
|
err = resp.DNS.Unpack(fullRes)
|
|
if err != nil {
|
|
return util.Response{}, fmt.Errorf("doq: unpack: %w", err)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|