2016-03-18 20:57:35 +00:00
|
|
|
package rewrite
|
|
|
|
|
|
|
|
|
|
import (
|
2018-04-22 08:34:35 +01:00
|
|
|
"context"
|
2017-03-06 16:32:17 -05:00
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2017-09-14 09:36:06 +01:00
|
|
|
"github.com/coredns/coredns/plugin"
|
2018-07-02 15:39:50 +01:00
|
|
|
"github.com/coredns/coredns/request"
|
2017-03-06 16:32:17 -05:00
|
|
|
|
2016-03-18 20:57:35 +00:00
|
|
|
"github.com/miekg/dns"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Result is the result of a rewrite
|
|
|
|
|
type Result int
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// RewriteIgnored is returned when rewrite is not done on request.
|
|
|
|
|
RewriteIgnored Result = iota
|
|
|
|
|
// RewriteDone is returned when rewrite is done on request.
|
|
|
|
|
RewriteDone
|
|
|
|
|
)
|
|
|
|
|
|
2017-09-20 13:06:53 -07:00
|
|
|
// These are defined processing mode.
|
|
|
|
|
const (
|
|
|
|
|
// Processing should stop after completing this rule
|
|
|
|
|
Stop = "stop"
|
|
|
|
|
// Processing should continue to next rule
|
|
|
|
|
Continue = "continue"
|
|
|
|
|
)
|
|
|
|
|
|
2019-09-26 20:19:45 +08:00
|
|
|
// Rewrite is a plugin to rewrite requests internally before being handled.
|
2016-03-18 20:57:35 +00:00
|
|
|
type Rewrite struct {
|
2021-05-04 10:05:45 +02:00
|
|
|
Next plugin.Handler
|
|
|
|
|
Rules []Rule
|
|
|
|
|
RevertPolicy
|
2016-03-18 20:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
2017-09-14 09:36:06 +01:00
|
|
|
// ServeDNS implements the plugin.Handler interface.
|
2016-03-19 07:18:57 +00:00
|
|
|
func (rw Rewrite) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
2021-05-04 10:05:45 +02:00
|
|
|
if rw.RevertPolicy == nil {
|
|
|
|
|
rw.RevertPolicy = NewRevertPolicy(false, false)
|
|
|
|
|
}
|
|
|
|
|
wr := NewResponseReverter(w, r, rw.RevertPolicy)
|
2018-07-02 15:39:50 +01:00
|
|
|
state := request.Request{W: w, Req: r}
|
|
|
|
|
|
2016-03-18 20:57:35 +00:00
|
|
|
for _, rule := range rw.Rules {
|
2021-05-04 10:05:45 +02:00
|
|
|
respRules, result := rule.Rewrite(ctx, state)
|
|
|
|
|
if result == RewriteDone {
|
2019-07-12 15:22:45 +03:00
|
|
|
if _, ok := dns.IsDomainName(state.Req.Question[0].Name); !ok {
|
|
|
|
|
err := fmt.Errorf("invalid name after rewrite: %s", state.Req.Question[0].Name)
|
2018-07-13 14:32:07 +01:00
|
|
|
state.Req.Question[0] = wr.originalQuestion
|
2019-07-12 15:22:45 +03:00
|
|
|
return dns.RcodeServerFailure, err
|
2018-07-13 14:32:07 +01:00
|
|
|
}
|
2021-05-04 10:05:45 +02:00
|
|
|
wr.ResponseRules = append(wr.ResponseRules, respRules...)
|
2017-09-20 13:06:53 -07:00
|
|
|
if rule.Mode() == Stop {
|
2025-04-04 20:27:39 +02:00
|
|
|
if !rw.DoRevert() {
|
2021-08-31 04:34:26 -04:00
|
|
|
return plugin.NextOrFailure(rw.Name(), rw.Next, ctx, w, r)
|
|
|
|
|
}
|
2022-02-01 16:54:06 -05:00
|
|
|
rcode, err := plugin.NextOrFailure(rw.Name(), rw.Next, ctx, wr, r)
|
|
|
|
|
if plugin.ClientWrite(rcode) {
|
|
|
|
|
return rcode, err
|
|
|
|
|
}
|
|
|
|
|
// The next plugins didn't write a response, so write one now with the ResponseReverter.
|
|
|
|
|
// If server.ServeDNS does this then it will create an answer mismatch.
|
|
|
|
|
res := new(dns.Msg).SetRcode(r, rcode)
|
|
|
|
|
state.SizeAndDo(res)
|
|
|
|
|
wr.WriteMsg(res)
|
|
|
|
|
// return success, so server does not write a second error response to client
|
|
|
|
|
return dns.RcodeSuccess, err
|
2016-04-07 17:42:35 +01:00
|
|
|
}
|
2016-03-18 20:57:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-04 20:27:39 +02:00
|
|
|
if !rw.DoRevert() || len(wr.ResponseRules) == 0 {
|
2018-04-27 02:05:44 -04:00
|
|
|
return plugin.NextOrFailure(rw.Name(), rw.Next, ctx, w, r)
|
|
|
|
|
}
|
|
|
|
|
return plugin.NextOrFailure(rw.Name(), rw.Next, ctx, wr, r)
|
2016-03-18 20:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-27 11:48:37 +00:00
|
|
|
// Name implements the Handler interface.
|
2016-10-26 10:01:52 +01:00
|
|
|
func (rw Rewrite) Name() string { return "rewrite" }
|
|
|
|
|
|
2017-03-06 16:32:17 -05:00
|
|
|
// Rule describes a rewrite rule.
|
2016-03-18 20:57:35 +00:00
|
|
|
type Rule interface {
|
2017-03-06 16:32:17 -05:00
|
|
|
// Rewrite rewrites the current request.
|
2021-05-04 10:05:45 +02:00
|
|
|
Rewrite(ctx context.Context, state request.Request) (ResponseRules, Result)
|
2018-01-18 10:41:14 -05:00
|
|
|
// Mode returns the processing mode stop or continue.
|
2017-09-20 13:06:53 -07:00
|
|
|
Mode() string
|
2017-03-06 16:32:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newRule(args ...string) (Rule, error) {
|
|
|
|
|
if len(args) == 0 {
|
2017-06-14 09:37:10 -07:00
|
|
|
return nil, fmt.Errorf("no rule type specified for rewrite")
|
2017-03-06 16:32:17 -05:00
|
|
|
}
|
|
|
|
|
|
2017-09-20 13:06:53 -07:00
|
|
|
arg0 := strings.ToLower(args[0])
|
|
|
|
|
var ruleType string
|
|
|
|
|
var expectNumArgs, startArg int
|
|
|
|
|
mode := Stop
|
|
|
|
|
switch arg0 {
|
|
|
|
|
case Continue:
|
2018-04-25 15:48:32 -04:00
|
|
|
mode = Continue
|
2022-06-26 16:06:43 -07:00
|
|
|
if len(args) < 2 {
|
|
|
|
|
return nil, fmt.Errorf("continue rule must begin with a rule type")
|
|
|
|
|
}
|
2017-09-20 13:06:53 -07:00
|
|
|
ruleType = strings.ToLower(args[1])
|
|
|
|
|
expectNumArgs = len(args) - 1
|
|
|
|
|
startArg = 2
|
|
|
|
|
case Stop:
|
2022-06-25 09:17:35 -07:00
|
|
|
if len(args) < 2 {
|
|
|
|
|
return nil, fmt.Errorf("stop rule must begin with a rule type")
|
|
|
|
|
}
|
2017-09-20 13:06:53 -07:00
|
|
|
ruleType = strings.ToLower(args[1])
|
|
|
|
|
expectNumArgs = len(args) - 1
|
|
|
|
|
startArg = 2
|
|
|
|
|
default:
|
2017-09-22 16:13:04 -07:00
|
|
|
// for backward compatibility
|
2017-09-20 13:06:53 -07:00
|
|
|
ruleType = arg0
|
|
|
|
|
expectNumArgs = len(args)
|
|
|
|
|
startArg = 1
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-06 16:32:17 -05:00
|
|
|
switch ruleType {
|
2018-08-29 10:41:03 -04:00
|
|
|
case "answer":
|
|
|
|
|
return nil, fmt.Errorf("response rewrites must begin with a name rule")
|
2017-03-06 16:32:17 -05:00
|
|
|
case "name":
|
2017-12-13 11:31:19 -05:00
|
|
|
return newNameRule(mode, args[startArg:]...)
|
2017-03-06 16:32:17 -05:00
|
|
|
case "class":
|
2018-08-29 10:41:03 -04:00
|
|
|
if expectNumArgs != 3 {
|
|
|
|
|
return nil, fmt.Errorf("%s rules must have exactly two arguments", ruleType)
|
|
|
|
|
}
|
2017-12-14 13:25:36 -05:00
|
|
|
return newClassRule(mode, args[startArg:]...)
|
2017-03-06 16:32:17 -05:00
|
|
|
case "type":
|
2018-08-29 10:41:03 -04:00
|
|
|
if expectNumArgs != 3 {
|
|
|
|
|
return nil, fmt.Errorf("%s rules must have exactly two arguments", ruleType)
|
|
|
|
|
}
|
2017-12-14 13:25:36 -05:00
|
|
|
return newTypeRule(mode, args[startArg:]...)
|
2017-03-06 16:32:17 -05:00
|
|
|
case "edns0":
|
2017-09-20 13:06:53 -07:00
|
|
|
return newEdns0Rule(mode, args[startArg:]...)
|
2018-08-29 10:41:03 -04:00
|
|
|
case "ttl":
|
2019-06-25 08:00:33 +01:00
|
|
|
return newTTLRule(mode, args[startArg:]...)
|
2023-04-13 17:49:36 +05:30
|
|
|
case "cname":
|
|
|
|
|
return newCNAMERule(mode, args[startArg:]...)
|
2023-08-26 22:20:12 -04:00
|
|
|
case "rcode":
|
|
|
|
|
return newRCodeRule(mode, args[startArg:]...)
|
2017-03-06 16:32:17 -05:00
|
|
|
default:
|
|
|
|
|
return nil, fmt.Errorf("invalid rule type %q", args[0])
|
|
|
|
|
}
|
2016-03-18 20:57:35 +00:00
|
|
|
}
|