描述
重写在客户端不可见。有简单重写(快)和复杂重写(慢),但它们功能强大,足以适应大多数动态后端应用程序。
语法
重写的简化/易于理解的语法为...
rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
-
字段表示请求/响应的哪一部分正在被重写。
类型
- 请求的类型字段将被重写。FROM/TO 必须是 DNS 记录类型 (A
、MX
等);例如,要将任何查询重写为 HINFO,请使用重写类型 ANY HINFO
。名称
- 请求中的查询名称被重写;默认情况下,这是名称的完全匹配,例如,重写名称 example.net example.org
。支持其他匹配类型,请参见下面的名称字段重写部分。类型
- 消息的类型将被重写。FROM/TO 必须是 DNS 类型 (IN
、CH
或HS
);例如,要将 CH 查询重写为 IN,请使用重写类型 CH IN
。edns0
- 可以将 EDNS0 选项附加到请求中,如下面的EDNS0 选项部分所述。TTL
- 响应中的TTL 值被重写。CNAME
- 如果响应有 CNAME 记录,则有 CNAME 目标
-
类型此可选元素可以为
名称
或TTL
字段指定。如果没有给定类型,则将假定为精确
类型。如果应指定选项,则必须给出类型。 -
FROM是要匹配的名称(精确、后缀、前缀、子字符串或正则表达式)或类型
-
TO是要重写到的目标名称或类型
-
TTL是要将 TTL 值设置为的秒数(仅适用于字段
TTL
) -
选项
对于字段
name
,可以进行进一步的选项控制响应重写。所有名称匹配类型都支持以下选项答复自动
- 尽力重写响应中的名称。答复名称 FROM TO
- 响应中的查询名称重写匹配 from 正则表达式模式。答复值 FROM TO
- 响应中的名称重写匹配 from 正则表达式模式。
在响应重写部分中参见下面以了解更多详细信息。
如果您指定多条规则,并且传入查询匹配多条规则,重写将会执行以下操作
继续
将继续应用规则列表中的下一条规则。stop
将认为当前已达最后规则而不会继续执行。stop
是默认行为
示例
名称字段重写
rewrite
插件提供匹配 DNS 请求问题部分中的名称的功能。匹配可以为完全匹配、子串匹配或基于前缀、后缀或正则表达式匹配。如果新使用的名称不是合法的域名,则该插件会向客户端返回错误。
名称重写的语法如下
rewrite [continue|stop] name [exact|prefix|suffix|substring|regex] STRING STRING [OPTIONS]
匹配类型(如exact
、substring
等)触发重写
- exact(默认):当请求的问题部分中的名称完全匹配时
- substring:当请求的问题部分中的名称部分匹配时
- prefix:当名称以匹配字符串开头时
- suffix:当名称以匹配字符串结尾时
- regex:当请求的问题部分中的名称匹配正则表达式时
如果未指定匹配类型,则假定为exact
匹配类型。如果给定了选项,则必须指定类型。
以下指令允许重写查询中包含子字符串service.us-west-1.example.org
的名称
rewrite name substring service.us-west-1.example.org service.us-west-1.consul
这样
- 传入请求名称:
ftp.service.us-west-1.example.org
- 重写请求名称:
ftp.service.us-west-1.consul
以下指令使用正则表达式。与正则表达式(.*)-(us-west-1)\.example\.org
匹配的请求中的名称将替换为{1}.service.{2}.consul
,其中{1}
和{2}
为正则表达式匹配组。
rewrite name regex (.*)-(us-west-1)\.example\.org {1}.service.{2}.consul
这样
- 传入请求名称:
ftp-us-west-1.example.org
- 重写请求名称:
ftp.service.us-west-1.consul
以下示例将后缀schmoogle.com
重写为google.com
。
rewrite name suffix .schmoogle.com. .google.com.
响应重写
当重写传入 DNS 请求的名称(字段name
)时,CoreDNS 会重写请求的QUESTION SECTION
部分。也许需要重写请求的ANSWER SECTION
,因为一些 DNS 解析程序会将QUESTION SECTION
和ANSWER SECTION
之间的不匹配视为中间人攻击 (MITM)。
例如,用户尝试解析ftp-us-west-1.coredns.rocks
。CoreDNS 配置文件具有以下规则
rewrite name regex (.*)-(us-west-1)\.coredns\.rocks {1}.service.{2}.consul
CoreDNS 将请求从ftp-us-west-1.coredns.rocks
重写为ftp.service.us-west-1.consul
,并最终将其解析为 3 条记录。解析后的记录,即下面的ANSWER SECTION
,不是来自coredns.rocks
,而是来自 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
上述是提问和所提供答案之间的一种不匹配。
共有三个指定答案重写的可能性
- 重写可以通过添加选项
answer auto
来请求尽力而为的答案重写。 - 重写可以用
answer name FROM TO
选项指定专用的基于正则表达式的响应名称重写。 - 可以通过
answer value FROM TO
选项请求对CNAME
、SRV
等的记录值进行基于正则表达式的重写。
在此,FROM/TO 遵循用于 regex
名称改写语法的规则。
自动响应名称改写
以下配置代码段允许根据对 QUESTION SECTION
的改写重写 ANSWER SECTION
rewrite stop {
name suffix .coredns.rocks .service.consul answer auto
}
答案中重写的任何显示问题在改写之前已映射回原始值。
请注意,始终会改写 exact
类型的改写答案。对于 suffix
名称规则,auto
会导致反向后缀响应改写,交换 FROM 和 TO 处的改写请求。
显式响应名称改写
以下配置代码段允许改写 ANSWER SECTION
,前提是已经改写了 QUESTION SECTION
rewrite stop {
name regex (.*)-(us-west-1)\.coredns\.rocks {1}.service.{2}.consul
answer name (.*)\.service\.(us-west-1)\.consul {1}-{2}.coredns.rocks
}
现在,ANSWER SECTION
匹配 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
改写其他响应值
还可以改写 DNS 响应记录中返回的其他值(例如 SRV
和 MX
记录中返回的服务器名称)。这可以通过向名称规则添加 answer value FROM TO
选项来启用,如下所示。answer value
需要一个正则表达式和一个改写名称作为参数,工作方式与 answer name
规则相同。
请注意,AUTHORITY SECTION
和 ADDITIONAL SECTION
中的名称也将根据指定规则进行改写。如果指定了 answer value
规则,则以下记录类型返回的名称将被改写:CNAME
、DNAME
、SOA
、SRV
、MX
、NAPTR
、NS
、PTR
。
DNS 请求和响应的改写语法如下
rewrite [continue|stop] {
name regex STRING STRING
answer name STRING STRING
[answer value STRING STRING]
}
请注意,上述语法是严格的。对于响应改写,只有 name
规则才能匹配问题部分。答案改写必须在名称之后,如语法示例所示。
示例:PTR 响应值改写
原始响应包含 ANSWER SECTION
VALUE
部分的域 service.consul.
$ 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.
以下配置代码段允许改写 ANSWER SECTION
中的值
rewrite stop {
name suffix .arpa .arpa
answer name auto
answer value (.*)\.service\.consul\. {1}.coredns.rocks.
}
现在,ANSWER SECTION
中的 VALUE
已在域部分中被覆盖
$ 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.
多个响应改写
name
和 value
改写可以通过追加多个答案改写选项来链接。对于除第一个之外的所有显示,关键字 answer
都可能被省略。
answer (auto | (name|value FROM TO)) { [answer] (auto | (name|value FROM TO)) }
例如
rewrite [continue|stop] name regex FROM TO answer name FROM TO [answer] value FROM TO
当使用 exact
名称改写规则时,答案会自动被改写,无需定义 answer name auto
。但仍然可以定义附加 answer value
和 answer value
选项。
下面的规则将请求中的 name 从 RED
重写为 BLUE
,随后将相应响应中的 name 从 BLUE
重写为 RED
。请求中的客户端只会看到 RED
,不会看到 BLUE
。
rewrite [continue|stop] name exact RED BLUE
TTL 字段重写
有时,可能需要重写 TTL 值。例如,DNS 服务器可能不会缓存 TTL 为零 (0
) 的记录。管理员可能希望增加 TTL 以确保将其缓存,例如将其增加到 15 秒。
在下面的示例中,coredns.rocks
域中答案的 TTL 被设置为 15
rewrite continue {
ttl regex (.*)\.coredns\.rocks 15
}
同样,管理员可以使用此功能通过将 TTL 值设置得非常低来防止或限制缓存。
TTL 重写规则的语法如下。exact|prefix|suffix|substring|regex
的含义与 name 重写规则中的相同。省略的类型默认为 exact
。
rewrite [continue|stop] ttl [exact|prefix|suffix|substring|regex] STRING [SECONDS|MIN-MAX]
可以提供一个 TTL 值范围而不是 SECONDS
参数中的单个值。如果提供了范围,则 TTL 值如果低于此范围,会被设置为 MIN
;如果高于此范围,会被设置为 MAX
。如果 TTL 值已经在提供的范围内,则会保持不变。范围可以在任一端不限。
带有范围的 TTL 示例
# 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
EDNS0 选项
使用 FIELD edns0,可以在请求中设置、追加或替换特定的 EDNS0 选项。
replace
会使用指定的选项修改任何“匹配”选项。“匹配”的条件根据 EDNS0 的类型而异。append
仅当不存在匹配选项时才添加此选项set
会修改匹配的选项,或在没有找到匹配项时添加一个选项
目前支持的是 EDNS0_LOCAL
、EDNS0_NSID
和 EDNS0_SUBNET
。
EDNS0_LOCAL
它有两个字段,代码和数据。匹配的定义是拥有相同的代码。数据可以是字符串或变量。
- 如果字符串数据以
0x
开头,则会将其视为十六进制。示例
. {
rewrite edns0 local set 0xffee 0x61626364
whoami
}
将带有代码 0xffee 的第一个本地选项重写为,将数据设置为“abcd”。这等同于
. {
rewrite edns0 local set 0xffee abcd
}
-
变量数据使用一对花括号
{}
指定。以下是支持的变量:{qname}、{qtype}、{client_ip}、{client_port}、{protocol}、{server_ip}、{server_port}。 -
如果启用了元数据插件,则标签如果放在花括号内,会被作为变量支持。变量数据会被替换为与该标签关联的值。如果未提供该标签,变量将会默默替换为空字符串。
示例
rewrite edns0 local set 0xffee {client_ip}
以下示例使用元数据和一个假想的“some-plugin”,它会提供“some-label”作为元数据信息。
metadata
some-plugin
rewrite edns0 local set 0xffee {some-plugin/some-label}
EDNS0_NSID
无字段;它将添加一个 NSID 选项,NSID 为空字符串。如果选项已存在且操作为 replace
或 set
,则该选项中的 NSID 将设置为非空字符串。
EDNS0_SUBNET
有字段两个,IPv4 比特遮罩长度和 IPv6 比特遮罩长度。位掩码长度用于从查询中的源 IP 地址中提取客户端子网。
示例
rewrite edns0 subnet set 24 56
- 如果查询的源 IP 地址是 IPv4 地址,IP 中的前 24 位将是网络子网。
- 如果查询的源 IP 地址是 IPv6 地址,IP 中的前 56 位将是网络子网。
CNAME 字段重写
可能存在需要重写响应的 CNAME
目标的情况。您可以使用 CNAME
字段重写来实现此目的。这将根据新的 CNAME
目标生成新的答案记录。
CNAME 重写规则的语法如下。exact | prefix | suffix | substring | regex
的含义与名称重写规则的含义相同。省略的类型默认为 exact
。
rewrite [continue|stop] cname [exact|prefix|suffix|substring|regex] FROM TO
考虑具有正则表达式类型的以下 CNAME
重写规则。
rewrite cname regex (.*).cdn.example.net. {1}.other.cdn.com.
如果不带上述规则发送以下 DNS 请求,示例响应将为
$ 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
如果您在设置了上述规则的情况下发送相同的 DNS 请求,示例响应将为
$ 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
请注意,在重写 CNAME
目标后,该答案将包含一组完全不同的答案记录。