mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 10:13:14 -04:00 
			
		
		
		
	Rewrite edns0 (#561)
* Add edns0 code rewrite * check arg count * change `new`; set EDNS0 if request doesn't have it set * change set to replace_or_append * change to append_or_replace * return error in new * update documents * fixt UT * return error * go fmt * Rework for more general EDNS0 use Also changed how rules are created and validated. Implements EDNS0 NSID in addition to local. * go fmt * README updates, NSID tests and fixes * gofmt -s -w * Fix tests for rewrite syntax change * Add tests, fix error message * Review nits * Missed on nit * More tests, integration test, fix edns0 parse issue * Fix README, use RewriteIgnored * go fmt
This commit is contained in:
		
				
					committed by
					
						 Miek Gieben
						Miek Gieben
					
				
			
			
				
	
			
			
			
						parent
						
							d1bb4ea130
						
					
				
				
					commit
					ef315ef3e2
				
			
							
								
								
									
										141
									
								
								middleware/rewrite/edns0.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								middleware/rewrite/edns0.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| // Package rewrite is middleware for rewriting requests internally to something different. | ||||
| package rewrite | ||||
|  | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| ) | ||||
|  | ||||
| // edns0LocalRule is a rewrite rule for EDNS0_LOCAL options | ||||
| type edns0LocalRule struct { | ||||
| 	action string | ||||
| 	code   uint16 | ||||
| 	data   []byte | ||||
| } | ||||
|  | ||||
| // ends0NsidRule is a rewrite rule for EDNS0_NSID options | ||||
| type edns0NsidRule struct { | ||||
| 	action string | ||||
| } | ||||
|  | ||||
| // setupEdns0Opt will retrieve the EDNS0 OPT or create it if it does not exist | ||||
| func setupEdns0Opt(r *dns.Msg) *dns.OPT { | ||||
| 	o := r.IsEdns0() | ||||
| 	if o == nil { | ||||
| 		r.SetEdns0(4096, true) | ||||
| 		o = r.IsEdns0() | ||||
| 	} | ||||
| 	return o | ||||
| } | ||||
|  | ||||
| // Rewrite will alter the request EDNS0 NSID option | ||||
| func (rule *edns0NsidRule) Rewrite(r *dns.Msg) Result { | ||||
| 	result := RewriteIgnored | ||||
| 	o := setupEdns0Opt(r) | ||||
| 	found := false | ||||
| 	for _, s := range o.Option { | ||||
| 		switch e := s.(type) { | ||||
| 		case *dns.EDNS0_NSID: | ||||
| 			if rule.action == "replace" || rule.action == "set" { | ||||
| 				e.Nsid = "" // make sure it is empty for request | ||||
| 				result = RewriteDone | ||||
| 			} | ||||
| 			found = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// add option if not found | ||||
| 	if !found && (rule.action == "append" || rule.action == "set") { | ||||
| 		o.SetDo(true) | ||||
| 		o.Option = append(o.Option, &dns.EDNS0_NSID{Code: dns.EDNS0NSID, Nsid: ""}) | ||||
| 		result = RewriteDone | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Rewrite will alter the request EDNS0 local options | ||||
| func (rule *edns0LocalRule) Rewrite(r *dns.Msg) Result { | ||||
| 	result := RewriteIgnored | ||||
| 	o := setupEdns0Opt(r) | ||||
| 	found := false | ||||
| 	for _, s := range o.Option { | ||||
| 		switch e := s.(type) { | ||||
| 		case *dns.EDNS0_LOCAL: | ||||
| 			if rule.code == e.Code { | ||||
| 				if rule.action == "replace" || rule.action == "set" { | ||||
| 					e.Data = rule.data | ||||
| 					result = RewriteDone | ||||
| 				} | ||||
| 				found = true | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// add option if not found | ||||
| 	if !found && (rule.action == "append" || rule.action == "set") { | ||||
| 		o.SetDo(true) | ||||
| 		var opt dns.EDNS0_LOCAL | ||||
| 		opt.Code = rule.code | ||||
| 		opt.Data = rule.data | ||||
| 		o.Option = append(o.Option, &opt) | ||||
| 		result = RewriteDone | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // newEdns0Rule creates an EDNS0 rule of the appropriate type based on the args | ||||
| func newEdns0Rule(args ...string) (Rule, error) { | ||||
| 	if len(args) < 2 { | ||||
| 		return nil, fmt.Errorf("Too few arguments for an EDNS0 rule") | ||||
| 	} | ||||
|  | ||||
| 	ruleType := strings.ToLower(args[0]) | ||||
| 	action := strings.ToLower(args[1]) | ||||
| 	switch action { | ||||
| 	case "append": | ||||
| 	case "replace": | ||||
| 	case "set": | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("invalid action: %q", action) | ||||
| 	} | ||||
|  | ||||
| 	switch ruleType { | ||||
| 	case "local": | ||||
| 		if len(args) != 4 { | ||||
| 			return nil, fmt.Errorf("EDNS0 local rules require exactly three args") | ||||
| 		} | ||||
| 		return newEdns0LocalRule(action, args[2], args[3]) | ||||
| 	case "nsid": | ||||
| 		if len(args) != 2 { | ||||
| 			return nil, fmt.Errorf("EDNS0 NSID rules do not accept args") | ||||
| 		} | ||||
| 		return &edns0NsidRule{action: action}, nil | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("invalid rule type %q", ruleType) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newEdns0LocalRule(action, code, data string) (*edns0LocalRule, error) { | ||||
| 	c, err := strconv.ParseUint(code, 0, 16) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	decoded := []byte(data) | ||||
| 	if strings.HasPrefix(data, "0x") { | ||||
| 		decoded, err = hex.DecodeString(data[2:]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &edns0LocalRule{action: action, code: uint16(c), data: decoded}, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user