首页 > 解决方案 > 创建响应服务器系统时间的简单 NTP 服务器时出现问题

问题描述

我正在尝试构建一个非常简单的 NTP (v3) 服务器,用于接收来自 LAN 上 IP 摄像机的 NTP 请求,以实现时间同步。摄像机与 Internet 断开连接,因此想法是使用本地 PC 服务器作为摄像机的 NTP 服务器。

我尝试了两种不同的方法。

  1. 编写简单的 UDP 转发到已知的 NTP 服务器(例如 time.windows.com)。这运作良好。
  2. 编写一个简单的 UDP 服务器,在端口 123 上侦听传入的 NTP 请求,它只返回服务器的系统时间。这对于简单的要求不高的 NTP 客户端(例如物理网络路由器)也很有效,但对于本地 HIKVISION 摄像头来说总是失败。

方法:接收一个48字节的缓冲区。确保偏移量 0 处的字节为 0x1B。将偏移量 0 处的字节转换为 0x1C 并将当前 UTC 时间写入最后 8 个字节作为 NTP 时间戳。这适用于大多数 NTP 客户端,但不适用于海康威视。

相机发送此请求:

1B-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
00-00-00-00-00-00-00-00-61-8C-DE-CA-C3-73-89-DC

最后 8 个字节非零。如果我尝试修改我的 UDP 转发解决方案 [1],以便在转发之前将最后 8 个字节清零,则相机会报告错误。所以事实证明这些位很重要,并且可能具有一些密码意义。

我正在研究 RFC 以试图理解这一点,但我找不到解释。我能找到的任何示例代码都完全忽略了这一点,并走上了简单的路线。

所以问题是......如何解释 NTP 请求的尾随字节以及如何返回正确的 NTP 响应?欢迎提供一些示例代码或资源指针。

标签: ntp

解决方案


有关NTP 数据包格式的说明,请参阅从https://www.ietf.org/rfc/rfc1305.pdf第 50 页开始的附录 A。最后 8 个字节应该携带服务器的响应时间戳——这正是您在构建最小响应数据包时将时间戳放入这些字节的原因。

但是,基于此客户端将值放入最后 8 个字节的事实,它看起来想要使用 SNTP(简单 NTP)协议第 5 节中描述的机制,每个https://www.ietf.org/ rfc/rfc2030.txt SNTP 使用与 NTP 相同的数据包格式,但使用字段的方式略有不同。在 SNTP 中,客户端放入字节 40 到 47 的值是客户端当前的时间概念。(在这种情况下,它偏离了一点,AFAICT 的时间戳大约是 1951 年左右。)

如果这是该客户端尝试执行的操作,那么它希望服务器将这 8 个字节复制到字节 24-31(原始时间戳字段),然后将服务器的当前时间写入字节 32-39(接收时间戳)写入字节 40-47(传输时间戳),并将其作为响应发送。当然,还要继续将响应中的第一个字节改为0x1C,以表明这个数据包来自一个服务器。您还应该将字节 1 中的 Stratum 值设置为合理的非零值,例如 3 或 4。

鉴于客户端的时钟已经关闭了很长时间,它可能需要几轮请求/响应才能使其同步。所以不要指望它的时钟会立即跳到匹配服务器的时钟。(它可能会这样做,但我不会指望它。)

我认为你不需要通过特别对待这个客户来使你的逻辑复杂化。您可能可以将完全相同的逻辑应用于来自客户端的数据包,这些数据包将零放入最后 8 个字节。这只是意味着当您构建对这些客户端的响应时,您将在 Originate Timestamp 字段中复制零。


推荐阅读