重寫

原始碼

rewrite 執行內部訊息重寫。

描述

重寫對客戶端是不可見的。有簡單的重寫(速度快)和複雜的重寫(速度較慢),但它們的功能足夠強大,可以適應大多數動態後端應用程式。

語法

rewrite 的簡化/易於理解的語法是...

rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
  • FIELD 指示正在重寫的請求/回應的哪個部分。

    • type - 請求的類型欄位將被重寫。FROM/TO 必須是 DNS 記錄類型 (AMX 等);例如,要將 ANY 查詢重寫為 HINFO,請使用 rewrite type ANY HINFO
    • name - 請求中的查詢名稱將被重寫;預設情況下,這是名稱的完整匹配,例如, rewrite name example.net example.org。其他匹配類型也支援,請參閱下面的名稱欄位重寫章節。
    • class - 訊息的類別將被重寫。FROM/TO 必須是 DNS 類別類型 (INCHHS);例如,要將 CH 查詢重寫為 IN,請使用 rewrite class CH IN
    • edns0 - 可以將 EDNS0 選項附加到請求,如下面的 EDNS0 選項章節所述。
    • ttl - 回應中的 TTL 值將被重寫。
    • cname - 如果回應有 CNAME 記錄,則為 CNAME 目標。
  • TYPE 此選用元素可以針對 namettl 欄位指定。如果未給定,將假定類型為 exact。如果要指定選項,則必須給定類型。

  • FROM 是要匹配的名稱(精確、後綴、前綴、子字串或正規表示式)或類型。

  • TO 是要重寫成的目標名稱或類型。

  • TTL 是將 TTL 值設定為的秒數(僅適用於欄位 ttl)。

  • 選項

    對於欄位 name,可以進一步控制回應重寫。所有名稱匹配類型都支援以下選項

    • answer auto - 以盡力而為的方式重寫回應中的名稱。
    • answer name FROM TO - 重寫回應中的查詢名稱,使其符合 from 正規表示式模式。
    • answer value FROM TO - 重寫回應中的名稱,使其符合 from 正規表示式模式。

    有關詳細資訊,請參閱下面的回應重寫章節。

如果您指定多個規則,且傳入的查詢符合多個規則,則重寫的行為如下

  • continue 將繼續應用規則清單中的下一個規則。
  • 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 SECTIONQUESTION 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 SECTIONVALUE 部分中的網域 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 選項。

以下規則將請求中的名稱從 RED 重寫為 BLUE,然後將對應回應中的名稱從 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 的含義與名稱重寫規則相同。省略的類型預設為 exact

rewrite [continue|stop] ttl [exact|prefix|suffix|substring|regex] STRING [SECONDS|MIN-MAX]

可以在 SECONDS 參數中提供 TTL 值的範圍,而不是單一值。如果提供範圍,則如果 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

此選項有兩個欄位,代碼 (code) 和數據 (data)。 匹配的定義是具有相同的代碼。數據可以是字串或變數。

  • 如果字串數據以 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}。

  • 如果已啟用 metadata 外掛程式,則如果標籤出現在大括號內,則這些標籤也支援作為變數。變數數據將會被替換為與該標籤相關聯的值。如果未提供該標籤,則該變數將會被靜默地替換為空字串。

範例

rewrite edns0 local set 0xffee {client_ip}

以下範例使用 metadata 和一個假設的 "some-plugin",該外掛程式會提供 "some-label" 作為 metadata 資訊。

metadata
some-plugin
rewrite edns0 local set 0xffee {some-plugin/some-label}

EDNS0_NSID

此選項沒有欄位;它會為 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

考慮以下使用 regex 類型的 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 目標之後,答案將會包含一組完全不同的答案記錄。