mirror of
https://github.com/folbricht/routedns.git
synced 2026-01-06 09:40:03 -06:00
Add empty-error for detecting unusual empty responses
This commit is contained in:
@@ -111,6 +111,7 @@ type group struct {
|
||||
// Failover/Failback options
|
||||
ResetAfter int `toml:"reset-after"` // Time in seconds after which to reset resolvers in fail-back and random groups, default 0 (reset immediately).
|
||||
ServfailError bool `toml:"servfail-error"` // If true, SERVFAIL responses are considered errors and cause failover etc.
|
||||
EmptyError bool `toml:"empty-error"` // If true, empty responses that are unusual (such as NOERROR with no records instead of NXDOMAIN) are considered errors and cause failover etc.
|
||||
|
||||
// Cache options
|
||||
Backend *cacheBackend
|
||||
|
||||
@@ -370,12 +370,14 @@ func instantiateGroup(id string, g group, resolvers map[string]rdns.Resolver) er
|
||||
case "fail-rotate":
|
||||
opt := rdns.FailRotateOptions{
|
||||
ServfailError: g.ServfailError,
|
||||
EmptyError: g.EmptyError,
|
||||
}
|
||||
resolvers[id] = rdns.NewFailRotate(id, opt, gr...)
|
||||
case "fail-back":
|
||||
opt := rdns.FailBackOptions{
|
||||
ResetAfter: time.Duration(time.Duration(g.ResetAfter) * time.Second),
|
||||
ServfailError: g.ServfailError,
|
||||
EmptyError: g.EmptyError,
|
||||
}
|
||||
resolvers[id] = rdns.NewFailBack(id, opt, gr...)
|
||||
case "fastest":
|
||||
@@ -384,6 +386,7 @@ func instantiateGroup(id string, g group, resolvers map[string]rdns.Resolver) er
|
||||
opt := rdns.RandomOptions{
|
||||
ResetAfter: time.Duration(time.Duration(g.ResetAfter) * time.Second),
|
||||
ServfailError: g.ServfailError,
|
||||
EmptyError: g.EmptyError,
|
||||
}
|
||||
resolvers[id] = rdns.NewRandom(id, opt, gr...)
|
||||
case "blocklist":
|
||||
|
||||
@@ -519,6 +519,7 @@ Options:
|
||||
|
||||
- `resolvers` - An array of upstream resolvers or modifiers.
|
||||
- `servfail-error` - If `true`, a SERVFAIL response from an upstream resolver is considered a failure triggering a switch to the next resolver. This can happen when DNSSEC validation fails for example. Default `false`.
|
||||
- `empty-error` - If `true`, a unusual empty reponse (such as NOERROR with no records instead of NXDOMAIN) from an upstream resolver is considered a failure triggering a switch to the next resolver. Default `false`.
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -539,8 +540,9 @@ Fail-Back groups are instantiated with `type = "fail-back"` in the groups sectio
|
||||
Options:
|
||||
|
||||
- `resolvers` - An array of upstream resolvers or modifiers. The first in the array is the preferred resolver.
|
||||
- `reset-after` - Time in seconds before switching from an alternative resolver back to the preferred resolver (first in the list), default 60. Note: This is not a timeout argument. After a failure of the preferred resolver, this defines the amount of time to use alternative/failover resolvers before switching back to the preferred. You can have as many resolvers in the array as the time limit allows.
|
||||
- `reset-after` - Time in seconds before switching from an alternative resolver back to the preferred resolver (first in the list), default 0 (meaning it will switch after a single request). Note: This is not a timeout argument. After a failure of the preferred resolver, this defines the amount of time to use alternative/failover resolvers before switching back to the preferred. You can have as many resolvers in the array as the time limit allows.
|
||||
- `servfail-error` - If `true`, a SERVFAIL response from an upstream resolver is considered a failure triggering a failover. This can happen when DNSSEC validation fails for example. Default `false`.
|
||||
- `empty-error` - If `true`, a unusual empty reponse (such as NOERROR with no records instead of NXDOMAIN) from an upstream resolver is considered a failure triggering a switch to the next resolver. Default `false`.
|
||||
|
||||
#### Examples
|
||||
|
||||
@@ -561,8 +563,9 @@ Random groups are instantiated with `type = "random"` in the groups section of t
|
||||
Options:
|
||||
|
||||
- `resolvers` - An array of upstream resolvers or modifiers.
|
||||
- `reset-after` - Time in seconds to disable a failed resolver, default 60.
|
||||
- `reset-after` - Time in seconds to disable a failed resolver, default 0 (disabled only for a single request).
|
||||
- `servfail-error` - If `true`, a SERVFAIL response from an upstream resolver is considered a failure which will take the resolver temporarily out of the group. This can happen when DNSSEC validation fails for example. Default `false`.
|
||||
- `empty-error` - If `true`, a unusual empty reponse (such as NOERROR with no records instead of NXDOMAIN) from an upstream resolver is considered a failure triggering a switch to the next resolver. Default `false`.
|
||||
|
||||
#### Examples
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ type FailBackOptions struct {
|
||||
// Determines if a SERVFAIL returned by a resolver should be considered an
|
||||
// error response and trigger a failover.
|
||||
ServfailError bool
|
||||
|
||||
// Determines if an empty reponse (that isn't NXDOMAIN) returned by a resolver
|
||||
// should be considered an error respone and trigger a failover.
|
||||
EmptyError bool
|
||||
}
|
||||
|
||||
var _ Resolver = &FailBack{}
|
||||
@@ -155,5 +159,7 @@ func (r *FailBack) startResetTimer() chan struct{} {
|
||||
|
||||
// Returns true is the response is considered successful given the options.
|
||||
func (r *FailBack) isSuccessResponse(a *dns.Msg) bool {
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure)
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure) &&
|
||||
!(r.opt.EmptyError && a.Rcode == dns.RcodeSuccess && len(a.Answer) == 0 ||
|
||||
a.Rcode == dns.RcodeNameError && len(a.Answer) == 1 && a.Answer[0].Header().Rrtype == dns.TypeCNAME)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ type FailRotateOptions struct {
|
||||
// Determines if a SERVFAIL returned by a resolver should be considered an
|
||||
// error response and trigger a failover.
|
||||
ServfailError bool
|
||||
|
||||
// Determines if an empty reponse (that isn't NXDOMAIN) returned by a resolver
|
||||
// should be considered an error respone and trigger a failover.
|
||||
EmptyError bool
|
||||
}
|
||||
|
||||
var _ Resolver = &FailRotate{}
|
||||
@@ -94,5 +98,7 @@ func (r *FailRotate) errorFrom(i int) {
|
||||
|
||||
// Returns true is the response is considered successful given the options.
|
||||
func (r *FailRotate) isSuccessResponse(a *dns.Msg) bool {
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure)
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure) &&
|
||||
!(r.opt.EmptyError && a.Rcode == dns.RcodeSuccess && len(a.Answer) == 0 ||
|
||||
a.Rcode == dns.RcodeNameError && len(a.Answer) == 1 && a.Answer[0].Header().Rrtype == dns.TypeCNAME)
|
||||
}
|
||||
|
||||
11
random.go
11
random.go
@@ -30,14 +30,15 @@ type RandomOptions struct {
|
||||
// Determines if a SERVFAIL returned by a resolver should be considered an
|
||||
// error response and cause the resolver to be removed from the group temporarily.
|
||||
ServfailError bool
|
||||
|
||||
// Determines if an empty reponse (that isn't NXDOMAIN) returned by a resolver
|
||||
// should be considered an error respone and trigger a failover.
|
||||
EmptyError bool
|
||||
}
|
||||
|
||||
// NewRandom returns a new instance of a random resolver group.
|
||||
func NewRandom(id string, opt RandomOptions, resolvers ...Resolver) *Random {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
if opt.ResetAfter == 0 {
|
||||
opt.ResetAfter = time.Minute
|
||||
}
|
||||
return &Random{
|
||||
id: id,
|
||||
resolvers: resolvers,
|
||||
@@ -121,5 +122,7 @@ func (r *Random) reactivateLater(resolver Resolver) {
|
||||
|
||||
// Returns true is the response is considered successful given the options.
|
||||
func (r *Random) isSuccessResponse(a *dns.Msg) bool {
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure)
|
||||
return a == nil || !(r.opt.ServfailError && a.Rcode == dns.RcodeServerFailure) &&
|
||||
!(r.opt.EmptyError && a.Rcode == dns.RcodeSuccess && len(a.Answer) == 0 ||
|
||||
a.Rcode == dns.RcodeNameError && len(a.Answer) == 1 && a.Answer[0].Header().Rrtype == dns.TypeCNAME)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user