3. 建立和管理 DNS-over-TLS 会话 (Establishing and Managing DNS-over-TLS Sessions)
3.1 会话发起
默认情况下, 支持 DNS over TLS 的 DNS 服务器MUST在端口 853 上监听并接受 TCP 连接, 除非它与客户端相互约定使用 853 以外的端口承载 DNS over TLS. 为使用 853 以外的端口, 客户端和服务器的软件都需要配置选项.
默认情况下, 希望从特定服务器获得 DNS over TLS 隐私保护的 DNS 客户端MUST与该服务器的端口 853 建立 TCP 连接, 除非它与服务器相互约定使用 853 以外的端口承载 DNS over TLS. 这种其他端口MUST NOT是端口 53, 但MAY来自 "first-come, first-served" 端口范围. 不建议将端口 53 用于 DNS over TLS, 是为了避免在选择使用或不使用 TLS 时引入复杂性, 并降低 downgrade attacks 的风险. 该 TCP 连接上的第一次数据交换MUST是客户端和服务器按照 [RFC5246] 中描述的过程发起 TLS handshake.
DNS 客户端和服务器MUST NOT使用端口 853 传输明文 DNS 消息. 在任何用于 DNS over TLS 的端口上, DNS 客户端MUST NOT发送明文 DNS 消息, DNS 服务器MUST NOT响应明文 DNS 消息, 例如 TLS handshake 失败后也不允许. 混合受保护和未受保护的数据存在重大安全问题, 因此给定服务器指定用于 DNS over TLS 的端口上的 TCP 连接仅保留给加密通信.
DNS 客户端SHOULD记住不支持 DNS over TLS 的服务器 IP 地址, 包括发生超时, 连接拒绝和 TLS handshake 失败的地址, 并在合理时间内不再向它们请求 DNS over TLS, 例如每个服务器一小时. 遵循带外 key-pinned privacy profile (第 4.2 节) 的 DNS 客户端MAY更积极地重试 DNS-over-TLS 连接失败.
3.2 TLS 握手和认证
一旦 DNS 客户端成功通过 TCP 连接到 DNS over TLS 的 well-known port, 它就继续执行 TLS handshake [RFC5246], 并遵循 [BCP195] 中规定的最佳实践.
随后, 如果需要, 客户端会认证服务器. 本文档不提出新的认证思路. 根据所使用的 privacy profile (第 4 节), DNS 客户端可以选择不要求认证服务器, 也可以使用受信任的 Subject Public Key Info (SPKI) Fingerprint pin set.
TLS 协商完成后, 连接将被加密, 此时已经受到保护, 可防止窃听.
3.3 发送和接收消息
已建立 TLS 会话中的所有消息, 包括请求和响应, MUST使用 [RFC1035] 第 4.2.2 节描述的 two-octet length 字段. 出于效率原因, DNS 客户端和服务器SHOULD同时将 two-octet length 字段以及该长度字段描述的消息传递给 TCP 层, 例如在单次 "write" 系统调用中传递, 以提高所有数据在单个 TCP segment 中传输的可能性 ([RFC7766] 第 8 节).
为了最小化延迟, 客户端SHOULD在一个 TLS 会话上流水线发送多个查询. 当 DNS 客户端向服务器发送多个查询时, 在发送下一个查询前不应等待尚未完成的回复 ([RFC7766] 第 6.2.1.1 节).
由于流水线响应可能乱序到达, 客户端MUST使用 Message ID 将响应与同一 TLS 连接上的未完成查询进行匹配. 如果响应包含 Question Section, 客户端MUST匹配 QNAME, QCLASS 和 QTYPE 字段. 客户端未能正确地将响应与未完成查询匹配, 可能对互操作性造成严重后果 ([RFC7766] 第 7 节).
3.4 连接复用, 关闭和重建
对于使用 "getaddrinfo()" 和 "gethostbyname()" 等库函数的 DNS 客户端, 已知当前实现会为每个 DNS 查询打开并关闭 TCP 连接. 为避免每个连接只承载一个查询而造成过多 TCP 连接, 客户端SHOULD复用到递归解析器的单个 TCP 连接. 作为替代, 客户端也可以优先使用 UDP 连接到同一机器上支持 DNS-over-TLS 的 caching resolver, 再由该 resolver 使用系统范围的 TCP 连接到递归解析器.
为了摊销 TCP 和 TLS 连接建立成本, 客户端和服务器SHOULD NOT在每次响应后立即关闭连接. 相反, 只要有足够资源, 客户端和服务器SHOULD为后续查询复用现有连接. 在某些情况下, 这意味着客户端和服务器可能需要让空闲连接保持打开一段时间.
正确管理已建立和空闲连接对 DNS 服务器的健康运行很重要. DNS over TLS 的实现者SHOULD遵循 [RFC7766] 中描述的 DNS over TCP 最佳实践. 未能做到这一点可能导致资源耗尽和拒绝服务.
虽然 [RFC1035] 时代的客户端和服务器实现已知 TCP 连接管理较差, 但本文档规定, 成功协商 TLS 表明双方愿意保持空闲 DNS 连接打开, 这独立于不带 TLS 的 DNS over TCP 的超时或其他建议. 换言之, 实现本协议的软件被假定支持空闲的持久连接, 并准备好管理多个可能长期存在的 TCP 连接.
本文档不对空闲连接的超时值提出具体建议. 客户端和服务器应根据可用资源水平复用和/或关闭连接. 在活动较低期间, 超时可以更长; 在活动较高期间, 超时可以更短. 该领域当前的工作也可能帮助 DNS-over-TLS 客户端和服务器选择有用的超时值 [RFC7828] [TDNS].
保持空闲连接打开的客户端和服务器MUST能够稳健处理任一方终止空闲连接的情况. 与当前 DNS over TCP 一样, DNS 服务器MAY随时关闭连接, 例如由于资源约束. 与当前 DNS over TCP 一样, 客户端MUST处理突然关闭, 并准备好重建连接和/或重试查询.
如 [RFC7766] 所讨论, 在重建已终止的 DNS-over-TCP 连接时, TCP Fast Open [RFC7413] 是有益的. 为强调仅在 DNS-over-TLS 端口上发送加密 DNS 数据这一要求 (第 3.2 节), 使用 TCP Fast Open 时, 客户端和服务器MUST立即发起或恢复 TLS handshake, 明文 DNS MUST NOT交换. DNS 服务器SHOULD启用快速 TLS session resumption [RFC5077], 并且在重建连接时SHOULD使用该机制.
关闭连接时, DNS 服务器SHOULD使用 TLS close-notify 请求将 TCP TIME-WAIT 状态转移给客户端. [RFC7766] 提供了优化 DNS over TCP 的其他要求和指导.