// ServeDNS implements the middleware.Handler interface. func (d Dnssec) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} do := state.Do() qname := state.Name() qtype := state.QType() zone := middleware.Zones(d.zones).Matches(qname) if zone == "" { return d.Next.ServeDNS(ctx, w, r) } // Intercept queries for DNSKEY, but only if one of the zones matches the qname, otherwise we let // the query through. if qtype == dns.TypeDNSKEY { for _, z := range d.zones { if qname == z { resp := d.getDNSKEY(state, z, do) state.SizeAndDo(resp) w.WriteMsg(resp) return dns.RcodeSuccess, nil } } } drr := NewDnssecResponseWriter(w, d) return d.Next.ServeDNS(ctx, drr, r) }
func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, false) if err != nil { return nil, debug, err } for _, serv := range services { ip := net.ParseIP(serv.Host) switch { case ip == nil: // Try to resolve as CNAME if it's not an IP, but only if we don't create loops. if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { // x CNAME x is a direct loop, don't add those continue } newRecord := serv.NewCNAME(state.QName(), serv.Host) if len(previousRecords) > 7 { // don't add it, and just continue continue } if isDuplicateCNAME(newRecord, previousRecords) { continue } state1 := copyState(state, serv.Host, state.QType()) nextRecords, nextDebug, err := e.AAAA(zone, state1, append(previousRecords, newRecord)) if err == nil { // Not only have we found something we should add the CNAME and the IP addresses. if len(nextRecords) > 0 { records = append(records, newRecord) records = append(records, nextRecords...) debug = append(debug, nextDebug...) } continue } // This means we can not complete the CNAME, try to look else where. target := newRecord.Target if dns.IsSubDomain(zone, target) { // We should already have found it continue } m1, e1 := e.Proxy.Lookup(state, target, state.QType()) if e1 != nil { continue } // Len(m1.Answer) > 0 here is well? records = append(records, newRecord) records = append(records, m1.Answer...) continue // both here again case ip.To4() != nil: // nada? case ip.To4() == nil: records = append(records, serv.NewAAAA(state.QName(), ip.To16())) } } return records, debug, nil }
func (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} if state.QClass() != dns.ClassCHAOS || state.QType() != dns.TypeTXT { return c.Next.ServeDNS(ctx, w, r) } m := new(dns.Msg) m.SetReply(r) hdr := dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0} switch state.Name() { default: return c.Next.ServeDNS(ctx, w, r) case "authors.bind.": for a, _ := range c.Authors { m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{trim(a)}}) } case "version.bind.", "version.server.": m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{trim(c.Version)}}} case "hostname.bind.", "id.server.": hostname, err := os.Hostname() if err != nil { hostname = "localhost" } m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{trim(hostname)}}} } state.SizeAndDo(m) w.WriteMsg(m) return 0, nil }
// ServeDNS implements the middleware.Handler interface. func (c Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} qname := state.Name() qtype := state.QType() zone := middleware.Zones(c.Zones).Matches(qname) if zone == "" { return c.Next.ServeDNS(ctx, w, r) } do := state.Do() // might need more from OPT record? if i, ok := c.get(qname, qtype, do); ok { resp := i.toMsg(r) state.SizeAndDo(resp) w.WriteMsg(resp) cacheHitCount.WithLabelValues(zone).Inc() return dns.RcodeSuccess, nil } cacheMissCount.WithLabelValues(zone).Inc() crr := NewCachingResponseWriter(w, c.cache, c.cap) return c.Next.ServeDNS(ctx, crr, r) }
func (k Kubernetes) A(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, err error) { services, err := k.records(state, false) if err != nil { return nil, err } for _, serv := range services { ip := net.ParseIP(serv.Host) switch { case ip == nil: // TODO(miek): lowercasing? Should lowercase in everything see #85 if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { // x CNAME x is a direct loop, don't add those continue } newRecord := serv.NewCNAME(state.QName(), serv.Host) if len(previousRecords) > 7 { // don't add it, and just continue continue } if isDuplicateCNAME(newRecord, previousRecords) { continue } state1 := copyState(state, serv.Host, state.QType()) nextRecords, err := k.A(zone, state1, append(previousRecords, newRecord)) if err == nil { // Not only have we found something we should add the CNAME and the IP addresses. if len(nextRecords) > 0 { records = append(records, newRecord) records = append(records, nextRecords...) } continue } // This means we can not complete the CNAME, try to look else where. target := newRecord.Target if dns.IsSubDomain(zone, target) { // We should already have found it continue } m1, e1 := k.Proxy.Lookup(state, target, state.QType()) if e1 != nil { continue } // Len(m1.Answer) > 0 here is well? records = append(records, newRecord) records = append(records, m1.Answer...) continue case ip.To4() != nil: records = append(records, serv.NewA(state.QName(), ip.To4())) case ip.To4() == nil: // nodata? } } return records, nil }
// 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() }
// Serve an AXFR (and fallback of IXFR) as well. func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} if !x.TransferAllowed(state) { return dns.RcodeServerFailure, nil } if state.QType() != dns.TypeAXFR && state.QType() != dns.TypeIXFR { return 0, fmt.Errorf("xfr called with non transfer type: %d", state.QType()) } records := x.All() if len(records) == 0 { return dns.RcodeServerFailure, nil } ch := make(chan *dns.Envelope) defer close(ch) tr := new(dns.Transfer) go tr.Out(w, r, ch) j, l := 0, 0 records = append(records, records[0]) // add closing SOA to the end log.Printf("[INFO] Outgoing transfer of %d records of zone %s to %s started", len(records), x.origin, state.IP()) for i, r := range records { l += dns.Len(r) if l > transferLength { ch <- &dns.Envelope{RR: records[j:i]} l = 0 j = i } } if j < len(records) { ch <- &dns.Envelope{RR: records[j:]} } w.Hijack() // w.Close() // Client closes connection return dns.RcodeSuccess, nil }
func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { state := middleware.State{W: w, Req: r} if state.QClass() != dns.ClassINET { return dns.RcodeServerFailure, errors.New("can only deal with ClassINET") } qname := state.Name() zone := middleware.Zones(f.Zones.Names).Matches(qname) if zone == "" { if f.Next != nil { return f.Next.ServeDNS(ctx, w, r) } return dns.RcodeServerFailure, errors.New("no next middleware found") } z, ok := f.Zones.Z[zone] if !ok { return f.Next.ServeDNS(ctx, w, r) } if z == nil { return dns.RcodeServerFailure, nil } if r.Opcode == dns.OpcodeNotify { if z.isNotify(state) { m := new(dns.Msg) m.SetReply(r) m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true state.SizeAndDo(m) w.WriteMsg(m) log.Printf("[INFO] Notify from %s for %s: checking transfer", state.IP(), zone) ok, err := z.shouldTransfer() if ok { z.TransferIn() } else { log.Printf("[INFO] Notify from %s for %s: no serial increase seen", state.IP(), zone) } if err != nil { log.Printf("[WARNING] Notify from %s for %s: failed primary check: %s", state.IP(), zone, err) } return dns.RcodeSuccess, nil } log.Printf("[INFO] Dropping notify from %s for %s", state.IP(), zone) return dns.RcodeSuccess, nil } if z.Expired != nil && *z.Expired { log.Printf("[ERROR] Zone %s is expired", zone) return dns.RcodeServerFailure, nil } if state.QType() == dns.TypeAXFR || state.QType() == dns.TypeIXFR { xfr := Xfr{z} return xfr.ServeDNS(ctx, w, r) } answer, ns, extra, result := z.Lookup(qname, state.QType(), state.Do()) m := new(dns.Msg) m.SetReply(r) m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true m.Answer, m.Ns, m.Extra = answer, ns, extra switch result { case Success: case NoData: case NameError: m.Rcode = dns.RcodeNameError case Delegation: m.Authoritative = false case ServerFailure: return dns.RcodeServerFailure, nil } state.SizeAndDo(m) m, _ = state.Scrub(m) w.WriteMsg(m) return dns.RcodeSuccess, nil }