2018-07-20 19:45:17 +01:00
package loop
import (
"context"
"sync"
"github.com/coredns/coredns/plugin"
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
var log = clog . NewWithPlugin ( "loop" )
// Loop is a plugin that implements loop detection by sending a "random" query.
type Loop struct {
Next plugin . Handler
zone string
qname string
2018-12-16 21:48:09 +00:00
addr string
2018-07-20 19:45:17 +01:00
sync . RWMutex
i int
off bool
}
// New returns a new initialized Loop.
func New ( zone string ) * Loop { return & Loop { zone : zone , qname : qname ( zone ) } }
// ServeDNS implements the plugin.Handler interface.
func ( l * Loop ) ServeDNS ( ctx context . Context , w dns . ResponseWriter , r * dns . Msg ) ( int , error ) {
if r . Question [ 0 ] . Qtype != dns . TypeHINFO {
return plugin . NextOrFailure ( l . Name ( ) , l . Next , ctx , w , r )
}
if l . disabled ( ) {
return plugin . NextOrFailure ( l . Name ( ) , l . Next , ctx , w , r )
}
state := request . Request { W : w , Req : r }
zone := plugin . Zones ( [ ] string { l . zone } ) . Matches ( state . Name ( ) )
if zone == "" {
return plugin . NextOrFailure ( l . Name ( ) , l . Next , ctx , w , r )
}
if state . Name ( ) == l . qname {
l . inc ( )
}
if l . seen ( ) > 2 {
2018-12-16 21:48:09 +00:00
log . Fatalf ( ` Loop (%s -> %s) detected for zone %q, see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO %s" ` , state . RemoteAddr ( ) , l . address ( ) , l . zone , l . qname )
2018-07-20 19:45:17 +01:00
}
return plugin . NextOrFailure ( l . Name ( ) , l . Next , ctx , w , r )
}
// Name implements the plugin.Handler interface.
func ( l * Loop ) Name ( ) string { return "loop" }
func ( l * Loop ) exchange ( addr string ) ( * dns . Msg , error ) {
m := new ( dns . Msg )
m . SetQuestion ( l . qname , dns . TypeHINFO )
return dns . Exchange ( m , addr )
}
func ( l * Loop ) seen ( ) int {
l . RLock ( )
defer l . RUnlock ( )
return l . i
}
func ( l * Loop ) inc ( ) {
l . Lock ( )
defer l . Unlock ( )
l . i ++
}
2018-10-31 18:20:43 +01:00
func ( l * Loop ) reset ( ) {
l . Lock ( )
defer l . Unlock ( )
l . i = 0
}
2018-07-20 19:45:17 +01:00
func ( l * Loop ) setDisabled ( ) {
l . Lock ( )
defer l . Unlock ( )
l . off = true
}
func ( l * Loop ) disabled ( ) bool {
l . RLock ( )
defer l . RUnlock ( )
return l . off
}
2018-12-16 21:48:09 +00:00
func ( l * Loop ) setAddress ( addr string ) {
l . Lock ( )
defer l . Unlock ( )
l . addr = addr
}
func ( l * Loop ) address ( ) string {
l . RLock ( )
defer l . RUnlock ( )
return l . addr
}