Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Small footprint clock synchronization without NTP

I'm looking for a simple clock synchronization protocol that would be easy to implement with small footprint and that would work also in the absence of internet connection, so that it could be used e.g. within closed laboratory networks. To be clear, I'm not looking for something that can be used just to order events (like vector clocks), but something that would enable processes on different nodes to synchronize their actions based on local clocks. As far as I understand, this would require a solution that can take clock drift into account. Presence of TCP/IP or similar relatively low-latency stream connections can be assumed.

like image 984
Antti Huima Avatar asked Apr 12 '11 23:04

Antti Huima


People also ask

Is NTP a TCP or UDP?

NTP time servers work within the TCP/IP suite and rely on User Datagram Protocol (UDP) port 123. NTP servers are normally dedicated NTP devices that use a single time reference to which they can synchronize a network. This time reference is most often a Coordinated Universal Time (UTC) source.

Why NTP server is required?

Network Time Protocol (NTP) is a protocol that allows the synchronization of system clocks (from desktops to servers). Having synchronized clocks is not only convenient but required for many distributed applications. Therefore the firewall policy must allow the NTP service if the time comes from an external server.

What protocol is used to synchronize clocks?

Network Time Protocol (NTP) is an internet protocol used to synchronize with computer clock time sources in a network. It belongs to and is one of the oldest parts of the TCP/IP suite. The term NTP applies to both the protocol and the client-server programs that run on computers.

Why does NTP use UDP?

NTP is based on the user datagram protocol (UDP), which enables connectionless data transport. The UDP port number for this is 123. NTP provides the basic protocol mechanisms necessary to synchronize the time of different systems to an accuracy of one nanosecond.


Video Answer


1 Answers

Disclaimer: I'm not an NTP expert by any means. Just a hobbyist having fun on the weekend.

I realize you said you didn't want an NTP implementation, because of the perceived complexity and because an Internet NTP server may not be available in your environment.

However, an simplified NTP look-up may be easy to implement, and if you have a local NTP server you can achieve good synchronization.

Here's how:

Review RFC 5905

You'll see NTP v4 packets look something like:

  • LI (2 bits)
  • VN (3 bits) - Use '100' (4)
  • Mode (3 bits)
  • Stratum (8 bits)
  • Poll (8 bits)
  • Precision (8 bits)
  • Root Delay (32 bits)
  • Root Dispersion (32 bits)
  • Reference Id (32 bits)
  • Reference Timestamp (64 bits)
  • Origin Timestamp (64 bits)
  • Receive Timestamp (64 bits)
  • Transmit Timestamp (64 bits)
  • Extension Field 1 (variable)
  • Extension Field 2 (variable)
  • ...
  • Key Identifier
  • Digest (128 bits)

The digest is not required, so forming a valid client request is very easy. Following the guidance in the RFC, use LI = '00', VN = '100' (decimal 4), Mode = '011' (decimal 3).

Using C# to illustrate:

byte[] ntpData = new byte[48]
Array.Clear(ntpData, 0, ntpData.Length);
ntpData[0] = 0x23;  // LI = 00, VN = 100, Mode = 011

Open a socket to your target server and send it over.

int ntpPort = 123;
IPEndPoint target = new IPEndPoint(Dns.GetHostEntry(serverDnsName).AddressList[0], ntpPort);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.Connect(target);
s.Send(ntpData);

In the response, the current time will be in the Transmit Timestamp (bytes [40 - 48]). Timestamps are 64-bit unsigned fixed-point numbers. The integer part is the first 32 bits, the fractional part is the last 32 bits. It represents the number of seconds since 0h on Jan-1-1900.

s.Receive(ntpData);
s.Close();

ulong intPart = 0;
ulong fractPart = 0;

for (int i = 0; i < 4; i++)
    intPart = (intPart << 8) | ntpData[40 + i];

for (int i = 4; i < 8; i++)
    fractPart = (fractPart << 8) | ntpData[40 + i];

To update the clock with (roughly) second granularity, use: # of seconds since 0h Jan-1-1900 = intPart + (fractPart / 2^32). (I say roughly because network latency isn't accounted for, and we're rounding down here)

ulong seconds = intPart + (fractPart / 4294967296);

TimeSpan ts = TimeSpan.FromTicks((long)seconds * TimeSpan.TicksPerSecond);

DateTime now = new DateTime(1900, 1, 1);
now = DateTime.SpecifyKind(now, DateTimeKind.Utc);
now += ts;

"now" is now a DateTime with the current time, in UTC.

While this might not answer your question, hopefully it makes NTP a little less opaque. =)

like image 127
Tails Avatar answered Sep 30 '22 14:09

Tails