mirror of
https://github.com/folbricht/routedns.git
synced 2026-01-06 01:30:00 -06:00
Prefix DoQ packets with length as per rfc9250
This commit is contained in:
@@ -8,7 +8,7 @@ Features:
|
||||
|
||||
- Support for DNS-over-TLS (DoT, [RFC7858](https://tools.ietf.org/html/rfc7858)), client and server
|
||||
- Support for DNS-over-HTTPS (DoH, [RFC8484](https://tools.ietf.org/html/rfc8484)), client and server with HTTP2
|
||||
- Support for DNS-over-QUIC (doq-i02, [draft-ietf-dprive-dnsoquic-02](https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic)), client and server
|
||||
- Support for DNS-over-QUIC (DoQ, [RFC9250](https://datatracker.ietf.org/doc/rfc9250/)), client and server
|
||||
- Support for DNS-over-DTLS ([RFC8094](https://tools.ietf.org/html/rfc8094)), client and server
|
||||
- DNS-over-HTTPS using a QUIC transport, client and server
|
||||
- Custom CAs and mutual-TLS
|
||||
@@ -81,7 +81,7 @@ RouteDNS supports building complex DNS processing pipelines. A typically configu
|
||||
|
||||
## QUIC support
|
||||
|
||||
Support for the QUIC protocol is still experimental. In the context of DNS, there are two implementations, DNS-over-QUIC ([draft-ietf-dprive-dnsoquic-02](https://datatracker.ietf.org/doc/html/draft-ietf-dprive-dnsoquic)) as well as DNS-over-HTTPS using QUIC. Both protocols are supported by RouteDNS, client and server implementations.
|
||||
Support for the QUIC protocol is still experimental. In the context of DNS, there are two implementations, DNS-over-QUIC (DoQ, [RFC9250](https://datatracker.ietf.org/doc/rfc9250/)) as well as DNS-over-HTTPS using QUIC. Both protocols are supported by RouteDNS, client and server implementations.
|
||||
|
||||
## Use-cases / Examples
|
||||
|
||||
|
||||
26
doqclient.go
26
doqclient.go
@@ -2,7 +2,8 @@ package rdns
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -123,12 +124,17 @@ func (d *DoQClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error) {
|
||||
defer func() { q.Id = id }()
|
||||
|
||||
// Encode the query
|
||||
b, err := q.Pack()
|
||||
p, err := q.Pack()
|
||||
if err != nil {
|
||||
d.metrics.err.Add("pack", 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add a length prefix
|
||||
b := make([]byte, 2+len(p))
|
||||
binary.BigEndian.PutUint16(b, uint16(len(p)))
|
||||
copy(b[2:], p)
|
||||
|
||||
// Get a new stream in the connection
|
||||
stream, err := d.connection.getStream()
|
||||
if err != nil {
|
||||
@@ -138,7 +144,7 @@ func (d *DoQClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error) {
|
||||
|
||||
// Write the query into the stream and close is. Only one stream per query/response
|
||||
_ = stream.SetWriteDeadline(time.Now().Add(time.Second))
|
||||
if _, err = stream.Write(b); err != nil {
|
||||
if _, err = stream.Write(p); err != nil {
|
||||
d.metrics.err.Add("write", 1)
|
||||
return nil, err
|
||||
}
|
||||
@@ -147,10 +153,18 @@ func (d *DoQClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read the response
|
||||
_ = stream.SetReadDeadline(time.Now().Add(time.Second))
|
||||
b, err = ioutil.ReadAll(stream)
|
||||
if err != nil {
|
||||
|
||||
// DoQ requires a length prefix, like TCP
|
||||
var length uint16
|
||||
if err := binary.Read(stream, binary.BigEndian, &length); err != nil {
|
||||
d.metrics.err.Add("read", 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read the response
|
||||
b = make([]byte, length)
|
||||
if _, err = io.ReadFull(stream, b); err != nil {
|
||||
d.metrics.err.Add("read", 1)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package rdns
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"expvar"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -142,10 +143,18 @@ func (s DoQListener) handleStream(stream quic.Stream, log *logrus.Entry, ci Clie
|
||||
defer stream.Close()
|
||||
s.metrics.stream.Add(1)
|
||||
|
||||
// DoQ requires a length prefix, like TCP
|
||||
var length uint16
|
||||
if err := binary.Read(stream, binary.BigEndian, &length); err != nil {
|
||||
s.metrics.err.Add("read", 1)
|
||||
log.WithError(err).Error("failed to read query")
|
||||
return
|
||||
}
|
||||
|
||||
// Read the raw query
|
||||
b := make([]byte, length)
|
||||
_ = stream.SetReadDeadline(time.Now().Add(time.Second)) // TODO: configurable timeout
|
||||
b, err := ioutil.ReadAll(stream)
|
||||
if err != nil {
|
||||
if _, err := io.ReadFull(stream, b); err != nil {
|
||||
s.metrics.err.Add("read", 1)
|
||||
log.WithError(err).Error("failed to read query")
|
||||
return
|
||||
@@ -182,13 +191,18 @@ func (s DoQListener) handleStream(stream quic.Stream, log *logrus.Entry, ci Clie
|
||||
a.SetRcode(q, dns.RcodeServerFailure)
|
||||
}
|
||||
|
||||
out, err := a.Pack()
|
||||
p, err := a.Pack()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("failed to encode response")
|
||||
s.metrics.err.Add("encode", 1)
|
||||
return
|
||||
}
|
||||
|
||||
// Add a length prefix
|
||||
out := make([]byte, 2+len(p))
|
||||
binary.BigEndian.PutUint16(out, uint16(len(p)))
|
||||
copy(out[2:], p)
|
||||
|
||||
// Send the response
|
||||
_ = stream.SetWriteDeadline(time.Now().Add(time.Second)) // TODO: configurable timeout
|
||||
if _, err = stream.Write(out); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user