2016-03-20 09:40:35 +00:00
# rewrite
2018-01-04 12:53:07 +00:00
## Name
*rewrite* - performs internal message rewriting.
## Description
2017-07-24 08:24:53 -07:00
Rewrites are invisible to the client. There are simple rewrites (fast) and complex rewrites
(slower), but they're powerful enough to accommodate most dynamic back-end applications.
2016-03-20 09:40:35 +00:00
## Syntax
2019-05-31 15:42:47 -07:00
A simplified/easy-to-digest syntax for *rewrite* is...
2016-03-20 09:40:35 +00:00
~~~
2021-05-04 10:05:45 +02:00
rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
2016-03-20 09:40:35 +00:00
~~~
2018-05-11 13:50:59 -04:00
* **FIELD** indicates what part of the request/response is being re-written.
2018-05-24 07:51:59 +01:00
2019-05-31 15:42:47 -07:00
* `type` - the type field of the request will be rewritten. FROM/TO must be a DNS record type (`A` , `MX` , etc.);
2017-02-07 16:53:16 -05:00
e.g., to rewrite ANY queries to HINFO, use `rewrite type ANY HINFO` .
2018-07-13 14:32:07 +01:00
* `name` - the query name in the _request_ is rewritten; by default this is a full match of the
name, e.g., `rewrite name example.net example.org` . Other match types are supported, see the **Name Field Rewrites** section below.
2021-05-04 10:05:45 +02:00
* `class` - the class of the message will be rewritten. FROM/TO must be a DNS class type (`IN` , `CH` , or `HS` ); e.g., to rewrite CH queries to IN use `rewrite class CH IN` .
* `edns0` - an EDNS0 option can be appended to the request as described below in the **EDNS0 Options** section.
2018-08-29 10:41:03 -04:00
* `ttl` - the TTL value in the _response_ is rewritten.
2023-04-13 17:49:36 +05:30
* `cname` - the CNAME target if the response has a CNAME record
2023-08-26 22:20:12 -04:00
* `rcode` - the response code (RCODE) value in the _response_ is rewritten.
2018-05-24 07:51:59 +01:00
2021-05-04 10:05:45 +02:00
* **TYPE** this optional element can be specified for a `name` or `ttl` field.
If not given type `exact` will be assumed. If options should be specified the
type must be given.
2018-08-29 10:41:03 -04:00
* **FROM** is the name (exact, suffix, prefix, substring, or regex) or type to match
2018-05-11 13:50:59 -04:00
* **TO** is the destination name or type to rewrite to
2021-05-04 10:05:45 +02:00
* **TTL** is the number of seconds to set the TTL value to (only for field `ttl` )
* **OPTIONS**
for field `name` further options are possible controlling the response rewrites.
All name matching types support the following options
* `answer auto` - the names in the _response_ is rewritten in a best effort manner.
* `answer name FROM TO` - the query name in the _response_ is rewritten matching the from regex pattern.
* `answer value FROM TO` - the names in the _response_ is rewritten matching the from regex pattern.
See below in the **Response Rewrites** section for further details.
2017-03-06 16:32:17 -05:00
2019-05-31 15:42:47 -07:00
If you specify multiple rules and an incoming query matches multiple rules, the rewrite
will behave as follows:
* `continue` will continue applying the next rule in the rule list.
* `stop` will consider the current rule the last rule and will not continue. The default behaviour is `stop`
2024-09-12 09:07:02 +08:00
* When multiple rules are matched, the request rewrite follows the line order in the configuration, while the response rewrite(`answer` option) is executed in reverse order.
2016-03-20 10:44:03 +00:00
2020-01-31 12:37:24 +01:00
## Examples
2018-01-22 22:01:13 -05:00
### Name Field Rewrites
2019-05-31 15:42:47 -07:00
The `rewrite` plugin offers the ability to match the name in the question section of
a DNS request. The match could be exact, a substring match, or based on a prefix, suffix, or regular
expression. If the newly used name is not a legal domain name, the plugin returns an error to the
2018-07-13 14:32:07 +01:00
client.
2018-01-22 22:01:13 -05:00
2019-05-31 15:42:47 -07:00
The syntax for name rewriting is as follows:
2018-01-22 22:01:13 -05:00
```
2021-05-04 10:05:45 +02:00
rewrite [continue|stop] name [exact|prefix|suffix|substring|regex] STRING STRING [OPTIONS]
2018-01-22 22:01:13 -05:00
```
2019-05-31 15:42:47 -07:00
The match type, e.g., `exact` , `substring` , etc., triggers rewrite:
2018-01-22 22:01:13 -05:00
2019-05-31 15:42:47 -07:00
* **exact** (default): on an exact match of the name in the question section of a request
2018-01-22 22:01:13 -05:00
* **substring**: on a partial match of the name in the question section of a request
* **prefix**: when the name begins with the matching string
* **suffix**: when the name ends with the matching string
* **regex**: when the name in the question section of a request matches a regular expression
2021-05-04 10:05:45 +02:00
If the match type is omitted, the `exact` match type is assumed. If OPTIONS are
given, the type must be specified.
2018-01-22 22:01:13 -05:00
2019-05-31 15:42:47 -07:00
The following instruction allows rewriting names in the query that
contain the substring `service.us-west-1.example.org` :
2018-01-22 22:01:13 -05:00
```
rewrite name substring service.us-west-1.example.org service.us-west-1.consul
```
Thus:
* Incoming Request Name: `ftp.service.us-west-1.example.org`
2019-05-31 15:42:47 -07:00
* Rewritten Request Name: `ftp.service.us-west-1.consul`
2018-01-22 22:01:13 -05:00
2019-05-31 15:42:47 -07:00
The following instruction uses regular expressions. Names in requests
matching the regular expression `(.*)-(us-west-1)\.example\.org` are replaced with
2018-01-22 22:01:13 -05:00
`{1}.service.{2}.consul` , where `{1}` and `{2}` are regular expression match groups.
```
rewrite name regex (.*)-(us-west-1)\.example\.org {1}.service.{2}.consul
```
Thus:
* Incoming Request Name: `ftp-us-west-1.example.org`
2019-05-31 15:42:47 -07:00
* Rewritten Request Name: `ftp.service.us-west-1.consul`
2018-01-22 22:01:13 -05:00
2018-09-17 16:41:38 -04:00
The following example rewrites the `schmoogle.com` suffix to `google.com` .
~~~
rewrite name suffix .schmoogle.com. .google.com.
~~~
2018-01-22 22:01:13 -05:00
### Response Rewrites
2021-05-04 10:05:45 +02:00
When rewriting incoming DNS requests' names (field `name` ), CoreDNS re-writes
the `QUESTION SECTION`
2019-05-31 15:42:47 -07:00
section of the requests. It may be necessary to rewrite the `ANSWER SECTION` of the
requests, because some DNS resolvers treat mismatches between the `QUESTION SECTION`
2018-01-22 22:01:13 -05:00
and `ANSWER SECTION` as a man-in-the-middle attack (MITM).
For example, a user tries to resolve `ftp-us-west-1.coredns.rocks` . The
CoreDNS configuration file has the following rule:
```
rewrite name regex (.*)-(us-west-1)\.coredns\.rocks {1}.service.{2}.consul
```
2019-05-31 15:42:47 -07:00
CoreDNS rewrote the request from `ftp-us-west-1.coredns.rocks` to
2018-01-22 22:01:13 -05:00
`ftp.service.us-west-1.consul` and ultimately resolved it to 3 records.
2019-05-31 15:42:47 -07:00
The resolved records, in the `ANSWER SECTION` below, were not from `coredns.rocks` , but
2018-01-22 22:01:13 -05:00
rather from `service.us-west-1.consul` .
```
$ dig @10 .1.1.1 ftp-us-west-1.coredns.rocks
;; QUESTION SECTION:
;ftp-us-west-1.coredns.rocks. IN A
;; ANSWER SECTION:
ftp.service.us-west-1.consul. 0 IN A 10.10.10.10
ftp.service.us-west-1.consul. 0 IN A 10.20.20.20
ftp.service.us-west-1.consul. 0 IN A 10.30.30.30
```
2019-05-31 15:42:47 -07:00
The above is a mismatch between the question asked and the answer provided.
2018-01-22 22:01:13 -05:00
2021-05-04 10:05:45 +02:00
There are three possibilities to specify an answer rewrite:
- A rewrite can request a best effort answer rewrite by adding the option `answer auto` .
- A rewrite may specify a dedicated regex based response name rewrite with the
`answer name FROM TO` option.
- A regex based rewrite of record values like `CNAME` , `SRV` , etc, can be requested by
an `answer value FROM TO` option.
Hereby FROM/TO follow the rules for the `regex` name rewrite syntax.
#### Auto Response Name Rewrite
The following configuration snippet allows for rewriting of the
`ANSWER SECTION` according to the rewrite of the `QUESTION SECTION` :
```
rewrite stop {
name suffix .coredns.rocks .service.consul answer auto
}
```
Any occurrence of the rewritten question in the answer is mapped
back to the original value before the rewrite.
Please note that answers for rewrites of type `exact` are always rewritten.
For a `suffix` name rule `auto` leads to a reverse suffix response rewrite,
exchanging FROM and TO from the rewrite request.
#### Explicit Response Name Rewrite
2019-05-31 15:42:47 -07:00
The following configuration snippet allows for rewriting of the
`ANSWER SECTION` , provided that the `QUESTION SECTION` was rewritten:
2018-01-22 22:01:13 -05:00
```
rewrite stop {
name regex (.*)-(us-west-1)\.coredns\.rocks {1}.service.{2}.consul
answer name (.*)\.service\.(us-west-1)\.consul {1}-{2}.coredns.rocks
}
```
Now, the `ANSWER SECTION` matches the `QUESTION SECTION` :
```
$ dig @10 .1.1.1 ftp-us-west-1.coredns.rocks
;; QUESTION SECTION:
;ftp-us-west-1.coredns.rocks. IN A
;; ANSWER SECTION:
ftp-us-west-1.coredns.rocks. 0 IN A 10.10.10.10
ftp-us-west-1.coredns.rocks. 0 IN A 10.20.20.20
ftp-us-west-1.coredns.rocks. 0 IN A 10.30.30.30
```
2021-05-04 10:05:45 +02:00
#### Rewriting other Response Values
2021-02-23 09:12:58 +00:00
It is also possible to rewrite other values returned in the DNS response records
(e.g. the server names returned in `SRV` and `MX` records). This can be enabled by adding
2021-05-04 10:05:45 +02:00
the `answer value FROM TO` option to a name rule as specified below. `answer value` takes a
2021-02-23 09:12:58 +00:00
regular expression and a rewrite name as parameters and works in the same way as the
2021-02-23 09:12:40 +00:00
`answer name` rule.
Note that names in the `AUTHORITY SECTION` and `ADDITIONAL SECTION` will also be
rewritten following the specified rules. The names returned by the following
2022-08-14 17:26:39 +03:00
record types: `CNAME` , `DNAME` , `SOA` , `SRV` , `MX` , `NAPTR` , `NS` , `PTR` will be rewritten
2021-02-23 09:12:40 +00:00
if the `answer value` rule is specified.
2018-04-25 15:48:32 -04:00
The syntax for the rewrite of DNS request and response is as follows:
2018-01-22 22:01:13 -05:00
```
rewrite [continue|stop] {
name regex STRING STRING
answer name STRING STRING
2021-02-23 09:12:40 +00:00
[answer value STRING STRING]
2018-01-22 22:01:13 -05:00
}
```
2019-05-31 15:42:47 -07:00
Note that the above syntax is strict. For response rewrites, only `name`
2021-05-04 10:05:45 +02:00
rules are allowed to match the question section. The answer rewrite must be
after the name, as in the syntax example.
2022-08-14 17:26:39 +03:00
##### Example: PTR Response Value Rewrite
The original response contains the domain `service.consul.` in the `VALUE` part
of the `ANSWER SECTION`
```
$ dig @10 .1.1.1 30.30.30.10.in-addr.arpa PTR
;; QUESTION SECTION:
;30.30.30.10.in-addr.arpa. IN PTR
;; ANSWER SECTION:
30.30.30.10.in-addr.arpa. 60 IN PTR ftp-us-west-1.service.consul.
```
The following configuration snippet allows for rewriting of the value
in the `ANSWER SECTION` :
```
rewrite stop {
name suffix .arpa .arpa
answer name auto
answer value (.*)\.service\.consul\. {1}.coredns.rocks.
}
```
Now, the `VALUE` in the `ANSWER SECTION` has been overwritten in the domain part:
```
$ dig @10 .1.1.1 30.30.30.10.in-addr.arpa PTR
;; QUESTION SECTION:
;30.30.30.10.in-addr.arpa. IN PTR
;; ANSWER SECTION:
30.30.30.10.in-addr.arpa. 60 IN PTR ftp-us-west-1.coredns.rocks.
```
2021-05-04 10:05:45 +02:00
#### Multiple Response Rewrites
`name` and `value` rewrites can be chained by appending multiple answer rewrite
options. For all occurrences but the first one the keyword `answer` might be
omitted.
2018-04-25 15:48:32 -04:00
2021-05-04 10:05:45 +02:00
```options
answer (auto | (name|value FROM TO)) { [answer] (auto | (name|value FROM TO)) }
```
2018-04-25 15:48:32 -04:00
2021-05-04 10:05:45 +02:00
For example:
2018-04-25 15:48:32 -04:00
```
2021-05-04 10:05:45 +02:00
rewrite [continue|stop] name regex FROM TO answer name FROM TO [answer] value FROM TO
2018-04-25 15:48:32 -04:00
```
2019-05-31 15:42:47 -07:00
When using `exact` name rewrite rules, the answer gets rewritten automatically,
2021-05-04 10:05:45 +02:00
and there is no need to define `answer name auto` . But it is still possible to define
additional `answer value` and `answer value` options.
The rule below rewrites the name in a request from `RED` to `BLUE` , and subsequently
2018-10-23 16:59:59 -04:00
rewrites the name in a corresponding response from `BLUE` to `RED` . The
client in the request would see only `RED` and no `BLUE` .
```
rewrite [continue|stop] name exact RED BLUE
```
2018-08-29 10:41:03 -04:00
### TTL Field Rewrites
2019-05-31 15:42:47 -07:00
At times, the need to rewrite a TTL value could arise. For example, a DNS server
may not cache records with a TTL of zero (`0` ). An administrator
may want to increase the TTL to ensure it is cached, e.g., by increasing it to 15 seconds.
2018-08-29 10:41:03 -04:00
In the below example, the TTL in the answers for `coredns.rocks` domain are
being set to `15` :
```
rewrite continue {
ttl regex (.*)\.coredns\.rocks 15
}
```
2019-05-31 15:42:47 -07:00
By the same token, an administrator may use this feature to prevent or limit caching by
setting the TTL value really low.
2018-08-29 10:41:03 -04:00
The syntax for the TTL rewrite rule is as follows. The meaning of
`exact|prefix|suffix|substring|regex` is the same as with the name rewrite rules.
2021-05-04 10:05:45 +02:00
An omitted type is defaulted to `exact` .
2018-08-29 10:41:03 -04:00
```
2022-08-17 21:33:51 +02:00
rewrite [continue|stop] ttl [exact|prefix|suffix|substring|regex] STRING [SECONDS|MIN-MAX]
```
It is possible to supply a range of TTL values in the `SECONDS` parameters instead of a single value.
If a range is supplied, the TTL value is set to `MIN` if it is below, or set to `MAX` if it is above.
The TTL value is left unchanged if it is already inside the provided range.
The ranges can be unbounded on either side.
TTL examples with ranges:
```
# rewrite TTL to be between 30s and 300s
rewrite ttl example.com. 30-300
# cap TTL at 30s
rewrite ttl example.com. -30 # equivalent to rewrite ttl example.com. 0-30
# increase TTL to a minimum of 30s
rewrite ttl example.com. 30-
# set TTL to 30s
rewrite ttl example.com. 30 # equivalent to rewrite ttl example.com. 30-30
2018-08-29 10:41:03 -04:00
```
2023-08-26 22:20:12 -04:00
### RCODE Field Rewrites
At times, the need to rewrite a RCODE value could arise. For example, a DNS server
may respond with a SERVFAIL instead of NOERROR records when AAAA records are requested.
In the below example, the rcode value the answer for `coredns.rocks` the replies with SERVFAIL
is being switched to NOERROR.
This example rewrites all the *.coredns.rocks domain SERVFAIL errors to NOERROR
```
rewrite continue {
rcode regex (.*)\.coredns\.rocks SERVFAIL NOERROR
}
```
The same result numeric values:
```
rewrite continue {
rcode regex (.*)\.coredns\.rocks 2 0
}
```
The syntax for the RCODE rewrite rule is as follows. The meaning of
`exact|prefix|suffix|substring|regex` is the same as with the name rewrite rules.
An omitted type is defaulted to `exact` .
```
rewrite [continue|stop] rcode [exact|prefix|suffix|substring|regex] STRING FROM TO
```
The values of FROM and TO can be any of the following, text value or numeric:
```
0 NOERROR
1 FORMERR
2 SERVFAIL
3 NXDOMAIN
4 NOTIMP
5 REFUSED
6 YXDOMAIN
7 YXRRSET
8 NXRRSET
9 NOTAUTH
10 NOTZONE
16 BADSIG
17 BADKEY
18 BADTIME
19 BADMODE
20 BADNAME
21 BADALG
22 BADTRUNC
23 BADCOOKIE
```
2017-03-06 16:32:17 -05:00
## EDNS0 Options
2017-02-07 16:53:16 -05:00
2025-06-20 00:49:37 +03:00
Using the FIELD edns0, you can set, append, replace, or unset specific EDNS0 options in the request.
2016-03-20 09:40:35 +00:00
2018-06-18 05:02:05 -04:00
* `replace` will modify any "matching" option with the specified option. The criteria for "matching" varies based on EDNS0 type.
* `append` will add the option only if no matching option exists
2017-03-06 16:32:17 -05:00
* `set` will modify a matching option or add one if none is found
2025-06-20 00:49:37 +03:00
* `unset` will remove the matching option if one exists
2016-03-20 09:40:35 +00:00
2017-09-08 13:36:09 -07:00
Currently supported are `EDNS0_LOCAL` , `EDNS0_NSID` and `EDNS0_SUBNET` .
2016-03-20 09:40:35 +00:00
2018-01-04 12:53:07 +00:00
### EDNS0_LOCAL
2016-03-20 09:40:35 +00:00
2018-01-04 12:53:07 +00:00
This has two fields, code and data. A match is defined as having the same code. Data may be a string or a variable.
2017-08-24 09:34:07 -07:00
2019-05-31 15:42:47 -07:00
* A string data is treated as hex if it starts with `0x` . Example:
2016-03-20 09:40:35 +00:00
2017-10-10 09:39:35 +02:00
~~~ corefile
. {
rewrite edns0 local set 0xffee 0x61626364
whoami
}
2016-03-20 09:40:35 +00:00
~~~
2019-05-31 15:42:47 -07:00
rewrites the first local option with code 0xffee, setting the data to "abcd". This is equivalent to:
2016-03-20 09:40:35 +00:00
2017-10-10 09:39:35 +02:00
~~~ corefile
. {
rewrite edns0 local set 0xffee abcd
}
2016-03-20 09:40:35 +00:00
~~~
2018-07-01 20:01:17 +01:00
* A variable data is specified with a pair of curly brackets `{}` . Following are the supported variables:
2018-01-04 12:53:07 +00:00
{qname}, {qtype}, {client_ip}, {client_port}, {protocol}, {server_ip}, {server_port}.
2017-08-24 09:34:07 -07:00
2018-07-09 13:08:02 +01:00
* If the metadata plugin is enabled, then labels are supported as variables if they are presented within curly brackets.
2019-05-31 15:42:47 -07:00
The variable data will be replaced with the value associated with that label. If that label is not provided,
the variable will be silently substituted with an empty string.
2018-07-08 03:18:01 -04:00
Examples:
2017-08-24 09:34:07 -07:00
2018-07-01 20:01:17 +01:00
~~~
rewrite edns0 local set 0xffee {client_ip}
2017-08-24 09:34:07 -07:00
~~~
2018-07-08 03:18:01 -04:00
The following example uses metadata and an imaginary "some-plugin" that would provide "some-label" as metadata information.
~~~
metadata
some-plugin
rewrite edns0 local set 0xffee {some-plugin/some-label}
~~~
2025-06-20 00:49:37 +03:00
A local option may be removed by unsetting its code. Example:
~~~
rewrite edns0 local unset 0xffee
~~~
2018-01-04 12:53:07 +00:00
### EDNS0_NSID
2016-03-20 09:40:35 +00:00
2017-03-06 16:32:17 -05:00
This has no fields; it will add an NSID option with an empty string for the NSID. If the option already exists
2025-09-10 00:30:27 +03:00
and the action is `replace` or `set` , then the NSID in the option will be set to the empty string.
2025-06-20 00:49:37 +03:00
The option can be removed with the `unset` action.
2017-09-08 13:36:09 -07:00
2018-01-04 12:53:07 +00:00
### EDNS0_SUBNET
2017-09-08 13:36:09 -07:00
This has two fields, IPv4 bitmask length and IPv6 bitmask length. The bitmask
2018-01-04 12:53:07 +00:00
length is used to extract the client subnet from the source IP address in the query.
2017-09-08 13:36:09 -07:00
Example:
~~~
2017-10-10 09:39:35 +02:00
rewrite edns0 subnet set 24 56
2017-09-08 13:36:09 -07:00
~~~
2019-05-31 15:42:47 -07:00
* If the query's source IP address is an IPv4 address, the first 24 bits in the IP will be the network subnet.
* If the query's source IP address is an IPv6 address, the first 56 bits in the IP will be the network subnet.
2023-04-13 17:49:36 +05:30
2025-06-20 00:49:37 +03:00
This option can be removed by using `unset` :
~~~
rewrite edns0 subnet unset
~~~
2024-10-07 20:47:56 +03:00
### EDNS0 Revert
2023-04-13 17:49:36 +05:30
2024-10-07 20:47:56 +03:00
Using the `revert` flag, you can revert the changes made by this rewrite call, so the response will not contain this option.
This example sets option, but response will not contain it
~~~ corefile
. {
rewrite edns0 local set 0xffee abcd revert
}
~~~
If only some calls contain the `revert` flag, then the value in the response will be changed to the previous one. So, in this example, the response will contain `abcd` data at `0xffee`
~~~ corefile
. {
rewrite continue {
edns0 local set 0xffee abcd
}
rewrite edns0 local replace 0xffee bcde revert
}
~~~
## CNAME Field Rewrites
2023-04-13 17:49:36 +05:30
There might be a scenario where you want the `CNAME` target of the response to be rewritten. You can do this by using the `CNAME` field rewrite. This will generate new answer records according to the new `CNAME` target.
The syntax for the CNAME rewrite rule is as follows. The meaning of
`exact|prefix|suffix|substring|regex` is the same as with the name rewrite rules.
An omitted type is defaulted to `exact` .
```
rewrite [continue|stop] cname [exact|prefix|suffix|substring|regex] FROM TO
```
Consider the following `CNAME` rewrite rule with regex type.
```
rewrite cname regex (.*).cdn.example.net. {1}.other.cdn.com.
```
If you were to send the following DNS request without the above rule, an example response would be:
```
$ dig @10 .1.1.1 my-app.com
;; QUESTION SECTION:
;my-app.com. IN A
;; ANSWER SECTION:
my-app.com. 200 IN CNAME my-app.com.cdn.example.net.
my-app.com.cdn.example.net. 300 IN A 20.2.0.1
my-app.com.cdn.example.net. 300 IN A 20.2.0.2
```
If you were to send the same DNS request with the above rule set up, an example response would be:
```
$ dig @10 .1.1.1 my-app.com
;; QUESTION SECTION:
;my-app.com. IN A
;; ANSWER SECTION:
my-app.com. 200 IN CNAME my-app.com.other.cdn.com.
my-app.com.other.cdn.com. 100 IN A 30.3.1.2
```
Note that the answer will contain a completely different set of answer records after rewriting the `CNAME` target.