範本

原始碼

template 允許根據傳入的查詢動態產生回應。

描述

template 外掛程式允許您透過編寫 (Go) 範本來動態回應查詢。

語法

template CLASS TYPE [ZONE...] {
    match REGEX...
    answer RR
    additional RR
    authority RR
    rcode CODE
    ederror EXTENDED_ERROR_CODE [EXTRA_REASON]
    fallthrough [FALLTHROUGH-ZONE...]
}
  • CLASS 查詢類別 (通常是 IN 或 ANY)。
  • TYPE 查詢類型 (A、PTR、… 可以是 ANY 以符合所有類型)。
  • ZONE 此範本的區域範圍。預設為伺服器區域。
  • match REGEX Go 正規表示式,會針對傳入的查詢名稱進行比對。如果未指定正規表示式,則會比對所有內容 (預設值:.*)。第一個符合的正規表示式會勝出。
  • answer|additional|authority RR 一個 RFC 1035 風格的資源記錄片段,由包含回覆的 Go 範本所建立。如果未指定 answer,則會產生一個空白 answer 區段的回應。
  • rcode CODE 一個回應碼 (NXDOMAIN、SERVFAIL、...)。預設值為 NOERROR。有效的回應碼值根據 miekg/dns 套件在 msg.go 中定義的 RcodeToString 對應。
  • ederror EXTENDED_ERROR_CODE 是一個擴充的 DNS 錯誤碼,為 RFC8914 中定義的數字 (0, 1, 2,…, 24)。EXTRA_REASON 是一個額外的字串,用於說明傳回錯誤的原因。
  • fallthrough 如果 templateZONE 符合查詢名稱但沒有正規表示式符合,則繼續使用下一個 template 執行個體。如果沒有下一個 template,則繼續使用下一個外掛程式進行解析。如果列出 [FALLTHROUGH-ZONE…] (例如 in-addr.arpaip6.arpa),則只有這些區域的查詢才會受到 fallthrough 的影響。如果沒有 fallthrough,當 templateZONE 符合查詢但沒有正規表示式符合時,則會傳回 SERVFAIL 回應。

另請參閱 包含額外的閱讀清單。

範本

每個資源記錄都是功能完整的 Go 範本,具有以下預先定義的資料

  • .Zone 相符的區域字串 (例如 example.)。
  • .Name 查詢名稱,以字串形式 (小寫)。
  • .Class 查詢類別 (通常為 IN)。
  • .Type 要求的 RR 類型 (例如 PTR)。
  • .Match 所有比對的陣列。index .Match 0 指的是整個比對。
  • .Group 具名擷取群組的對應。
  • .Message 完整的傳入 DNS 訊息。
  • .Question 相符的問題區段。
  • .Remote 用戶端的 IP 位址
  • .Meta 一個函式,它接受中繼資料名稱並傳回值 (如果已啟用中繼資料外掛程式)。例如,.Meta "kubernetes/client-namespace"

以及以下預先定義的 範本函式

  • parseInt 以給定的基數和位元大小解譯字串。相當於 strconv.ParseUint

範本的輸出必須是 RFC 1035 風格的資源記錄 (通常稱為「區域檔」)。

警告 Go 範本和 CoreDNS 設定檔存在語法問題。類似 {{$var}} 的運算式會被 CoreDNS (和 Caddy) 解釋為對環境變數的參考,而 {{ $var }} 則可以運作。請參閱 錯誤 和 corefile(5)。

度量

如果已啟用監控 (透過 prometheus 外掛程式),則會匯出以下度量

  • coredns_template_matches_total{server, zone, view, class, type} 依正規表示式比對的要求總數。
  • coredns_template_template_failures_total{server, zone, view, class, type, section, template} Go 範本失敗的次數。可以使用正規表示式、區段和範本標籤值將錯誤對應回設定檔。
  • coredns_template_rr_failures_total{server, zone, view, class, type, section, template} 範本化的資源記錄無效且無法剖析的次數。可以使用正規表示式、區段和範本標籤值將錯誤對應回設定檔。

兩種失敗情況都表示範本設定有問題。server 標籤表示遞增度量的伺服器,詳細資訊請參閱 metrics 外掛程式。

範例

將所有內容解析為 NXDOMAIN

最簡單的範本是

. {
    template ANY ANY {
      rcode NXDOMAIN
    }
}
  1. 此範本使用預設區域 (. 或所有查詢)
  2. 所有查詢都將得到回覆 (沒有 fallthrough)
  3. 答案始終是 NXDOMAIN

將 .invalid 解析為 NXDOMAIN

.invalid 網域是保留的 TLD (請參閱 RFC 2606 保留的頂級 DNS 名稱),用於指示無效的網域。

. {
    forward . 8.8.8.8

    template ANY ANY invalid {
      rcode NXDOMAIN
      authority "invalid. 60 {{ .Class }} SOA ns.invalid. hostmaster.invalid. (1 60 60 60 60)"
      ederror 21 "Blocked according to RFC2606"
    }
}
  1. 對 .invalid 的查詢將會產生 NXDOMAIN (rcode)
  2. 會傳送虛擬 SOA 記錄,以便為快取目的發放 60 秒的 TTL
  3. CH 類別中查詢 .invalid 也會導致 NXDOMAIN/SOA 回應
  4. 預設的正規表示式為 .*

封鎖無效的搜尋網域完成

假設您執行 example.com,資料中心為 dc1.example.com。資料中心網域是 DNS 搜尋網域的一部分。但是,something.example.com.dc1.example.com 表示一個完整網域名稱 (something.example.com),該名稱無意中新增了預設網域或搜尋路徑 (dc1.example.com)。

. {
    forward . 8.8.8.8

    template IN ANY example.com.dc1.example.com {
      rcode NXDOMAIN
      authority "{{ .Zone }} 60 IN SOA ns.example.com hostmaster.example.com (1 60 60 60 60)"
    }
}

更詳細的基於正規表示式的等效項將會是

. {
    forward . 8.8.8.8

    template IN ANY example.com {
      match "example\.com\.(dc1\.example\.com\.)$"
      rcode NXDOMAIN
      authority "{{ index .Match 1 }} 60 IN SOA ns.{{ index .Match 1 }} hostmaster.{{ index .Match 1 }} (1 60 60 60 60)"
      fallthrough
    }
}

基於正規表示式的版本可以進行更複雜的比對/範本化,而基於區域的範本化更容易讀取和使用。

為 .example 解析 A/PTR

. {
    forward . 8.8.8.8

    # ip-a-b-c-d.example A a.b.c.d

    template IN A example {
      match (^|[.])ip-(?P<a>[0-9]*)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
      answer "{{ .Name }} 60 IN A {{ .Group.a }}.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      fallthrough
    }

    # d.c.b.a.in-addr.arpa PTR ip-a-b-c-d.example

    template IN PTR in-addr.arpa {
      match ^(?P<d>[0-9]*)[.](?P<c>[0-9]*)[.](?P<b>[0-9]*)[.](?P<a>[0-9]*)[.]in-addr[.]arpa[.]$
      answer "{{ .Name }} 60 IN PTR ip-{{ .Group.a }}-{{ .Group.b }}-{{ .Group.c }}-{{ .Group.d }}.example."
    }
}

IPv4 位址由 4 個位元組組成,a.b.c.d。具名群組使其在 PTR 案例中反轉 IP 位址時較不容易出錯。請嘗試使用具名群組來解釋您的正規表示式和範本的作用。

請注意,A 記錄實際上是萬用字元:IP 位址的任何子網域都會解析為 IP 位址。

使用範本對應某些 PTR/A 配對是一種常見模式。

對於只有部分回應被範本化的混合網域,需要使用 Fallthrough。

使用 parseInt 解析十六進位 IP 模式

. {
    forward . 8.8.8.8

    template IN A example {
      match "^ip0a(?P<b>[a-f0-9]{2})(?P<c>[a-f0-9]{2})(?P<d>[a-f0-9]{2})[.]example[.]$"
      answer "{{ .Name }} 60 IN A 10.{{ parseInt .Group.b 16 8 }}.{{ parseInt .Group.c 16 8 }}.{{ parseInt .Group.d 16 8 }}"
      fallthrough
    }
}

IPv4 位址可以使用其十六進位編碼以更緊湊的形式表示。例如,ip-10-123-123.example. 可以改為表示為 ip0a7b7b7b.example.

解析多個 IP 模式

. {
    forward . 8.8.8.8

    template IN A example {
      match "^ip-(?P<a>10)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]dc[.]example[.]$"
      match "^(?P<a>[0-9]*)[.](?P<b>[0-9]*)[.](?P<c>[0-9]*)[.](?P<d>[0-9]*)[.]ext[.]example[.]$"
      answer "{{ .Name }} 60 IN A {{ .Group.a}}.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      fallthrough
    }
}

具名擷取群組可以用於為多個模式範本化一個回應。

為 .example 中的 IP 範本解析 A 和 MX 記錄

. {
    forward . 8.8.8.8

    template IN A example {
      match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
      answer "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      fallthrough
    }
    template IN MX example {
      match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
      answer "{{ .Name }} 60 IN MX 10 {{ .Name }}"
      additional "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      fallthrough
    }
}

在回應中新增權威名稱伺服器

. {
    forward . 8.8.8.8

    template IN A example {
      match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
      answer "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      authority  "example. 60 IN NS ns0.example."
      authority  "example. 60 IN NS ns1.example."
      additional "ns0.example. 60 IN A 203.0.113.8"
      additional "ns1.example. 60 IN A 198.51.100.8"
      fallthrough
    }
    template IN MX example {
      match ^ip-10-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]example[.]$
      answer "{{ .Name }} 60 IN MX 10 {{ .Name }}"
      additional "{{ .Name }} 60 IN A 10.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
      authority  "example. 60 IN NS ns0.example."
      authority  "example. 60 IN NS ns1.example."
      additional "ns0.example. 60 IN A 203.0.113.8"
      additional "ns1.example. 60 IN A 198.51.100.8"
      fallthrough
    }
}

捏造 CNAME

此範例會將任何完全針對 foogle.com 提出的 DNS 查詢,以 CNAME 回應至 google.com。如果上游名稱伺服器可以傳回所要求類型的記錄,則答案也會包含 google.com 的記錄。

. {
  template IN ANY foogle.com {
    match "^foogle\.com\.$"
    answer "foogle.com 60 IN CNAME google.com"
  }
  forward . 8.8.8.8
}

另請參閱

錯誤

CoreDNS 透過 {$ENV_VAR} 的概念支援 caddyfile 環境變數。此剖析器功能將會中斷類似 {{$variable}}Go 範本變數標記法。等效標記法 {{ $variable }} 將會運作。請嘗試避免在此外掛程式的內容中使用 Go 範本變數。