Skip to main content

8. On-Wire Protocol (线上协议)

NTP线上协议的核心是在服务器、对等体和客户端之间交换时间值的核心机制 (core mechanism). 它天生抵抗丢失或重复的数据包. 数据完整性由IP和UDP校验和提供. 不提供也不需要流量控制或重传设施. 协议使用时间戳 (timestamps), 这些时间戳要么从数据包头中提取, 要么在数据包到达或离开时从系统时钟获取. 时间戳是精密数据, 在链路级重传的情况下应该重新获取, 并在传输时为计算MAC的时间进行校正.

NTP消息使用两种不同的通信模式, 一对一和一对多 (one-to-one and one-to-many), 通常称为单播和广播 (unicast and broadcast). 就本文档而言, 术语广播被解释为任何可用的一对多机制. 对于IPv4, 这等同于IPv4广播或IPv4组播 (multicast). 对于IPv6, 这等同于IPv6组播. 为此, IANA已分配IPv4组播地址224.0.1.1和以:101结尾的IPv6组播地址, 前缀由作用域规则确定. 除了这些已分配的组播地址外, 还可以使用任何其他未分配的组播地址.

线上协议使用编号为t1到t4的四个时间戳和三个状态变量org、rec和xmt, 如图15所示. 此图显示了最一般的情况, 其中两个对等体A和B各自独立测量相对于另一个的偏移和延迟. 为了说明的目的, 数据包时间戳以小写显示, 而状态变量以大写显示. 状态变量在数据包到达或离开时从数据包时间戳复制.

          t2            t3           t6            t7
+---------+ +---------+ +---------+ +---------+
| 0 | | t1 | | t3 | | t5 |
+---------+ +---------+ +---------+ +---------+
| 0 | | t2 | | t4 | | t6 | Packet
+---------+ +---------+ +---------+ +---------+ Timestamps
| t1 | |t3=clock | | t5 | |t7=clock |
+---------+ +---------+ +---------+ +---------+
|t2=clock | |t6=clock |
+---------+ +---------+
Peer B
+---------+ +---------+ +---------+ +---------+
org | T1 | | T1 | | t5<>T1? | | T5 |
+---------+ +---------+ +---------+ +---------+ State
rec | T2 | | T2 | | T6 | | T6 | Variables
+---------+ +---------+ +---------+ +---------+
xmt | 0 | | T3 | | t3=T3? | | T7 |
+---------+ +---------+ +---------+ +---------+

t2 t3 t6 t7
---------------------------------------------------------
/\ \ /\ \
/ \ / \
/ \ / \
/ \/ / \/
---------------------------------------------------------
t1 t4 t5 t8

t1 t4 t5 t8
+---------+ +---------+ +---------+ +---------+
| 0 | | t1 | | t3 | | t5 |
+---------+ +---------+ +---------+ +---------+
| 0 | | t2 | | t4 | | t6 | Packet
+---------+ +---------+ +---------+ +---------+ Timestamps
|t1=clock | | t3 | |t5=clock | | t7 |
+---------+ +---------+ +---------+ +---------+
|t4=clock | |t8=clock |
+---------+ +---------+
Peer A
+---------+ +---------+ +---------+ +---------+
org | 0 | | t3<>0? | | T3 | | t7<>T3? |
+---------+ +---------+ +---------+ +---------+ State
rec | 0 | | T4 | | T4 | | T8 | Variables
+---------+ +---------+ +---------+ +---------+
xmt | T1 | | t1=T1? | | T5 | | t5=T5? |
+---------+ +---------+ +---------+ +---------+

图15: 线上协议

在图中, A传输的第一个数据包仅包含起源时间戳 (origin timestamp) t1, 然后将其复制到T1. B在t2接收数据包, 并将t1复制到T1, 将接收时间戳t2复制到T2. 此时或稍后在t3时, B向A发送包含t1、t2和传输时间戳t3的数据包. 所有三个时间戳都复制到相应的状态变量. A在t4接收包含三个时间戳t1、t2和t3以及目的时间戳t4的数据包. 这四个时间戳用于计算B相对于A的偏移和延迟, 如下所述.

在更新xmt和org状态变量之前, 执行两个完整性检查 (sanity checks) 以防止重复、伪造或重放数据包. 在上述交换中, 如果数据包中的传输时间戳t3与org状态变量T3匹配, 则数据包是重复或重放. 如果数据包中的起源时间戳t1与xmt状态变量T1不匹配, 则数据包是伪造的. 在这两种情况下, 状态变量都会更新, 然后丢弃数据包. 为了防止重放最后传输的数据包, 在成功的伪造检查后, xmt状态变量立即设置为零.

四个最近的时间戳T1到T4用于计算B相对于A的偏移 (offset)

theta = T(B) - T(A) = 1/2 * [(T2-T1) + (T3-T4)]

和往返延迟 (round-trip delay)

delta = T(ABA) = (T4-T1) - (T3-T2).

请注意, 括号内的数量是从64位无符号时间戳计算的, 结果是带有63个有效位加符号的有符号值. 这些值可以表示从过去68年到未来68年的日期. 但是, 偏移和延迟是作为这些值的和与差计算的, 它们包含62个有效位和两个符号位, 因此它们可以表示从过去34年到未来34年的明确值. 换句话说, 在启动服务之前, 客户端的时间必须设置在服务器的34年内. 这是64位整数算术的基本限制.

在可用浮点双精度算术 (floating double arithmetic) 的实现中, 一阶差分可以转换为浮点双精度, 并在该算术中计算二阶和与差. 由于二阶项相对于时间戳幅度通常非常小, 因此不会损失精度, 但明确范围从34年恢复到68年.

在某些情况下, 客户端的初始频率偏移相对较大而实际传播时间较小, 延迟计算可能变为负值. 例如, 如果频率差为100 ppm且间隔T4-T1为64秒, 则表观延迟为-6.4毫秒. 由于负值在后续计算中会产生误导, delta的值应夹紧不小于s.rho, 其中s.rho是第11.1节中描述的系统精度, 以秒表示.

上述讨论假设最一般的情况, 其中两个对称对等体独立测量它们之间的偏移和延迟. 在无状态服务器 (stateless server) 的情况下, 协议可以简化. 无状态服务器将T3和T4从客户端数据包复制到服务器数据包的T1和T2, 并在将其发送到客户端之前附加传输时间戳T3. 填写其余协议字段的其他详细信息在第9节和后续章节以及附录中给出.

请注意, 如所述的线上协议抵抗服务器响应数据包的重放. 但是, 它不抵抗客户端请求数据包的重放, 这将导致具有新T2和T3值的服务器回复数据包, 并导致错误的偏移和延迟. 通过在计算偏移和延迟后将xmt状态变量设置为零, 可以避免此漏洞.