4. 基本消息交换 (Basic Message Exchange)
4.1. "application/dns-message" Content-Format
本文档为 Internet 媒体类型 "application/dns-message" 定义一个 CoAP Content-Format ID, 其助记值为 553, 该值基于 DNS 的端口分配. 该媒体类型按照 [RFC8484] 第 6 节定义, 即一个以 DNS 线上格式 [STD13] 编码的单个 DNS 消息. DoC 客户端和 DoC 服务器都必须能够解析 "application/dns-message" Content-Format 中的内容. 本文档仅为 DNS over CoAP 消息指定 OPCODE 0 (Query). 未来文档可以为额外 OPCODE 提供考虑事项, 或扩展其规范, 例如描述哪些 OPCODE 是否需要使用其他 CoAP 代码. 除非另一个错误具有优先级, DoC 服务器在响应带有未实现 OPCODE 的查询时, 会使用 RCODE = 4, NotImp [STD13] (另见第 4.3.3 节).
4.2. CoAP 请求中的 DNS 查询 (DNS Queries in CoAP Requests)
DoC 客户端将单个 DNS 查询编码到一个或多个使用 CoAP FETCH [RFC8132] 请求方法的 CoAP 请求消息中. 请求应当 (SHOULD) 包含 Accept 选项, 以指示响应中可解析的内容类型.
由于 CoAP 在消息层提供可靠性 (例如通过 Confirmable 消息), 因此不需要 [STD13] 中定义的 DNS 协议重传机制.
4.2.1. 请求格式 (Request Format)
发送 CoAP 请求时, DoC 客户端必须在 CoAP 请求的正文中包含 DNS 查询. 如 [RFC8132] 第 2.3.1 节所规定, 正文的内容类型必须使用 Content-Format 选项指示. 本文档规定使用 Content-Format "application/dns-message" (详情见第 4.1 节).
4.2.2. CoAP 缓存支持 (Support of CoAP Caching)
DoC 客户端应当 (SHOULD) 将 DNS 头部的 ID 字段设置为 0, 以便 CoAP 缓存 (例如路径上的 CoAP 代理) 能够使用缓存条目响应相同 DNS 查询. 这确保在多个针对相同 DNS 数据且由 CoAP 请求承载的 DNS 查询发出时, CoAP Cache-Key (见 [RFC8132] 第 2 节) 不会改变. 除了失去这些缓存收益之外, 不将其设置为 0 并无害处, 例如查询从其他位置接收时就是如此. 在任何情况下, DoC 服务器都必须在对该查询的响应中复制查询中的 ID.
4.2.3. 示例 (Example)
以下示例说明如何使用 CoAP 消息基于 URI "coaps://[2001:db8::1]/" 解析 "example.org. IN AAAA". CoAP 正文以 "application/dns-message" Content-Format 编码.
FETCH coaps://[2001:db8::1]/
Content-Format: 553 (application/dns-message)
Accept: 553 (application/dns-message)
Payload (binary):
00 00 01 00 00 01 00 00 00 00 00 00 07 65 78 61
6d 70 6c 65 03 6f 72 67 00 00 1c 00 01
Payload (human-readable):
;; ->>Header<<- opcode: QUERY, status: NOERROR, id: 0
;; flags: rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.org. IN AAAA
4.3. CoAP 响应中的 DNS 响应 (DNS Responses in CoAP Responses)
每个 DNS 查询-响应对都会映射到一个 CoAP 请求-响应操作. DNS 响应在 CoAP 响应的正文中提供, 即也可以使用块式传输 [RFC7959] 传输它们. 当被请求时, DoC 服务器必须能够生成 "application/dns-message" Content-Format 的响应 (详情见第 4.1 节). 请求中使用 Accept 选项是可选的 (OPTIONAL). 但是, 所有 DoC 客户端都必须能够解析 "application/dns-message" 响应 (另见第 4.1 节). 除 "application/dns-message" 之外的任何响应 Content-Format 都必须由 DoC 服务器使用 Content-Format 选项指示.
4.3.1. 响应代码以及 DNS 和 CoAP 错误处理 (Response Codes and Handling DNS and CoAP Errors)
DNS 响应通过 DNS 头部中的 RCODE 指示成功或失败 (见 [STD13]). 推荐 (RECOMMENDED) 承载可解析 DNS 响应的 CoAP 响应使用 2.05 (Content) 响应代码.
使用非成功响应代码的 CoAP 响应禁止包含 DNS 响应, 并且只能用于 CoAP 层错误, 或用于请求不满足 DoC 协议要求的情况.
与上游 DNS 服务器的通信错误 (例如超时) 必须通过在成功 CoAP 响应中包含带有适当 RCODE 的 DNS 响应来指示, 即使用 2.xx 响应代码. 当 CoAP 层发生错误时, 例如使用了意外的请求方法或请求中使用了不受支持的 Content-Format, DoC 服务器应当 (SHOULD) 以适当的 CoAP 错误响应.
除非另有禁止, DoC 客户端可以尝试重复一次非成功交换. DoC 客户端也可以决定使用不同 URI 重复一次非成功交换, 例如当响应指示不支持的 Content-Format 时.
4.3.2. CoAP 缓存支持 (Support of CoAP Caching)
出于可靠性和节能措施, 内容解耦 (例如代理上的路径缓存) 在 CoAP 中比在 HTTP 中发挥更大作用. 同样, CoAP 可以使用缓存验证来刷新陈旧缓存条目, 以减少大型响应消息的数量. 对于缓存验证, CoAP 实现通常对消息内容进行哈希以生成 ETag (见 [RFC7252] 第 5.10.6 节). 因此, DoH 中提出的用于保证 DNS 响应具有相同缓存键的方法 ([RFC8484] 第 5.1 节) 并不足够, 需要更新, 使响应中的 TTL 更常在不受查询时间影响的情况下保持一致.
DoC 服务器必须确保 CoAP 响应的 Max-Age 值与 DNS 响应中任何 TTL 的总和小于或等于从上游 DNS 服务器收到的对应 TTL. 当未提供 Max-Age 选项时, 这也包括默认 Max-Age 值 60 秒 (见 [RFC7252] 第 5.10.5 节). 然后, DoC 客户端必须在接收时将承载该 DNS 响应的 CoAP 响应的 Max-Age 值加到 DNS 响应中的所有 TTL 上, 并使用这些计算出的 TTL 作为相关记录的 TTL.
为满足 DoC 的要求, 推荐 (RECOMMENDED) DoC 服务器采用以下算法: 将响应的 Max-Age 选项设置为 DNS 响应中的最小 TTL, 并从该 DNS 响应的所有 TTL 中减去该值. 这可防止过期记录意外地从中间 CoAP 缓存提供. 此外, 如果用于缓存验证的 ETag 基于响应内容, 这种做法允许该 ETag 不发生变化. 即使 TTL 值由上游 DNS 缓存更新, 这一点也仍然成立. 如果假定每个 DNS 响应只有一个记录集, 则该算法的简化形式是直接将响应中的所有 TTL 设置为 0, 并在 DoC 客户端将 TTL 设置为 Max-Age 选项的值.
如果更短的缓存周期是合理的, 例如消息的 RCODE 指示只应缓存极短时间的错误, 则 Max-Age 选项的值应当 (SHOULD) 相应设置. 该值可以是 0, 但如果 DoC 服务器知道错误会持续存在, 根据预计的错误持续时间, 也可以设想使用更大的值. 对于由于任何原因不携带任何带 TTL 记录的 DNS 响应, 同样适用.
4.3.3. 示例 (Examples)
以下示例说明对查询 "example.org. IN AAAA record" 的响应, 其中递归已开启. 成功响应承载一个答案记录, 包括地址 2001:db8:1:0:1:2:3:4 和 TTL 79689.
成功响应:
2.05 Content
Content-Format: 553 (application/dns-message)
Max-Age: 58719
Payload (human-readable):
;; ->>Header<<- opcode: QUERY, status: NOERROR, id: 0
;; flags: qr rd ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;example.org. IN AAAA
;; ANSWER SECTION:
;example.org. 79689 IN AAAA 2001:db8:1:0:1:2:3:4
当 DNS 响应中指出 DNS 错误 - 在此情况下是 "does.not.exist" 的 NxDomain (RCODE = 3) - 时, CoAP 响应仍然指示成功.
2.05 Content
Content-Format: 553 (application/dns-message)
Payload (human-readable):
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 0
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;does.not.exist. IN AAAA
如第 4.1 节所述, 如果 DoC 服务器不支持某个 OPCODE, 则使用 NotImp (RCODE = 4). 在此示例中, 它对 "example.org" 的 DNS Update (OPCODE = 5) 返回错误.
2.05 Content
Content-Format: 553 (application/dns-message)
Payload (human-readable):
;; ->>Header<<- opcode: UPDATE, status: NOTIMP, id: 0
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; QUERY SECTION:
;example.org. IN AAAA
当 CoAP 层发生错误时, DoC 服务器会以适当的 CoAP 错误响应. 例如, 如果请求中的 Content-Format 选项未设置为 "application/dns-message", 且服务器也不支持该 Content-Format, 则响应 4.15 (Unsupported Content-Format).
4.15 Unsupported Content-Format
[no payload]