diff options
Diffstat (limited to 'plugin/forward/health.go')
-rw-r--r-- | plugin/forward/health.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/plugin/forward/health.go b/plugin/forward/health.go new file mode 100644 index 000000000..e277f30a6 --- /dev/null +++ b/plugin/forward/health.go @@ -0,0 +1,67 @@ +package forward + +import ( + "log" + "sync/atomic" + + "github.com/miekg/dns" +) + +// For HC we send to . IN NS +norec message to the upstream. Dial timeouts and empty +// replies are considered fails, basically anything else constitutes a healthy upstream. + +func (h *host) Check() { + h.Lock() + + if h.checking { + h.Unlock() + return + } + + h.checking = true + h.Unlock() + + err := h.send() + if err != nil { + log.Printf("[INFO] healtheck of %s failed with %s", h.addr, err) + + HealthcheckFailureCount.WithLabelValues(h.addr).Add(1) + + atomic.AddUint32(&h.fails, 1) + } else { + atomic.StoreUint32(&h.fails, 0) + } + + h.Lock() + h.checking = false + h.Unlock() + + return +} + +func (h *host) send() error { + hcping := new(dns.Msg) + hcping.SetQuestion(".", dns.TypeNS) + hcping.RecursionDesired = false + + m, _, err := h.client.Exchange(hcping, h.addr) + // If we got a header, we're alright, basically only care about I/O errors 'n stuff + if err != nil && m != nil { + // Silly check, something sane came back + if m.Response || m.Opcode == dns.OpcodeQuery { + err = nil + } + } + + return err +} + +// down returns true is this host has more than maxfails fails. +func (h *host) down(maxfails uint32) bool { + if maxfails == 0 { + return false + } + + fails := atomic.LoadUint32(&h.fails) + return fails > maxfails +} |