func (p ReverseProxy) ServeDNS(w dns.ResponseWriter, r *dns.Msg, extra []dns.RR) error { var ( reply *dns.Msg err error ) switch { case middleware.Proto(w) == "tcp": reply, err = middleware.Exchange(p.Client.TCP, r, p.Host) default: reply, err = middleware.Exchange(p.Client.UDP, r, p.Host) } if reply != nil && reply.Truncated { // Suppress proxy error for truncated responses err = nil } if err != nil { return err } reply.Compress = true reply.Id = r.Id w.WriteMsg(reply) return nil }
// shouldTransfer checks the primaries of zone, retrieves the SOA record, checks the current serial // and the remote serial and will return true if the remote one is higher than the locally configured one. func (z *Zone) shouldTransfer() (bool, error) { c := new(dns.Client) c.Net = "tcp" // do this query over TCP to minimize spoofing m := new(dns.Msg) m.SetQuestion(z.origin, dns.TypeSOA) var Err error serial := -1 Transfer: for _, tr := range z.TransferFrom { Err = nil ret, err := middleware.Exchange(c, m, tr) if err != nil || ret.Rcode != dns.RcodeSuccess { Err = err continue } for _, a := range ret.Answer { if a.Header().Rrtype == dns.TypeSOA { serial = int(a.(*dns.SOA).Serial) break Transfer } } } if serial == -1 { return false, Err } return less(z.Apex.SOA.Serial, uint32(serial)), Err }
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 }
func notifyAddr(c *dns.Client, m *dns.Msg, s string) error { for i := 0; i < 3; i++ { ret, err := middleware.Exchange(c, m, s) if err != nil { continue } if ret.Rcode == dns.RcodeSuccess || ret.Rcode == dns.RcodeNotImplemented { return nil } } return fmt.Errorf("Failed to send notify for zone '%s' to '%s'", m.Question[0].Name, s) }
func Exchange(m *dns.Msg, server, net string) (*dns.Msg, error) { c := new(dns.Client) c.Net = net return middleware.Exchange(c, m, server) }