创建响应服务器系统时间的简单 NTP 服务器时出现问题

Problem creating a simple NTP server that responds with server's system time

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

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

  1. 将简单的 UDP 转发写入已知的 NTP 服务器(例如 time.windows.com)。这很好用。
  2. 编写一个简单的 UDP 服务器,在端口 123 上侦听传入的 NTP 请求,这只是 returns 服务器的系统时间。这对于简单的、要求不高的 NTP 客户端(例如物理网络路由器)也很有效,但对于本地海康威视相机来说它总是失败。

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

相机发送此请求:

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 请求的尾随字节以及如何 return 正确的 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 的值是客户端当前的时间概念。 (在这种情况下,它有点偏离,据我所知,时间戳大约在 1951 年左右。)

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

鉴于客户端的时钟偏差很长,可能需要几轮 request/response 才能同步。所以不要指望它的时钟会立即跳转以匹配服务器的时钟。 (它可能会那样做,但我不会指望它。)

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