mirror of
https://github.com/coredns/coredns.git
synced 2025-12-06 10:25:10 -05:00
Rewrite SRV targets and additional names in response (#4287)
* Rewrite plugin - rewrite SRV targets and names in response answer and additional records Signed-off-by: Nic Colledge <nic@njcolledge.net> * Added README content to describe new behaviour Signed-off-by: Nic Colledge <nic@njcolledge.net> * Added more record types to rewrite handling based on PR/Issue feedback Signed-off-by: Nic Colledge <nic@njcolledge.net> * Updated README.md for plugin Signed-off-by: Nic Colledge <nic@njcolledge.net> * Updated unit tests. Small refactor of getTarget... function. Signed-off-by: Nic Colledge <nic@njcolledge.net> * Refactor to add response value rewrite as answer value option Signed-off-by: Nic Colledge <nic@njcolledge.net> * Removed TODO comment, added test for NAPTR record. Signed-off-by: Nic Colledge <nic@njcolledge.net>
This commit is contained in:
@@ -42,46 +42,116 @@ func (r *ResponseReverter) WriteMsg(res1 *dns.Msg) error {
|
||||
|
||||
res.Question[0] = r.originalQuestion
|
||||
if r.ResponseRewrite {
|
||||
for _, rr := range res.Answer {
|
||||
var (
|
||||
isNameRewritten bool
|
||||
isTTLRewritten bool
|
||||
name = rr.Header().Name
|
||||
ttl = rr.Header().Ttl
|
||||
)
|
||||
for _, rule := range r.ResponseRules {
|
||||
if rule.Type == "" {
|
||||
rule.Type = "name"
|
||||
}
|
||||
switch rule.Type {
|
||||
case "name":
|
||||
regexGroups := rule.Pattern.FindStringSubmatch(name)
|
||||
if len(regexGroups) == 0 {
|
||||
continue
|
||||
}
|
||||
s := rule.Replacement
|
||||
for groupIndex, groupValue := range regexGroups {
|
||||
groupIndexStr := "{" + strconv.Itoa(groupIndex) + "}"
|
||||
s = strings.Replace(s, groupIndexStr, groupValue, -1)
|
||||
}
|
||||
name = s
|
||||
isNameRewritten = true
|
||||
case "ttl":
|
||||
ttl = rule.TTL
|
||||
isTTLRewritten = true
|
||||
}
|
||||
}
|
||||
if isNameRewritten {
|
||||
rr.Header().Name = name
|
||||
}
|
||||
if isTTLRewritten {
|
||||
rr.Header().Ttl = ttl
|
||||
}
|
||||
for _, rr := range res.Ns {
|
||||
rewriteResourceRecord(res, rr, r)
|
||||
}
|
||||
|
||||
for _, rr := range res.Answer {
|
||||
rewriteResourceRecord(res, rr, r)
|
||||
}
|
||||
|
||||
for _, rr := range res.Extra {
|
||||
rewriteResourceRecord(res, rr, r)
|
||||
}
|
||||
|
||||
}
|
||||
return r.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
func rewriteResourceRecord(res *dns.Msg, rr dns.RR, r *ResponseReverter) {
|
||||
var (
|
||||
isNameRewritten bool
|
||||
isTTLRewritten bool
|
||||
isValueRewritten bool
|
||||
name = rr.Header().Name
|
||||
ttl = rr.Header().Ttl
|
||||
value string
|
||||
)
|
||||
|
||||
for _, rule := range r.ResponseRules {
|
||||
if rule.Type == "" {
|
||||
rule.Type = "name"
|
||||
}
|
||||
switch rule.Type {
|
||||
case "name":
|
||||
rewriteString(rule, &name, &isNameRewritten)
|
||||
case "value":
|
||||
value = getRecordValueForRewrite(rr)
|
||||
if value != "" {
|
||||
rewriteString(rule, &value, &isValueRewritten)
|
||||
}
|
||||
case "ttl":
|
||||
ttl = rule.TTL
|
||||
isTTLRewritten = true
|
||||
}
|
||||
}
|
||||
|
||||
if isNameRewritten {
|
||||
rr.Header().Name = name
|
||||
}
|
||||
if isTTLRewritten {
|
||||
rr.Header().Ttl = ttl
|
||||
}
|
||||
if isValueRewritten {
|
||||
setRewrittenRecordValue(rr, value)
|
||||
}
|
||||
}
|
||||
|
||||
func getRecordValueForRewrite(rr dns.RR) (name string) {
|
||||
switch rr.Header().Rrtype {
|
||||
case dns.TypeSRV:
|
||||
return rr.(*dns.SRV).Target
|
||||
case dns.TypeMX:
|
||||
return rr.(*dns.MX).Mx
|
||||
case dns.TypeCNAME:
|
||||
return rr.(*dns.CNAME).Target
|
||||
case dns.TypeNS:
|
||||
return rr.(*dns.NS).Ns
|
||||
case dns.TypeDNAME:
|
||||
return rr.(*dns.DNAME).Target
|
||||
case dns.TypeNAPTR:
|
||||
return rr.(*dns.NAPTR).Replacement
|
||||
case dns.TypeSOA:
|
||||
return rr.(*dns.SOA).Ns
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func setRewrittenRecordValue(rr dns.RR, value string) {
|
||||
switch rr.Header().Rrtype {
|
||||
case dns.TypeSRV:
|
||||
rr.(*dns.SRV).Target = value
|
||||
case dns.TypeMX:
|
||||
rr.(*dns.MX).Mx = value
|
||||
case dns.TypeCNAME:
|
||||
rr.(*dns.CNAME).Target = value
|
||||
case dns.TypeNS:
|
||||
rr.(*dns.NS).Ns = value
|
||||
case dns.TypeDNAME:
|
||||
rr.(*dns.DNAME).Target = value
|
||||
case dns.TypeNAPTR:
|
||||
rr.(*dns.NAPTR).Replacement = value
|
||||
case dns.TypeSOA:
|
||||
rr.(*dns.SOA).Ns = value
|
||||
}
|
||||
}
|
||||
|
||||
func rewriteString(rule ResponseRule, str *string, isStringRewritten *bool) {
|
||||
regexGroups := rule.Pattern.FindStringSubmatch(*str)
|
||||
if len(regexGroups) == 0 {
|
||||
return
|
||||
}
|
||||
s := rule.Replacement
|
||||
for groupIndex, groupValue := range regexGroups {
|
||||
groupIndexStr := "{" + strconv.Itoa(groupIndex) + "}"
|
||||
s = strings.Replace(s, groupIndexStr, groupValue, -1)
|
||||
}
|
||||
|
||||
*isStringRewritten = true
|
||||
*str = s
|
||||
}
|
||||
|
||||
// Write is a wrapper that records the size of the message that gets written.
|
||||
func (r *ResponseReverter) Write(buf []byte) (int, error) {
|
||||
n, err := r.ResponseWriter.Write(buf)
|
||||
|
||||
Reference in New Issue
Block a user