diff options
Diffstat (limited to 'middleware/pkg/response/typify.go')
-rw-r--r-- | middleware/pkg/response/typify.go | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/middleware/pkg/response/typify.go b/middleware/pkg/response/typify.go new file mode 100644 index 000000000..6fdd0137a --- /dev/null +++ b/middleware/pkg/response/typify.go @@ -0,0 +1,96 @@ +package response + +import ( + "fmt" + + "github.com/miekg/dns" +) + +// Type is the type of the message +type Type int + +const ( + // Success indicates a positive reply + NoError Type = iota + // NameError is a NXDOMAIN in header, SOA in auth. + NameError + // NoData indicated name found, but not the type: NOERROR in header, SOA in auth. + NoData + // Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked). + Delegation + // OtherError indicated any other error: don't cache these. + OtherError +) + +func (t Type) String() string { + switch t { + case NoError: + return "NOERROR" + case NameError: + return "NXDOMAIN" + case NoData: + return "NODATA" + case Delegation: + return "DELEGATION" + case OtherError: + return "OTHERERROR" + } + return "" +} + +// TypeFromString returns the type from the string s. If not type matches +// the OtherError type and an error are returned. +func TypeFromString(s string) (Type, error) { + switch s { + case "NOERROR": + return NoError, nil + case "NXDOMAIN": + return NameError, nil + case "NODATA": + return NoData, nil + case "DELEGATION": + return Delegation, nil + case "OTHERERROR": + return OtherError, nil + } + return NoError, fmt.Errorf("invalid Type: %s", s) +} + +// Typify classifies a message, it returns the Type. +func Typify(m *dns.Msg) (Type, *dns.OPT) { + opt := m.IsEdns0() + + if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess { + return NoError, opt + } + + soa := false + ns := 0 + for _, r := range m.Ns { + if r.Header().Rrtype == dns.TypeSOA { + soa = true + continue + } + if r.Header().Rrtype == dns.TypeNS { + ns++ + } + } + + // Check length of different sections, and drop stuff that is just to large? TODO(miek). + if soa && m.Rcode == dns.RcodeSuccess { + return NoData, opt + } + if soa && m.Rcode == dns.RcodeNameError { + return NameError, opt + } + + if ns > 0 && ns == len(m.Ns) && m.Rcode == dns.RcodeSuccess { + return Delegation, opt + } + + if m.Rcode == dns.RcodeSuccess { + return NoError, opt + } + + return OtherError, opt +} |