轉發

原始碼

forward 能夠將 DNS 訊息代理轉發至上游解析器。

描述

forward 外掛程式會重複使用已開啟的連線至上游。它支援 UDP、TCP 和 DNS over TLS,並使用內建的健康檢查。

當偵測到錯誤時,會執行健康檢查。此檢查會在迴圈中執行,以 _0.5 秒_ 的間隔執行每次檢查,只要上游回報為不健康狀態。一旦恢復健康,我們就會停止健康檢查 (直到下次發生錯誤)。健康檢查使用遞迴 DNS 查詢 (. IN NS) 來取得上游的健康狀態。任何非網路錯誤的回應 (REFUSED、NOTIMPL、SERVFAIL 等) 都會被視為上游健康。健康檢查會使用在 TO 中指定的相同協定。如果 max_fails 設定為 0,則不會執行檢查,且上游將始終被視為健康。

所有上游都關閉時,它會假設健康檢查機制已失敗,並會嘗試連線至隨機上游 (這可能有效或無效)。

語法

最基本的形式中,一個簡單的轉發器使用此語法

forward FROM TO...
  • FROM 是要比對以轉發請求的基礎網域。使用 CIDR 表示法展開為多個反向區域的網域不完全支援;僅使用第一個展開的區域。
  • TO… 是要轉發到的目的地端點。TO 語法允許您指定協定,例如 tls://9.9.9.9dns:// (或沒有協定) 代表純 DNS。上游的數量限制為 15 個。

多個上游會在第一次使用時隨機化 (請參閱 policy)。當一個健康的代理在交換期間返回錯誤時,會嘗試清單中的下一個上游。

可使用展開的語法取得額外的控制項

forward FROM TO... {
    except IGNORED_NAMES...
    force_tcp
    prefer_udp
    expire DURATION
    max_fails INTEGER
    tls CERT KEY CA
    tls_servername NAME
    policy random|round_robin|sequential
    health_check DURATION [no_rec] [domain FQDN]
    max_concurrent MAX
}
  • FROMTO… 如上所述。

  • except 中的 IGNORED_NAMES 是以空格分隔的網域清單,會排除在轉發之外。符合這些名稱的請求將會被略過。

  • force_tcp,即使請求是透過 UDP 傳入,仍使用 TCP。

  • prefer_udp,即使請求是透過 TCP 傳入,仍先嘗試使用 UDP。如果回應被截斷 (回應中設定了 TC 旗標),則透過 TCP 再次嘗試。如果同時指定了 force_tcpprefer_udp 選項,則 force_tcp 優先。

  • max_fails 是在上游被視為關閉之前,需要後續失敗的健康檢查次數。如果為 0,則上游將永遠不會被標記為關閉 (也不會進行健康檢查)。預設值為 2。

  • expire DURATION,在此時間之後過期 (快取) 連線,預設值為 10 秒。

  • tls CERT KEY CA 定義 TLS 連線的 TLS 屬性。可以提供 0 到 3 個參數,其含義如下所述

    • tls - 不使用用戶端驗證,並使用系統 CA 來驗證伺服器憑證
    • tls CA - 不使用用戶端驗證,並使用檔案 CA 來驗證伺服器憑證
    • tls CERT KEY - 用戶端驗證使用指定的憑證/金鑰對。伺服器憑證會使用系統 CA 進行驗證
    • tls CERT KEY CA - 用戶端驗證使用指定的憑證/金鑰對。伺服器憑證會使用指定的 CA 檔案進行驗證
  • tls_servername NAME 允許您在 TLS 設定中設定伺服器名稱;例如 9.9.9.9 需要將其設定為 dns.quad9.net。在此案例中仍然允許使用多個上游,但它們必須使用相同的 tls_servername。例如,將 9.9.9.9 (QuadDNS) 與 1.1.1.1 (Cloudflare) 混合將無法運作。使用 TLS 轉發但未設定 tls_servername 會導致任何人都能夠對您轉發至 DNS 伺服器的連線進行中間人攻擊。因此,強烈建議在使用 TLS 轉發時設定此值。

  • policy 指定用於選擇上游伺服器的策略。預設值為 random

    • random 是一種實作隨機上游選擇的策略。
    • round_robin 是一種基於循環配置順序選擇主機的策略。
    • sequential 是一種基於循序選擇主機的策略。
  • health_check 設定上游伺服器健康檢查的行為

    • <duration> - 使用不同的持續時間進行健康檢查,預設持續時間為 0.5 秒。
    • no_rec - 可選參數,將健康檢查中使用的 dns 查詢的 RecursionDesired 旗標設定為 false。此旗標預設為 true
    • domain FQDN - 將健康檢查所使用的網域名稱設定為 FQDN。如果未設定,則健康檢查所使用的網域名稱為 .
  • max_concurrent MAX 將並行查詢的數量限制為 MAX。任何會使並行查詢數量超過 MAX 的新查詢都會導致 REFUSED 回應。此回應不會被視為健康失敗。在選擇 MAX 的值時,請選擇一個至少大於上游伺服器的預期上游查詢速率 * 延遲 的數字。作為 MAX 的上限,請考慮每個並行查詢將使用大約 2kb 的記憶體。

另請注意,TLS 設定對於整個轉發代理是「全域」的,如果您需要針對不同的上游使用不同的 tls_servername,那就沒辦法了。

在每個端點上,通訊的逾時設定如下

  • 撥號逾時預設為 30 秒,並且可以根據早期結果自動減少到 1 秒。
  • 讀取逾時固定為 2 秒。

中繼資料

如果也啟用了 metadata 外掛程式,則 forward 外掛程式會發佈以下中繼資料

  • forward/upstream:用於轉發請求的上游

指標

如果啟用了監控 (透過 prometheus 外掛程式),則會匯出以下指標

  • coredns_forward_healthcheck_broken_total{} - 當所有上游都不健康時的計數,我們會隨機 (這始終使用 random 策略) 向一個上游發送請求。
  • coredns_forward_max_concurrent_rejects_total{} - 由於並行查詢的數量達到最大值而被拒絕的查詢計數。
  • coredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode} - 每個上游、RCODE 的直方圖
  • coredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode} - 每個上游失敗的健康檢查計數。
  • coredns_proxy_conn_cache_hits_total{proxy_name="forward", to, proto}- 每個上游和協定的連線快取命中計數。
  • coredns_proxy_conn_cache_misses_total{proxy_name="forward", to, proto} - 每個上游和協定的連線快取未命中計數。

其中 to 是其中一個上游伺服器 (來自設定的 TO),rcode 是從上游返回的 RCODE,proto 是傳輸協定,如 udptcptcp-tls

以下指標最近已被棄用

  • coredns_forward_healthcheck_failures_total{to, rcode}
    • 可以使用 coredns_proxy_healthcheck_failures_total{proxy_name="forward", to, rcode} 來取代
  • coredns_forward_requests_total{to}
    • 可以使用 sum(coredns_proxy_request_duration_seconds_count{proxy_name="forward", to}) 來取代
  • coredns_forward_responses_total{to, rcode}
    • 可以使用 coredns_proxy_request_duration_seconds_count{proxy_name="forward", to, rcode} 來取代
  • coredns_forward_request_duration_seconds{to, rcode}
    • 可以使用 coredns_proxy_request_duration_seconds{proxy_name="forward", to, rcode} 來取代

範例

example.org. 內的所有請求代理轉發到在不同連接埠上執行的名稱伺服器

example.org {
    forward . 127.0.0.1:9005
}

lab.example.local. 內的所有請求傳送至 10.20.0.1,將 example.local. (且不在 lab.example.local. 中) 內的所有請求傳送至 10.0.0.1,將所有其他請求傳送至 /etc/resolv.conf 中定義的伺服器,並快取結果。請注意,在伺服器區塊中設定多個 forward 外掛程式的 CoreDNS 伺服器會在處理請求時依照列出的順序評估這些 forward 外掛程式。因此,子網域應放置在父網域之前,否則子網域請求將會轉發至父網域的上游。因此,在此範例中,lab.example.localexample.local 之前,而 example.local. 之前。

. {
    cache
    forward lab.example.local 10.20.0.1
    forward example.local 10.0.0.1
    forward . /etc/resolv.conf
}

上面的範例幾乎等同於以下範例,只是以下範例定義了三個獨立的外掛程式鏈 (因此有 3 個獨立的 cache 執行個體)。

lab.example.local {
    cache
    forward . 10.20.0.1
}
example.local {
    cache
    forward . 10.0.0.1
}
. {
    cache
    forward . /etc/resolv.conf
}

在三個解析器之間進行所有請求的負載平衡,其中一個解析器具有 IPv6 位址。

. {
    forward . 10.0.0.10:53 10.0.0.11:1053 [2003::1]:53
}

轉發除 example.org 以外的所有請求

. {
    forward . 10.0.0.10:1234 {
        except example.org
    }
}

使用主機的 resolv.conf 的名稱伺服器代理除 example.org 以外的所有內容

. {
    forward . /etc/resolv.conf {
        except example.org
    }
}

使用 DNS over TLS (DoT) 協定將所有請求代理轉發至 9.9.9.9,並將每個答案快取最多 30 秒。請注意,如果您想要正常運作的設定,則 tls_servername 是強制性的,因為 9.9.9.9 無法在 TLS 交涉中使用。此外,請將健康檢查持續時間設定為 5 秒,以免健康檢查完全淹沒服務。

. {
    forward . tls://9.9.9.9 {
       tls_servername dns.quad9.net
       health_check 5s
    }
    cache 30
}

或為健康檢查請求設定其他網域名稱

. {
    forward . tls://9.9.9.9 {
       tls_servername dns.quad9.net
       health_check 5s domain example.org
    }
    cache 30
}

或來自同一提供者的多個上游

. {
    forward . tls://1.1.1.1 tls://1.0.0.1 {
       tls_servername cloudflare-dns.com
       health_check 5s
    }
    cache 30
}

或者,當您有多個具有不同 tls_servername 的 DoT 上游時,您可以執行以下操作

. {
    forward . 127.0.0.1:5301 127.0.0.1:5302
}

.:5301 {
    forward . tls://8.8.8.8 tls://8.8.4.4 {
        tls_servername dns.google
    }
}

.:5302 {
    forward . tls://1.1.1.1 tls://1.0.0.1 {
        tls_servername cloudflare-dns.com
    }
}

另請參閱

RFC 7858,了解 DNS over TLS。