6. Name Server Implementation (名称服务器实现)
本章讨论DNS名称服务器的实现注意事项。
6.1. Architecture (架构)
名称服务器的最佳结构将取决于主机操作系统, 以及名称服务器是否通过支持递归服务或与解析器共享其数据库来与解析器操作集成。
本节讨论与解析器共享数据库的名称服务器的实现注意事项, 但这些问题大多存在于任何名称服务器中。
6.1.1. Control (控制)
名称服务器必须采用多个并发活动, 无论它们是作为主机操作系统中的独立任务实现还是在单个名称服务器程序内部复用。
要求:
-
UDP非阻塞: 名称服务器在等待TCP数据进行刷新或查询活动时阻塞UDP请求的服务是完全不可接受的
-
并行处理: 名称服务器不应尝试在不并行处理此类请求的情况下提供递归服务, 尽管它可以选择:
- 序列化来自单个客户端的请求
- 将来自同一客户端的相同请求视为重复
-
非阻塞区域操作: 名称服务器不应在以下情况下大幅延迟请求:
- 从主文件重新加载区域
- 将新刷新的区域合并到其数据库中
6.1.2. Database (数据库)
虽然名称服务器实现可以自由使用它们选择的任何内部数据结构, 但建议的结构由三个主要部分组成:
建议的数据库结构
1. 目录数据结构 (Catalog Data Structure):
- 列出此服务器可用的区域
- 包含指向区域数据结构的"指针"
- 主要目的: 为到达的标准查询查找最近的祖先区域 (如果有)
2. 区域数据结构 (Zone Data Structures):
- 名称服务器持有的每个区域的独立数据结构
- 包含区域的权威数据
3. 缓存数据结构 (Cache Data Structure):
- 用于缓存数据的数据结构
- 可能对不同的类有单独的缓存
实现注意事项
树结构: 所有这些数据结构都可以以相同的树结构格式实现, 不同部分的节点上链接不同的数据:
- 在目录中: 数据是指向区域的指针
- 在区域和缓存数据结构中: 数据将是RR
查询处理要求: 在设计树框架时, 设计者应该认识到:
- 查询处理将需要使用不区分大小写的标签比较遍历树
- 在真实数据中, 少数节点具有非常高的分支因子 (100-1000或更多)
- 绝大多数具有非常低的分支因子 (0-1)
不区分大小写的存储解决方案
解决大小写问题的一种方法是将每个节点的标签分两部分存储:
- 标签的标准化大小写表示, 其中所有ASCII字符都是单一大小写
- 一个位掩码, 表示哪些字符实际上是不同的大小写
分支因子优化
分支因子多样性可以通过以下方式处理:
- 对节点使用简单的链表, 直到分支因子超过某个阈值
- 超过阈值后转换到哈希结构
重要: 用于存储树段的哈希结构必须确保哈希函数和过程保留DNS的大小写约定。
独立结构的好处
对数据库的不同部分使用独立结构的动机来自几个因素:
1. 目录稳定性:
- 目录结构可以是几乎静态的结构
- 只有当系统管理员更改服务器支持的区域时才需要更改
- 还可以存储用于控制刷新活动的参数
2. 原子区域替换:
- 区域的单独数据结构允许通过更改目录中的指针来简单地替换区域
- 区域刷新操作可以构建一个新结构, 完成后通过简单的指针替换将其拼接到数据库中
- 关键: 当区域刷新时, 查询不应同时使用旧数据和新数据
3. 数据优先级:
- 通过适当的搜索过程, 区域中的权威数据将始终"隐藏", 从而优先于缓存数据
4. 错误隔离:
- 导致区域重叠的区域定义中的错误可能导致对查询的错误响应
- 问题确定被简化
- 一个"坏"区域的内容不能破坏另一个区域
5. 缓存管理:
- 由于缓存是最频繁更新的, 因此在系统重启期间最容易损坏
- 它也可能充满过期的RR数据
- 在任何情况下, 它都可以轻松丢弃而不会干扰区域数据
崩溃恢复
数据库设计的一个主要方面是选择一个允许名称服务器处理名称服务器主机崩溃的结构。
名称服务器应在系统崩溃中保存的状态信息:
- 目录结构 (包括每个区域的刷新状态)
- 区域数据本身
6.1.3. Time (时间)
RR的TTL数据和刷新活动的时间数据都依赖于以秒为单位的32位计时器。
时间表示
概念模型:
- 在数据库内部, 缓存数据的刷新计时器和TTL在概念上"倒计时"
- 区域中的数据保持恒定的TTL
推荐的实现策略:
以两种方式存储时间: 作为相对增量和作为绝对时间。
一种方法是使用:
- 正32位数用于一种类型
- 负数用于另一种类型
用法:
- 区域中的RR使用相对时间
- 刷新计时器和缓存数据使用绝对时间
- 绝对数相对于某个已知原点获取, 并在放入对查询的响应中时转换为相对值
- 当绝对TTL在转换为相对值后为负时, 则数据已过期并应被忽略
6.2. Standard Query Processing (标准查询处理)
标准查询处理的主要算法在RFC-1034中提出。
特殊情况和规则
QCLASS= 处理*:
- 当处理具有
QCLASS=*或匹配多个类的其他QCLASS的查询时 - 除非服务器可以保证响应覆盖所有类, 否则响应永远不应该是权威的
重复RR处理:
- 在组成响应时, 要插入到附加部分但在答案或权威部分中重复的RR可以从附加部分中省略
截断策略:
- 当响应太长以至于需要截断时
- 截断应从响应末尾开始并在数据报中向前工作
- 因此, 如果权威部分有任何数据, 则保证答案部分是唯一的
SOA MINIMUM 字段:
- SOA中的MINIMUM值应用于为从区域分发的数据的TTL设置下限
- 此下限函数应在将数据复制到响应中时完成
- 这将允许未来的动态更新协议更改SOA MINIMUM字段而没有歧义语义
6.3. Zone Refresh and Reload Processing (区域刷新和重载处理)
错误处理
尽管服务器尽了最大努力, 它可能无法:
- 由于语法错误等原因从主文件加载区域数据
- 在其过期参数内刷新区域
在这种情况下: 名称服务器应该回答查询, 就好像它不应该拥有该区域一样。
区域传输一致性
如果主服务器通过AXFR发送区域, 并且在传输期间创建了新版本:
- 主服务器应该继续发送旧版本 (如果可能)
- 在任何情况下, 它都不应该发送一个版本的一部分和另一个版本的一部分
- 如果无法完成, 主服务器应该重置正在进行区域传输的连接
6.4. Inverse Queries (反向查询) (可选)
反向查询是DNS的可选部分。
支持要求
- 名称服务器不需要支持任何形式的反向查询
- 如果名称服务器接收到它不支持的反向查询, 它将返回一个错误响应, 并在标头中设置"Not Implemented"错误
- 虽然反向查询支持是可选的, 但所有名称服务器必须至少能够返回错误响应
6.4.1. The Contents of Inverse Queries and Responses (反向查询和响应的内容)
反向查询反转标准查询操作执行的映射:
- 标准查询将域名映射到资源
- 反向查询将资源映射到域名
示例:
- 标准查询可能将域名绑定到主机地址
- 相应的反向查询将主机地址绑定到域名
格式
反向查询采用以下形式:
- 消息答案部分中的单个RR
- 空问题部分
- 查询RR的所有者名称及其TTL不重要
响应
响应在问题部分中携带问题, 这些问题标识拥有查询RR 的名称服务器知道的所有名称。
重要限制:
- 由于没有名称服务器知道所有域名空间, 因此响应永远不能假定为完整
- 因此, 反向查询主要用于数据库管理和调试活动
- 反向查询不是将主机地址映射到主机名的可接受方法; 请改用IN-ADDR.ARPA域
不区分大小写的比较
在可能的情况下, 名称服务器应为反向查询提供不区分大小写的比较:
- 询问
Venera.isi.edu的MX RR的反向查询应该得到与询问VENERA.ISI.EDU的查询相同的响应 - HINFO RR
IBM-PC UNIX的反向查询应该产生与IBM-pc unix的反向查询相同的结果
注意: 这不能保证, 因为名称服务器可能拥有包含字符串的RR, 但名称服务器不知道数据是字符。
处理结果
当名称服务器处理反向查询时, 它返回:
- 指定资源的零个、一个或多个域名作为问题部分中的QNAME
- 指示名称服务器不支持指定资源类型的反向映射的错误代码
响应修改
当对反向查询的响应包含一个或多个QNAME时:
- 答案部分中定义反向查询的RR的所有者名称和TTL被修改为完全匹配在第一个QNAME处找到的RR
缓存限制
反向查询中返回的RR不能使用与用于对标准查询的回复相同的机制进行缓存。
原因: 名称可能具有相同类型的多个RR, 并且只会出现一个。例如, 对多宿主主机的单个地址的反向查询可能会造成只有一个地址存在的印象。
6.4.2. Inverse Query and Response Example (反向查询和响应示例)
用于检索对应于Internet地址 10.1.0.52 的域名的反向查询的整体结构:
查询:
+-----------------------------------------+
| Header | OPCODE=IQUERY, ID=997 |
+-----------------------------------------+
| Question | <empty> |
+-----------------------------------------+
| Answer | <anyname> A IN 10.1.0.52 |
+-----------------------------------------+
| Authority | <empty> |
+-----------------------------------------+
|Additional | <empty> |
+-----------------------------------------+
说明:
- 此查询要求一个问题, 其答案是Internet样式地址10.1.0.52
- 由于所有者名称未知, 因此可以使用任何域名作为占位符 (并被忽略)
- 通常使用单个零八位字节 (表示根), 因为它最小化了消息的长度
- RR的TTL不重要
响应:
+-----------------------------------------+
| Header | OPCODE=RESPONSE, ID=997 |
+-----------------------------------------+
| Question | QTYPE=A, QCLASS=IN, |
| | QNAME=VENERA.ISI.EDU |
+-----------------------------------------+
| Answer | VENERA.ISI.EDU A IN |
| | 10.1.0.52 |
+-----------------------------------------+
| Authority | <empty> |
+-----------------------------------------+
|Additional | <empty> |
+-----------------------------------------+
注意: 对反向查询的响应中的QTYPE与反向查询答案部分中的TYPE字段相同。对反向查询的响应可能包含多个问题, 当反向不唯一时。如果响应中的问题部分不为空, 则答案部分中的RR将被修改为对应于第一个QNAME处的RR的精确副本。
6.4.3. Inverse Query Processing (反向查询处理)
支持反向查询的名称服务器可以通过对其数据库的详尽搜索来支持这些操作, 但随着数据库大小的增加, 这变得不切实际。
替代方法: 根据搜索键反转数据库。
大型服务器的建议
对于支持多个区域和大量数据的名称服务器, 推荐的方法是:
- 为每个区域单独反转
- 当在刷新期间更改特定区域时, 只需要重做其反转
注意: 对这种类型的反转的传输支持可能包含在域系统的未来版本中, 但在此版本中不受支持。
6.5. Completion Queries and Responses (完成查询和响应)
RFC-882和RFC-883中描述的可选完成服务已被删除。
重新设计的服务可能在未来可用。