创建响应服务器系统时间的简单 NTP 服务器时出现问题
Problem creating a simple NTP server that responds with server's system time
我正在尝试构建一个非常简单的 NTP (v3) 服务器,该服务器从 LAN 上的 IP 摄像机接收 NTP 请求以实现时间同步。摄像头与互联网断开连接,因此想法是使用本地 PC 服务器作为摄像头的 NTP 服务器。
我尝试了两种不同的方法。
- 将简单的 UDP 转发写入已知的 NTP 服务器(例如 time.windows.com)。这很好用。
- 编写一个简单的 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 字段中。
我正在尝试构建一个非常简单的 NTP (v3) 服务器,该服务器从 LAN 上的 IP 摄像机接收 NTP 请求以实现时间同步。摄像头与互联网断开连接,因此想法是使用本地 PC 服务器作为摄像头的 NTP 服务器。
我尝试了两种不同的方法。
- 将简单的 UDP 转发写入已知的 NTP 服务器(例如 time.windows.com)。这很好用。
- 编写一个简单的 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 字段中。