mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			86 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package etcd
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"log"
 | |
| 
 | |
| 	"github.com/miekg/coredns/middleware"
 | |
| 
 | |
| 	"github.com/miekg/dns"
 | |
| 	"golang.org/x/net/context"
 | |
| )
 | |
| 
 | |
| // Stub wraps an Etcd. We have this type so that it can have a ServeDNS method.
 | |
| type Stub struct {
 | |
| 	Etcd
 | |
| 	Zone string // for what zone (and thus what nameservers are we called)
 | |
| }
 | |
| 
 | |
| func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg) (int, error) {
 | |
| 	if hasStubEdns0(req) {
 | |
| 		log.Printf("[WARNING] Forwarding cycle detected, refusing msg: %s", req.Question[0].Name)
 | |
| 		return dns.RcodeRefused, errors.New("stub forward cycle")
 | |
| 	}
 | |
| 	req = addStubEdns0(req)
 | |
| 	proxy, ok := (*s.Etcd.Stubmap)[s.Zone]
 | |
| 	if !ok { // somebody made a mistake..
 | |
| 		return dns.RcodeServerFailure, nil
 | |
| 	}
 | |
| 
 | |
| 	state := middleware.State{W: w, Req: req}
 | |
| 	m, e := proxy.Forward(state)
 | |
| 	if e != nil {
 | |
| 		return dns.RcodeServerFailure, e
 | |
| 	}
 | |
| 	m.RecursionAvailable, m.Compress = true, true
 | |
| 	state.SizeAndDo(m)
 | |
| 	w.WriteMsg(m)
 | |
| 	return dns.RcodeSuccess, nil
 | |
| }
 | |
| 
 | |
| // hasStubEdns0 checks if the message is carrying our special edns0 zero option.
 | |
| func hasStubEdns0(m *dns.Msg) bool {
 | |
| 	option := m.IsEdns0()
 | |
| 	if option == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	for _, o := range option.Option {
 | |
| 		if o.Option() == ednsStubCode && len(o.(*dns.EDNS0_LOCAL).Data) == 1 &&
 | |
| 			o.(*dns.EDNS0_LOCAL).Data[0] == 1 {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // addStubEdns0 adds our special option to the message's OPT record.
 | |
| func addStubEdns0(m *dns.Msg) *dns.Msg {
 | |
| 	option := m.IsEdns0()
 | |
| 	// Add a custom EDNS0 option to the packet, so we can detect loops when 2 stubs are forwarding to each other.
 | |
| 	if option != nil {
 | |
| 		option.Option = append(option.Option, &dns.EDNS0_LOCAL{ednsStubCode, []byte{1}})
 | |
| 		return m
 | |
| 	}
 | |
| 
 | |
| 	m.Extra = append(m.Extra, ednsStub)
 | |
| 	return m
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	ednsStubCode = dns.EDNS0LOCALSTART + 10
 | |
| 	stubDomain   = "stub.dns"
 | |
| )
 | |
| 
 | |
| var ednsStub = func() *dns.OPT {
 | |
| 	o := new(dns.OPT)
 | |
| 	o.Hdr.Name = "."
 | |
| 	o.Hdr.Rrtype = dns.TypeOPT
 | |
| 	o.SetUDPSize(4096)
 | |
| 
 | |
| 	e := new(dns.EDNS0_LOCAL)
 | |
| 	e.Code = ednsStubCode
 | |
| 	e.Data = []byte{1}
 | |
| 	o.Option = append(o.Option, e)
 | |
| 	return o
 | |
| }()
 |