重写

源代码

重写执行内部消息重写。

描述

重写在客户端不可见。有简单重写(快)和复杂重写(慢),但它们功能强大,足以适应大多数动态后端应用程序。

语法

重写的简化/易于理解的语法为...

rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
  • 字段表示请求/响应的哪一部分正在被重写。

    • 类型 - 请求的类型字段将被重写。FROM/TO 必须是 DNS 记录类型 (AMX 等);例如,要将任何查询重写为 HINFO,请使用 重写类型 ANY HINFO
    • 名称 - 请求中的查询名称被重写;默认情况下,这是名称的完全匹配,例如,重写名称 example.net example.org。支持其他匹配类型,请参见下面的名称字段重写部分。
    • 类型 - 消息的类型将被重写。FROM/TO 必须是 DNS 类型 (INCHHS);例如,要将 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]

匹配类型(如exactsubstring等)触发重写

  • 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 SECTIONANSWER 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 选项请求对 CNAMESRV等的记录值进行基于正则表达式的重写。

在此,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 响应记录中返回的其他值(例如 SRVMX 记录中返回的服务器名称)。这可以通过向名称规则添加 answer value FROM TO 选项来启用,如下所示。answer value 需要一个正则表达式和一个改写名称作为参数,工作方式与 answer name 规则相同。

请注意,AUTHORITY SECTIONADDITIONAL SECTION 中的名称也将根据指定规则进行改写。如果指定了 answer value 规则,则以下记录类型返回的名称将被改写:CNAMEDNAMESOASRVMXNAPTRNSPTR

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.

多个响应改写

namevalue 改写可以通过追加多个答案改写选项来链接。对于除第一个之外的所有显示,关键字 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 valueanswer 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_LOCALEDNS0_NSIDEDNS0_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 为空字符串。如果选项已存在且操作为 replaceset,则该选项中的 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 目标后,该答案将包含一组完全不同的答案记录。