| 
									
										
										
										
											2016-11-13 14:03:12 +00:00
										 |  |  | // Package edns provides function useful for adding/inspecting OPT records to/in messages.
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | package edns
 | 
					
						
							| 
									
										
										
										
											2016-04-09 11:13:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"errors"
 | 
					
						
							| 
									
										
										
										
											2018-12-06 21:18:11 +00:00
										 |  |  | 	"sync"
 | 
					
						
							| 
									
										
										
										
											2016-04-09 11:13:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-06 21:18:11 +00:00
										 |  |  | var sup = &supported{m: make(map[uint16]struct{})}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type supported struct {
 | 
					
						
							|  |  |  | 	m map[uint16]struct{}
 | 
					
						
							|  |  |  | 	sync.RWMutex
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetSupportedOption adds a new supported option the set of EDNS0 options that we support. Plugins typically call
 | 
					
						
							|  |  |  | // this in their setup code to signal support for a new option.
 | 
					
						
							|  |  |  | // By default we support:
 | 
					
						
							|  |  |  | // dns.EDNS0NSID, dns.EDNS0EXPIRE, dns.EDNS0COOKIE, dns.EDNS0TCPKEEPALIVE, dns.EDNS0PADDING. These
 | 
					
						
							|  |  |  | // values are not in this map and checked directly in the server.
 | 
					
						
							|  |  |  | func SetSupportedOption(option uint16) {
 | 
					
						
							|  |  |  | 	sup.Lock()
 | 
					
						
							|  |  |  | 	sup.m[option] = struct{}{}
 | 
					
						
							|  |  |  | 	sup.Unlock()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SupportedOption returns true if the option code is supported as an extra EDNS0 option.
 | 
					
						
							|  |  |  | func SupportedOption(option uint16) bool {
 | 
					
						
							|  |  |  | 	sup.RLock()
 | 
					
						
							|  |  |  | 	_, ok := sup.m[option]
 | 
					
						
							|  |  |  | 	sup.RUnlock()
 | 
					
						
							|  |  |  | 	return ok
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | // Version checks the EDNS version in the request. If error
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | // is nil everything is OK and we can invoke the plugin. If non-nil, the
 | 
					
						
							| 
									
										
										
										
											2016-04-09 11:13:04 +01:00
										 |  |  | // returned Msg is valid to be returned to the client (and should). For some
 | 
					
						
							|  |  |  | // reason this response should not contain a question RR in the question section.
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | func Version(req *dns.Msg) (*dns.Msg, error) {
 | 
					
						
							| 
									
										
										
										
											2016-04-09 11:13:04 +01:00
										 |  |  | 	opt := req.IsEdns0()
 | 
					
						
							|  |  |  | 	if opt == nil {
 | 
					
						
							|  |  |  | 		return nil, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if opt.Version() == 0 {
 | 
					
						
							|  |  |  | 		return nil, nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	m := new(dns.Msg)
 | 
					
						
							|  |  |  | 	m.SetReply(req)
 | 
					
						
							|  |  |  | 	// zero out question section, wtf.
 | 
					
						
							|  |  |  | 	m.Question = nil
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	o := new(dns.OPT)
 | 
					
						
							|  |  |  | 	o.Hdr.Name = "."
 | 
					
						
							|  |  |  | 	o.Hdr.Rrtype = dns.TypeOPT
 | 
					
						
							|  |  |  | 	o.SetVersion(0)
 | 
					
						
							| 
									
										
										
										
											2018-12-11 20:27:29 +00:00
										 |  |  | 	m.Rcode = dns.RcodeBadVers
 | 
					
						
							| 
									
										
										
										
											2016-04-09 11:13:04 +01:00
										 |  |  | 	o.SetExtendedRcode(dns.RcodeBadVers)
 | 
					
						
							|  |  |  | 	m.Extra = []dns.RR{o}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return m, errors.New("EDNS0 BADVERS")
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2016-04-09 16:17:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | // Size returns a normalized size based on proto.
 | 
					
						
							| 
									
										
										
										
											2019-10-04 09:44:58 +01:00
										 |  |  | func Size(proto string, size uint16) uint16 {
 | 
					
						
							| 
									
										
										
										
											2016-04-09 16:17:53 +01:00
										 |  |  | 	if proto == "tcp" {
 | 
					
						
							|  |  |  | 		return dns.MaxMsgSize
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if size < dns.MinMsgSize {
 | 
					
						
							|  |  |  | 		return dns.MinMsgSize
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return size
 | 
					
						
							|  |  |  | }
 |