+* Changes from Dave Mills: in/out-bound data rates, leapsecond cleanup,
+ driftfile write cleanup, packet buffer length checks, documentation updates.
* More assertion checks and malloc()->emalloc(), courtesy of Calysto.
* [Bug 864] Place ntpd service in maintenance mode if using SMF on Solaris
* [Bug 862] includefile nesting; preserve phonelist on reconfig.
<dd>This option is used only with broadcast server and manycast client modes. It specifies the time-to-live <i><tt>ttl</tt></i> to use on broadcast server and multicast server and the maximum <i><tt>ttl</tt></i> for the expanding ring search with manycast client packets. Selection of the proper value, which defaults to 127, is something of a black art and should be coordinated with the network administrator.
<dt><tt>version <i>version</i></tt>
<dd>Specifies the version number to be used for outgoing NTP packets. Versions 1-4 are the choices, with version 4 the default. This option is valid only with the <tt>server,</tt> <tt>peer</tt> and <tt>broadcast</tt> commands.
+ <dt><tt>dynamic</tt>
+ <dd>Allows a server/peer to be configured even if it is not reachable at configuration time. It is assumed that at some point in the future the network environment changes so that this server/peer can be reached. This option is useful to configure servers/peers on mobile systems with intermittent network access (e.g. wlan clients).
</dl>
<h4 id="aux">Auxilliary Commands</h4>
<dl>
<p>Cycle crossings relative to the corrected slice level determine the width of each pulse and its value - zero, one or position identifier (PI). The data encode ten characters (20 BCD digits) which determine the second, minute, hour and day of the year and with some IRIG generators the year and synchronization condition. The comb filter exponentially averages the corresponding samples of successive baud intervals in order to reliably identify the reference carrier cycle.</p>
<p>A type-II phase-lock loop (PLL) performs additional integration and interpolation to accurately determine the zero crossing of that cycle, which determines the reference timestamp. A pulse-width discriminator demodulates the data pulses, which are then encoded as the BCD digits of the timecode. The timecode and reference timestamp are updated once each second with IRIG-B (ten seconds with IRIG-E) and local clock offset samples saved for later processing. At poll intervals of 64 s, the saved samples are processed by a median filter and used to update the system clock.</p>
<h4>Monitor Data</h4>
-
-
- The timecode format used for debugging and data recording includes data helpful in diagnosing problems with the IRIG signal and codec connections. With debugging enabled (<tt>-d</tt> on the <tt>ntpd</tt> command line), the driver produces one line for each timecode in the following format:
- <p><tt>00 1 98 23 19:26:52 721 143 0.694 20 0.3 66.5 3094572411.00027</tt></p>
- <p>The first field containes the error flags in hex, where the hex bits are interpreted as below. This is followed by the IRIG status indicator, year of century, day of year and time of day. Note that the time of day is for the previous minute, not the current time. The status indicator and year are not produced by some IRIG devices and appear as zeros. Following these fields are the carrier amplitude (0-6000), codec gain (0-255), modulation index (0-1), time constant (4-20), carrier phase error (0±0.5) and carrier frequency error (PPM). The last field is the on-time timestamp in NTP format.</p>
+ The timecode format used for debugging and data recording includes data helpful in diagnosing problems with the IRIG signal and codec connections. The driver produces one line for each timecode in the following format:
+ <p><tt>00 00 98 23 19:26:52 2782 143 0.694 10 0.3 66.5 3094572411.00027</tt></p>
+ <p>If clockstats is enabled, the most recent line is written to the clockstats file every 64 s. If verbose recording is enabled (fudge flag 4) each line is written as generated.</p>
+ <p>The first field containes the error flags in hex, where the hex bits are interpreted as below. This is followed by the year of century, day of year and time of day. Note that the time of day is for the previous minute, not the current time. The status indicator and year are not produced by some IRIG devices and appear as zeros. Following these fields are the carrier amplitude (0-3000), codec gain (0-255), modulation index (0-1), time constant (4-10), carrier phase error (0±0.5) and carrier frequency error (PPM). The last field is the on-time timestamp in NTP format.</p>
<p>The error flags are defined as follows in hex:</p>
<dl>
<dt><tt>x01</tt>
<h3>The Network Time Protocol (NTP) Distribution</h3>
<img src="pic/barnstable.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/%7emills/pictures.html"><i>P.T. Bridgeport Bear</i>; from <i>Pogo</i>, Walt Kelly</a>
<p>Pleased to meet you.</p>
- <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">18:39</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="246">Thursday, July 28, 2005</csobj></p>
+ <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">03:09</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="223">Friday, June 22, 2007</csobj></p>
<br clear="left">
<h4>Related Links</h4>
<script type="text/javascript" language="javascript" src="scripts/links7.txt"></script>
<li class="inline"><a href="tickadj.html"><tt>tickadj</tt> - set time-related kernel variables</a>
<li class="inline"><a href="ntptime.html"><tt>ntptime</tt> - read kernel time variables</a>
<li class="inline"><a href="keygen.html"><tt>ntp-keygen</tt> - generate public and private keys</a>
- <li class="inline"><a href="ntpdsim.html"><tt>ntpdsim</tt> - Network Time Protocol (NTP) simulator</a>
+ <li class="inline"><a href="ntpdsim_new.html"><tt>ntpdsim</tt> - Network Time Protocol (NTP) simulator</a>
</ul>
<h4 id="docs">Supporting Documentation</h4>
<ul>
<h3>Miscellaneous Options</h3>
<img src="pic/boom3.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/~mills/pictures.html">from <i>Pogo</i>, Walt Kelly</a>
<p>We have three, now looking for more.</p>
- <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">18:50</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="271">Monday, January 09, 2006</csobj></p>
+ <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">16:01</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="268">Wednesday, July 18, 2007</csobj></p>
<br clear="left">
<h4>Related Links</h4>
<script type="text/javascript" language="javascript" src="scripts/links7.txt"></script>
<dd>The broadcast and multicast modes require a special calibration to determine the network delay between the local and remote servers. Ordinarily, this is done automatically by the initial protocol exchanges between the client and server. In some cases, the calibration procedure may fail due to network or server access controls, for example. This command specifies the default delay to be used under these circumstances. Typically (for Ethernet), a number between 0.003 and 0.007 seconds is appropriate. The default when this command is not used is 0.004 seconds.
<dt><tt>calldelay <i>delay</i></tt>
<dd>This option controls the delay in seconds between the first and second packets sent in burst or iburst mode to allow additional time for a modem or ISDN call to complete.
- <dt><tt>driftfile <i>driftfile</i> [<i>
- minutes </i> [<i> tolerance </i>] ]</tt>
+ <dt><tt>driftfile <i>driftfile</i> { <i>tolerance</i> ]</tt>
<dd>This command specifies the complete path and name of the file used to record the frequency of the local clock oscillator. This is the same operation as the <tt>-f</tt> command linke option. If the file exists, it is read at startup in order to set the initial frequency and then updated once per hour with the current frequency computed by the daemon. If the file name is specified, but the file itself does not exist, the starts with an initial frequency of zero and creates the file when writing it for the first time. If this command is not given, the daemon will always start with an initial frequency of zero.
<p>The file format consists of a single line containing a single floating point number, which records the frequency offset measured in parts-per-million (PPM). The file is updated by first writing the current drift value into a temporary file and then renaming this file to replace the old version. This implies that <tt>ntpd</tt> must have write permission for the directory the drift file is located in, and that file system links, symbolic or otherwise, should be avoided.</p>
-<p>The two optional values determine how often the file is written, and
-are particuarly useful when is it desirable to avoid spinning up the
-disk unnecessarily. The parameter <tt>minutes</tt> is how often the file will be written. If omitted or less
-than 1, the interval will be 60 minutes (one hour). The parameter <tt>tolerance</tt> is the
-threshold to skip writing the new value. If the new value is within
-<tt>tolerance</tt> percent of the last value written (compared out to 3
-decimal places), the write will be
-skipped. The default is 0.0, which means that the write will occur
-unless the current and previous values are the same. A tolerance of
-.1 equates roughly to a difference in the 2nd decimal place.</p>
+<p>The parameter <tt>tolerance</tt> is the wander threshold to skip writing the new value. If the value of wander computed from recent frequency changes is greater than this threshold the file will be updated once per hour. If below the threshold, the file will not be written.</p>
<dt><tt>enable [ auth | bclient | calibrate | kernel | monitor | ntp | pps | stats]</tt><br>
<tt>disable [ auth | bclient | calibrate | kernel | monitor | ntp | pps | stats ]</tt>
<dd>Provides a way to enable or disable various system options. Flags not mentioned are unaffected. Note that all of these flags can be controlled remotely using the <a href="ntpdc.html"><tt>ntpdc</tt></a> utility program.
<h3><tt>ntpd</tt> - Network Time Protocol (NTP) daemon</h3>
<img src="pic/alice47.gif" alt="gif" align="left"><a href="http://www.eecis.udel.edu/~mills/pictures.html">from <i>Alice's Adventures in Wonderland</i>, Lewis Carroll</a>
<p>The mushroom knows all the command line options.</p>
- <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">18:44</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="246">Thursday, July 28, 2005</csobj></p>
+ <p>Last update: <csobj format="ShortTime" h="25" locale="00000409" region="0" t="DateTime" w="61">19:27</csobj> UTC <csobj format="LongDate" h="25" locale="00000409" region="0" t="DateTime" w="229">Sunday, July 01, 2007</csobj></p>
<br clear="left">
<h4>Related Links</h4>
<script type="text/javascript" language="javascript" src="scripts/links7.txt"></script>
<li class="inline"><a href="#freq">Frequency Discipline</a><br>
<li class="inline"><a href="#modes">Operating Modes</a><br>
<li class="inline"><a href="#poll">Poll Interval Control</a><br>
- <li class="inline"><a href="#poll">Poll Interval Control</a><br>
- <li class="inline"><a href="#notes">Notes</a><br>
+ <li class="inline"><a href="#leap">Leap Second Processing</a><br>
+ <li class="inline"><a href="#notes">Additional Features</a><br>
+
+
+
+
<li class="inline"><a href="#cmd">Command Line Options</a><br>
<li class="inline"><a href="#cfg">The Configuration File</a><br>
<li class="inline"><a href="#opt">Configuration Options</a><br>
<h4 id="synop">Synopsis</h4>
<tt>ntpd [ -46aAbdDgLmnNqx ] [ -c <i>conffile</i> ] [ -f <i>driftfile</i> ] [ -i <i>jaildir</i> ] [ -k <i>keyfile</i> ] [ -l <i>logfile</i> ] [ -p <i>pidfile</i> ] [ -P <i>priority</i> ] [ -r <i>broadcastdelay</i> ] [ -s <i>statsdir</i> ] [ -t <i>key</i> ] [ -u <i>user</i>[:<i>group</i>] ] [ -U <i>interface_update_interval</i> ] [ -v <i>variable</i> ] [ -V <i>variable</i> ]</tt>
<h4 id="descr">Description</h4>
- <p>The <tt>ntpd</tt> program is an operating system daemon which sets and maintains the system time of day in synchronism with Internet standard time servers. It is a complete implementation of the Network Time Protocol (NTP) version 4, but also retains compatibility with version 3, as defined by RFC-1305, and version 1 and 2, as defined by RFC-1059 and RFC-1119, respectively. <tt>ntpd</tt> does most computations in 64-bit floating point arithmetic and does relatively clumsy 64-bit fixed point operations only when necessary to preserve the ultimate precision, about 232 picoseconds. While the ultimate precision is not achievable with ordinary workstations and networks of today, it may be required with future gigahertz CPU clocks and gigabit LANs.</p>
+ <p>The <tt>ntpd</tt> program is an operating system daemon which sets and maintains the system time of day in synchronism with Internet standard time servers. It is a complete implementation of the Network Time Protocol (NTP) version 4, but also retains compatibility with version 3, as defined by RFC-1305, and version 1 and 2, as defined by RFC-1059 and RFC-1119, respectively. <tt>ntpd</tt> does most computations in 64-bit floating-point arithmetic and does relatively clumsy 64-bit fixed-point operations only when necessary to preserve the ultimate precision, about 232 picoseconds. While the ultimate precision is not achievable with ordinary workstations and networks of today, it may be required with future gigahertz CPU clocks and gigabit LANs.</p>
<h4 id="op">How NTP Operates</h4>
- <p>The <tt>ntpd</tt> program operates by exchanging messages with one or more configured servers at designated poll intervals. When started, whether for the first or subsequent times, the program requires several exchanges from the majority of these servers so the signal processing and mitigation algorithms can accumulate and groom the data and set the clock. In order to protect the network from bursts, the initial poll interval for each server is delayed an interval randomized over a few seconds. At the default initial poll interval of 64s, several minutes can elapse before the clock is set. The initial delay to set the clock can be reduced using the <tt>iburst</tt> keyword with the <tt>server</tt> configuration command, as described on the <a href="confopt.html">Configuration Options</a> page.</p>
- <p>Most operating systems and hardware of today incorporate a time-of-year (TOY) chip to maintain the time during periods when the power is off. When the machine is booted, the chip is used to initialize the operating system time. After the machine has synchronized to a NTP server, the operating system corrects the chip from time to time. In case there is no TOY chip or for some reason its time is more than 1000s from the server time, <tt>ntpd</tt> assumes something must be terribly wrong and the only reliable action is for the operator to intervene and set the clock by hand. This causes <tt>ntpd</tt> to exit with a panic message to the system log. The <tt>-g</tt> option overrides this check and the clock will be set to the server time regardless of the chip time. However, and to protect against broken hardware, such as when the CMOS battery fails or the clock counter becomes defective, once the clock has been set, an error greater than 1000s will cause <tt>ntpd</tt> to exit anyway.</p>
- <p>Under ordinary conditions, <tt>ntpd</tt> adjusts the clock in small steps so that the timescale is effectively continuous and without discontinuities. Under conditions of extreme network congestion, the roundtrip delay jitter can exceed three seconds and the synchronization distance, which is equal to one-half the roundtrip delay plus error budget terms, can become very large. The <tt>ntpd</tt> algorithms discard sample offsets exceeding 128 ms, unless the interval during which no sample offset is less than 128 ms exceeds 900s. The first sample after that, no matter what the offset, steps the clock to the indicated time. In practice this reduces the false alarm rate where the clock is stepped in error to a vanishingly low incidence.</p>
- <p>As the result of this behavior, once the clock has been set, it very rarely strays more than 128 ms, even under extreme cases of network path congestion and jitter. Sometimes, in particular when <tt>ntpd</tt> is first started, the error might exceed 128 ms. This may on occasion cause the clock to be set backwards if the local clock time is more than 128 s in the future relative to the server. In some applications, this behavior may be unacceptable. If the <tt>-x</tt> option is included on the command line, the clock will never be stepped and only slew corrections will be used.</p>
+ <p>The <tt>ntpd</tt> program operates by exchanging messages with one or more configured servers at designated poll intervals. When started, whether for the first or subsequent times, the program requires several exchanges from the majority of these servers so the signal processing and mitigation algorithms can accumulate and groom the data to set the clock. In order to protect the network from bunching, the initial poll interval for each server is delayed an interval randomized over a few seconds. At the default initial poll interval of 64 s, several minutes can elapse before the clock is set. The initial delay to set the clock can be reduced using the <tt>iburst</tt> keyword with the <tt>server</tt> configuration command, as described on the <a href="confopt.html">Server Options</a> page.</p>
+ <p>Most operating systems and hardware of today incorporate a time-of-year (TOY) chip to maintain the time during periods when the power is off. When the machine is booted, the chip is used to initialize the operating system time. After the machine has synchronized to a NTP server, the operating system corrects the chip from time to time. In case there is no TOY chip or for some reason its time is more than 1000 s, called the <i>panic threshold</i>, from the server time, <tt>ntpd</tt> assumes something must be terribly wrong and the only reliable action is for the operator to intervene and set the clock by hand. This causes <tt>ntpd</tt> to exit with a panic message to the system log. The <tt>-g</tt> option overrides this check and the clock will be set to the server time regardless of the chip time. However, and to protect against broken hardware, such as when the CMOS battery fails or the clock counter becomes defective, once the clock has been set, an error greater than 1000 s will cause <tt>ntpd</tt> to exit anyway.</p>
+ <p>Under ordinary conditions, <tt>ntpd</tt> adjusts the clock in small steps so that the timescale is effectively continuous and never runs backwards. Under conditions of extreme network congestion, the roundtrip delay jitter can exceed three seconds and the synchronization distance, which is equal to one-half the roundtrip delay plus error budget terms, can become very large. The <tt>ntpd</tt> algorithms discard offsets exceeding 128 ms, called the <i>step threshold</i>, unless the interval during which no sample offset is less than 128 ms exceeds 900 s, called the <i>stepout threshold</i>. The first sample after that, no matter what the offset, steps the clock to the indicated time. In practice this reduces the false alarm rate where the clock is stepped in error to a vanishingly low incidence.</p>
+ <p>As the result of this behavior, once the clock has been set, it very rarely strays more than 128 ms, even under extreme cases of network congestion and jitter. Sometimes, in particular when <tt>ntpd</tt> is first started, the error might exceed 128 ms. This may on occasion cause the clock to be set backwards if the local clock time is more than 128 s in the future relative to the server. In some applications, this behavior may be unacceptable. If the <tt>-x</tt> option is included on the command line, the clock will always be slewed unless the offset exceeds 600 s (10 minutes), in which case it will be stepped.</p>
<p>The issues should be carefully explored before deciding to use the <tt>-x</tt> option. The maximum slew rate possible is limited to 500 parts-per-million (PPM) as a consequence of the correctness principles on which the NTP protocol and algorithm design are based. As a result, the local clock can take a long time to converge to an acceptable offset, about 2,000 s for each second the clock is outside the acceptable range. During this interval the local clock will not be consistent with any other network clock and the system cannot be used for distributed applications that require correctly synchronized network time.</p>
- <p>In spite of the above precautions, sometimes when large frequency errors are present the resulting time offsets stray outside the 128-ms range and an eventual step or slew time correction is required. If following such a correction the frequency error is so large that the first sample is outside the acceptable range, <tt>ntpd</tt> enters the same state as when the <tt>ntp.drift</tt> file is not present. The intent of this behavior is to quickly correct the frequency and restore operation to the normal tracking mode. In the most extreme cases (<tt>time.ien.it</tt> comes to mind), there may be occasional step/slew corrections and subsequent frequency corrections. It helps in these cases to use the <tt>burst</tt> keyword when configuring the server.</p>
<h4 id="freq">Frequency Discipline</h4>
- <p>The <tt>ntpd</tt> behavior at startup depends on whether the frequency file, usually <tt>ntp.drift</tt>, exists. This file contains the latest estimate of clock frequency error. When the <tt>ntpd</tt> is started and the file does not exist, the <tt>ntpd</tt> enters a special mode designed to quickly adapt to the particular system clock oscillator time and frequency error. This takes approximately 15 minutes, after which the time and frequency are set to nominal values and the <tt>ntpd</tt> enters normal mode, where the time and frequency are continuously tracked relative to the server. After one hour the frequency file is created and the current frequency offset written to it. When the <tt>ntpd</tt> is started and the file does exist, the <tt>ntpd</tt> frequency is initialized from the file and enters normal mode immediately. After that the current frequency offset is written to the file at hourly intervals.</p>
+ <p>The <tt>ntpd</tt> behavior at startup depends on whether the frequency file, usually called <tt>ntp.drift</tt>, exists. This file contains the latest estimate of clock frequency offset. When <tt>ntpd</tt> is started and the file does not exist, <tt>ntpd</tt> enters a special mode designed to directly measure the particular clock frequency offset. This takes 15 minutes, after which the time and frequency are set to nominal values and <tt>ntpd</tt> enters normal mode, where the time and frequency are continuously adjusted.</p>
+ <p>After one hour the frequency file is created and the current frequency offset written to it. When <tt>ntpd</tt> is started and the file does exist, <tt>ntpd</tt> initializes the frequency from the file and then enters normal mode immediately. In either case the current frequency offset is written to the file at hourly intervals.</p>
<h4 id="modes">Operating Modes</h4>
- <p><tt>ntpd</tt> can operate in any of several modes, including symmetric active/passive, client/server broadcast/multicast and manycast, as described in the <a href="assoc.html">Association Management</a> page. It normally operates continuously while monitoring for small changes in frequency and trimming the clock for the ultimate precision. However, it can operate in a one-time mode where the time is set from an external server and frequency is set from a previously recorded frequency file. A broadcast/multicast or manycast client can discover remote servers, compute server-client propagation delay correction factors and configure itself automatically. This makes it possible to deploy a fleet of workstations without specifying configuration details specific to the local environment.</p>
- <p>By default, <tt>ntpd</tt> runs in continuous mode where each of possibly several external servers is polled at intervals determined by an intricate state machine. The state machine measures the incidental roundtrip delay jitter and oscillator frequency wander and determines the best poll interval using a heuristic algorithm. Ordinarily, and in most operating environments, the state machine will start with 64s intervals and eventually increase in steps to 1024s. A small amount of random variation is introduced in order to avoid bunching at the servers. In addition, should a server become unreachable for some time, the poll interval is increased in steps to 1024s in order to reduce network overhead.</p>
- <p>In some cases it may not be practical for <tt>ntpd</tt> to run continuously. A common workaround has been to run the <tt>ntpdate</tt> program from a <tt>cron</tt> job at designated times. However, this program does not have the crafted signal processing, error checking and mitigation algorithms of <tt>ntpd</tt>. The <tt>-q</tt> option is intended for this purpose. Setting this option will cause <tt>ntpd</tt> to exit just after setting the clock for the first time. The procedure for initially setting the clock is the same as in continuous mode; most applications will probably want to specify the <tt>iburst</tt> keyword with the <tt>server</tt> configuration command. With this keyword a volley of messages are exchanged to groom the data and the clock is set in about 10 s. If nothing is heard after a couple of minutes, the daemon times out and exits. After a suitable period of mourning, the <tt>ntpdate</tt> program may be retired.</p>
- <p>When kernel support is available to discipline the clock frequency, which is the case for stock Solaris, Tru64, Linux and FreeBSD, a useful feature is available to discipline the clock frequency. First, <tt>ntpd</tt> is run in continuous mode with selected servers in order to measure and record the intrinsic clock frequency offset in the frequency file. It may take some hours for the frequency and offset to settle down. Then the <tt>ntpd</tt> is stopped and run in one-time mode as required. At each startup, the frequency is read from the file and initializes the kernel frequency.</p>
+ <p><tt>ntpd</tt> can operate in any of several modes, including symmetric active/passive, client/server broadcast/multicast and manycast, as described in the <a href="assoc.html">Association Management</a> page. It normally operates continuously while adjusting the system clock time and frequency with respect to external sources. In some cases it may not be practical to run <tt>ntpd</tt> continuously. A common workaround has been to run the <tt>ntpdate</tt> program from a <tt>cron</tt> job at designated times. However, this program does not have the crafted signal processing, error checking and mitigation algorithms of <tt>ntpd</tt>. If the <tt>-q</tt> option is specified on the command line, <tt>ntpd</tt> will operate as in continous mode, but exit just after setting the clock for the first time. Most applications will probably want to specify the <tt>iburst</tt> keyword with the <tt>server</tt> configuration command. With this keyword a volley of messages is exchanged to groom the data and set the clock in about 10 s. If nothing is heard after a couple of minutes, the daemon times out and exits.</p>
+ <p>A broadcast/multicast or manycast client can discover remote servers, compute server-client propagation delay correction factors and configure itself automatically. This makes it possible to deploy a fleet of workstations without specifying configuration details specific to the local environment. An alternative to broadcast/multicast is manycast mode, in which a client broadcasts a request and one or more servers in range offer service. Further details are on the <a href="manyopt.html">Automatic NTP Configuration Options</a> page.</p>
+ <p>By default, <tt>ntpd</tt> runs in continuous mode where each of possibly several external servers is polled at intervals determined by an intricate phase/frequncy-lock feedback loop. The feedback loop measures the incidental clock offset jitter and oscillator frequency wander and determines the best poll interval using a heuristic algorithm. Ordinarily, and in most operating environments, the feedback loop will start with 64 s poll intervals and eventually increase in steps to 1024 s. A small amount of random variation is introduced in order to avoid bunching. In addition, should a server become unreachable for some time, the poll interval is increased in steps to 1024 s in order to reduce network overhead.</p>
<h4 id="poll">Poll Interval Control</h4>
- <p>This version of NTP includes an intricate state machine to reduce the network load while maintaining a quality of synchronization consistent with the observed jitter and wander. There are a number of ways to tailor the operation in order enhance accuracy by reducing the interval or to reduce network overhead by increasing it. However, the user is advised to carefully consider the consequences of changing the poll adjustment range from the default minimum of 64 s to the default maximum of 1,024 s. The default minimum can be changed with the <tt>tinker minpoll</tt> command to a value not less than 16 s. This value is used for all configured associations, unless overridden by the <tt>minpoll</tt> option on the configuration command. Note that most device drivers will not operate properly if the poll interval is less than 64 s and that the broadcast server and manycast client associations will also use the default, unless overridden.</p>
- <p>In some cases involving dial up or toll services, it may be useful to increase the minimum interval to a few tens of minutes and maximum interval to a day or so. Under normal operation conditions, once the clock discipline loop has stabilized the interval will be increased in steps from the minimum to the maximum. However, this assumes the intrinsic clock frequency error is small enough for the discipline loop correct it. The capture range of the loop is 500 PPM at an interval of 64s decreasing by a factor of two for each doubling of interval. At a minimum of 1,024 s, for example, the capture range is only 31 PPM. If the intrinsic error is greater than this, the drift file <tt>ntp.drift</tt> will have to be specially tailored to reduce the residual error below this limit. Once this is done, the drift file is automatically updated once per hour and is available to initialize the frequency on subsequent daemon restarts.</p>
+ <p>NTP uses an intricate clock discipline algorithm to automatically control the poll interval for maximum accuracy consistent with minimum network load. The default minimum interval is 64 s and the maximum 1024 s, which is suitable for most conditions. The default minimum and maximum intervals can be changed using the <tt>tinker minpoll</tt> and <tt>tinker maxpoll </tt> commands, respectively. These values are used for all configured associations, unless overridden by the <tt>minpoll</tt> or <tt>minpoll</tt> options on the <tt>server</tt>configuration command.</p>
+ <p>In some cases involving dial-up or ISDN toll services, it may be useful to set the minimum interval to 12 (4096 s) and maximum interval to 17 (36 h). Under normal operation conditions, once the clock discipline loop has stabilized the interval will be increased in steps from the minimum to the maximum. However, this assumes the residual clock frequency error is small enough for the discipline loop to capture and correct it. The capture range of the loop is 500 PPM with a 64-s interval decreasing by a factor of two for each interval doubling. At a 36-hr interval, for example, the capture range is only 0.24 PPM. If the frequency changes abruptly, due for instance a large change in temperature, one or more step adjustments may occur.is greater than this, the frequency file <tt>ntp.drift</tt></p>
<h4 id="huff">The huff-n'-puff Filter</h4>
<p>In scenarios where a considerable amount of data are to be downloaded or uploaded over telephone modems, timekeeping quality can be seriously degraded. This occurs because the differential delays on the two directions of transmission can be quite large. In many cases the apparent time errors are so large as to exceed the step threshold and a step correction can occur during and after the data transfer is in progress.</p>
<p>The huff-n'-puff filter is designed to correct the apparent time offset in these cases. It depends on knowledge of the propagation delay when no other traffic is present. In common scenarios this occurs during other than work hours. The filter maintains a shift register that remembers the minimum delay over the most recent interval measured usually in hours. Under conditions of severe delay, the filter corrects the apparent offset using the sign of the offset and the difference between the apparent delay and minimum delay. The name of the filter reflects the negative (huff) and positive (puff) correction, which depends on the sign of the offset.</p>
- <p>The filter is activated by the <tt>tinker</tt> command and <tt>huffpuff</tt> keyword, as described in the <a href="miscopt.html">Miscellaneous Options</a> page.</p>
- <h4 id="notes">Notes</h4>
- <p>If NetInfo support is built into <tt>ntpd</tt>, then <tt>ntpd</tt> will attempt to read its configuration from the NetInfo if the default ntp.conf file cannot be read and no file is specified by the <tt>-c</tt> option.</p>
+ <p>The filter is activated by the <tt>tinker huffpuff</tt> command, as described in the <a href="miscopt.html">Miscellaneous Options</a> page.</p>
+ <h4 id="leap">Leap Second Processing</h4>
+ <p>As provided by international agreement, an extra second is sometimes inserted in Coordinated Universal Time (UTC) at the end of a selected month, usually June or December. The National Institutes of Standards and Technology (NIST) provides an historic leapseconds file at time.nist.gov for retrieval via FTP. When this file, usually called ntp.leap, is installed, <tt>ntpd</tt> reads it at startup and initializes three leapsecond values, the offset of International Atomic Time (TAI) after the last leap in the file, the NTP seconds of that leap and the NTP seconds when the leapseconds file expires.</p>
+ <p>If a host does not have the leapsecond values, they can be obtained over the net using the Autokey security protocol. Ordinarily, the leapseconds file is installed on the primary servers and the values flow from them to dependent servers and eventually clients. When multiple servers are involved, the values with the latest expiration time are used.</p>
+ <p>If the latest leap is in the past, nothing further is done other than to install the TAI offset in the kernel where it can be retrieved by the <tt>ntp_gettimeofday()</tt> system call. If the leap is in the future less than 28 days, the leap warning bits are set to insert one second. If in the future less than 23 hours, the kernel is armed to insert one second at the end of the current day. If the kernel is enabled, the leap is done automatically at that time; otherwise, the clock is stepped back one second at that time.</p>
+ <p>Dependent servers and clients tally the leap warning bits of surviving servers and reference clocks. When a majority of the survivors show warning, a leap is programmed at the end of the current month. During the month and day of insertion, they operate as above. In this way the leap is propagated at all dependent servers and clients.</p>
+ <h4 id="notes">Additional Features</h4>
+ <p>If <tt>ntpd</tt>, is configured with NetInfo support, it will attempt to read its configuration from the NetInfo service if the default <tt></tt>ntp.conf</tt> file cannot be read and no file is specified by the <tt>-c</tt> option.</p>
<p>In contexts where a host name is expected, a <tt>-4</tt> qualifier preceding the host name forces DNS resolution to the IPv4 namespace, while a <tt>-6</tt> qualifier forces DNS resolution to the IPv6 namespace.</p>
<p>Various internal <tt>ntpd</tt> variables can be displayed and configuration options altered while the <tt>ntpd</tt> is running using the <tt><a href="ntpq.html">ntpq</a></tt> and <tt><a href="ntpdc.html">ntpdc</a></tt> utility programs.</p>
<p>When <tt>ntpd</tt> starts it looks at the value of <tt>umask</tt>, and if zero <tt>ntpd</tt> will set the <tt>umask</tt> to <tt>022</tt>.</p>
<h4 id="cfg">The Configuration File</h4>
<p>Ordinarily, <tt>ntpd</tt> reads the <tt>ntp.conf</tt> configuration file at startup time in order to determine the synchronization sources and operating modes. It is also possible to specify a working, although limited, configuration entirely on the command line, obviating the need for a configuration file. This may be particularly useful when the local host is to be configured as a broadcast/multicast client, with all peers being determined by listening to broadcasts at run time.</p>
<p>Usually, the configuration file is installed in the <tt>/etc</tt> directory, but could be installed elsewhere (see the <tt>-c <i>conffile</i></tt> command line option). The file format is similar to other Unix configuration files - comments begin with a <tt>#</tt> character and extend to the end of the line; blank lines are ignored.</p>
- <p>Configuration commands consist of an initial keyword followed by a list of arguments, some of which may be optional, separated by whitespace. Commands may not be continued over multiple lines. Arguments may be host names, host addresses written in numeric, dotted-quad form, integers, floating point numbers (when specifying times in seconds) and text strings. Optional arguments are delimited by <tt>[ ]</tt> in the following descriptions, while alternatives are separated by <tt>|</tt>. The notation <tt>[ ... ]</tt> means an optional, indefinite repetition of the last item before the <tt>[ ... ]</tt>.</p>
+ <p>Configuration commands consist of an initial keyword followed by a list of arguments, some of which may be optional, separated by whitespace. Commands may not be continued over multiple lines. Arguments may be host names, host addresses written in numeric, dotted-quad form, integers, floating point numbers (when specifying times in seconds) and text strings. Optional arguments are delimited by <tt>[ ]</tt> in the following option pages, while alternatives are separated by <tt>|</tt>. The notation <tt>[ ... ]</tt> means an optional, indefinite repetition of the last item before the <tt>[ ... ]</tt>.</p>
<h4 id="opt">Configuration Options</h4>
<p><a href="confopt.html">Server Options</a><br>
<a href="authopt.html">Authentication Options</a><br>
<dt><tt>addpeer <i>peer_address</i> [
<i>keyid</i> ] [ <i>version</i> ] [
<tt>minpoll# | prefer | iburst | burst | minpoll
- <i>N</i> | <tt>maxpoll</tt> <i>N</i> [...] ]</tt>
+ <i>N</i> | <tt>maxpoll</tt> <i>N</i> [ <i>dynamic</i> ] [...] ]</tt>
<dt><tt>addpeer <i>peer_address</i> [
<tt>prefer | iburst | burst | minpoll
<i>N</i> | <tt>maxpoll</tt> <i>N</i> | <tt>keyid</tt>
ntpd. See the <a href="confopt.html">Server Options</a> page for further information.
Each flag (or its absence) replaces the
previous setting. The <tt>prefer</tt> keyword indicates a preferred peer (and thus will be used primarily for clock synchronisation if possible). The preferred peer also determines the validity of the PPS signal - if the preferred peer is suitable for synchronisation so is the PPS signal.
+ The <tt>dynamic</tt> keyword allows association configuration even when no suitable network interface is found at configuration time. The dynamic interface update mechanism may complete the configuration when new interfaces appear (e.g. WLAN/PPP interfaces) at a later time and thus render the association operable.
<dt><tt>addserver <i>peer_address</i> [
<i>keyid</i> ] [ <i>version</i> ] [
<tt>minpoll# | prefer | iburst | burst | minpoll
<dt><tt>addserver <i>peer_address</i> [
<tt>prefer | iburst | burst | minpoll
<i>N</i> | <tt>maxpoll</tt> <i>N</i> | <tt>keyid</tt>
- <i>N</i> | <tt>version</tt> <i>N</i> [...] ]</tt>
+ <i>N</i> | <tt>version</tt> <i>N</i> [...] [ <i>dynamic</i> ] ]</tt>
<dd>Identical to the addpeer command, except that the operating mode is client.
<dt><tt>broadcast <i>peer_address</i> [
<i>keyid</i> ] [ <i>version</i> ] [ <i>prefer</i> ]</tt>
document.write("<ul>\\r
-<li class='inline'><a href='confopt.html'>Server Options</a><br>\\r
+<li class='inline'><a href='accopt.html'>Access Control Options</a><br>\
<li class='inline'><a href='authopt.html'>Authentication Options</a><br>\\r
+<li class='inline'><a href='miscopt.html'>Miscellaneous Options</a><br>\
<li class='inline'><a href='monopt.html'>Monitoring Options</a><br>\\r
+<li class='inline'><a href='clockopt.html'>Reference Clock Options</a><br>\
+<li class='inline'><a href='confopt.html'>Server Options</a><br>\
<li class='inline'><a href='ntp_conf.html'>Configuration File Definition (Advanced)</a><br>\
</ul>")
\ No newline at end of file
double disp; /* peer dispersion */
double estbdelay; /* clock offset to broadcast server */
+ /*
+ * Variables used to correct for packet length and asymmetry.
+ */
+ double t21; /* outbound packet delay */
+ int t21_bytes; /* outbound packet length */
+ int t21_last; /* last outbound packet length */
+ double r21; /* outbound data rate */
+ double t34; /* inbound packet delay */
+ int t34_bytes; /* inbound packet length */
+ double r34; /* inbound data rate */
+
/*
* End of clear-to-zero area
*/
#define FLAG_FIXPOLL 0x1000 /* stick at minpoll */
#define FLAG_TRUE 0x2000 /* select truechimer */
#define FLAG_PREEMPT 0x4000 /* preemptable association */
-
+#define FLAG_ASYM 0x8000 /* asymmetric delay compensation */
/*
* Definitions for the clear() routine. We use memset() to clear
* the parts of the peer structure which go to zero. These are
#define CS_VERSION 18
#define CS_STABIL 19
#define CS_VARLIST 20
+#define CS_TAI 21
+#define CS_LEAPTAB 22
+#define CS_LEAPEND 23
#ifdef OPENSSL
-#define CS_FLAGS 21
-#define CS_HOST 22
-#define CS_PUBLIC 23
-#define CS_CERTIF 24
-#define CS_REVTIME 25
-#define CS_LEAPTAB 26
-#define CS_TAI 27
+#define CS_FLAGS 24
+#define CS_HOST 25
+#define CS_PUBLIC 26
+#define CS_CERTIF 27
#define CS_DIGEST 28
#define CS_IDENT 29
-#define CS_REVOKE 30
-#define CS_MAXCODE CS_REVOKE
+#define CS_REVTIME 30
+#define CS_MAXCODE CS_REVTIME
#else
-#define CS_MAXCODE CS_VARLIST
+#define CS_MAXCODE CS_LEAPEND
#endif /* OPENSSL */
/*
#define CP_FLASH 35
#define CP_TTL 36
#define CP_VARLIST 37
+#define CP_IN 38
+#define CP_OUT 39
#ifdef OPENSSL
-#define CP_FLAGS 38
-#define CP_HOST 39
-#define CP_VALID 40
-#define CP_INITSEQ 41
-#define CP_INITKEY 42
-#define CP_INITTSP 43
-#define CP_DIGEST 44
-#define CP_IDENT 45
+#define CP_FLAGS 40
+#define CP_HOST 41
+#define CP_VALID 42
+#define CP_INITSEQ 43
+#define CP_INITKEY 44
+#define CP_INITTSP 45
+#define CP_DIGEST 46
+#define CP_IDENT 47
#define CP_MAXCODE CP_IDENT
#else
-#define CP_MAXCODE CP_VARLIST
+#define CP_MAXCODE CP_OUT
#endif /* OPENSSL */
/*
#define CRYPTO_CERT CRYPTO_CMD(2) /* certificate */
#define CRYPTO_COOK CRYPTO_CMD(3) /* cookie value */
#define CRYPTO_AUTO CRYPTO_CMD(4) /* autokey values */
-#define CRYPTO_TAI CRYPTO_CMD(5) /* leapseconds table */
+#define CRYPTO_TAI CRYPTO_CMD(5) /* leapsecond values */
#define CRYPTO_SIGN CRYPTO_CMD(6) /* certificate sign */
#define CRYPTO_IFF CRYPTO_CMD(7) /* IFF identity scheme */
#define CRYPTO_GQ CRYPTO_CMD(8) /* GQ identity scheme */
* Miscellaneous crypto stuff
*/
#define NTP_MAXSESSION 100 /* maximum session key list entries */
-#define NTP_AUTOMAX 13 /* log2 default max session key life */
-#define KEY_REVOKE 16 /* log2 default key revoke timeout */
+#define NTP_AUTOMAX 3600 /* default max session key lifetime */
+#define KEY_REVOKE 86400 /* default key revoke timeout */
#define NTP_MAXEXTEN 1024 /* maximum extension field size */
/*
extern void huffpuff (void);
extern u_long sys_clocktime;
extern u_int sys_tai;
+extern int clock_stepcnt;
/* ntp_monitor.c */
extern void init_mon (void);
/* ntp_crypto.c */
#ifdef OPENSSL
extern int crypto_recv (struct peer *, struct recvbuf *);
-extern int crypto_xmit (struct pkt *, struct sockaddr_storage *, int, struct exten *, keyid_t);
-extern keyid_t session_key (struct sockaddr_storage *, struct sockaddr_storage *, keyid_t, keyid_t, u_long);
+extern int crypto_xmit (struct pkt *, struct sockaddr_storage *,
+ int *, struct exten *, keyid_t);
+extern keyid_t session_key (struct sockaddr_storage *,
+ struct sockaddr_storage *, keyid_t,
+ keyid_t, u_long);
extern int make_keylist (struct peer *, struct interface *);
extern void key_expire (struct peer *);
extern void crypto_update (void);
/* ntp_proto.c */
extern void transmit (struct peer *);
extern void receive (struct recvbuf *);
-extern void peer_crypto_clear (struct peer *peer);
extern void peer_clear (struct peer *, char *);
-extern void process_packet (struct peer *, struct pkt *);
+extern void process_packet (struct peer *, struct pkt *, u_int);
extern void clock_select (void);
extern void kod_proto (void);
+extern int leap_tai;
extern u_long leap_ins;
extern u_long leap_expire;
extern u_long leap_sec;
extern void timer_clr_stats (void);
extern void timer_interfacetimeout (u_long);
extern volatile int interface_interval;
-
#ifdef OPENSSL
extern char *sys_hostname;
-extern l_fp sys_revoketime;
+extern u_long sys_revoke; /* keys revoke timeout */
+extern u_long sys_automax; /* session key timeout */
#endif /* OPENSSL */
/* ntp_util.c */
extern struct peer *sys_peer; /* our current peer */
extern struct peer *sys_pps; /* our current PPS peer */
extern struct peer *sys_prefer; /* our cherished peer */
-extern u_long sys_automax; /* maximum session key lifetime */
/*
* Nonspecified system state variables.
/* ntp_timer.c */
extern volatile int alarm_flag; /* alarm flag */
-extern u_char sys_revoke; /* keys revoke timeout (log2 s) */
extern volatile u_long alarm_overflow;
extern u_long current_time; /* current time (s) */
extern u_long timer_timereset;
my_config.auth.trusted_key_list = NULL;
}
- /* Revoke Command */
#ifdef OPENSSL
+ /* Revoke Command */
if (my_config.auth.revoke)
- sys_revoke = (u_char) max(my_config.auth.revoke, KEY_REVOKE);
+ sys_revoke = my_config.auth.revoke;
#endif /* OPENSSL */
#if !defined(VMS) && !defined(SYS_VXWORKS)
}
break;
case T_DriftMinutes:
+
+#if 0 /* this code is bogus and should be replaced with wander threshold */
stats_write_period = 60 * curr_var->value.i;
+#endif
break;
case T_Leapfile:
stats_config(STATS_LEAP_FILE, curr_var->value.s);
curr_var->value.s);
free(curr_var->value.s);
break;
- case T_Automax:
#ifdef OPENSSL
- sys_automax = 1 << max(curr_var->value.i, 10);
-#else
- printf("Warning: Automax command ignored!\n");
-#endif
+ case T_Automax:
+ sys_automax = curr_var->value.i;
break;
+#endif
}
free_node(curr_var);
}
static void ctl_puthex (const char *, u_long);
static void ctl_putint (const char *, long);
static void ctl_putts (const char *, l_fp *);
-static void ctl_putadr (const char *, u_int32, struct sockaddr_storage*);
+static void ctl_putadr (const char *, u_int32,
+ struct sockaddr_storage*);
static void ctl_putid (const char *, char *);
static void ctl_putarray (const char *, double *, int);
static void ctl_putsys (int);
static void ctl_putpeer (int, struct peer *);
-#ifdef OPENSSL
static void ctl_putfs (const char *, tstamp_t);
-#endif
#ifdef REFCLOCK
static void ctl_putclock (int, struct refclockstat *, int);
#endif /* REFCLOCK */
{ CS_VERSION, RO, "version" }, /* 18 */
{ CS_STABIL, RO, "stability" }, /* 19 */
{ CS_VARLIST, RO, "sys_var_list" }, /* 20 */
+ { CS_TAI, RO, "tai" }, /* 21 */
+ { CS_LEAPTAB, RO, "leapsec" }, /* 22 */
+ { CS_LEAPEND, RO, "expire" }, /* 23 */
#ifdef OPENSSL
- { CS_FLAGS, RO, "flags" }, /* 21 */
- { CS_HOST, RO, "hostname" }, /* 22 */
- { CS_PUBLIC, RO, "update" }, /* 23 */
- { CS_CERTIF, RO, "cert" }, /* 24 */
- { CS_REVTIME, RO, "expire" }, /* 25 */
- { CS_LEAPTAB, RO, "leapsec" }, /* 26 */
- { CS_TAI, RO, "tai" }, /* 27 */
+ { CS_FLAGS, RO, "flags" }, /* 24 */
+ { CS_HOST, RO, "hostname" }, /* 25 */
+ { CS_PUBLIC, RO, "update" }, /* 26 */
+ { CS_CERTIF, RO, "cert" }, /* 27 */
{ CS_DIGEST, RO, "signature" }, /* 28 */
{ CS_IDENT, RO, "ident" }, /* 29 */
- { CS_REVOKE, RO, "expire" }, /* 30 */
+ { CS_REVTIME, RO, "until" }, /* 30 */
#endif /* OPENSSL */
- { 0, EOV, "" } /* 21/31 */
+ { 0, EOV, "" } /* 24/31 */
};
static struct ctl_var *ext_sys_var = (struct ctl_var *)0;
CS_JITTER,
CS_ERROR,
CS_STABIL,
+ CS_TAI,
+ CS_LEAPTAB,
+ CS_LEAPEND,
#ifdef OPENSSL
CS_HOST,
CS_DIGEST,
CS_FLAGS,
CS_PUBLIC,
CS_IDENT,
- CS_LEAPTAB,
- CS_TAI,
CS_CERTIF,
#endif /* OPENSSL */
0
{ CP_FLASH, RO, "flash" }, /* 35 */
{ CP_TTL, RO, "ttl" }, /* 36 */
{ CP_VARLIST, RO, "peer_var_list" }, /* 37 */
+ { CP_IN, RO, "in" }, /* 38 */
+ { CP_OUT, RO, "out" }, /* 39 */
#ifdef OPENSSL
- { CP_FLAGS, RO, "flags" }, /* 38 */
- { CP_HOST, RO, "hostname" }, /* 39 */
- { CP_VALID, RO, "valid" }, /* 40 */
- { CP_INITSEQ, RO, "initsequence" }, /* 41 */
- { CP_INITKEY, RO, "initkey" }, /* 42 */
- { CP_INITTSP, RO, "timestamp" }, /* 43 */
- { CP_DIGEST, RO, "signature" }, /* 44 */
- { CP_IDENT, RO, "trust" }, /* 45 */
+ { CP_FLAGS, RO, "flags" }, /* 40 */
+ { CP_HOST, RO, "hostname" }, /* 41 */
+ { CP_VALID, RO, "valid" }, /* 42 */
+ { CP_INITSEQ, RO, "initsequence" }, /* 43 */
+ { CP_INITKEY, RO, "initkey" }, /* 44 */
+ { CP_INITTSP, RO, "timestamp" }, /* 45 */
+ { CP_DIGEST, RO, "signature" }, /* 46 */
+ { CP_IDENT, RO, "trust" }, /* 47 */
#endif /* OPENSSL */
- { 0, EOV, "" } /* 38/46 */
+ { 0, EOV, "" } /* 40/48 */
};
CP_SRCPORT,
CP_DSTADR,
CP_DSTPORT,
+ CP_OUT,
+ CP_IN,
CP_LEAP,
CP_STRATUM,
CP_PRECISION,
(void)sprintf(cp, "%.3f", ts);
while (*cp != '\0')
cp++;
- ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
+ ctl_putdata(buffer, (unsigned)(cp - buffer), 0);
}
/*
/*
* ctl_putfs - write a decoded filestamp into the response
*/
-#ifdef OPENSSL
static void
ctl_putfs(
const char *tag,
cp++;
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
}
-#endif
/*
- * ctl_puthex - write a tagged unsigned integer, in hex, into the response
+ * ctl_puthex - write a tagged unsigned integer, in hex, into the
+ * response
*/
static void
ctl_puthex(
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "0x%08lx.%08lx",
- ts->l_ui & 0xffffffffUL,
- ts->l_uf & 0xffffffffUL);
+ (void) sprintf(cp, "0x%08lx.%08lx", ts->l_ui & 0xffffffffUL,
+ ts->l_uf & 0xffffffffUL);
while (*cp != '\0')
cp++;
ctl_putdata(buffer, (unsigned)( cp - buffer ), 0);
ctl_putuint(sys_var[CS_PEERID].text, 0);
else
ctl_putuint(sys_var[CS_PEERID].text,
- sys_peer->associd);
+ sys_peer->associd);
break;
case CS_STATE:
}
break;
+ case CS_TAI:
+ if (sys_tai > 0)
+ ctl_putuint(sys_var[CS_TAI].text, sys_tai);
+ break;
+
+ case CS_LEAPTAB:
+ if (leap_sec > 0)
+ ctl_putuint(sys_var[CS_LEAPTAB].text,
+ leap_sec);
+ break;
+
+ case CS_LEAPEND:
+ if (leap_expire > 0)
+ ctl_putfs(sys_var[CS_LEAPEND].text,
+ leap_expire);
+ break;
+
#ifdef OPENSSL
case CS_FLAGS:
- if (crypto_flags) {
- ctl_puthex(sys_var[CS_FLAGS].text, crypto_flags);
- }
+ if (crypto_flags)
+ ctl_puthex(sys_var[CS_FLAGS].text,
+ crypto_flags);
break;
case CS_DIGEST:
cp->issuer, cp->flags);
ctl_putstr(sys_var[CS_CERTIF].text, cbuf,
strlen(cbuf));
- ctl_putfs(sys_var[CS_REVOKE].text, cp->last);
+ ctl_putfs(sys_var[CS_REVTIME].text, cp->last);
}
break;
ntohl(hostval.tstamp));
break;
- case CS_REVTIME:
- if (hostval.tstamp != 0)
- ctl_putfs(sys_var[CS_REVTIME].text,
- ntohl(hostval.tstamp));
- break;
-
case CS_IDENT:
if (iffpar_pkey != NULL)
ctl_putstr(sys_var[CS_IDENT].text,
mvpar_file, strlen(mvpar_file));
break;
- case CS_LEAPTAB:
- ctl_putuint(sys_var[CS_LEAPTAB].text,
- leap_sec);
- break;
-
- case CS_TAI:
- ctl_putuint(sys_var[CS_TAI].text, sys_tai);
- break;
-
#endif /* OPENSSL */
}
}
ntohs(((struct sockaddr_in*)&peer->dstadr->sin)->sin_port) : 0));
break;
+ case CP_OUT:
+ if (peer->r21 > 0)
+ ctl_putdbl(peer_var[CP_IN].text,
+ peer->r21 / 1e3);
+ break;
+
+ case CP_IN:
+ if (peer->r34 >0)
+ ctl_putdbl(peer_var[CP_OUT].text,
+ peer->r34 / 1e3);
+ break;
+
case CP_LEAP:
ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
break;
* +-------+-------+
* | op | len | <- extension pointer
* +-------+-------+
- * | assocID |
+ * | associd |
* +---------------+
* | timestamp | <- value pointer
* +---------------+
static char *host_file = NULL; /* host key file */
static char *sign_file = NULL; /* sign key file */
static char *cert_file = NULL; /* certificate file */
-static char *leap_file = NULL; /* leapseconds file */
static tstamp_t if_fstamp = 0; /* IFF filestamp */
static tstamp_t gq_fstamp = 0; /* GQ file stamp */
static tstamp_t mv_fstamp = 0; /* MV filestamp */
static int crypto_iff (struct exten *, struct peer *);
static int crypto_gq (struct exten *, struct peer *);
static int crypto_mv (struct exten *, struct peer *);
-static u_int crypto_send (struct exten *, struct value *);
+static u_int crypto_send (struct exten *, struct value *, int *);
static tstamp_t crypto_time (void);
static u_long asn2ntp (ASN1_TIME *);
static struct cert_info *cert_parse (u_char *, u_int, tstamp_t);
static EVP_PKEY *crypto_key (char *, tstamp_t *);
static int bighash (BIGNUM *, BIGNUM *);
static struct cert_info *crypto_cert (char *);
-static void crypto_tai (char *);
#ifdef SYS_WINNT
int
* session key is the MD5 hash of these values, while the next key ID is
* the first four octets of the hash.
*
- * Returns the next key ID
+ * Returns the next key ID or 0 if there is no destination address.
*/
keyid_t
session_key(
hdlen = 0;
switch(srcadr->ss_family) {
case AF_INET:
- header[0] = ((struct sockaddr_in *)srcadr)->sin_addr.s_addr;
- header[1] = ((struct sockaddr_in *)dstadr)->sin_addr.s_addr;
+ header[0] =
+ ((struct sockaddr_in *)srcadr)->sin_addr.s_addr;
+ header[1] =
+ ((struct sockaddr_in *)dstadr)->sin_addr.s_addr;
header[2] = htonl(keyno);
header[3] = htonl(private);
hdlen = 4 * sizeof(u_int32);
* Returns
* XEVNT_OK success
* XEVNT_PER host certificate expired
+ * XEVNT_ERR protocol error
*
* This routine constructs a pseudo-random sequence by repeatedly
* hashing the session key starting from a given source address,
struct value *vp; /* value pointer */
keyid_t keyid = 0; /* next key ID */
keyid_t cookie; /* private value */
- u_long lifetime;
+ long lifetime;
u_int len, mpoll;
int i;
if (!dstadr)
- return XEVNT_OK;
+ return XEVNT_ERR;
/*
* Allocate the key list if necessary.
* NTP_MAXKEY.
*/
while (1) {
- keyid = (ntp_random() + NTP_MAXKEY + 1) & ((1 <<
- sizeof(keyid_t)) - 1);
+ keyid = ntp_random() & 0xffffffff;
+ if (keyid <= NTP_MAXKEY)
+ continue;
+
if (authhavekey(keyid))
continue;
break;
peer->keylist[i] = keyid;
peer->keynumber = i;
keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,
- cookie, lifetime);
+ cookie, lifetime + mpoll);
lifetime -= mpoll;
if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||
- lifetime <= mpoll)
+ lifetime < 0)
break;
}
* valid length and is verified. There are a few cases where some values
* are believed even if the signature fails, but only if the proventic
* bit is not set.
+ *
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_LEN bad field format or length
+ * XEVNT_ERR protocol error
*/
int
crypto_recv(
ep = (struct exten *)pkt;
code = ntohl(ep->opcode) & 0xffff0000;
len = ntohl(ep->opcode) & 0x0000ffff;
- associd = (associd_t) ntohl(pkt[1]);
+ associd = (associd_t)ntohl(pkt[1]);
rval = XEVNT_OK;
#ifdef DEBUG
if (debug)
printf(
- "crypto_recv: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
+ "crypto_recv: flags 0x%x ext offset %d len %u code 0x%x associd %d\n",
peer->crypto, authlen, len, code >> 16,
associd);
#endif
* fake association ID over the fence, we better toss it
* out. Only the first one counts.
*/
- if (code & CRYPTO_RESP) {
+ if (!(code & CRYPTO_RESP)) {
if (peer->assoc == 0)
peer->assoc = associd;
else if (peer->assoc != associd)
* Decrypt the cookie, hunting all the time for
* errors.
*/
- if (vallen == (u_int) EVP_PKEY_size(host_pkey)) {
+ if (vallen == (u_int)EVP_PKEY_size(host_pkey)) {
RSA_private_decrypt(vallen,
(u_char *)ep->pkt,
(u_char *)&temp32,
peer->tai_leap.vallen = ep->vallen;
/*
- * Install the new table if there is no stored
- * table or the new table is more recent than
- * the stored table. Since a filestamp may have
- * changed, recompute the signatures.
+ * If the packet leap values are more recent
+ * that the stored ones, install the new leap
+ * values and changed, recompute the signatures.
*/
- if (ntohl(peer->tai_leap.fstamp) >
- ntohl(tai_leap.fstamp)) {
+ if (ntohl(ep->pkt[2]) > leap_expire) {
+ tai_leap.tstamp = ep->tstamp;
tai_leap.fstamp = ep->fstamp;
tai_leap.vallen = ep->vallen;
- if (tai_leap.ptr != NULL)
- free(tai_leap.ptr);
- tai_leap.ptr = emalloc(vallen);
- memcpy(tai_leap.ptr, ep->pkt, vallen);
+ leap_tai = ntohl(ep->pkt[0]);
+ leap_ins = ntohl(ep->pkt[1]);
+ leap_expire = ntohl(ep->pkt[2]);
crypto_update();
}
- crypto_flags |= CRYPTO_FLAG_TAI;
peer->crypto |= CRYPTO_FLAG_LEAP;
peer->flash &= ~TEST8;
- sprintf(statstr, "leap %u ts %u fs %u", vallen,
- ntohl(ep->tstamp), ntohl(ep->fstamp));
+ sprintf(statstr,
+ "leap tai %d add %u expire %u fs %u",
+ ntohl(ep->pkt[0]), ntohl(ep->pkt[1]),
+ ntohl(ep->pkt[2]), ntohl(ep->fstamp));
record_crypto_stats(&peer->srcadr, statstr);
#ifdef DEBUG
if (debug)
} else if (rval > XEVNT_OK && (code & CRYPTO_RESP)) {
rval = XEVNT_OK;
}
- authlen += len;
+ authlen += (len + 3) / 4 * 4;
}
return (rval);
}
* autokey information, in which case the caller has to provide the
* association ID to match the association.
*
- * Returns length of extension field.
+ * Side effect: update the packet offset.
+ *
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_LEN bad field format or length
+ * XEVNT_CRT bad or missing certificate
+ * XEVNT_ERR protocol error
+ * XEVNT_SRV server certificate expired
*/
int
crypto_xmit(
struct pkt *xpkt, /* transmit packet pointer */
struct sockaddr_storage *srcadr_sin, /* active runway */
- int start, /* offset to extension field */
+ int *start, /* offset to extension field */
struct exten *ep, /* extension pointer */
keyid_t cookie /* session cookie */
)
* and association ID. If this is a response and the host is not
* synchronized, light the error bit and go home.
*/
- pkt = (u_int32 *)xpkt + start / 4;
+ pkt = (u_int32 *)xpkt + *start / 4;
fp = (struct exten *)pkt;
opcode = ntohl(ep->opcode);
associd = (associd_t) ntohl(ep->associd);
- fp->associd = htonl(associd);
+ fp->associd = ep->associd;
len = 8;
rval = XEVNT_OK;
tstamp = crypto_time();
* contains only the status word.
*/
case CRYPTO_ASSOC | CRYPTO_RESP:
- len += crypto_send(fp, &hostval);
+ rval = crypto_send(fp, &hostval, &len);
fp->fstamp = htonl(crypto_flags);
break;
case CRYPTO_ASSOC:
- len += crypto_send(fp, &hostval);
+ rval = crypto_send(fp, &hostval, &len);
fp->fstamp = htonl(crypto_flags | ident_scheme);
break;
vtemp.fstamp = ep->fstamp;
vtemp.vallen = ep->vallen;
vtemp.ptr = (u_char *)ep->pkt;
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
break;
/*
else if (tstamp < xp->first || tstamp > xp->last)
rval = XEVNT_SRV;
else
- len += crypto_send(fp, &xp->cert);
+ rval = crypto_send(fp, &xp->cert, &len);
break;
/*
break;
}
if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
*/
case CRYPTO_IFF | CRYPTO_RESP:
if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
break;
}
if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
*/
case CRYPTO_GQ | CRYPTO_RESP:
if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
break;
}
if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
*/
case CRYPTO_MV | CRYPTO_RESP:
if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) {
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
}
break;
*/
case CRYPTO_SIGN | CRYPTO_RESP:
if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK)
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
break;
* key.
*/
case CRYPTO_COOK:
- len += crypto_send(fp, &pubkey);
+ rval = crypto_send(fp, &pubkey, &len);
break;
/*
}
if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) ==
XEVNT_OK)
- len += crypto_send(fp, &vtemp);
+ rval = crypto_send(fp, &vtemp, &len);
value_free(&vtemp);
break;
break;
}
peer->flags &= ~FLAG_ASSOC;
- len += crypto_send(fp, &peer->sndval);
+ rval = crypto_send(fp, &peer->sndval, &len);
break;
/*
*/
case CRYPTO_TAI:
case CRYPTO_TAI | CRYPTO_RESP:
- if (crypto_flags & CRYPTO_FLAG_TAI)
- len += crypto_send(fp, &tai_leap);
+ rval = crypto_send(fp, &tai_leap, &len);
break;
/*
if (opcode & CRYPTO_RESP)
rval = XEVNT_ERR;
}
+ fp->opcode = htonl((opcode & 0xffff0000) | len);
/*
* In case of error, flame the log. If a request, toss the
if (!(opcode & CRYPTO_RESP))
return (0);
}
-
- /*
- * Round up the field length to a multiple of 8 bytes and save
- * the request code and length.
- */
- len = ((len + 7) / 8) * 8;
- fp->opcode = htonl((opcode & 0xffff0000) | len);
#ifdef DEBUG
if (debug)
printf(
- "crypto_xmit: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",
- crypto_flags, start, len, opcode >> 16, associd);
+ "crypto_xmit: flags 0x%x ext offset %d len %u code 0x%x associd %d\n",
+ crypto_flags, *start, len, opcode >> 16, associd);
#endif
- return (len);
+ *start += len;
+ return (rval);
}
*
* This routine determines which identity scheme is in use and
* constructs an extension field for that scheme.
+ *
+ * Returns
+ * CRYTPO_IFF IFF scheme
+ * CRYPTO_GQ GQ scheme
+ * CRYPTO_MV MV scheme
+ * CRYPTO_NULL no available scheme
*/
u_int
crypto_ident(
*/
msyslog(LOG_INFO,
"crypto_ident: no compatible identity scheme found");
- return (0);
+ return (CRYPTO_NULL);
}
ep->opcode = htonl(opcode + len);
/*
- * If a response, send our ID; if a request, send the
- * responder's ID.
+ * If a request, send our ID; if a response, send the
+ * requestor's ID.
*/
- if (opcode & CRYPTO_RESP)
- ep->associd = htonl(peer->associd);
- else
- ep->associd = htonl(peer->assoc);
+ ep->associd = htonl(peer->associd);
ep->tstamp = htonl(tstamp);
ep->fstamp = hostval.tstamp;
ep->vallen = 0;
/*
* crypto_send - construct extension field from value components
*
- * Returns extension field length. Note: it is not polite to send a
- * nonempty signature with zero timestamp or a nonzero timestamp with
- * empty signature, but these rules are not enforced here.
+ * The value and signature fields are zero-padded to a word boundary.
+ * Note: it is not polite to send a nonempty signature with zero
+ * timestamp or a nonzero timestamp with an empty signature, but those
+ * rules are not enforced here.
+ *
+ * Returns
+ * XEVNT_OK success
+ * XEVNT_LEN bad field format or length
*/
u_int
crypto_send(
struct exten *ep, /* extension field pointer */
- struct value *vp /* value pointer */
+ struct value *vp, /* value pointer */
+ int *start /* buffer offset */
)
{
- u_int len, temp32;
- int i;
+ u_int len, vallen, siglen;
+ int i, j;
/*
- * Copy data. If the data field is empty or zero length, encode
- * an empty value with length zero.
+ * Calculate extension field length and check for buffer
+ * overflow. Leave room for the MAC.
+ */
+ len = 16;
+ vallen = ntohl(vp->vallen);
+ len += ((vallen + 3) / 4 + 1) * 4;
+ siglen = ntohl(vp->siglen);
+ len += ((siglen + 3) / 4 + 1) * 4;
+ if (*start + len > NTP_MAXEXTEN - LEN_PKT_NOMAC - MAX_MAC_LEN)
+ return (XEVNT_LEN);
+
+ /*
+ * Copy timestamps.
*/
ep->tstamp = vp->tstamp;
ep->fstamp = vp->fstamp;
ep->vallen = vp->vallen;
- len = 12;
- temp32 = ntohl(vp->vallen);
- if (temp32 > 0 && vp->ptr != NULL)
- memcpy(ep->pkt, vp->ptr, temp32);
+
+ /*
+ * Copy value. If the data field is empty or zero length,
+ * encode an empty value with length zero.
+ */
+ i = 0;
+ if (vallen > 0 && vp->ptr != NULL) {
+ j = vallen / 4;
+ if (j * 4 < vallen)
+ ep->pkt[i + j++] = 0;
+ memcpy(&ep->pkt[i], vp->ptr, vallen);
+ i += j;
+ }
/*
* Copy signature. If the signature field is empty or zero
* length, encode an empty signature with length zero.
*/
- i = (temp32 + 3) / 4;
- len += i * 4 + 4;
ep->pkt[i++] = vp->siglen;
- temp32 = ntohl(vp->siglen);
- if (temp32 > 0 && vp->sig != NULL)
- memcpy(&ep->pkt[i], vp->sig, temp32);
- len += temp32;
- return (len);
+ if (siglen > 0 && vp->sig != NULL) {
+ j = vallen / 4;
+ if (j * 4 < siglen)
+ ep->pkt[i + j++] = 0;
+ memcpy(&ep->pkt[i], vp->sig, siglen);
+ i += j;
+ }
+ *start += len;
+ return (XEVNT_OK);
}
* hostval host name (not signed)
* pubkey public key
* cinfo certificate info/value list
- * tai_leap leapseconds file
+ * tai_leap leap values
*
* Filestamps are proventicated data, so this routine is run only when
* the host has been synchronized to a proventicated source. Thus, the
struct cert_info *cp, *cpn; /* certificate info/value */
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
tstamp_t tstamp; /* NTP timestamp */
+ u_int32 *ptr;
u_int len;
if ((tstamp = crypto_time()) == 0)
}
/*
- * Sign leapseconds table and timestamps. The filestamp is
- * derived from the leapsecond file extension from wherever the
- * file was generated.
+ * Sign leapseconds values and timestamps. Note it is not an
+ * error to return null values.
*/
- if (tai_leap.vallen != 0) {
- tai_leap.tstamp = hostval.tstamp;
- tai_leap.siglen = 0;
- if (tai_leap.sig == NULL)
- tai_leap.sig = emalloc(sign_siglen);
- EVP_SignInit(&ctx, sign_digest);
- EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12);
- EVP_SignUpdate(&ctx, tai_leap.ptr,
- ntohl(tai_leap.vallen));
- if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey))
- tai_leap.siglen = htonl(len);
- }
+ tai_leap.tstamp = hostval.tstamp;
+ tai_leap.fstamp = hostval.tstamp;
+ len = 3 * sizeof(u_int32);
+ if (tai_leap.ptr == NULL)
+ tai_leap.ptr = emalloc(len);
+ tai_leap.vallen = htonl(len);
+ ptr = (u_int32 *)tai_leap.ptr;
+ ptr[0] = htonl(leap_tai);
+ ptr[1] = htonl(leap_ins);
+ ptr[2] = htonl(leap_expire);
+ if (tai_leap.sig == NULL)
+ tai_leap.sig = emalloc(sign_siglen);
+ EVP_SignInit(&ctx, sign_digest);
+ EVP_SignUpdate(&ctx, (u_char *)&tai_leap, 12);
+ EVP_SignUpdate(&ctx, tai_leap.ptr, len);
+ if (EVP_SignFinal(&ctx, tai_leap.sig, &len, sign_pkey))
+ tai_leap.siglen = htonl(len);
+ if (leap_tai > 0)
+ crypto_flags |= CRYPTO_FLAG_TAI;
sprintf(statstr, "update ts %u", ntohl(hostval.tstamp));
record_crypto_stats(NULL, statstr);
#ifdef DEBUG
char *v; /* pointer to ASN1_TIME string */
struct tm tm; /* used to convert to NTP time */
- NTP_REQUIRE(asn1time != NULL);
- NTP_REQUIRE(asn1time->data != NULL);
-
/*
* Extract time string YYMMDDHHMMSSZ from ASN1 time structure.
* Note that the YY, MM, DD fields start with one, the HH, MM,
- * SS fields start with zero and the Z character should be 'Z'
+ * SS fiels start with zero and the Z character should be 'Z'
* for UTC. Also note that years less than 50 map to years
* greater than 100. Dontcha love ASN.1? Better than MIL-188.
*/
EVP_DigestUpdate(&ctx, ptr, len);
EVP_DigestFinal(&ctx, dgst, &len);
BN_bin2bn(dgst, len, bk);
-
- /* XXX MEMLEAK? free ptr? */
-
+ free(ptr);
return (1);
}
cnt = X509_get_ext_count(cert);
for (i = 0; i < cnt; i++) {
ext = X509_get_ext(cert, i);
- NTP_INSIST(ext != NULL);
- NTP_INSIST(ext->value != NULL);
method = X509V3_EXT_get(ext);
temp = OBJ_obj2nid(ext->object);
switch (temp) {
}
-/*
- * crypto_tai - load leapseconds table from file
- *
- * This routine loads the ERTS leapsecond file in NIST text format,
- * converts to a value structure and extracts a filestamp from the file
- * name. The data are used to establish the TAI offset from UTC, which
- * is provided to the kernel if supported. Later the data can be sent to
- * another machine on request.
- */
-static void
-crypto_tai(
- char *cp /* file name */
- )
-{
- FILE *str; /* file handle */
- char buf[NTP_MAXSTRLEN]; /* file line buffer */
- u_int32 leapsec[MAX_LEAP]; /* NTP time at leaps */
- u_long expire; /* NTP time when file expires */
- int offset; /* offset at leap (s) */
- char filename[MAXFILENAME]; /* name of leapseconds file */
- char linkname[MAXFILENAME]; /* file link (for filestamp) */
- char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
- tstamp_t fstamp; /* filestamp */
- u_int len;
- u_int32 *ptr;
- char *dp;
- int rval, i, j;
-
- /*
- * Open the file and discard comment lines. If the first
- * character of the file name is not '/', prepend the keys
- * directory string. If the file is not found, not to worry; it
- * can be retrieved over the net. But, if it is found with
- * errors, we crash and burn.
- */
- if (*cp == '/')
- strcpy(filename, cp);
- else
- snprintf(filename, MAXFILENAME, "%s/%s", keysdir, cp);
- if ((str = fopen(filename, "r")) == NULL)
- return;
-
- /*
- * Extract filestamp if present.
- */
- rval = readlink(filename, linkname, MAXFILENAME - 1);
- if (rval > 0) {
- linkname[rval] = '\0';
- dp = strrchr(linkname, '.');
- } else {
- dp = strrchr(filename, '.');
- }
- if (dp != NULL)
- sscanf(++dp, "%u", &fstamp);
- else
- fstamp = 0;
- tai_leap.fstamp = htonl(fstamp);
-
- /*
- * We are rather paranoid here, since an intruder might cause a
- * coredump by infiltrating naughty values. Empty lines and
- * comments are ignored. Other lines must begin with two
- * integers followed by junk or comments. The first integer is
- * the NTP seconds of leap insertion, the second is the offset
- * of TAI relative to UTC after that insertion. The second word
- * must equal the initial insertion of ten seconds on 1 January
- * 1972 plus one second for each succeeding insertion.
- */
- i = TAI_1972;
- expire = 0;
- while (i < MAX_LEAP) {
- dp = fgets(buf, NTP_MAXSTRLEN - 1, str);
- if (dp == NULL)
- break;
-
- if (strlen(buf) < 1)
- continue;
-
- if (buf[0] == '#') {
- if (buf[1] == '@') {
- if (sscanf(&buf[2], "%lu", &expire) !=
- 1)
- break;
- }
- }
- continue;
-
- if (sscanf(buf, "%u %d", &leapsec[i], &offset) != 2)
- continue;
-
- if (i != offset)
- break;
-
- i++;
- }
- fclose(str);
- if (dp != NULL) {
- msyslog(LOG_INFO,
- "crypto_tai: leapseconds file %s error %d", cp,
- rval);
- exit (-1);
- }
-
- /*
- * The extension field table entries consists of the NTP seconds
- * of leap insertion in network byte order.
- */
- len = i * sizeof(u_int32);
- tai_leap.vallen = htonl(len);
- ptr = emalloc(len);
- tai_leap.ptr = (u_char *)ptr;
- for (j = 0; j < i; j++)
- *ptr++ = htonl(leapsec[j]);
- sys_tai = offset;
- leap_ins = leapsec[--j];
- leap_expire = expire;
- crypto_flags |= CRYPTO_FLAG_TAI;
- sprintf(statstr,
- "%s fs %u leap %lu tai %d expire %lu len %u", cp,
- fstamp, leap_ins, sys_tai, leap_expire, len);
- record_crypto_stats(NULL, statstr);
-#ifdef DEBUG
- if (debug)
- printf("crypto_tai: %s\n", statstr);
-#endif
-}
-
-
/*
* crypto_setup - load keys, certificate and leapseconds table
*
/*
* It the certificate is trusted, the subject must be the same
- * as the issuer, in other words it must be self signed.
+ * as the issuer, in other words it must be self-signed.
*/
if (cinfo->flags & CERT_TRUST && strcmp(cinfo->subject,
cinfo->issuer) != 0) {
if (cinfo->flags & CERT_PRIV)
crypto_flags |= CRYPTO_FLAG_PRIV;
crypto_flags |= cinfo->nid << 16;
-
- /*
- * Load optional leapseconds table from file "ntpkey_leap". If
- * the file is missing or defective, the values can later be
- * retrieved from a server.
- */
- if (leap_file == NULL)
- leap_file = "ntpkey_leap";
- crypto_tai(leap_file);
#ifdef DEBUG
if (debug)
printf(
cert_file = emalloc(strlen(cp) + 1);
strcpy(cert_file, cp);
break;
-
- /*
- * Set leapseconds file name.
- */
- case CRYPTO_CONF_LEAP:
- leap_file = emalloc(strlen(cp) + 1);
- strcpy(leap_file, cp);
- break;
}
crypto_flags |= CRYPTO_FLAG_ENAB;
}
u_char sys_poll = NTP_MINDPOLL; /* time constant/poll (log2 s) */
int tc_counter; /* jiggle counter */
double last_offset; /* last offset (s) */
+int clock_stepcnt; /* step counter */
/*
* Huff-n'-puff filter variables
* monitor and record the offsets anyway in order to determine
* the open-loop response and then go home.
*/
-#ifdef DEBUG
- if (debug)
- printf(
- "local_clock: assocID %d offset %.9f freq %.3f state %d\n",
- peer->associd, fp_offset, drift_comp * 1e6, state);
-#endif
#ifdef LOCKCLOCK
return (0);
sys_poll = NTP_MINPOLL;
clock_jitter = LOGTOD(sys_precision);
rval = 2;
- if (state == S_NSET) {
+ clock_stepcnt++;
+ if (state == S_NSET || clock_stepcnt > 2) {
rstclock(S_FREQ, peer->epoch, 0);
return (rval);
}
{
#ifdef DEBUG
if (debug)
- printf("local_clock: time %lu offset %.6f freq %.3f state %d\n",
- update, offset, drift_comp * 1e6, trans);
+ printf("local_clock: at %lu offset %.6f freq %.3f state %d step %d\n",
+ update, offset, drift_comp * 1e6, trans,
+ clock_stepcnt);
#endif
state = trans;
sys_clocktime = update;
for (n = 0; n < NTP_HASH_SIZE; n++) {
for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
next_peer = peer->next;
- if (!(peer->cast_flags & (MDF_ACAST | MDF_MCAST |
- MDF_BCAST))) {
+ if (!(peer->cast_flags & (MDF_ACAST |
+ MDF_MCAST | MDF_BCAST))) {
peer->hpoll = peer->minpoll;
peer_clear(peer, "STEP");
}
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
if (peer_to_remove->flags & FLAG_SKEY) {
- sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x",
+ sprintf(statstr,
+ "unpeer %d flash %x reach %03o flags %04x",
peer_to_remove->associd, peer_to_remove->flash,
peer_to_remove->reach, peer_to_remove->flags);
record_crypto_stats(&peer_to_remove->srcadr, statstr);
peer_associations, peer_preempt);
#endif
set_peerdstadr(peer_to_remove, NULL);
-
- /* XXXMEMLEAK? peer_clear->crypto allocation */
-
hash = NTP_HASH_ADDR(&peer_to_remove->srcadr);
peer_hash_count[hash]--;
peer_demobilizations++;
refclock_unpeer(peer_to_remove);
#endif
peer_to_remove->action = 0; /* disable timeout actions */
- if (peer_hash[hash] == peer_to_remove)
+ if (peer_hash[hash] == peer_to_remove) {
peer_hash[hash] = peer_to_remove->next;
- else {
+ } else {
register struct peer *peer;
peer = peer_hash[hash];
while (peer != 0 && peer->next != peer_to_remove)
- peer = peer->next;
+ peer = peer->next;
if (peer == 0) {
peer_hash_count[hash]++;
- msyslog(LOG_ERR, "peer struct for %s not in table!",
- stoa(&peer->srcadr));
+ msyslog(LOG_ERR,
+ "peer struct for %s not in table!",
+ stoa(&peer->srcadr));
} else {
peer->next = peer_to_remove->next;
}
*/
hash = peer_to_remove->associd & NTP_HASH_MASK;
assoc_hash_count[hash]--;
- if (assoc_hash[hash] == peer_to_remove)
+ if (assoc_hash[hash] == peer_to_remove) {
assoc_hash[hash] = peer_to_remove->ass_next;
- else {
+ } else {
register struct peer *peer;
peer = assoc_hash[hash];
if (peer == 0) {
assoc_hash_count[hash]++;
msyslog(LOG_ERR,
- "peer struct for %s not in association table!",
+ "peer struct for %s not in association table!",
stoa(&peer->srcadr));
} else {
peer->ass_next = peer_to_remove->ass_next;
while (peer != 0) {
if (peer->dstadr == dstadr)
break;
+
if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
peer->dstadr == findinterface(srcadr))
- break;
+ break;
+
peer = findexistingpeer(srcadr, peer, hmode);
}
}
peer->minpoll = (u_char) minpoll;
peer->maxpoll = (u_char) maxpoll;
peer->flags = flags | FLAG_CONFIG |
- (peer->flags & FLAG_REFCLOCK);
+ (peer->flags & FLAG_REFCLOCK);
peer->cast_flags = cast_flags;
peer->ttl = (u_char) ttl;
peer->keyid = key;
(interface->flags & INT_MCASTIF) &&
peer->burst) {
/*
- * don't accept updates to a true multicast reception
- * interface while a BCLNT peer is running it's
- * unicast protocol
+ * don't accept updates to a true multicast
+ * reception interface while a BCLNT peer is
+ * running it's unicast protocol
*/
return;
}
- if (peer->dstadr != NULL)
- {
+ if (peer->dstadr != NULL) {
peer->dstadr->peercnt--;
- ISC_LIST_UNLINK_TYPE(peer->dstadr->peers, peer, ilink, struct peer);
+ ISC_LIST_UNLINK_TYPE(peer->dstadr->peers, peer,
+ ilink, struct peer);
}
DPRINTF(4, ("set_peerdstadr(%s): change interface from %s to %s\n",
stoa(&peer->srcadr),
- (peer->dstadr != NULL) ? stoa(&peer->dstadr->sin) : "<null>",
- (interface != NULL) ? stoa(&interface->sin) : "<null>"));
-
+ (peer->dstadr != NULL) ?
+ stoa(&peer->dstadr->sin) : "<null>",
+ (interface != NULL) ?
+ stoa(&interface->sin) : "<null>"));
peer->dstadr = interface;
-
- if (peer->dstadr != NULL)
- {
- ISC_LIST_APPEND(peer->dstadr->peers, peer, ilink);
+ if (peer->dstadr != NULL) {
+ ISC_LIST_APPEND(peer->dstadr->peers, peer,
+ ilink);
peer->dstadr->peercnt++;
}
}
{
struct interface *niface, *piface;
- niface = select_peerinterface(peer, &peer->srcadr, NULL, peer->cast_flags);
+ niface = select_peerinterface(peer, &peer->srcadr, NULL,
+ peer->cast_flags);
#ifdef DEBUG
if (debug > 3)
{
printf(
- "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x: new interface: ",
- peer->dstadr == NULL ? "<null>" : stoa(&peer->dstadr->sin),
- stoa(&peer->srcadr),
- peer->hmode, peer->version, peer->minpoll,
- peer->maxpoll, peer->flags, peer->cast_flags,
- peer->ttl, peer->keyid);
- if (niface != NULL)
- {
- printf("fd=%d, bfd=%d, name=%.16s, flags=0x%x, scope=%d, ",
- niface->fd,
- niface->bfd,
- niface->name,
- niface->flags,
- niface->scopeid);
+ "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x: new interface: ",
+ peer->dstadr == NULL ? "<null>" :
+ stoa(&peer->dstadr->sin), stoa(&peer->srcadr),
+ peer->hmode, peer->version, peer->minpoll,
+ peer->maxpoll, peer->flags, peer->cast_flags,
+ peer->ttl, peer->keyid);
+ if (niface != NULL) {
+ printf(
+ "fd=%d, bfd=%d, name=%.16s, flags=0x%x, scope=%d, ",
+ niface->fd, niface->bfd, niface->name,
+ niface->flags, niface->scopeid);
/* Leave these as three printf calls. */
- printf(", sin=%s",
- stoa((&niface->sin)));
+ printf(", sin=%s", stoa((&niface->sin)));
if (niface->flags & INT_BROADCAST)
printf(", bcast=%s,",
- stoa((&niface->bcast)));
- printf(", mask=%s\n",
- stoa((&niface->mask)));
- }
- else
- {
+ stoa((&niface->bcast)));
+ printf(", mask=%s\n", stoa((&niface->mask)));
+ } else {
printf("<NONE>\n");
}
}
#endif
piface = peer->dstadr;
-
set_peerdstadr(peer, niface);
-
if (peer->dstadr) {
/*
* clear crypto if we change the local address
*/
- if (peer->dstadr != piface && !(peer->cast_flags & MDF_BCLNT)) {
- peer_crypto_clear(peer);
- }
+ if (peer->dstadr != piface && !(peer->cast_flags &
+ MDF_BCLNT))
+ peer_clear(peer, "XFAC");
/*
* Broadcast needs the socket enabled for broadcast
}
/*
- * Multicast needs the socket interface enabled for multicast
+ * Multicast needs the socket interface enabled for
+ * multicast
*/
if (peer->cast_flags & MDF_MCAST) {
- enable_multicast_if(peer->dstadr, &peer->srcadr);
+ enable_multicast_if(peer->dstadr,
+ &peer->srcadr);
}
}
}
if (debug > 3) {
if (interface != NULL)
printf("Found *-cast interface address %s, for address %s\n",
- stoa(&(interface)->sin), stoa(srcadr));
+ stoa(&(interface)->sin), stoa(srcadr));
else
printf("No *-cast local address found for address %s\n",
stoa(srcadr));
}
#endif
/*
- * If it was a multicast packet, findbcastinter() may not
- * find it, so try a little harder.
+ * If it was a multicast packet,
+ * findbcastinter() may not find it, so try a
+ * little harder.
*/
if (interface == ANY_INTERFACE_CHOOSE(srcadr))
interface = findinterface(srcadr);
}
- else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr))
+ else if (dstadr != NULL && dstadr !=
+ ANY_INTERFACE_CHOOSE(srcadr))
interface = dstadr;
else
interface = findinterface(srcadr);
ISC_LINK_INIT(peer, ilink); /* set up interface link chain */
- set_peerdstadr(peer, select_peerinterface(peer, srcadr, dstadr, cast_flags));
+ set_peerdstadr(peer, select_peerinterface(peer, srcadr, dstadr,
+ cast_flags));
peer->srcadr = *srcadr;
peer->hmode = (u_char)hmode;
peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
peer->flags = flags;
-
#ifdef DEBUG
if (debug > 2) {
if (peer->dstadr)
printf("newpeer: using fd %d and our addr %s\n",
- peer->dstadr->fd, stoa(&peer->dstadr->sin));
+ peer->dstadr->fd,
+ stoa(&peer->dstadr->sin));
else
printf("newpeer: local interface currently not bound\n");
}
}
/*
- * peer_clr_stats - clear peer module stat counters
+ * peer_clr_stats - clear peer module statiistics counters
*/
void
peer_clr_stats(void)
}
/*
- * peer_reset - reset stat counters in a peer structure
+ * peer_reset - reset statistics counters
*/
void
peer_reset(
/*
- * peer_all_reset - reset all peer stat counters
+ * peer_all_reset - reset all peer statistics counters
*/
void
peer_all_reset(void)
* peer list for all associations and flush only the key list
* and cookie. If a manycast client association, flush
* everything. Then, recompute and sign the agreement public
- * value, if present.
+ * values, if present, and refresh the leap values.
*/
if (!crypto_flags)
return;
peer->hmode == MODE_PASSIVE) {
key_expire(peer);
peer->crypto &= ~(CRYPTO_FLAG_AUTO |
- CRYPTO_FLAG_AGREE);
+ CRYPTO_FLAG_AGREE |
+ CRYPTO_FLAG_LEAP);
}
}
#include <stdio.h>
#ifdef HAVE_LIBSCF_H
#include <libscf.h>
-#endif
+#include <unistd.h>
+#endif /* HAVE_LIBSCF_H */
+
#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/
#include "ntp_refclock.h"
struct peer *sys_prefer; /* our cherished peer */
int sys_kod; /* kod credit */
int sys_kod_rate = 2; /* max kod packets per second */
-#ifdef OPENSSL
-u_long sys_automax; /* maximum session key lifetime */
-#endif /* OPENSSL */
/*
* Nonspecified system state variables.
double sys_jitter; /* system jitter (s) */
static int sys_hopper; /* anticlockhop counter */
static int sys_maxhop = MAXHOP; /* anticlockhop counter threshold */
+int leap_tai; /* TAI at next next leap */
u_long leap_ins; /* seconds at next leap */
u_long leap_expire; /* seconds leapfile expires */
u_long leap_sec; /* leap countdown */
static void fast_xmit (struct recvbuf *, int, keyid_t,
int);
static void clock_update (void);
-static int default_get_precision (void);
+static int default_get_precision (void);
static int peer_unfit (struct peer *);
peer_ntpdate--;
if (peer_ntpdate == 0) {
msyslog(LOG_NOTICE,
- "no reply; clock not set");
+ "proto: no reply; clock not set");
exit (0);
}
}
is_authentic = AUTH_NONE; /* not required */
#ifdef DEBUG
if (debug)
- printf("receive: at %ld %s<-%s mode %d code %d auth %d\n",
+ printf("receive: at %ld %s<-%s mode %d len %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode,
+ authlen);
#endif
} else if (has_mac == 4) {
is_authentic = AUTH_CRYPTO; /* crypto-NAK */
#ifdef DEBUG
if (debug)
printf(
- "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n",
+ "receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- skeyid, authlen, has_mac, is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode, skeyid,
+ authlen + has_mac, is_authentic);
#endif
} else {
#ifdef OPENSSL
#ifdef DEBUG
if (debug)
printf(
- "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n",
+ "receive: at %ld %s<-%s mode %d keyid %08x len %d auth %d\n",
current_time, stoa(dstadr_sin),
- stoa(&rbufp->recv_srcadr), hismode, retcode,
- skeyid, authlen, has_mac, is_authentic);
+ stoa(&rbufp->recv_srcadr), hismode, skeyid,
+ authlen + has_mac, is_authentic);
#endif
}
/*
* Update the origin and destination timestamps. If
* unsynchronized or bogus abandon ship. If the crypto machine
- * breaks, light the crypto bit and plaint the log.
+ * breaks, demobilize the association and wait for calmer seas.
*/
peer->org = p_xmt;
peer->rec = rbufp->recv_time;
#ifdef OPENSSL
if (crypto_flags && (peer->flags & FLAG_SKEY)) {
rval = crypto_recv(peer, rbufp);
- if (rval != XEVNT_OK) {
+ if (rval != XEVNT_OK)
peer_clear(peer, "CRYP");
- peer->flash |= TEST9; /* crypto error */
- }
}
#endif /* OPENSSL */
return; /* unsynch */
* the packet over the fence for processing, which may light up
* more flashers.
*/
- process_packet(peer, pkt);
+ process_packet(peer, pkt, rbufp->recv_length);
/*
- * Well, that was nice. If TEST4 is lit, either the crypto
- * machine jammed or a kiss-o'-death packet flew in, either of
- * which is fatal.
+ * Well, that was nice. If TEST4 is lit access was denied.
*/
if (peer->flash & TEST4) {
msyslog(LOG_INFO, "receive: fatal error %04x for %s",
void
process_packet(
register struct peer *peer,
- register struct pkt *pkt
+ register struct pkt *pkt,
+ u_int len
)
{
double t34, t21;
l_fp ci;
u_char pmode, pleap, pstratum;
+ double etemp, ftemp; /* experimental */
+ int itemp;
+ double td;
+
sys_processed++;
peer->processed++;
p_del = FPTOD(NTOHS_FP(pkt->rootdelay));
if (memcmp(&pkt->refid, "DENY", 4) == 0) {
peer_clear(peer, "DENY");
peer->flash |= TEST4; /* access denied */
+ return;
}
}
/*
* Capture the header values.
*/
- record_raw_stats(&peer->srcadr, peer->dstadr ? &peer->dstadr->sin : NULL, &p_org,
- &p_rec, &p_xmt, &peer->rec);
+ record_raw_stats(&peer->srcadr, peer->dstadr ?
+ &peer->dstadr->sin : NULL, &p_org, &p_rec, &p_xmt,
+ &peer->rec);
peer->leap = pleap;
peer->stratum = min(pstratum, STRATUM_UNSPEC);
peer->pmode = pmode;
ci = peer->rec; /* t4 - t1 */
L_SUB(&ci, &p_org);
+ /*
+ * This code calculates the outbound and inbound data rates by
+ * measuring the differences between timestamps at different
+ * packet lengths. This is helpful in cases of large asymmetric
+ * delays commonly experienced on deep space communication
+ * links.
+ */
+ if (peer->t21_last > 0 && peer->t34_bytes > 0) {
+ itemp = peer->t21_bytes - peer->t21_last;
+ if (itemp > 25) {
+ etemp = t21 - peer->t21;
+ if (fabs(etemp) > 1e-6) {
+ ftemp = itemp / etemp;
+ if (ftemp > 1000.)
+ peer->r21 = ftemp;
+ }
+ }
+ itemp = len - peer->t34_bytes;
+ if (itemp > 25) {
+ etemp = -t34 - peer->t34;
+ if (fabs(etemp) > 1e-6) {
+ ftemp = itemp / etemp;
+ if (ftemp > 1000.)
+ peer->r34 = ftemp;
+ }
+ }
+ }
+ peer->t21 = t21;
+ peer->t21_last = peer->t21_bytes;
+ peer->t34 = -t34;
+ peer->t34_bytes = len;
+ p_del = t21 - t34;
+#ifdef DEBUG
+ if (debug > 1)
+ printf("proto: t21 %.6lf %d t34 %.6lf %d\n", peer->t21,
+ peer->t21_bytes, peer->t34, peer->t34_bytes);
+#endif
+
+ /*
+ * The following section compensates for different data rates on
+ * the outbound (d21) and inbound (t34) directions. To do this,
+ * it finds t such that r21 * t - r34 * (d - t) = 0, where d is
+ * the roundtrip delay. Then it calculates the correction as a
+ * fraction of d.
+ */
+ if (peer->r21 > 0 && peer->r34 > 0 && p_del > 0) {
+ if (pmode != MODE_BROADCAST)
+ td = (peer->r34 / (peer->r21 + peer->r34) -
+ .5) * p_del;
+ else
+ td = 0;
+#if 0 /* temporarily disabled */
+ t21 -= td;
+ t34 -= td;
+#endif
+#ifdef DEBUG
+ if (debug > 1)
+ printf("proto: del %.6lf r21 %.1lf r34 %.1lf %.6lf\n",
+ p_del, peer->r21 / 1e3, peer->r34 / 1e3,
+ td);
+#endif
+ }
+
/*
* If running in a broadcast association, the clock offset is
* (t1 - t0) corrected by the one-way delay, but we can't
p_disp = 0;
} else {
p_offset = (t21 + t34) / 2.;
- p_del = t21 - t34;
LFPTOD(&ci, p_disp);
p_disp = LOGTOD(sys_precision) +
LOGTOD(peer->precision) + clock_phi * p_disp;
static void
clock_update(void)
{
- u_char oleap;
u_char ostratum;
double dtemp;
l_fp now;
#ifdef HAVE_LIBSCF_H
- char *fmri;
-#endif
+ char *fmri;
+#endif /* HAVE_LIBSCF_H */
/*
* There must be a system peer at this point. If we just changed
#ifdef DEBUG
if (debug)
- printf("clock_update: at %ld assoc %d \n", current_time,
- peer_associations);
+ printf("clock_update: at %lu associd %d leap %lu TAI %d\n",
+ current_time, sys_peer->associd, leap_sec, sys_tai);
#endif
- oleap = sys_leap;
ostratum = sys_stratum;
switch (local_clock(sys_peer, sys_offset)) {
case -1:
report_event(EVNT_SYSFAULT, NULL);
#ifdef HAVE_LIBSCF_H
- /* enter the maintenance mode */
- if ((fmri = getenv("SMF_FMRI")) != NULL) {
- if (smf_maintain_instance(fmri, 0) < 0) {
- printf("smf_maintain_instance:%s\n",
- scf_strerror(scf_error()));
- exit(1);
- }
- /* sleep until SMF kills us */
- for (;;)
- pause();
- }
-#endif
+ /*
+ * For Solaris enter the maintenance mode.
+ */
+ if ((fmri = getenv("SMF_FMRI")) != NULL) {
+ if (smf_maintain_instance(fmri, 0) < 0) {
+ printf("smf_maintain_instance: %s\n",
+ scf_strerror(scf_error()));
+ exit(1);
+ }
+ /*
+ * Sleep until SMF kills us.
+ */
+ for (;;)
+ pause();
+ }
+#endif /* HAVE_LIBSCF_H */
exit (-1);
/* not reached */
clear_all();
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
- sys_peer = NULL;
sys_rootdelay = 0;
sys_rootdispersion = 0;
+ L_CLR(&sys_reftime);
+ sys_jitter = LOGTOD(sys_precision);
memcpy(&sys_refid, "STEP", 4);
report_event(EVNT_CLOCKRESET, NULL);
break;
sys_reftime = sys_peer->rec;
/*
- * If a leapseconds file is not present or expired and
- * the number of upstream server leap bits is at least
- * the sanity threshold, schedule a leap for the end of
- * the current month.
+ * If a leapseconds file is not present and the number
+ * of survivor leap bits is greater than half the number
+ * of survivors, schedule a leap for the end of the
+ * current month.
*/
get_systime(&now);
- if (now.l_ui > leap_expire) {
- if (leap_next >= sys_minsane) {
+ if (leap_ins == 0) {
+ if (leap_next > sys_survivors / 2) {
if (!leap_sw) {
leap_sw++;
leap_sec = leap_month(now.l_ui);
msyslog(LOG_NOTICE,
- "leap second armed %lu s",
+ "proto: leap second armed %lu s",
leap_sec);
}
} else {
}
/*
- * If a leapseconds file is present and not expired and
- * a future leap is scheduled, decrement the TAI offset.
- * If the kernel code is available and enabled, pass the
- * TAI offset to the kernel. If less than 28 days remain
- * to the leap, schedule a leap when the leapseconds
- * counter expires.
+ * If a leapseconds file is present and a future leap is
+ * indicated, decrement the TAI offset. If the kernel
+ * code is available and enabled, pass the TAI offset to
+ * the kernel. If less than 28 days remain to the leap,
+ * schedule a leap when the leapseconds counter expires.
*/
} else if (leap_sec == 0) {
if (leap_ins > now.l_ui) {
if (leap_ins - now.l_ui < 28 * 86400) {
leap_sec = leap_ins - now.l_ui;
msyslog(LOG_NOTICE,
- "leap second armed %lu s",
+ "proto: leap second armed %lu s",
leap_sec);
}
- if (!leap_sw)
- sys_tai--;
+ sys_tai = leap_tai - 1;
+ } else {
+ sys_tai = leap_tai;
}
if (!leap_sw) {
leap_sw++;
msyslog(LOG_NOTICE,
- "TAI offset %d s", sys_tai);
+ "proto: TAI offset %d s at %u",
+ sys_tai, now.l_ui);
#ifdef KERNEL_PLL
if (pll_control && kern_enable)
loop_config(LOOP_LEAP, 0);
/*
* If this is the first time the clock is set,
- * reset the leap bits.
+ * reset the leap bits. If crypto, the timer will goose
+ * the setup process.
*/
- if (sys_leap == LEAP_NOTINSYNC)
+ if (sys_leap == LEAP_NOTINSYNC) {
sys_leap = LEAP_NOWARNING;
+ report_event(EVNT_SYNCCHG, NULL);
+ }
/*
* In orphan mode the stratum defaults to the orphan
sys_rootdispersion = dtemp +
sys_peer->rootdispersion;
}
- if (oleap == LEAP_NOTINSYNC) {
- report_event(EVNT_SYNCCHG, NULL);
-#ifdef OPENSSL
- expire_all();
- crypto_update();
-#endif /* OPENSSL */
- }
break;
/*
* Popcorn spike or step threshold exceeded. Pretend it never
#endif
}
+
/*
- * peer_crypto_clear - discard crypto information
+ * peer_clear - clear peer filter registers. See Section 3.4.8 of the spec.
*/
void
-peer_crypto_clear(
- struct peer *peer
- )
+peer_clear(
+ struct peer *peer, /* peer structure */
+ char *ident /* tally lights */
+ )
{
+ int i;
+#ifdef OPENSSL
+ char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
+#endif /* OPENSSL */
+
+ if (peer == sys_peer)
+ sys_peer = NULL;
+
+ /*
+ * Wipe the association clean and initialize the nonzero values.
+ */
+ memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
+
+#ifdef OPENSSL
/*
* If cryptographic credentials have been acquired, toss them to
* Valhalla. Note that autokeys are ephemeral, in that they are
* purged, too. This makes it much harder to sneak in some
* unauthenticated data in the clock filter.
*/
- DPRINTF(1, ("peer_crypto_clear: at %ld next %ld assoc ID %d\n",
- current_time, peer->nextdate, peer->associd));
-
-#ifdef OPENSSL
peer->assoc = 0;
peer->crypto = 0;
if (peer->pkey != NULL)
key_expire(peer);
value_free(&peer->encrypt);
#endif /* OPENSSL */
-}
-
-/*
- * peer_clear - clear peer filter registers. See Section 3.4.8 of the spec.
- */
-void
-peer_clear(
- struct peer *peer, /* peer structure */
- char *ident /* tally lights */
- )
-{
- int i;
-
- peer_crypto_clear(peer);
-
- if (peer == sys_peer)
- sys_peer = NULL;
-
- /*
- * Wipe the association clean and initialize the nonzero values.
- */
- memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO);
peer->estbdelay = sys_bdelay;
peer->ppoll = peer->maxpoll;
peer->hpoll = peer->minpoll;
else
peer->nextdate += (ntp_random() & ((1 << NTP_MINDPOLL) -
1));
-
- DPRINTF(1, ("peer_clear: at %ld next %ld assoc ID %d refid %s\n",
- current_time, peer->nextdate, peer->associd, ident));
+#ifdef OPENSSL
+ sprintf(statstr, "clear %d ident %s", peer->associd,
+ ident);
+ record_crypto_stats(&peer->srcadr, statstr);
+#endif /* OPENSSL */
+ DPRINTF(1, ("peer_clear: at %ld next %ld associd %d refid %s\n",
+ current_time, peer->nextdate, peer->associd,
+ ident));
}
/*
* clock_select - find the pick-of-the-litter clock
*
- * LOCKCLOCK: If the local clock is the prefer peer, it will always be
- * enabled, even if declared falseticker, (2) only the prefer peer can
- * be selected as the system peer, (3) if the external source is down,
- * the system leap bits are set to 11 and the stratum set to infinity.
+ * LOCKCLOCK: (1) If the local clock is the prefer peer, it will always
+ * be enabled, even if declared falseticker, (2) only the prefer peer
+ * can be selected as the system peer, (3) if the external source is
+ * down, the system leap bits are set to 11 and the stratum set to
+ * infinity.
*/
void
clock_select(void)
if (!(peer->flags & FLAG_AUTHENABLE)) {
get_systime(&peer->xmt);
HTONL_FP(&peer->xmt, &xpkt.xmt);
+ peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl],
&xpkt, sendlen);
peer->sent++;
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d\n",
+ printf("transmit: at %ld %s->%s mode %d len %d\n",
current_time, peer->dstadr ?
stoa(&peer->dstadr->sin) : "-",
- stoa(&peer->srcadr), peer->hmode);
+ stoa(&peer->srcadr), peer->hmode, sendlen);
#endif
return;
}
* messages have the same code as the request, but have
* a response bit and possibly an error bit set. In this
* implementation, a message may contain no more than
- * one command and no more than one response.
+ * one command and one or more responses.
*
* Cryptographic session keys include both a public and
* a private componet. Request and response messages
* identifier to verify authenticity.
*
* If for some reason a key is no longer in the
- * key cache, a birthday has happened and the
- * pseudo-random sequence is probably broken. In
- * that case, purge the keylist and regenerate
- * it.
+ * key cache, a birthday has happened or the key
+ * has expired, so the pseudo-random sequence is
+ * broken. In that case, purge the keylist and
+ * regenerate it.
*/
if (peer->keynumber == 0)
make_keylist(peer, peer->dstadr);
*/
case MODE_ACTIVE:
case MODE_PASSIVE:
- if (peer->flash & TEST9)
+ if (peer->flash & (TEST4 | TEST9))
break;
/*
* Parameter and certificate.
peer->leap != LEAP_NOTINSYNC &&
!(peer->crypto & CRYPTO_FLAG_AGREE))
exten = crypto_args(peer, CRYPTO_COOK,
- NULL);
+ NULL);
else if (peer->flags & FLAG_ASSOC)
exten = crypto_args(peer, CRYPTO_AUTO |
- CRYPTO_RESP, NULL);
+ CRYPTO_RESP, NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO))
exten = crypto_args(peer, CRYPTO_AUTO,
- NULL);
+ NULL);
/*
* Postamble. We trade leapseconds only when the
*/
else if (sys_leap != LEAP_NOTINSYNC &&
peer->leap != LEAP_NOTINSYNC &&
- peer->crypto & CRYPTO_FLAG_TAI &&
!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_TAI,
NULL);
* If the crypto bit is lit, don't send requests.
*/
case MODE_CLIENT:
- if (peer->flash & TEST9)
+ if (peer->flash & (TEST4 | TEST9))
break;
/*
* Parameter and certificate.
peer->issuer);
/*
- * Identity
+ * Identity. Nothing special here.
*/
else if (!(peer->crypto & CRYPTO_FLAG_VRFY))
exten = crypto_args(peer,
crypto_ident(peer), NULL);
/*
- * Autokey
+ * Cookie and autokey data. In broadcast client
+ * mode we request the autokey values now to
+ * avoid having to wait for the next key list.
*/
else if (!(peer->crypto & CRYPTO_FLAG_AGREE))
exten = crypto_args(peer, CRYPTO_COOK,
- NULL);
+ NULL);
else if (!(peer->crypto & CRYPTO_FLAG_AUTO) &&
(peer->cast_flags & MDF_BCLNT))
exten = crypto_args(peer, CRYPTO_AUTO,
* since there is no chance of deadlock.
*/
else if (sys_leap != LEAP_NOTINSYNC &&
- !(peer->crypto & CRYPTO_FLAG_SIGN))
+ !(peer->crypto & CRYPTO_FLAG_SIGN))
exten = crypto_args(peer, CRYPTO_SIGN,
- sys_hostname);
+ sys_hostname);
else if (sys_leap != LEAP_NOTINSYNC &&
- peer->crypto & CRYPTO_FLAG_TAI &&
!(peer->crypto & CRYPTO_FLAG_LEAP))
exten = crypto_args(peer, CRYPTO_TAI,
NULL);
*/
if (peer->cmmd != NULL) {
peer->cmmd->associd = htonl(peer->associd);
- sendlen += crypto_xmit(&xpkt, &peer->srcadr,
- sendlen, peer->cmmd, 0);
+ crypto_xmit(&xpkt, &peer->srcadr, &sendlen,
+ peer->cmmd, 0);
free(peer->cmmd);
peer->cmmd = NULL;
}
if (exten != NULL) {
- int ltemp = 0;
-
- if (exten->opcode != 0) {
- ltemp = crypto_xmit(&xpkt,
- &peer->srcadr, sendlen, exten, 0);
- if (ltemp == 0) {
- peer->flash |= TEST9; /* crypto error */
- free(exten);
- return;
- }
- }
- sendlen += ltemp;
+ if (exten->opcode != 0)
+ crypto_xmit(&xpkt, &peer->srcadr,
+ &sendlen, exten, 0);
free(exten);
}
/*
* Stash the transmit timestamp corrected for the encryption
* delay. If autokey, give back the key, as we use keys only
- * once. Check for errors such as missing keys, buffer overflow,
- * etc.
+ * once. Check for errors such as missing keys, etc.
*/
xkeyid = peer->keyid;
get_systime(&peer->xmt);
msyslog(LOG_ERR, "buffer overflow %u", sendlen);
exit (-1);
}
+ peer->t21_bytes = sendlen;
sendpkt(&peer->srcadr, peer->dstadr, sys_ttl[peer->ttl], &xpkt,
sendlen);
#ifdef OPENSSL
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d index %d\n",
+ printf("transmit: at %ld %s->%s mode %d keyid %08x len %d index %d\n",
current_time, peer->dstadr ?
ntoa(&peer->dstadr->sin) : "-",
- ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
- authlen, authlen, peer->keynumber);
+ ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen,
+ peer->keynumber);
#endif
-#else
+#else /* OPENSSL */
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
+ printf("transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
current_time, peer->dstadr ?
ntoa(&peer->dstadr->sin) : "-",
- ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen -
- authlen, authlen);
+ ntoa(&peer->srcadr), peer->hmode, xkeyid, sendlen);
#endif
#endif /* OPENSSL */
}
int mask /* restrict mask */
)
{
- struct pkt xpkt; /* transmit packet structure */
- struct pkt *rpkt; /* receive packet structure */
- l_fp xmt_ts; /* timestamp */
- l_fp xmt_tx; /* timestamp after authent */
+ struct pkt xpkt; /* transmit packet structure */
+ struct pkt *rpkt; /* receive packet structure */
+ l_fp xmt_ts; /* timestamp */
+ l_fp xmt_tx; /* timestamp after authent */
int sendlen, authlen;
#ifdef OPENSSL
u_int32 temp32;
/*
* This is an orphan parent. Show leap synchronized, orphan
- * stratum, loopack reference ID and zero root delay.
+ * stratum, loopback reference ID and zero root delay.
*/
} else {
xpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING,
sendlen);
#ifdef DEBUG
if (debug)
- printf("transmit: at %ld %s->%s mode %d\n",
+ printf("transmit: at %ld %s->%s mode %d len %d\n",
current_time, stoa(&rbufp->dstadr->sin),
- stoa(&rbufp->recv_srcadr), xmode);
+ stoa(&rbufp->recv_srcadr), xmode, sendlen);
#endif
return;
}
&rbufp->recv_srcadr, xkeyid, 0, 2);
temp32 = CRYPTO_RESP;
rpkt->exten[0] |= htonl(temp32);
- sendlen += crypto_xmit(&xpkt,
- &rbufp->recv_srcadr, sendlen,
- (struct exten *)rpkt->exten, cookie);
+ crypto_xmit(&xpkt, &rbufp->recv_srcadr,
+ &sendlen, (struct exten *)rpkt->exten,
+ cookie);
} else {
session_key(&rbufp->dstadr->sin,
&rbufp->recv_srcadr, xkeyid, cookie, 2);
authtrust(xkeyid, 0);
#endif /* OPENSSL */
get_systime(&xmt_tx);
- if (sendlen > sizeof(xpkt)) {
- msyslog(LOG_ERR, "buffer overflow %u", sendlen);
- exit (-1);
- }
sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, 0, &xpkt, sendlen);
/*
#ifdef DEBUG
if (debug)
printf(
- "transmit: at %ld %s->%s mode %d keyid %08x len %d mac %d\n",
+ "transmit: at %ld %s->%s mode %d keyid %08x len %d\n",
current_time, ntoa(&rbufp->dstadr->sin),
- ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen -
- authlen, authlen);
+ ntoa(&rbufp->recv_srcadr), xmode, xkeyid, sendlen);
#endif
}
}
value_free(&peer->sndval);
peer->keynumber = 0;
+ peer->flags &= ~FLAG_ASSOC;
#ifdef DEBUG
if (debug)
printf("key_expire: at %lu\n", current_time);
/*
* Fill in the sys_* stuff. Default is don't listen to
- * broadcasting, authenticate.
+ * broadcasting, require authentication.
*/
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
sys_peer = NULL;
sys_rootdelay = 0;
sys_rootdispersion = 0;
+ L_CLR(&sys_reftime);
+ sys_jitter = 0;
+ sys_peer = NULL;
+
memcpy(&sys_refid, "INIT", 4);
sys_precision = (s_char)default_get_precision();
- sys_jitter = LOGTOD(sys_precision);
sys_orphandelay = (double)(ntp_random() & 0xffff) / 65536. *
sys_maxdist;
- L_CLR(&sys_reftime);
- sys_peer = NULL;
- sys_survivors = 0;
get_systime(&dummy);
+ sys_survivors = 0;
sys_manycastserver = 0;
sys_bclient = 0;
sys_bdelay = DEFBROADDELAY;
sys_ttl[i] = (u_char)((i * 256) / MAX_TTL);
sys_ttlmax = i;
}
-#ifdef OPENSSL
- sys_automax = 1 << NTP_AUTOMAX;
-#endif /* OPENSSL */
pps_enable = 0;
stats_control = 1;
}
volatile int interface_interval = 300; /* update interface every 5 minutes as default */
/*
- * Alarm flag. The mainline code imports this.
+ * Alarm flag. The mainline code imports this.
*/
volatile int alarm_flag;
/*
- * The counters
+ * The counters and timeouts
*/
-static u_long adjust_timer; /* second timer */
-static u_long keys_timer; /* minute timer */
-static u_long stats_timer; /* stats timer */
-static u_long huffpuff_timer; /* huff-n'-puff timer */
-static u_long interface_timer; /* interface update timer */
+static u_long adjust_timer; /* second timer */
+static u_long stats_timer; /* stats timer */
+static u_long huffpuff_timer; /* huff-n'-puff timer */
+static u_long interface_timer; /* interface update timer */
#ifdef OPENSSL
-static u_long revoke_timer; /* keys revoke timer */
-u_char sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
+static u_long revoke_timer; /* keys revoke timer */
+u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */
+static u_long keys_timer; /* session key timer */
+u_long sys_automax = NTP_AUTOMAX; /* session key timeout */
#endif /* OPENSSL */
/*
volatile u_long alarm_overflow;
#define MINUTE 60
-#define HOUR (60 * 60)
+#define HOUR (60 * MINUTE)
+#define DAY (24 * HOUR)
u_long current_time; /* seconds since startup */
#endif
/*
- * timer - dispatch anyone who needs to be
+ * timer - event timer
*/
void
timer(void)
char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
#endif /* OPENSSL */
u_int n;
-
- current_time += (1<<EVENT_TIMEOUT);
+ l_fp now;
/*
- * Adjustment timeout first.
+ * The basic timerevent is one second. This is used to adjust
+ * the system clock in time and frequency, implement the
+ * kiss-o'-deatch function and implement the association
+ * polling function..
*/
+ current_time += (1<<EVENT_TIMEOUT);
if (adjust_timer <= current_time) {
adjust_timer += 1;
adj_host_clock();
sys_leap = LEAP_ADDSECOND;
leap_sec--;
if (leap_sec == 0) {
+ get_systime(&now);
+ msyslog(LOG_NOTICE, "timer: leap second at %u",
+ now.l_ui);
sys_leap = LEAP_NOWARNING;
if (sys_tai > 0) {
sys_tai++;
- msyslog(LOG_NOTICE, "TAI offset %d s",
- sys_tai);
#ifdef KERNEL_PLL
if (!(pll_control && kern_enable))
step_systime(-1.0);
#else /* KERNEL_PLL */
step_systime(-1.0);
#endif /* KERNEL_PLL */
+ msyslog(LOG_NOTICE,
+ "timer: TAI offset %d s", sys_tai);
}
- msyslog(LOG_NOTICE, "leap second %+.6f s",
- -1.0);
}
}
/*
- * Garbage collect expired keys.
- */
- if (keys_timer <= current_time) {
- keys_timer += MINUTE;
- auth_agekeys();
- }
-
- /*
- * Huff-n'-puff filter
+ * Update huff-n'-puff filter.
*/
if (huffpuff_timer <= current_time) {
huffpuff_timer += HUFFPUFF;
}
#ifdef OPENSSL
+
+ /*
+ * Garbage collect expired keys.
+ */
+ if (keys_timer <= current_time) {
+ keys_timer += sys_automax;
+ auth_agekeys();
+ }
+
/*
- * Garbage collect old keys and generate new private value
+ * Garbage collect key list and generate new private value. The
+ * timer runs only after initial synchronization and fires about
+ * once per day.
*/
- if (revoke_timer <= current_time) {
- revoke_timer += RANDPOLL(sys_revoke);
+ if (revoke_timer <= current_time && sys_leap !=
+ LEAP_NOTINSYNC) {
+ revoke_timer += sys_revoke;
expire_all();
- sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
+ sprintf(statstr, "refresh ts %u",
+ ntohl(hostval.tstamp));
record_crypto_stats(NULL, statstr);
#ifdef DEBUG
if (debug)
#endif /* OPENSSL */
/*
- * interface update timer
+ * Interface update timer
*/
if (interface_interval && interface_timer <= current_time) {
- timer_interfacetimeout(current_time + interface_interval);
+ timer_interfacetimeout(current_time +
+ interface_interval);
#ifdef DEBUG
- if (debug)
- printf("timer: interface update\n");
+ if (debug > 1)
+ printf("timer: interface update\n");
#endif
- interface_update(NULL, NULL);
+ interface_update(NULL, NULL);
}
/*
- * Finally, periodically write stats.
+ * Finally, write stats once per hour.
*/
if (stats_timer <= current_time) {
- if (stats_timer != 0)
- write_stats();
- stats_timer += stats_write_period;
+ stats_timer += HOUR;
+ write_stats();
}
}
char *leapseconds_file_name; /* leapseconds file name */
char *stats_drift_file; /* frequency file name */
static char *stats_temp_file; /* temp frequency file name */
-int stats_write_period = 3600; /* seconds between writes. */
+static double wander_resid; /* wander threshold */
+double wander_threshold = 1e-7; /* initial wander threshold */
/*
* Statistics file stuff
sys_poll);
record_sys_stats();
+ clock_stepcnt = 0;
ftemp = fabs(prev_drift_comp - drift_comp);
prev_drift_comp = drift_comp;
if (ftemp > clock_phi)
return;
if (stats_drift_file != 0) {
- if (state == 4) {
+
+ /*
+ * When the frequency file is written, initialize the
+ * wander threshold to a configured initial value.
+ * Thereafter reduce it by a factor of 0.85. When it
+ * drops below the frequency wander, write the frequency
+ * file. This adapts to the prevailing wander yet
+ * minimizes the file writes.
+ */
+ wander_resid *= 0.8;
+#ifdef DEBUG
+ if (debug)
+ printf("write_stats: wander %.6lf thresh %.6lf, freq %.6lf\n",
+ clock_stability * 1e6, wander_resid * 1e6,
+ drift_comp * 1e6);
+#endif
+ if (state == 4 && clock_stability > wander_resid) {
+ wander_resid = wander_threshold;
if ((fp = fopen(stats_temp_file, "w")) == NULL)
{
msyslog(LOG_ERR, "can't open %s: %m",
#endif /* SYS_WINNT */
#ifndef NO_RENAME
- (void) rename(stats_temp_file, stats_drift_file);
+ (void) rename(stats_temp_file,
+ stats_drift_file);
#else
/* we have no rename NFS of ftp in use */
if ((fp = fopen(stats_drift_file, "w")) == NULL)
break;
}
if (fscanf(fp, "%lf", &old_drift) != 1) {
- msyslog(LOG_ERR, "Frequency format error in %s",
+ msyslog(LOG_ERR, "frequency format error in %s",
stats_drift_file);
old_drift = 1e9;
fclose(fp);
)
{
FILE *str; /* file handle */
- char buf[NTP_MAXSTRLEN]; /* file line buffer */
+ char buf[NTP_MAXSTRLEN]; /* file line buffer */
u_long leapsec; /* NTP time at leap */
u_long expire; /* NTP time when file expires */
int offset; /* TAI offset at leap (s) */
NTP_REQUIRE(cp != NULL);
/*
- * Open the file and discard comment lines. If the first
- * character of the file name is not '/', prepend the keys
- * directory string. If the file is not found, ignore; if found
- * with errors, report to the log and ignore.
+ * Open the leapseconds file. If the first character of the
+ * file name is not '/', prepend the keys directory string. If
+ * the file is not found, ignore; if found with errors, report
+ * to the log and ignore.
*/
if (*cp == '/')
strcpy(filename, cp);
* seconds at the leap, the second is the TAI offset after the
* leap. The second word must equal the initial insertion of ten
* seconds on 1 January 1972 plus one second for each succeeding
- * insertion.
+ * insertion. The line beginning with #@ contains the file
+ * expiration time in NTP seconds.
*/
i = TAI_1972;
expire = 0;
1)
break;
}
+ continue;
}
- continue;
if (sscanf(buf, "%lu %d", &leapsec, &offset) != 2)
continue;
}
fclose(str);
if (dp != NULL) {
- msyslog(LOG_INFO, "leapseconds %s error", cp);
+ msyslog(LOG_INFO, "leap_file: %s error", cp);
} else {
- sys_tai = offset;
+ leap_tai = offset;
leap_ins = leapsec;
leap_expire = expire;
msyslog(LOG_INFO,
- "TAI offset %d s at %lu file %s expire %lu",
- sys_tai, leap_ins, cp, leap_expire);
+ "leap_file: %s TAI offset %d s insert %lu expire %lu",
+ cp, leap_tai, leap_ins, leap_expire);
}
}
up = (struct actsunit *)pp->unitptr;
#ifdef DEBUG
ioctl(pp->io.fd, TIOCMGET, (char *)&modem);
- sprintf(tbuf, "acts: %04x (%d %d) %lu %s", modem, up->state,
+ sprintf(tbuf, "acts: %04x (%d %d) %d %s", modem, up->state,
up->timer, strlen(pp->a_lastcode), pp->a_lastcode);
if (debug)
printf("%s\n", tbuf);