mirror of
https://github.com/coredns/coredns.git
synced 2026-07-18 05:30:13 -04:00
Merge commit from fork
DoH, DoQ, and DNS-over-gRPC unpack messages without the acceptance checks used by UDP and TCP. An unauthenticated request with a large QDCOUNT can therefore force excessive allocations while names are decoded and exhaust server memory. Enforce the same request policy across all server transports. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/coredns/caddy"
|
"github.com/coredns/caddy"
|
||||||
"github.com/coredns/coredns/pb"
|
"github.com/coredns/coredns/pb"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
"github.com/coredns/coredns/plugin/pkg/transport"
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
@@ -177,8 +178,7 @@ func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket
|
|||||||
if len(in.GetMsg()) > dns.MaxMsgSize {
|
if len(in.GetMsg()) > dns.MaxMsgSize {
|
||||||
return nil, fmt.Errorf("dns message exceeds size limit: %d", len(in.GetMsg()))
|
return nil, fmt.Errorf("dns message exceeds size limit: %d", len(in.GetMsg()))
|
||||||
}
|
}
|
||||||
msg := new(dns.Msg)
|
msg, err := dnsutil.UnpackRequest(in.GetMsg())
|
||||||
err := msg.Unpack(in.GetMsg())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coredns/coredns/plugin/metrics/vars"
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
clog "github.com/coredns/coredns/plugin/pkg/log"
|
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||||
cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto"
|
cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto"
|
||||||
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
@@ -211,8 +212,7 @@ func (s *ServerQUIC) serveQUICStream(stream *quic.Stream, conn *quic.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &dns.Msg{}
|
req, err := dnsutil.UnpackRequest(buf)
|
||||||
err = req.Unpack(buf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
clog.Debugf("unpacking quic packet: %s", err)
|
clog.Debugf("unpacking quic packet: %s", err)
|
||||||
s.closeQUICConn(conn, DoQCodeProtocolError)
|
s.closeQUICConn(conn, DoQCodeProtocolError)
|
||||||
|
|||||||
24
plugin/pkg/dnsutil/message.go
Normal file
24
plugin/pkg/dnsutil/message.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errRequestRejected = errors.New("dns request rejected")
|
||||||
|
|
||||||
|
// UnpackRequest unpacks a request after applying the default miekg/dns request policy.
|
||||||
|
func UnpackRequest(msg []byte) (*dns.Msg, error) {
|
||||||
|
var header dns.Header
|
||||||
|
if _, err := binary.Decode(msg, binary.BigEndian, &header); err != nil {
|
||||||
|
return nil, dns.ErrBuf
|
||||||
|
}
|
||||||
|
if dns.DefaultMsgAcceptFunc(header) != dns.MsgAccept {
|
||||||
|
return nil, errRequestRejected
|
||||||
|
}
|
||||||
|
|
||||||
|
request := new(dns.Msg)
|
||||||
|
return request, request.Unpack(msg)
|
||||||
|
}
|
||||||
29
plugin/pkg/dnsutil/message_test.go
Normal file
29
plugin/pkg/dnsutil/message_test.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnpackRequest(t *testing.T) {
|
||||||
|
request := new(dns.Msg)
|
||||||
|
request.SetQuestion("example.org.", dns.TypeA)
|
||||||
|
|
||||||
|
wire, err := request.Pack()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := UnpackRequest(wire); err != nil {
|
||||||
|
t.Fatalf("UnpackRequest() rejected a valid request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Question = append(request.Question, request.Question[0])
|
||||||
|
wire, err = request.Pack()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := UnpackRequest(wire); err == nil {
|
||||||
|
t.Fatal("UnpackRequest() accepted multiple questions")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -106,7 +108,12 @@ func RequestToMsgWire(req *http.Request) (*dns.Msg, []byte, error) {
|
|||||||
// requestToMsgPost extracts the dns message from the request body.
|
// requestToMsgPost extracts the dns message from the request body.
|
||||||
func requestToMsgPost(req *http.Request) (*dns.Msg, []byte, error) {
|
func requestToMsgPost(req *http.Request) (*dns.Msg, []byte, error) {
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
return toMsgWire(req.Body)
|
buf, err := io.ReadAll(http.MaxBytesReader(nil, req.Body, maxDNSQuerySize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
m, err := dnsutil.UnpackRequest(buf)
|
||||||
|
return m, buf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxDNSQuerySize = 65536
|
const maxDNSQuerySize = 65536
|
||||||
@@ -149,9 +156,7 @@ func base64ToMsgWire(b64 string) (*dns.Msg, []byte, error) {
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m := new(dns.Msg)
|
m, err := dnsutil.UnpackRequest(buf)
|
||||||
err = m.Unpack(buf)
|
|
||||||
|
|
||||||
return m, buf, err
|
return m, buf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user