aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2017-08-31 16:24:11 +0200
committerGravatar GitHub <noreply@github.com> 2017-08-31 16:24:11 +0200
commit5eccfa2d1e4b76ac0320dc4123413cb0300a39b9 (patch)
tree365dd3669dbbb33dfdde6950c850ce626054de89
parentc72084187c42a526e4b754741c392a38733ceec2 (diff)
downloadcoredns-5eccfa2d1e4b76ac0320dc4123413cb0300a39b9.tar.gz
coredns-5eccfa2d1e4b76ac0320dc4123413cb0300a39b9.tar.zst
coredns-5eccfa2d1e4b76ac0320dc4123413cb0300a39b9.zip
core: harden request.Request (#1009)
Check for a nil message and if we have a question section. Request is usually called with an external Msg that already saw validation checks, but we may also call it from message we create of our own, that may or may not adhire to this. Just be more robust in this case. This PR reverts a previous commit that was applied to master.
-rw-r--r--core/dnsserver/server.go6
-rw-r--r--request/request.go76
-rw-r--r--request/request_test.go29
3 files changed, 98 insertions, 13 deletions
diff --git a/core/dnsserver/server.go b/core/dnsserver/server.go
index 8e2f0ba76..3f01cac5f 100644
--- a/core/dnsserver/server.go
+++ b/core/dnsserver/server.go
@@ -289,12 +289,6 @@ func DefaultErrorFunc(w dns.ResponseWriter, r *dns.Msg, rc int) {
answer := new(dns.Msg)
answer.SetRcode(r, rc)
- if r == nil {
- log.Printf("[WARNING] DefaultErrorFunc called with nil *dns.Msg (Remote: %s)", w.RemoteAddr().String())
- w.WriteMsg(answer)
- return
- }
-
state.SizeAndDo(answer)
vars.Report(state, vars.Dropped, rcode.ToString(rc), answer.Len(), time.Now())
diff --git a/request/request.go b/request/request.go
index 89b4a4cf4..a2428c464 100644
--- a/request/request.go
+++ b/request/request.go
@@ -205,31 +205,93 @@ func (r *Request) Scrub(reply *dns.Msg) (*dns.Msg, Result) {
return reply, ScrubDone
}
-// Type returns the type of the question as a string.
-func (r *Request) Type() string { return dns.Type(r.Req.Question[0].Qtype).String() }
+// Type returns the type of the question as a string. If the request is malformed
+// the empty string is returned.
+func (r *Request) Type() string {
+ if r.Req == nil {
+ return ""
+ }
+ if len(r.Req.Question) == 0 {
+ return ""
+ }
-// QType returns the type of the question as an uint16.
-func (r *Request) QType() uint16 { return r.Req.Question[0].Qtype }
+ return dns.Type(r.Req.Question[0].Qtype).String()
+}
+
+// QType returns the type of the question as an uint16. If the request is malformed
+// 0 is returned.
+func (r *Request) QType() uint16 {
+ if r.Req == nil {
+ return 0
+ }
+ if len(r.Req.Question) == 0 {
+ return 0
+ }
+
+ return r.Req.Question[0].Qtype
+}
// Name returns the name of the question in the request. Note
// this name will always have a closing dot and will be lower cased. After a call Name
// the value will be cached. To clear this caching call Clear.
+// If the request is malformed the root zone is returned.
func (r *Request) Name() string {
if r.name != "" {
return r.name
}
+ if r.Req == nil {
+ r.name = "."
+ return "."
+ }
+ if len(r.Req.Question) == 0 {
+ r.name = "."
+ return "."
+ }
+
r.name = strings.ToLower(dns.Name(r.Req.Question[0].Name).String())
return r.name
}
// QName returns the name of the question in the request.
-func (r *Request) QName() string { return dns.Name(r.Req.Question[0].Name).String() }
+// If the request is malformed the root zone is returned.
+func (r *Request) QName() string {
+ if r.Req == nil {
+ return "."
+ }
+ if len(r.Req.Question) == 0 {
+ return "."
+ }
+
+ return dns.Name(r.Req.Question[0].Name).String()
+}
// Class returns the class of the question in the request.
-func (r *Request) Class() string { return dns.Class(r.Req.Question[0].Qclass).String() }
+// If the request is malformed the empty string is returned.
+func (r *Request) Class() string {
+ if r.Req == nil {
+ return ""
+ }
+ if len(r.Req.Question) == 0 {
+ return ""
+ }
+
+ return dns.Class(r.Req.Question[0].Qclass).String()
+
+}
// QClass returns the class of the question in the request.
-func (r *Request) QClass() uint16 { return r.Req.Question[0].Qclass }
+// If the request is malformed 0 returned.
+func (r *Request) QClass() uint16 {
+ if r.Req == nil {
+ return 0
+ }
+ if len(r.Req.Question) == 0 {
+ return 0
+ }
+
+ return r.Req.Question[0].Qclass
+
+}
// ErrorMessage returns an error message suitable for sending
// back to the client.
diff --git a/request/request_test.go b/request/request_test.go
index 563e6dfe2..bc08ea6ab 100644
--- a/request/request_test.go
+++ b/request/request_test.go
@@ -31,6 +31,35 @@ func TestRequestRemote(t *testing.T) {
}
}
+func TestRequestMalformed(t *testing.T) {
+ m := new(dns.Msg)
+ st := Request{Req: m}
+
+ if x := st.QType(); x != 0 {
+ t.Errorf("Expected 0 Qtype, got %d", x)
+ }
+
+ if x := st.QClass(); x != 0 {
+ t.Errorf("Expected 0 QClass, got %d", x)
+ }
+
+ if x := st.QName(); x != "." {
+ t.Errorf("Expected . Qname, got %s", x)
+ }
+
+ if x := st.Name(); x != "." {
+ t.Errorf("Expected . Name, got %s", x)
+ }
+
+ if x := st.Type(); x != "" {
+ t.Errorf("Expected empty Type, got %s", x)
+ }
+
+ if x := st.Class(); x != "" {
+ t.Errorf("Expected empty Class, got %s", x)
+ }
+}
+
func BenchmarkRequestDo(b *testing.B) {
st := testRequest()