转发

源代码

forward 简化了将 DNS 消息代理到上游解析器。

说明

forward 外挂插件可重复使用已打开的上游套接字。它支持 UDP、TCP 及 DNS-over-TLS 并使用带内健康检查。

当检测到错误时,将执行健康检查。此检查会以循环方式运行,在报告上游状态不佳的情况下,以间隔0.5 秒执行每次检查,直到其状态恢复正常。一旦正常后,我们将停止健康检查(直到下一个错误出现)。健康检查使用递归 DNS 查询(. IN NS)获取上游状态信息。任何不是网络错误(拒绝、未实现、服务器故障等)的响应都视为上游状态正常。健康检查使用与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持续时间,(缓存的)连接在此时间之后过期,默认值为 10 秒。

  • tls 证书 密钥 CA 为 TLS 连接定义 TLS 属性。可提供 0 到 3 个参数,具体含义如下

    • tls - 不使用客户端身份验证,并且使用系统 CA 来验证服务器证书
    • tls CA - 不使用客户端身份验证,并且使用文件 CA 来验证服务器证书
    • tls CERT KEY - 使用指定的证书/密钥对进行客户端身份验证。服务器证书通过系统 CA 验证
    • tls CERT KEY CA - 使用指定的证书/密钥对进行客户端身份验证。服务器证书使用指定的 CA 文件验证
  • tls_servername 名称 允许您在 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 转发时强烈建议设置此值。

  • 策略 指定用于选择上游服务器的策略。默认值为 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_servername,则 TLS 配置对于整个转发代理是“全局”的。

在每个端点上,通信的超时设置如下

  • 拨号超时默认值为 30 秒,可以根据早期结果自动降至 1 秒。
  • 读取超时固定为 2 秒。

元数据

如果已启用元数据插件,向前插件会发布以下元数据

  • 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
    }
}

除发往example.org的请求外,使用主机的resolv.conf中的名称服务器代理所有请求

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

使用 DNS-over-TLS (DoT) 协议将所有请求代理到 9.9.9.9,并缓存每个答案最长 30 秒。请注意,如果想让设置正常运行,tls_servername 是必须的,因为无法在 TLS 协商中使用 9.9.9.9。还要将运行状况检查的持续时间设置为 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。