I've written a C# class to handle communications with a SNTP server, mainly
as a learning exercise. It is working perfectly except for one aspect which
has confused me. That is the reference identifier as it is used by secondary
servers and using version 4.
Here's what RFC 2030 says:
In the 'Introduction' section:
"In Version 4 secondary servers and clients, it [the reference identifier]
contains the low order 32 bits of the last transmit timestamp received from
the synchronization source."
In the 'Operating Modes and Addressing' section:
"In NTP Version 3, the reference identifier was often used to walk-back the
synchronization subnet to the root (primary server) for management purposes.
In NTP Version 4, this feature is not available, since the addresses are
longer than 32 bits. However, the intent in the protocol design was to
provide a way to detect and avoid loops. A peer could determine that a loop
was possible by comparing the contents of this field with the IPv4
destination address in the same packet. A NTP Version 4 server can
accomplish the same thing by comparing the contents of this field with the
low order 32 bits of the originate timestamp in the same packet. There is a
small possibility of false alarm in this scheme, but the false alarm rate
can be minimized by randomizing the low order unused bits of the transmit
timestamp."
Here's how far I've managed to get:
In the transmit timestamp that is sent to the server in the outgoing NTP
message, randomize the low order unused bits. That's just the final byte, so
I fill that final byte with a random value in the range 0..255.
As always the NTP/SNTP server copies the incoming transmit timestamp into
the originate timestamp section of the outgoing NTP message.
Now on receipt of the NTP message from the server, as some kind of error
checking that I don't really understand, the low order 32 bits of the
originate timestamp - its final 4 bytes - can be compared with the 4 bytes
of the reference identifier.
But what exactly as I supposed to do now? Should I convert both sets of 4
bytes to a double as if they were the low order bits of a timestamp (that's
what I did at first)? I don't think so, if I'm testing for equality then I
may as well skip that and compare the values of the 2 sequences of 4 bytes.
Either way I don't get equal values. But then I'm not sure I'm supposed to.
Any help explaining this to me would be greatly appreciated.
Many thanks and regards,
Matt
It's an opaque hash of the identity of the server's upstream server.
New code is not supposed to put any further meaning on it.
>
Thanks David. But...
Then why does RFC 2030 say the reference identifier "contains the low order
>>
>> It's an opaque hash of the identity of the server's upstream server.
>> New code is not supposed to put any further meaning on it.
>
> Thanks David. But...
>
> Then why does RFC 2030 say the reference identifier "contains the low
> order 32 bits of the last transmit timestamp received from the
> synchronization source."
Version 4 NTP is still in draft and I think real version 4 servers tend
to implement the version 3 behaviour, so RFC 2030 was somewhat premature
in specifying version 4 behaviour.
The problem with the version 3 behaviour is that it doesn't work well
with IPv6 addresses. I think the insignificant bits in the timestamps
are now randomised, so an ntpd implementation seeing a packet with a
reference identifier that exactly matches the low order bits of a
timestamp it recently sent can be reasonably sure that it is seeing a loop.
The current(?) draft for NTPV4 uses a hash, in the way I described:
<http://www.ietf.org/id/draft-ietf-ntp-ntpv4-proto-13.txt>, bottom of
page 23. It behaves the same as NTPV3 when using IPV4 addresses.
You also need to take note of the errata
<http://www.rfc-editor.org/errata_search.php?rfc=2030>, although this
question is not covered there.
One quick thing if you have a moment to clarify it for me. Was I right in
writing that in the transmit timestamp (in a NTP message being sent to the
server) that the "low order unused bits" get randomized. 2 questions about
that; is that just version 4 not 3, and are the "low order unused bits" of
that timestamp just the final byte?
Thanks again. Regards,
Matt
Yes, I know about that because of the incorrect round trip delay and local
clock offset calculations in RFC 2030. Thanks for thinking of it though. :)
Dave Mills and I have argued somewhat over this over the last few years.
The refid for a system is either the IPv4 address of the system or a
digest of the IPv6 address. See the function addr2refid() in
a_md5encypt.c in the reference implementation.
The controversy arises because a system may well have more than one IPv4
address and will certainly have more than one IPv6 address but it uses
the address it's using to send out the packet. The refid is essentially
used just for loop prevention but by having more than one address on
your system you are not really preventing loops. The system needs to
have just one refid to prevent loops so it really needs to use the same
id for all connections. Also a refid is just a number and has no meaning
beyond that. People have used the refid to find the stratum parent but
this is a dangerous assumption.
For SNTP you should take a look at the sntp implementation in the
reference implementation for ideas and to understand the implementation
requirements.
Danny
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
See Section 6 Data Types of the draft. The number of used bits is
defined as the precision p and any leftover bits in the timestamp should
be randomized. The precision is specified in the header of the NTP packet.