跳到主要内容

3. Server Behavior (服务器行为)

3. 服务器行为 (Server Behavior)​

服务器收到 UPDATE 请求后, 如果不识别 UPDATE opcode, 或者识别但尚未实现, 将向请求者发出 NOTIMP 信号. 否则, 处理按如下方式继续.

3.1 处理 ZONE Section (Process Zone Section)​

3.1.1. 检查 Zone Section, 确认其中恰好有一个 RR, 且该 RR 的 ZTYPE 为 SOA, 否则向请求者发出 FORMERR 信号. 接着检查 ZNAME 和 ZCLASS, 确认如此命名的 zone 是此服务器的权威 zone 之一, 否则向请求者发出 NOTAUTH 信号. 如果服务器是 zone slave, 请求将被朝 primary master 转发.

3.1.2 - ZONE Section 处理伪代码 (Pseudocode For Zone Section Processing)​

if (zcount != 1 || ztype != SOA)
return (FORMERR)
if (zone_type(zname, zclass) == SLAVE)
return forward()
if (zone_type(zname, zclass) == MASTER)
return update()
return (NOTAUTH)

第 3.2 到 3.8 节描述 primary master 的行为, 而第 6 节描述 forwarder 的行为.

3.2 处理 PREREQ Section (Process Prerequisite Section)​

接下来检查 Prerequisite Section, 确认所有 prerequisite 都由 zone 的当前状态满足. 使用第 1.2 节表达的定义, 如果任何 RR 的 NAME 不在 Zone Section 指定的 zone 内, 则向请求者发出 NOTZONE 信号.

3.2.1. 对于此 section 中 CLASS 为 ANY 的 RR, 测试 TTL 和 RDLENGTH 是否均为零 (0), 否则向请求者发出 FORMERR 信号. 如果 TYPE 为 ANY, 测试 zone 中是否至少有一个 RR 的 NAME 与 Prerequisite RR 的 NAME 相同, 否则向请求者发出 NXDOMAIN 信号. 如果 TYPE 不是 ANY, 测试 zone 中是否至少有一个 RR 的 NAME 和 TYPE 与 Prerequisite RR 的 NAME 和 TYPE 相同, 否则向请求者发出 NXRRSET 信号.

3.2.2. 对于此 section 中 CLASS 为 NONE 的 RR, 测试 TTL 和 RDLENGTH 是否均为零 (0), 否则向请求者发出 FORMERR 信号. 如果 TYPE 为 ANY, 测试 zone 中是否不存在 NAME 与 Prerequisite RR 的 NAME 相同的 RR, 否则向请求者发出 YXDOMAIN 信号. 如果 TYPE 不是 ANY, 测试 zone 中是否不存在 NAME 和 TYPE 与 Prerequisite RR 的 NAME 和 TYPE 相同的 RR, 否则向请求者发出 YXRRSET 信号.

3.2.3. 对于此 section 中 CLASS 与 ZCLASS 相同的 RR, 测试 TTL 是否为零 (0), 否则向请求者发出 FORMERR 信号. 然后, 为每个唯一的 <NAME,TYPE> 构建一个 RRset, 并将每个所得 RRset 与 zone 中的 RRset 做集合相等性比较 (成员相同, 不多也不少). 如果任何 Prerequisite RRset 未被某个 zone RRset 完全且精确匹配, 则向请求者发出 NXRRSET 信号. 如果此 section 中任何 RR 的 CLASS 不是 ZCLASS, NONE 或 ANY, 则向请求者发出 FORMERR 信号.

3.2.4 - PREREQ Section 中使用的元值表 (Table Of Metavalues Used In Prerequisite Section)​

CLASSTYPERDATA含义
ANYANYempty名称正在使用
ANYrrsetemptyRRset 存在 (与值无关)
NONEANYempty名称未在使用
NONErrsetemptyRRset 不存在
zonerrsetrrRRset 存在 (与值相关)

3.2.5 - PREREQ Section 处理伪代码 (Pseudocode for Prerequisite Section Processing)​

for rr in prerequisites
if (rr.ttl != 0)
return (FORMERR)
if (zone_of(rr.name) != ZNAME)
return (NOTZONE);
if (rr.class == ANY)
if (rr.rdlength != 0)
return (FORMERR)
if (rr.type == ANY)
if (!zone_name<rr.name>)
return (NXDOMAIN)
else
if (!zone_rrset<rr.name, rr.type>)
return (NXRRSET)
if (rr.class == NONE)
if (rr.rdlength != 0)
return (FORMERR)
if (rr.type == ANY)
if (zone_name<rr.name>)
return (YXDOMAIN)
else
if (zone_rrset<rr.name, rr.type>)
return (YXRRSET)
if (rr.class == zclass)
temp<rr.name, rr.type> += rr
else
return (FORMERR)

for rrset in temp
if (zone_rrset<rrset.name, rrset.type> != rrset)
return (NXRRSET)

3.3 检查请求者权限 (Check Requestor's Permissions)​

3.3.1. 接下来, 可以用实现相关方式, 或用后续 Secure DNS Update 协议指定的机制, 测试请求者是否有权更新 Update Section 中命名的 RR. 如果请求者无权执行这些更新, 服务器可以在其操作日志中写入一条警告消息, 并且可以向请求者发出 REFUSED 信号, 或忽略该权限问题并继续更新.

3.3.2. 虽然确切处理由实现定义, 但如果要执行这些验证活动, 就应在服务器处理流程的这一点执行. 因为如果在某个更新已部分应用后才遇到 REFUSED 条件, 则必须先撤销该部分更新并将 zone 恢复到原始状态, 然后才能答复请求者.

3.3.3 - 权限检查伪代码 (Pseudocode for Permission Checking)​

if (security policy exists)
if (this update is not permitted)
if (local option)
log a message about permission problem
if (local option)
return (REFUSED)

3.4 处理 UPDATE Section (Process Update Section)​

接下来按如下方式处理 Update Section.

3.4.1 - 预扫描 (Prescan)​

Update Section 被解析为 RR, 并检查每个 RR 的 CLASS 是否为 ANY, NONE 或与 Zone Class 相同, 否则向请求者发出 FORMERR 信号. 使用第 1.2 节中的定义, 每个 RR 的 NAME 必须位于 Zone Section 指定的 zone 内, 否则向请求者发出 NOTZONE 信号.

3.4.1.2. 对于 CLASS 不是 ANY 的 RR, 检查 TYPE. 如果它是 ANY, AXFR, MAILA, MAILB, 任何其他 QUERY metatype, 或任何未识别的类型, 则向请求者发出 FORMERR 信号. 对于 CLASS 为 ANY 或 NONE 的 RR, 检查 TTL 是否为零 (0), 否则向请求者发出 FORMERR 信号. 对于任何 CLASS 为 ANY 的 RR, 检查 RDLENGTH 以确保其为零 (0) (即 RDATA 字段为空), 并确保 TYPE 不是 AXFR, MAILA, MAILB, 除 ANY 之外的任何其他 QUERY metatype, 或任何未识别的类型, 否则向请求者发出 FORMERR 信号.

3.4.1.3 - UPDATE Section 预扫描伪代码 (Pseudocode For Update Section Prescan)​

[rr] for rr in updates
if (zone_of(rr.name) != ZNAME)
return (NOTZONE);
if (rr.class == zclass)
if (rr.type & ANY|AXFR|MAILA|MAILB)
return (FORMERR)
elsif (rr.class == ANY)
if (rr.ttl != 0 || rr.rdlength != 0
|| rr.type & AXFR|MAILA|MAILB)
return (FORMERR)
elsif (rr.class == NONE)
if (rr.ttl != 0 || rr.type & ANY|AXFR|MAILA|MAILB)
return (FORMERR)
else
return (FORMERR)

3.4.2 - 更新 (Update)​

Update Section 被解析为 RR, 这些 RR 按顺序处理.

3.4.2.1. 如果在处理此 section 期间发生任何系统故障 (例如内存不足条件, 或持久存储中的硬件错误), 则向请求者发出 SERVFAIL 信号, 并撤销此事务期间已应用到 zone 的所有更新.

3.4.2.2. 任何 CLASS 与 ZCLASS 相同的 Update RR 都被添加到 zone. 如果存在重复的 RDATA (这对 SOA RR 总是成立, 对 WKS RR 则在 ADDRESS 和 PROTOCOL 字段均匹配时成立), Zone RR 将由 Update RR 替换. 如果 TYPE 为 SOA 且不存在 Zone SOA RR, 或者新的 SOA.SERIAL 低于 (按照 [RFC1982]) 或等于当前 Zone SOA RR 的 SOA.SERIAL, 则忽略该 Update RR. 对于 CNAME Update RR 与非 CNAME Zone RRset 并存的情况, 或反过来的情况, 忽略该 CNAME Update RR, 否则用该 CNAME Update RR 替换 CNAME Zone RR.

3.4.2.3. 对于任何 CLASS 为 ANY 且 TYPE 为 ANY 的 Update RR, 删除所有 NAME 相同的 Zone RR, 除非 NAME 与 ZNAME 相同, 在这种情况下只删除 TYPE 不是 SOA 或 NS 的 RR. 对于任何 CLASS 为 ANY 且 TYPE 不是 ANY 的 Update RR, 删除所有 NAME 和 TYPE 相同的 Zone RR, 除非 NAME 与 ZNAME 相同, 在这种情况下既不删除 SOA RR 也不删除 NS RR.

3.4.2.4. 对于任何 CLASS 为 NONE 的 Update RR, 删除任何 NAME, TYPE, RDATA 和 RDLENGTH 均与该 Update RR 相等的 Zone RR, 除非 NAME 与 ZNAME 相同, 且 TYPE 为 SOA, 或 TYPE 为 NS 且匹配的 Zone RR 是该 RRset 中剩余的唯一 NS. 在这些情况下, 忽略该 Update RR.

3.4.2.5. 向请求者发出 NOERROR 信号.

3.4.2.6 - UPDATE Section 中使用的元值表 (Table Of Metavalues Used In Update Section)​

CLASSTYPERDATA含义
ANYANYempty从一个名称删除所有 RRset
ANYrrsetempty删除一个 RRset
NONErrsetrr从一个 RRset 删除一个 RR
zonerrsetrr添加到一个 RRset

3.4.2.7 - UPDATE Section 处理伪代码 (Pseudocode For Update Section Processing)​

[rr] for rr in updates
if (rr.class == zclass)
if (rr.type == CNAME)
if (zone_rrset<rr.name, ~CNAME>)
next [rr]
elsif (zone_rrset<rr.name, CNAME>)
next [rr]
if (rr.type == SOA)
if (!zone_rrset<rr.name, SOA> ||
zone_rr<rr.name, SOA>.serial > rr.soa.serial)
zone_rr<rr.name, SOA> = rr
elsif (rr.type == WKS)
if (zone_rrset<rr.name, WKS, rr.proto, rr.address>)
zone_rr<rr.name, WKS, rr.proto, rr.address> = rr
else
zone_rrset<rr.name, WKS> += rr
else
zone_rrset<rr.name, rr.type> += rr
elsif (rr.class == ANY)
if (rr.type == ANY)
if (rr.name == zname)
zone_rrset<rr.name, ~(SOA|NS)> = Nil
else
zone_rrset<rr.name, *> = Nil
elsif (rr.name == zname &&
(rr.type == SOA || rr.type == NS))
next [rr]
else
zone_rrset<rr.name, rr.type> = Nil
elsif (rr.class == NONE)
if (rr.type == SOA)
next [rr]
if (rr.type == NS && zone_rrset<rr.name, NS> == rr)
next [rr]
zone_rr<rr.name, rr.type, rr.data> = Nil
return (NOERROR)

3.5 处理 ADDITIONAL Section (Process Additional Data Section)​

本文档不描述 Additional Data 处理. 服务器应静默忽略 Additional Data Section 中与 UPDATE 处理相关的 RR. 但是, 如果 Additional Data Section 包含服务器为了使更新有用而需要的 RR (例如新 NS RR 目标的 glue A RR), 则应处理此 section.

3.6 将变更追加到事务日志 (Append Changes to Transaction Log)​

如果 zone 有事务日志, 对 zone 所做的变更 MAY 被追加到其中, 或许采用一条最小 UPDATE 消息的形式. 注意, 只有当 SOA RR 是 UPDATE 消息的一部分, 或服务器策略规定 SOA SERIAL 自动递增时, SOA SERIAL 才会被更新.

3.7 向请求者发送响应 (Send Response to Requestor)​

此时, 必须组装响应消息并发送回请求者. 头部不包含特殊选项, 且 Zone Section (Query 中的 Question Section) 从请求的相应 section 复制. PRCOUNT, UPCOUNT 和 ADCOUNT 均设置为零 (0). 响应代码为 NOERROR, 除非发生某些处理错误或权限错误, 在这种情况下发送适当的 RCODE. 应在响应的 Answer Section 中发送 zone 当前 SOA RR 的副本 (即使发生错误也如此), 以便那些使用 UPDATE 改变 SOA 参数且需要关于实际状态反馈的请求者受益.

3.8 通知 slave (Signal Slaves)​

primary master 应使用 DNS NOTIFY 等机制 (参见 [RFC1996]) 通知任何已知 slave 该 zone 已更新. 注意, 即使 SOA SERIAL 因策略或 UPDATE 内容而未递增, 也应发送此 notify.