func (p Proxy) lookup(state middleware.State, r *dns.Msg) (*dns.Msg, error) { var ( reply *dns.Msg err error ) for _, upstream := range p.Upstreams { // allowed bla bla bla TODO(miek): fix full proxy spec from caddy? start := time.Now() // Since Select() should give us "up" hosts, keep retrying // hosts until timeout (or until we get a nil host). for time.Now().Sub(start) < tryDuration { host := upstream.Select() if host == nil { return nil, errUnreachable } atomic.AddInt64(&host.Conns, 1) // tls+tcp ? if state.Proto() == "tcp" { reply, err = middleware.Exchange(p.Client.TCP, r, host.Name) } else { reply, err = middleware.Exchange(p.Client.UDP, r, host.Name) } atomic.AddInt64(&host.Conns, -1) if err == nil { return reply, nil } timeout := host.FailTimeout if timeout == 0 { timeout = 10 * time.Second } atomic.AddInt32(&host.Fails, 1) go func(host *UpstreamHost, timeout time.Duration) { time.Sleep(timeout) atomic.AddInt32(&host.Fails, -1) }(host, timeout) } return nil, errUnreachable } return nil, errUnreachable }
// Report is a plain reporting function that the server can use for REFUSED and other // queries that are turned down because they don't match any middleware. func Report(state middleware.State, zone, rcode string, size int, start time.Time) { if requestCount == nil { // no metrics are enabled return } // Proto and Family net := state.Proto() fam := "1" if state.Family() == 2 { fam = "2" } typ := state.QType() requestCount.WithLabelValues(zone, net, fam).Inc() requestDuration.WithLabelValues(zone).Observe(float64(time.Since(start) / time.Millisecond)) if state.Do() { requestDo.WithLabelValues(zone).Inc() } if _, known := monitorType[typ]; known { requestType.WithLabelValues(zone, dns.Type(typ).String()).Inc() } else { requestType.WithLabelValues(zone, other).Inc() } if typ == dns.TypeIXFR || typ == dns.TypeAXFR { responseTransferSize.WithLabelValues(zone, net).Observe(float64(size)) requestTransferSize.WithLabelValues(zone, net).Observe(float64(state.Size())) } else { responseSize.WithLabelValues(zone, net).Observe(float64(size)) requestSize.WithLabelValues(zone, net).Observe(float64(state.Size())) } responseRcode.WithLabelValues(zone, rcode).Inc() }