middleware/log: allows logging based on response classes (#325)
Add the ability to add a class of responses to be logged; success, denial or error. The default is to log everything (all). Fixes #258
This commit is contained in:
parent
caa3976bfe
commit
c22b7b2252
13 changed files with 348 additions and 108 deletions
|
@ -1,74 +1,73 @@
|
|||
package response
|
||||
|
||||
import "github.com/miekg/dns"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// Type is the type of the message
|
||||
type Type int
|
||||
|
||||
const (
|
||||
// Success indicates a positive reply
|
||||
Success 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
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func (t Type) String() string {
|
||||
switch t {
|
||||
// Class holds sets of Types
|
||||
type Class int
|
||||
|
||||
const (
|
||||
// All is a meta class encompassing all the classes.
|
||||
All Class = iota
|
||||
// Success is a class for a successful response.
|
||||
Success
|
||||
// Denial is a class for denying existence (NXDOMAIN, or a nodata: type does not exist)
|
||||
Denial
|
||||
// Error is a class for errors, right now defined as not Success and not Denial
|
||||
Error
|
||||
)
|
||||
|
||||
func (c Class) String() string {
|
||||
switch c {
|
||||
case All:
|
||||
return "all"
|
||||
case Success:
|
||||
return "NOERROR"
|
||||
case NameError:
|
||||
return "NXDOMAIN"
|
||||
case NoData:
|
||||
return "NODATA"
|
||||
case Delegation:
|
||||
return "DELEGATION"
|
||||
case OtherError:
|
||||
return "OTHERERROR"
|
||||
return "success"
|
||||
case Denial:
|
||||
return "denial"
|
||||
case Error:
|
||||
return "error"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Classify classifies a message, it returns the Type.
|
||||
func Classify(m *dns.Msg) (Type, *dns.OPT) {
|
||||
opt := m.IsEdns0()
|
||||
|
||||
if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess {
|
||||
return Success, opt
|
||||
// ClassFromString returns the class from the string s. If not class matches
|
||||
// the All class and an error are returned
|
||||
func ClassFromString(s string) (Class, error) {
|
||||
switch s {
|
||||
case "all":
|
||||
return All, nil
|
||||
case "success":
|
||||
return Success, nil
|
||||
case "denial":
|
||||
return Denial, nil
|
||||
case "error":
|
||||
return Error, nil
|
||||
}
|
||||
|
||||
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 Success, opt
|
||||
}
|
||||
|
||||
return OtherError, opt
|
||||
return All, fmt.Errorf("invalid Class: %s", s)
|
||||
}
|
||||
|
||||
// Classify classifies a dns message: it returns its Class.
|
||||
func Classify(m *dns.Msg) (Class, *dns.OPT) {
|
||||
t, o := Typify(m)
|
||||
return classify(t), o
|
||||
}
|
||||
|
||||
// Does need to be exported?
|
||||
func classify(t Type) Class {
|
||||
switch t {
|
||||
case NoError, Delegation:
|
||||
return Success
|
||||
case NameError, NoData:
|
||||
return Denial
|
||||
case OtherError:
|
||||
fallthrough
|
||||
default:
|
||||
return Error
|
||||
}
|
||||
// never reached
|
||||
return All
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue