跳到主要内容

7. DNS Stateful Operations 的基础 TLV

本节描述 DNS Stateful Operations 的三个基础 TLV: Keepalive, Retry Delay 和 Encryption Padding.

7.1. Keepalive TLV

Keepalive TLV (DSO-TYPE=1) 执行两个功能. 其主要功能是建立 Session Timeout 值. 附带地, 它还会重置 DSO Session 的保活定时器, 因而可作为一种用于保持会话存活的 "no-op" 消息. 客户端请求期望的 Session Timeout 值, 服务器则以它要求客户端使用的响应值进行确认.

以 Keepalive TLV 作为 Primary TLV 的 DSO 消息可以出现在 early data 中.

Keepalive TLV 的 DSO-DATA 如下:

                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| INACTIVITY TIMEOUT (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| KEEPALIVE INTERVAL (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • INACTIVITY TIMEOUT: 当前 DSO Session 的非活动超时, 以网络字节序 (big endian) 的 32 位无符号整数表示, 单位为毫秒. 这是客户端必须开始关闭非活动 DSO Session 的超时时间. 非活动超时可以是服务器选择的任何值. 如果客户端没有优雅关闭非活动 DSO Session, 则在 5 秒或该间隔的两倍之后 (取较大者), 服务器会强制中止连接.

  • KEEPALIVE INTERVAL: 当前 DSO Session 的保活间隔, 以网络字节序 (big endian) 的 32 位无符号整数表示, 单位为毫秒. 这是客户端必须生成 DSO keepalive 流量以维护连接状态的间隔. 保活间隔禁止小于 10 秒. 如果客户端没有生成强制要求的 DSO keepalive 流量, 则在该间隔的两倍之后服务器会强制中止连接. 由于允许的最小保活间隔为 10 秒, 服务器因客户端未生成强制要求的 DSO keepalive 流量而强制断开客户端的最短时间为 20 秒.

DSO Keepalive 消息 (即 Keepalive TLV 为第一个 TLV 的消息) 的发送或接收只重置保活定时器, 不重置非活动定时器. 原因是周期性 DSO Keepalive 消息的唯一目的, 是在 DSO Session 具有当前或近期非维护活动且值得保持存活时, 保持该 DSO Session 存活. 发送 DSO keepalive 流量本身不视为客户端活动; 它是为其他客户端活动服务的维护活动. 如果 DSO keepalive 流量本身会重置非活动定时器, 就会形成循环活锁, 即无限期发送 keepalive 流量以保持 DSO Session 存活. 在这种场景中, 该 DSO Session 上唯一的活动就是 keepalive 流量, 它保持会话存活只是为了能发送更多 keepalive 流量. 因此, 单纯发送或接收 DSO Keepalive 消息不会重置非活动定时器.

客户端发送 DSO Keepalive request message 时, 必须把它作为带有非零 MESSAGE ID 的 DSO request message 发送. 如果服务器收到 MESSAGE ID 为零的 DSO Keepalive 消息, 这是致命错误, 服务器必须立即强制中止连接. DSO Keepalive request message 会重置 DSO Session 的保活定时器, 同时向服务器传递客户端请求的 Session Timeout 值. 在服务器对客户端发起的 DSO Keepalive request message 的响应中, Session Timeout 包含服务器从该时刻起为该 DSO Session 选择的值, 客户端必须遵守. 这建模自 DHCP 协议: 客户端用 DHCP option 51 [RFC2132] 请求某个租约生命期, 但最终由服务器决定实际授予的租约生命期.

当客户端向服务器发送第二个及后续 DSO Keepalive request message 时, 客户端应继续每次请求其首选值. 这样可提供灵活性, 使得如果 DSO Session 生命周期内条件发生变化, 服务器可以调整响应以更好匹配客户端需求.

一旦 DSO Session 正在进行 (第 5.1 节), 服务器可以发起 DSO Keepalive 消息. 服务器发送时, DSO Keepalive 消息必须作为 MESSAGE ID 设为零的 DSO unidirectional message 发送. 客户端禁止为服务器发起的 DSO Keepalive 消息生成响应. 如果客户端收到带非零 MESSAGE ID 的 DSO Keepalive request message, 这是致命错误, 客户端必须立即强制中止连接. 服务器发送的 DSO Keepalive unidirectional message 会重置 DSO Session 的保活定时器, 同时单方面告知客户端从该时刻起在该 DSO Session 中使用新的 Session Timeout 值. 对此单方面声明, 不需要也不允许客户端发送 DSO 响应.

在 DSO Keepalive response message 中, 必须恰好存在一个 Keepalive TLV 实例, 且它只能作为 Response Primary TLV, 用作对客户端 DSO Keepalive request message 的回复. 禁止把 Keepalive TLV 作为 Response Additional TLV 添加到其他响应中. 如果服务器希望在不是响应客户端 DSO Keepalive request message 的情况下更新客户端的 Session Timeout 值, 它会如上所述发送自己的 DSO Keepalive unidirectional message.

并非每个 DSO Session 都必须使用 Keepalive TLV. 虽然许多 DSO 操作会与长期会话状态一起使用, 但不是所有 DSO 操作都需要长期会话状态; 在某些情况下, 非活动超时和保活间隔都使用默认 15 秒可能完全合适. 不过请注意, 对只实现本文定义的 DSO-TYPE 的客户端而言, DSO Keepalive request message 是客户端发起 DSO Session 的唯一方式.

7.1.1. 客户端处理收到的 Session Timeout 值

当客户端收到其发起的 DSO Keepalive request message 的响应, 或收到服务器发起的 DSO Keepalive unidirectional message 时, 它就收到了服务器指定的 Session Timeout 值. 服务器 Keepalive TLV 中包含的两个超时值, 相对于客户端先前为该 DSO Session 持有的对应 Session Timeout 值, 可以更高, 更低或相同.

对保活定时器而言, 收到值的处理很直接. 接收包含 DSO Keepalive TLV 的消息这一动作本身会重置保活定时器, 并更新该 DSO Session 的保活间隔. 新保活间隔表示, 如果该 DSO Session 要保持存活, 在其上发送或接收另一条消息之前最多允许经过多长时间.

对非活动超时而言, 收到值的处理稍微微妙一些, 不过非活动超时的含义仍如规范所述: 它仍表示 DSO Session 上无有用活动时允许的最长时间. 接收包含 Keepalive TLV 的消息这一动作本身不会重置非活动定时器. 自该 DSO Session 上最近一次有用活动以来已经经过的时间, 不受 DSO Keepalive 消息交换影响. 收到消息中 Keepalive TLV 的新非活动超时值会更新正在运行的非活动定时器关联的超时, 它会成为 DSO Session 无活动时新的最大允许时间.

  • 如果当前非活动定时器值小于新的非活动超时, 则 DSO Session 目前可以保持打开. 当非活动定时器值达到新的非活动超时时, 客户端必须按上述方式开始关闭 DSO Session.

  • 如果当前非活动定时器值等于新的非活动超时, 则该 DSO Session 已经精确非活动了服务器允许的时长, 客户端现在必须立即开始关闭该 DSO Session.

  • 如果当前非活动定时器值已经大于新的非活动超时, 则该 DSO Session 已经非活动超过服务器允许的时长, 客户端必须立即开始关闭该 DSO Session.

  • 如果当前非活动定时器值已经超过新的非活动超时两倍, 则客户端立即被视为失约 (该 DSO Session 立即有资格被服务器强制终止), 客户端必须立即开始关闭该 DSO Session. 但是, 如果服务器以这种方式突然降低非活动超时, 为给客户端时间在服务器强制中止连接前优雅关闭连接, 服务器应给予客户端额外宽限期, 其长度为 5 秒或新非活动超时的四分之一, 取较大者.

7.1.2. 与 edns-tcp-keepalive EDNS(0) Option 的关系

Keepalive TLV (DSO-TYPE=1) 中的非活动超时值与 edns-tcp-keepalive EDNS(0) Option [RFC7828] 意图相似. 支持 DSO 的客户端/服务器对在 DSO Session 建立后, 禁止在任何消息中使用 edns-tcp-keepalive EDNS(0) Option. 已发送 DSO 消息以建立会话的客户端, 从该时刻起禁止发送 edns-tcp-keepalive EDNS(0) Option. 一旦 DSO Session 建立, 如果客户端或服务器在 DSO Session 上收到包含 edns-tcp-keepalive EDNS(0) Option 的 DNS 消息, 这是致命错误, 收到该 edns-tcp-keepalive EDNS(0) Option 的一方必须立即强制中止连接.

7.2. Retry Delay TLV

Retry Delay TLV (DSO-TYPE=2) 可以在服务器到客户端的消息中作为 Primary TLV (单向) 使用, 也可以在任一方向作为 Response Additional TLV 使用. 以 Retry Delay TLV 作为 Primary TLV 的 DSO 消息不允许出现在 early data 中.

Retry Delay TLV 的 DSO-DATA 如下:

                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RETRY DELAY (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • RETRY DELAY: 一个时间值, 以网络字节序 (big endian) 的 32 位无符号整数表示, 单位为毫秒. 在该时间内, 发起方禁止重试此操作或重试连接到此服务器. RETRY DELAY 值的建议见第 6.6.1 节.

7.2.1. Retry Delay TLV 作为 Primary TLV

当 Retry Delay TLV 在 DSO unidirectional message 中作为 Primary TLV 使用时, 它由服务器发送给客户端. 服务器使用它指示客户端关闭 DSO Session 和底层连接, 并在指定时间间隔内不要重新连接.

在这种情况下, 它适用于整个 DSO Session, 客户端必须按第 6.6.1 节所述开始关闭 DSO Session. 消息头中的 RCODE 应指示终止的主要原因:

  • NOERROR 表示例行关闭或重启.

  • FORMERR 表示客户端 DSO 请求格式严重错误, 会话无法继续.

  • SERVFAIL 表示服务器因资源耗尽而过载, 需要卸载负载.

  • REFUSED 表示服务器已重新配置, 当前无法执行先前在该 DSO Session 上执行的一个或多个长期客户端操作.

  • NOTAUTH 表示服务器已重新配置, 当前由于不再对相关名称具有权威, 无法执行先前在该 DSO Session 上执行的一个或多个长期客户端操作. 例如, DNS Push Notification 服务器可以重新配置为不再接受一个或多个当前已订阅名称的 DNS Push Notification 请求.

本文只为 DSO Retry Delay 消息规定这些 RCODE 值. 发送 DSO Retry Delay 消息的服务器应使用其中一个值. 但未来情况可能使其他 RCODE 值适合用于 DSO Retry Delay 消息, 因而客户端必须准备接受带任意 RCODE 值的 DSO Retry Delay 消息.

在某些情况下, 当服务器向客户端发送 DSO Retry Delay unidirectional message 时, 服务器想结束会话可能有多个原因. 可能配置发生变化, 使得某些长期客户端操作由于策略原因 (REFUSED) 无法继续, 另一些长期客户端操作由于服务器不再对相关名称具有权威 (NOTAUTH) 而无法继续. 在这类情况下, 服务器可以使用任何适用的 RCODE 值, 或使用 RCODE=NOERROR (例行关闭或重启).

注意, DSO Retry Delay 消息中选择哪个 RCODE 值并不关键, 因为 RCODE 值通常只用于信息目的, 例如写入日志供之后人工分析断开连接的性质. 一般而言, 客户端不会根据 RCODE 值改变行为. 消息中的 RETRY DELAY 告诉客户端在尝试与该服务实例建立新连接前应等待多久.

如果客户端确实会根据 RCODE 值以某种方式改变行为, 它们应把未知 RCODE 值按 RCODE=NOERROR (例行关闭或重启) 处理.

服务器到客户端的 DSO Retry Delay 消息 (Primary TLV 为 Retry Delay 的 DSO 消息) 是 DSO unidirectional message; 发送消息中的 MESSAGE ID 必须设为零, 客户端禁止发送响应.

客户端禁止向服务器发送 DSO Retry Delay 消息. 如果服务器收到 Primary TLV 为 Retry Delay TLV 的 DSO 消息, 这是致命错误, 服务器必须立即强制中止连接.

7.2.2. Retry Delay TLV 作为 Response Additional TLV

对于产生非零 RCODE 值的 DSO request message, 响应方可以在响应后追加 Retry Delay TLV, 指示发起方不应再次尝试该操作的时间间隔.

指示的发起方不应重试的时间间隔只适用于失败操作, 不适用于整个 DSO Session.

客户端或服务器, 只要它在某个 DSO request message 中扮演响应方角色, 都可以把 Retry Delay TLV 追加到其发送的错误响应中.

7.3. Encryption Padding TLV

Encryption Padding TLV (DSO-TYPE=3) 只能作为 Additional TLV 或 Response Additional TLV 使用. 它只适用于 DSO Transport 层使用 TLS 等加密的情况.

Padding TLV 的 DSO-DATA 是可选的, 是包含未指定值的可变长度字段. DSO-LENGTH 为 0 实际上提供 4 字节填充 (最小量).

                                             1   1   1   1   1   1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| |
/ PADDING -- VARIABLE NUMBER OF BYTES /
/ /
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

如 EDNS(0) Padding Option [RFC7830] 所规定, PADDING 字节应设为 0x00. 也可以使用其他值, 例如担心填充后的消息在加密前可能被压缩的情况. 接收消息中的任意值 PADDING 字节都必须被接受.

Encryption Padding TLV 可以包含在 DSO request message, response 或两者中. 如 EDNS(0) Padding Option [RFC7830] 所规定, 如果收到的 DSO request message 带有 Encryption Padding TLV, 则 DSO response 也必须包含 Encryption Padding TLV.

本文有意不规定填充长度; 它取决于关于前面 TLV 中数据类型和长度的当前最佳实践 [RFC8467].