| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | package etcd
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2018-04-22 08:34:35 +01:00
										 |  |  | 	"context"
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:50:01 +01:00
										 |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:30:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:30:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stub wraps an Etcd. We have this type so that it can have a ServeDNS method.
 | 
					
						
							|  |  |  | type Stub struct {
 | 
					
						
							| 
									
										
										
										
											2016-08-08 19:18:55 -07:00
										 |  |  | 	*Etcd
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	Zone string // for what zone (and thus what nameservers are we called)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // ServeDNS implements the plugin.Handler interface.
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | func (s Stub) ServeDNS(ctx context.Context, w dns.ResponseWriter, req *dns.Msg) (int, error) {
 | 
					
						
							|  |  |  | 	if hasStubEdns0(req) {
 | 
					
						
							| 
									
										
										
										
											2018-04-19 07:41:56 +01:00
										 |  |  | 		log.Warningf("Forwarding cycle detected, refusing msg: %s", req.Question[0].Name)
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:50:01 +01:00
										 |  |  | 		return dns.RcodeRefused, errors.New("stub forward cycle")
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	req = addStubEdns0(req)
 | 
					
						
							|  |  |  | 	proxy, ok := (*s.Etcd.Stubmap)[s.Zone]
 | 
					
						
							|  |  |  | 	if !ok { // somebody made a mistake..
 | 
					
						
							|  |  |  | 		return dns.RcodeServerFailure, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 	state := request.Request{W: w, Req: req}
 | 
					
						
							| 
									
										
										
										
											2016-04-09 16:17:53 +01:00
										 |  |  | 	m, e := proxy.Forward(state)
 | 
					
						
							|  |  |  | 	if e != nil {
 | 
					
						
							|  |  |  | 		return dns.RcodeServerFailure, e
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2018-05-01 21:04:06 +01:00
										 |  |  | 	m.RecursionAvailable = true
 | 
					
						
							| 
									
										
										
										
											2016-04-09 16:17:53 +01:00
										 |  |  | 	w.WriteMsg(m)
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	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 {
 | 
					
						
							| 
									
										
										
										
											2016-06-11 08:00:47 +10:00
										 |  |  | 		option.Option = append(option.Option, &dns.EDNS0_LOCAL{Code: ednsStubCode, Data: []byte{1}})
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:30:08 +01:00
										 |  |  | 		return m
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:30:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	m.Extra = append(m.Extra, ednsStub)
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 	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
 | 
					
						
							| 
									
										
										
										
											2016-04-12 21:30:08 +01:00
										 |  |  | 	o.SetUDPSize(4096)
 | 
					
						
							| 
									
										
										
										
											2016-03-25 20:26:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	e := new(dns.EDNS0_LOCAL)
 | 
					
						
							|  |  |  | 	e.Code = ednsStubCode
 | 
					
						
							|  |  |  | 	e.Data = []byte{1}
 | 
					
						
							|  |  |  | 	o.Option = append(o.Option, e)
 | 
					
						
							|  |  |  | 	return o
 | 
					
						
							|  |  |  | }()
 |