Compare commits

...

51 Commits

Author SHA1 Message Date
Miroslav Lichvar
711cda6aed Update NEWS 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
0c738d84af Update copyright years 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
be1e1dc441 Fix password handling in chronyc 2012-02-28 13:11:56 +01:00
Miroslav Lichvar
2a305d8e16 Fix compiler warnings 2012-02-27 16:08:21 +01:00
Miroslav Lichvar
15b6ab77ea Update configure help text 2012-02-27 15:45:27 +01:00
Miroslav Lichvar
6199822783 Test leap second timezone on start 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
0b72b2940a Update documentation 2012-02-27 13:28:14 +01:00
Miroslav Lichvar
d4ce3f19c3 Reschedule fast slew timeout on offset change 2012-02-24 16:26:53 +01:00
Miroslav Lichvar
824e86a82f Add leap status to tracking log and report 2012-02-24 11:06:20 +01:00
Miroslav Lichvar
2a5c045c3d Add support for reading leap second data from tz database
leapsectz directive is used to set the name of the timezone in the
system tz database which chronyd can use to find out when will the next
leap second occur.  It will periodically check if dates Jun 30 23:59:60
and Dec 31 23:59:60 are valid in that timezone. This is mainly useful
with reference clocks which don't provide the leap second information.
It is not necessary to restart chronyd if the tz database is updated
with a new leap second at least 12 hours before the event.
2012-02-24 11:06:20 +01:00
Miroslav Lichvar
f7c65a4b88 Add maxchange directive
This directive sets the maximum allowed offset corrected on a clock
update.  The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock.  When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then chronyd will give up
and exit (a negative value can be used to never exit).  In both cases
a message is sent to syslog.
2012-02-21 14:34:09 +01:00
Miroslav Lichvar
a8956f2f56 Move refclock slew and dispersion handler init 2012-02-14 18:13:15 +01:00
Miroslav Lichvar
91c9f84a01 Step system time in RTC preinit only with offsets over 1 second 2012-02-14 17:49:55 +01:00
Miroslav Lichvar
2be89bc6f2 Fix last commit 2012-02-14 14:47:57 +01:00
Miroslav Lichvar
d6c447a445 Better estimate RTC offset right after trim 2012-02-13 16:54:18 +01:00
Miroslav Lichvar
a60586eaad Return success on empty command 2012-02-10 18:30:11 +01:00
Miroslav Lichvar
d77356837a Support passwords encoded in HEX 2012-02-09 16:56:17 +01:00
Miroslav Lichvar
d6842301dd Update reported RMS offset quickly on start 2012-02-08 14:30:35 +01:00
Miroslav Lichvar
19b3c5be26 Extend tracking, sources and activity reports 2012-02-03 17:22:53 +01:00
Miroslav Lichvar
5fb5a89f02 Use +/- when logging skew on start 2012-02-03 17:22:52 +01:00
Miroslav Lichvar
9367e7b9af Fix logged offset in manual reference 2012-02-03 15:23:25 +01:00
Miroslav Lichvar
6673cadfa2 Check if struct in6_pktinfo is usable 2012-01-05 15:11:54 +01:00
Miroslav Lichvar
b485051b65 Fix reported number of runs to correspond to reported number of samples 2011-11-28 11:19:48 +01:00
Miroslav Lichvar
9a01ccc07f Add corrtimeratio directive
The corrtimeratio directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval).  Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.

Increasing corrtimeratio makes the overall frequency error of
the system clock smaller, but increases the overall time error as
the corrections will take longer.

By default, the ratio is 1, which means the duration of an average
correction will be close to the update interval.
2011-11-15 18:25:49 +01:00
Miroslav Lichvar
1b8deaf354 Control offset correction rate in Linux driver
The kernel currently doesn't support a linear adjustment with
programmable rate, extend the use of the kernel PLL with locked
frequency instead.

Set the PLL time constant according to the correction time corresponding
to the correction rate and corrected offset.

On kernels with nano PLL adjtime() is no longer used.
2011-11-15 12:30:59 +01:00
Miroslav Lichvar
c7d0232bb1 Introduce offset correction rate
We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.

Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval (assuming linear adjustment). The offset and the
time needed to make the correction are inversely proportional.

This is only a suggestion and it's up to the system driver how the
adjustment will be executed.
2011-11-15 12:27:44 +01:00
Miroslav Lichvar
79e5f2be13 Include clock steps in calculated reference update interval 2011-11-14 15:55:19 +01:00
Miroslav Lichvar
9ab181eb9c Document extended keyfile format and authhash command 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
3cc6021e03 Add support for libtomcrypt 2011-11-02 13:53:00 +01:00
Miroslav Lichvar
375389fa1e Add support for NSS library
This adds support for the NSSLOWHASH API provided by the freebl3
library.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
777303f130 Add support for different authentication hashes
Allow different hash functions to be used in the NTP and cmdmon
protocols. This breaks the cmdmon protocol compatibility. Extended key
file format is used to specify the hash functions for chronyd and new
authhash command is added to chronyc. MD5 is the default and the only
function included in the chrony source code, other functions will be
available from libraries.
2011-11-02 13:53:00 +01:00
Miroslav Lichvar
6015f99d98 Fix writing rtc data when called soon after trimrtc 2011-09-14 18:03:01 +02:00
Miroslav Lichvar
78fc17c661 Use ADJ_OFFSET_SS_READ mode only with kernels 2.6.28 and later 2011-09-13 16:39:08 +02:00
Miroslav Lichvar
d42addf746 Add macro for maximum fastslew timeout 2011-09-01 18:08:45 +02:00
Miroslav Lichvar
f570eb76b3 Check for timepps.h also in sys directory 2011-09-01 17:06:54 +02:00
Miroslav Lichvar
cc3f5962b8 Merge NCR_Process functions 2011-09-01 16:25:13 +02:00
Miroslav Lichvar
6ab3d1daa3 Add support for ADJ_SETOFFSET mode
This adjtimex mode allows precise stepping of the system clock.
2011-09-01 15:31:11 +02:00
Miroslav Lichvar
b088b70f82 Check sample ordering on accumulation
If the newly accumulated sample is not newer than than the last one,
discard the source history and start from scratch. This can happen after
loading an invalid dump or when the system clock was stepped.
2011-08-31 18:36:10 +02:00
Miroslav Lichvar
fbbb6bbc00 Update gpsd SOCK example in documentation 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
5c36342958 Use initial delay also for burst samples 2011-08-26 18:34:00 +02:00
Miroslav Lichvar
f1a0cacc5a Make scheduling loop detector less sensitive
It could be triggered by delayed name resolving as it adds multiple new
timeouts which can be called in the same dispatching if the DNS responses
are slower than initial delay and sampling separation.

Compare number of dispatched events also with current number of
timeouts.
2011-08-26 18:34:00 +02:00
Miroslav Lichvar
1d2a0856b4 Wait in foreground process until daemon is fully initialized
Exit when all sockets are ready and initstepslew command and rtc step
are completed. Also, in case of a fatal error, print the error message
and exit with a non-zero status.
2011-08-26 18:31:26 +02:00
Miroslav Lichvar
7fb50d9a3e Always use delayed name resolving for server and peer directives
This significantly reduces initialization time.
2011-08-26 14:22:10 +02:00
Miroslav Lichvar
919b5b5a7d Change working directory to / 2011-08-25 18:49:34 +02:00
Miroslav Lichvar
1e35b26826 Read config after opening syslog 2011-08-25 14:46:16 +02:00
Miroslav Lichvar
27b0b5824a Disable maxdelayratio test by default
Change default maxdelayratio from 16384.0 to 0.0. A value larger
than 1.0 is required to enable the test.
2011-08-12 15:38:05 +02:00
Miroslav Lichvar
1d72d22bc5 Match skew in ntp_core to sourcestats skew 2011-08-12 15:38:05 +02:00
Miroslav Lichvar
e0c9ed44f9 Limit skew used in NTP test4
With iburst and very jittery sources the source skew can reach very high
values which makes the NTP test4 fail even with relatively small delays.
Limit the skew to 2000 ppm to avoid getting state where a source is unable
to accept more than first three iburst samples.
2011-08-12 15:37:58 +02:00
Miroslav Lichvar
411f4da340 Fix creating logdir 2011-08-11 14:15:15 +02:00
Miroslav Lichvar
4fac84098e Update NEWS 2011-07-13 14:55:28 +02:00
Miroslav Lichvar
21b2063a6f Retry on permanent DNS error by default 2011-07-13 14:49:22 +02:00
52 changed files with 1796 additions and 713 deletions

View File

@@ -34,27 +34,24 @@ CPPFLAGS = @CPPFLAGS@
DESTDIR= DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \ OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \ sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \ sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o md5.o keys.o \ logging.o conf.o cmdmon.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \ nameserv.o acquire.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \ cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_shm.o refclock_sock.o \ broadcast.o refclock.o refclock_shm.o refclock_sock.o \
refclock_pps.o tempcomp.o refclock_pps.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@ EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \ CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o pktlength.o util.o $(HASH_OBJ)
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS) ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
SRCS = $(patsubst %.o,%.c,$(OBJS))
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ LIBS = @LIBS@
@@ -67,14 +64,17 @@ EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
all : chronyd chronyc all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS) chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) @HASH_LINK@ $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS) chronyc : $(CLI_OBJS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS) $(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ @HASH_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
client.o : client.c client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $< $(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean distclean : clean
-rm -f Makefile -rm -f Makefile

17
NEWS
View File

@@ -1,3 +1,19 @@
New in version 1.27
===================
* Support for stronger keys via NSS or libtomcrypt library
* Support reading leap second data from tz database
* Support for precise clock stepping on Linux
* Make offset corrections smoother on Linux
* Add corrtimeratio and maxchange directives
* Extend tracking, sources and activity reports
* Wait in foreground process until daemon is fully initialized
* Fix crash with slow name resolving
* Fix iburst with jittery sources
* Fix offset stored in rtc data right after trimrtc
* Don't use readonly adjtime on Linux kernels before 2.6.28
* Changed chronyc protocol, incompatible with older versions
New in version 1.26 New in version 1.26
=================== ===================
@@ -6,6 +22,7 @@ New in version 1.26
* Accept NTP packets with versions 4, 3 and 2 * Accept NTP packets with versions 4, 3 and 2
* Cope with unexpected backward time jumps * Cope with unexpected backward time jumps
* Don't reset kernel frequency on start without drift file * Don't reset kernel frequency on start without drift file
* Retry on permanent DNS error by default
* Add waitsync command * Add waitsync command
New in version 1.25 New in version 1.25

View File

@@ -708,7 +708,7 @@ process_measurements(void)
LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)", LOG(LOGS_INFO, LOGF_Acquire, "System's initial offset : %.6f seconds %s of true (slew)",
fabs(estimated_offset), fabs(estimated_offset),
(estimated_offset >= 0) ? "fast" : "slow"); (estimated_offset >= 0) ? "fast" : "slow");
LCL_AccumulateOffset(estimated_offset); LCL_AccumulateOffset(estimated_offset, 0.0);
} }
} else { } else {

28
candm.h
View File

@@ -31,6 +31,7 @@
#include "sysincl.h" #include "sysincl.h"
#include "addressing.h" #include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is /* This is the default port to use for CANDM, if no alternative is
defined */ defined */
@@ -368,9 +369,11 @@ typedef struct {
and used also instead of integer microseconds, new commands: modify stratum, and used also instead of integer microseconds, new commands: modify stratum,
modify polltarget, modify maxdelaydevratio, reselect, reselectdistance modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
Version 5 : auth data moved to the end of the packet to allow hashes with
different sizes, extended sources, tracking and activity reports
*/ */
#define PROTO_VERSION_NUMBER 4 #define PROTO_VERSION_NUMBER 5
/* The oldest protocol version that is compatible enough with /* The oldest protocol version that is compatible enough with
the current version to report a version mismatch */ the current version to report a version mismatch */
@@ -390,7 +393,6 @@ typedef struct {
uint32_t sequence; /* Client's sequence number */ uint32_t sequence; /* Client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */ uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */ uint32_t token; /* Command token (to prevent replay attack) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union { union {
REQ_Online online; REQ_Online online;
@@ -435,6 +437,10 @@ typedef struct {
REQ_ReselectDistance reselect_distance; REQ_ReselectDistance reselect_distance;
} data; /* Command specific parameters */ } data; /* Command specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request; } CMD_Request;
/* ================================================== */ /* ================================================== */
@@ -503,12 +509,17 @@ typedef struct {
#define RPY_SD_ST_CANDIDATE 4 #define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLYER 5 #define RPY_SD_ST_OUTLYER 5
#define RPY_SD_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
typedef struct { typedef struct {
IPAddr ip_addr; IPAddr ip_addr;
uint16_t poll; uint16_t poll;
uint16_t stratum; uint16_t stratum;
uint16_t state; uint16_t state;
uint16_t mode; uint16_t mode;
uint16_t flags;
uint16_t reachability;
uint32_t since_sample; uint32_t since_sample;
Float orig_latest_meas; Float orig_latest_meas;
Float latest_meas; Float latest_meas;
@@ -519,14 +530,18 @@ typedef struct {
typedef struct { typedef struct {
uint32_t ref_id; uint32_t ref_id;
IPAddr ip_addr; IPAddr ip_addr;
uint32_t stratum; uint16_t stratum;
uint16_t leap_status;
Timeval ref_time; Timeval ref_time;
Float current_correction; Float current_correction;
Float last_offset;
Float rms_offset;
Float freq_ppm; Float freq_ppm;
Float resid_freq_ppm; Float resid_freq_ppm;
Float skew_ppm; Float skew_ppm;
Float root_delay; Float root_delay;
Float root_dispersion; Float root_dispersion;
Float last_update_interval;
int32_t EOR; int32_t EOR;
} RPY_Tracking; } RPY_Tracking;
@@ -614,6 +629,7 @@ typedef struct {
int32_t offline; int32_t offline;
int32_t burst_online; int32_t burst_online;
int32_t burst_offline; int32_t burst_offline;
int32_t unresolved;
int32_t EOR; int32_t EOR;
} RPY_Activity; } RPY_Activity;
@@ -632,8 +648,6 @@ typedef struct {
uint32_t utoken; /* Unique token per incarnation of daemon */ uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully uint32_t token; /* New command token (only if command was successfully
authenticated) */ authenticated) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union { union {
RPY_Null null; RPY_Null null;
RPY_N_Sources n_sources; RPY_N_Sources n_sources;
@@ -649,6 +663,10 @@ typedef struct {
RPY_Activity activity; RPY_Activity activity;
} data; /* Reply specific parameters */ } data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply; } CMD_Reply;
/* ================================================== */ /* ================================================== */

View File

@@ -1173,6 +1173,7 @@ directives can occur in any order in the file.
* cmdallow directive:: Give control access to chronyc on other computers * cmdallow directive:: Give control access to chronyc on other computers
* cmddeny directive:: Deny control access to chronyc on other computers * cmddeny directive:: Deny control access to chronyc on other computers
* commandkey directive:: Set runtime command key * commandkey directive:: Set runtime command key
* corrtimeratio directive:: Set correction time ratio
* cmdport directive:: Set port to use for runtime commanding * cmdport directive:: Set port to use for runtime commanding
* deny directive:: Deny access to NTP clients * deny directive:: Deny access to NTP clients
* driftfile directive:: Specify location of file containing drift data * driftfile directive:: Specify location of file containing drift data
@@ -1182,6 +1183,7 @@ directives can occur in any order in the file.
* include directive:: Include a configuration file * include directive:: Include a configuration file
* initstepslew directive:: Trim the system clock on boot-up. * initstepslew directive:: Trim the system clock on boot-up.
* keyfile directive:: Specify location of file containing keys * keyfile directive:: Specify location of file containing keys
* leapsectz directive:: Read leap second data from tz database
* linux_hz directive:: Define a non-standard value of the kernel HZ constant * linux_hz directive:: Define a non-standard value of the kernel HZ constant
* linux_freq_scale directive:: Define a non-standard value to compensate the kernel frequency bias * linux_freq_scale directive:: Define a non-standard value to compensate the kernel frequency bias
* local directive:: Allow unsynchronised machine to act as server * local directive:: Allow unsynchronised machine to act as server
@@ -1191,6 +1193,7 @@ directives can occur in any order in the file.
* logdir directive:: Specify directory for logging * logdir directive:: Specify directory for logging
* mailonchange directive:: Send email if a clock correction above a threshold occurs * mailonchange directive:: Send email if a clock correction above a threshold occurs
* makestep directive:: Step system clock if large correction is needed * makestep directive:: Step system clock if large correction is needed
* maxchange directive:: Set maximum allowed offset
* manual directive:: Allow manual entry using chronyc's settime cmd. * manual directive:: Allow manual entry using chronyc's settime cmd.
* maxclockerror directive:: Set maximum frequency error of local clock * maxclockerror directive:: Set maximum frequency error of local clock
* maxupdateskew directive:: Stop bad estimates upsetting machine clock * maxupdateskew directive:: Stop bad estimates upsetting machine clock
@@ -1493,6 +1496,38 @@ cmdport 257
This would make @code{chronyd} use 257/udp as its command port. This would make @code{chronyd} use 257/udp as its command port.
(@code{chronyc} would need to be run with the @code{-p 257} switch to (@code{chronyc} would need to be run with the @code{-p 257} switch to
inter-operate correctly). inter-operate correctly).
@c }}}
@c {{{ corrtimeratio
@node corrtimeratio directive
@subsection corrtimeratio
When @code{chronyd} makes a time correction, it controls how quickly
the system clock is slewed (so far only on Linux). This rate
temporarily affects the frequency error of the system clock.
The @code{corrtimeratio} directive controls the ratio between the
duration in which the clock is slewed for an average correction
according to the source history and the interval in which the
corrections are done (usually the NTP polling interval). Corrections
larger than the average take less time and smaller corrections take
more time, the amount of the correction and the correction time are
inversely proportional.
Increasing @code{corrtimeratio} makes the overall frequency error of
the system clock smaller, but increases the overall time error as
the corrections will take longer.
By default, the ratio is 1, which means the duration of an average
correction will be close to the update interval.
The syntax is
@example
corrtimeratio 10
@end example
The current remaining correction is shown in the @code{tracking} report
(@pxref{tracking command}) as the @code{System time} value.
@c }}} @c }}}
@c {{{ deny @c {{{ deny
@node deny directive @node deny directive
@@ -1694,21 +1729,50 @@ pairs. The format of the file is shown below
@example @example
10 tulip 10 tulip
11 hyacinth 11 hyacinth
20 crocus 20 MD5 ASCII:crocus
25 iris 25 SHA1 HEX:1dc764e0791b11fa67efc7ecbc4b0d73f68a070c
... ...
@end example @end example
Each line consists of an ID and a password. The ID can be any Each line consists of an ID, a name of authentication hash function (optional)
unsigned integer in the range 0 through 2**32-1. The password can be and a password. The ID can be any unsigned integer in the range 0 through
any string of characters not containing a space. 2**32-1. The hash function is MD5 by default, depending on how was
@code{chronyd} compiled other allowed hash functions may be SHA1, SHA256,
For NTP use, the MD5 authentication scheme is always used. This must be SHA384, SHA512, RMD128, RMD160, RMD256, RMD320, TIGER and WHIRLPOOL. The
borne in mind if @code{chronyd} is to inter-operate in authenticated password can be encoded as a string of characters not containing a space with
mode with @code{xntpd} running on other computers. optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
prefix.
The ID for the chronyc authentication key is specified with the The ID for the chronyc authentication key is specified with the
commandkey command (see earlier). commandkey command (see earlier).
@c }}}
@c {{{ leapsectz
@node leapsectz directive
@subsection leapsectz
This directive is used to set the name of the timezone in the system
tz database which @code{chronyd} can use to find out when will the
next leap second occur. It will periodically check if the times
23:59:59 and 23:59:60 are valid on Jun 30 and Dec 31 in the timezone.
A useful timezone is @code{right/UTC}.
This is mainly useful with reference clocks which don't provide the
leap second information. It is not necessary to restart
@code{chronyd} if the tz database is updated with a new leap second at
least 12 hours before the event.
An example of the command is
@example
leapsectz right/UTC
@end example
The following shell command verifies that the timezone contains leap
seconds and can be used with this directive
@example
$ TZ=right/UTC date -d 'Dec 31 2008 23:59:60'
Wed Dec 31 23:59:60 UTC 2008
@end example
@c }}} @c }}}
@c {{{ local @c {{{ local
@node local directive @node local directive
@@ -1859,9 +1923,9 @@ expressed in UTC, not the local time zone.
IP address of server/peer from which measurement comes [158.152.1.76] IP address of server/peer from which measurement comes [158.152.1.76]
@item @item
Leap status (@code{N} means normal, @code{+} means that the last minute Leap status (@code{N} means normal, @code{+} means that the last minute
of today has 61 seconds, @code{-} means that the last minute of the day of the current month has 61 seconds, @code{-} means that the last minute
has 59 seconds, @code{?} means the remote computer is not currently of the month has 59 seconds, @code{?} means the remote computer is not
synchronised.) [N] currently synchronised.) [N]
@item @item
Stratum of remote computer. [2] Stratum of remote computer. [2]
@item @item
@@ -1966,7 +2030,7 @@ An example line (which actually appears as a single line in the file)
from the tracking log file is shown below. from the tracking log file is shown below.
@example @example
1998-07-22 05:40:50 158.152.1.76 3 340.529 1.606 1.046e-03 2012-02-23 05:40:50 158.152.1.76 3 340.529 1.606 1.046e-03 N
@end example @end example
The columns are as follows (the quantities in square brackets are the The columns are as follows (the quantities in square brackets are the
@@ -1974,7 +2038,7 @@ values from the example line above) :
@enumerate 1 @enumerate 1
@item @item
Date [1998-07-22] Date [2012-02-03]
@item @item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone. expressed in UTC, not the local time zone.
@@ -1992,6 +2056,10 @@ The error bounds on the frequency (in ppm) [1.606]
The estimated local offset at the epoch (which is rapidly corrected by The estimated local offset at the epoch (which is rapidly corrected by
slewing the local clock. (In seconds, positive indicates the local slewing the local clock. (In seconds, positive indicates the local
system is fast of UTC). [1.046e-3] system is fast of UTC). [1.046e-3]
@item
Leap status (@code{N} means normal, @code{+} means that the last minute
of this month has 61 seconds, @code{-} means that the last minute of the month
has 59 seconds, @code{?} means the clock is not currently synchronised.) [N]
@end enumerate @end enumerate
A banner is periodically written to the log file to indicate the A banner is periodically written to the log file to indicate the
@@ -2075,8 +2143,8 @@ Sequence number of driver poll within one polling interval for raw
samples, or @code{-} for filtered samples. [7] samples, or @code{-} for filtered samples. [7]
@item @item
Leap status (@code{N} means normal, @code{+} means that the last minute Leap status (@code{N} means normal, @code{+} means that the last minute
of today has 61 seconds, @code{-} means that the last minute of the day of the current month has 61 seconds, @code{-} means that the last minute
has 59 seconds). [N] of the month has 59 seconds). [N]
@item @item
Flag indicating whether the sample comes from PPS source. (1 for yes, Flag indicating whether the sample comes from PPS source. (1 for yes,
0 for no, or @code{-} for filtered sample). [1] 0 for no, or @code{-} for filtered sample). [1]
@@ -2210,6 +2278,27 @@ makestep 1000 10
This would step system clock if the adjustment is larger than 1000 This would step system clock if the adjustment is larger than 1000
seconds, but only in the first ten clock updates. seconds, but only in the first ten clock updates.
@c }}} @c }}}
@c {{{ maxchange
@node maxchange directive
@subsection maxchange
This directive sets the maximum allowed offset corrected on a clock
update. The check is performed only after the specified number of
updates to allow a large initial adjustment of the system clock. When
an offset larger than the specified maximum occurs, it will be ignored
for the specified number of times and then @code{chronyd} will give up
and exit (a negative value can be used to never exit). In both cases
a message is sent to syslog.
An example of the use of this directive is
@example
maxchange 1000 1 2
@end example
After the first clock update, @code{chronyd} will check the offset on
every clock update, it will ignore two adjustments larger than 1000
seconds and exit on another one.
@c }}}
@c {{{ manual @c {{{ manual
@node manual directive @node manual directive
@subsection manual @subsection manual
@@ -2390,7 +2479,7 @@ protocol. The path where the socket should be created is described in the
@code{gpsd(8)} man page. For example: @code{gpsd(8)} man page. For example:
@example @example
refclock SOCK /tmp/chrony.tty0.sock refclock SOCK /var/run/chrony.ttyS0.sock
@end example @end example
@end table @end table
@@ -2694,7 +2783,7 @@ NTP client mode datagram.
The NTP protocol supports the inclusion of checksums in the packets, to The NTP protocol supports the inclusion of checksums in the packets, to
prevent computers having their system time upset by rogue packets being prevent computers having their system time upset by rogue packets being
sent to them. The checksums are generated as a function of a password, sent to them. The checksums are generated as a function of a password,
using the MD5 algorithm. using the cryptographic hash function set in the key file.
The association between key numbers and passwords is contained in the The association between key numbers and passwords is contained in the
keys file, defined by the keyfile command. keys file, defined by the keyfile command.
@@ -2889,6 +2978,7 @@ password:
@itemize @bullet @itemize @bullet
@item @code{activity} @item @code{activity}
@item @code{authhash}
@item @code{dns} @item @code{dns}
@item @code{exit} @item @code{exit}
@item @code{help} @item @code{help}
@@ -2919,6 +3009,7 @@ interface.
* add server command:: Add a new NTP server * add server command:: Add a new NTP server
* allow command:: Allowing NTP client access * allow command:: Allowing NTP client access
* allow all command:: Allowing NTP client access * allow all command:: Allowing NTP client access
* authhash command:: Set the command authentication hash function
* burst command:: Initiating a rapid set of measurements * burst command:: Initiating a rapid set of measurements
* clients command:: Show clients that have accessed the server * clients command:: Show clients that have accessed the server
* cmdaccheck command:: Verifying command client access * cmdaccheck command:: Verifying command client access
@@ -2990,7 +3081,7 @@ If the auto_offline option is used in specifying some of the servers/peers, the
@code{activity} command may be useful for detecting when all of them have @code{activity} command may be useful for detecting when all of them have
entered the offline state after the PPP link has been disconnected. entered the offline state after the PPP link has been disconnected.
The report shows the number of servers/peers in 4 states: The report shows the number of servers/peers in 5 states:
@itemize @itemize
@item @code{online} : the server/peer is currently online (i.e. assumed by @item @code{online} : the server/peer is currently online (i.e. assumed by
chronyd to be reachable) chronyd to be reachable)
@@ -3002,6 +3093,9 @@ server/peer will be returned to the online state.
@item @code{burst_offline} : a burst command has been initiated for the @item @code{burst_offline} : a burst command has been initiated for the
server/peer and is being performed; after the burst is complete, the server/peer and is being performed; after the burst is complete, the
server/peer will be returned to the offline state. server/peer will be returned to the offline state.
@item @code{unresolved} : the name of the server/peer wasn't resolved to an
address yet; this server is not visible in the @code{sources} and
@code{sourcestats} reports.
@end itemize @end itemize
@c }}} @c }}}
@c {{{ add peer @c {{{ add peer
@@ -3065,6 +3159,20 @@ directive in the configuration file.
The effect of the allow command is identical to the @code{allow all} The effect of the allow command is identical to the @code{allow all}
directive in the configuration file (@pxref{allow directive}). directive in the configuration file (@pxref{allow directive}).
@c }}} @c }}}
@c {{{ authhash
@node authhash command
@subsubsection authhash
This command sets the hash function used for authenticating user commands.
For successful authentication the hash function has to be the same as the one
set for the command key in the keys file on the server. It needs to be set
before the @code{password} command is used. The default hash function is MD5.
An example is
@example
authhash SHA1
@end example
@c }}}
@c {{{ burst @c {{{ burst
@node burst command @node burst command
@subsubsection burst @subsubsection burst
@@ -3715,6 +3823,8 @@ password on the command line is as follows
@example @example
password xyzzy password xyzzy
password ASCII:xyzzy
password HEX:78797a7a79
@end example @end example
To enter the password without it being echoed, enter To enter the password without it being echoed, enter
@@ -3728,9 +3838,10 @@ should enter the password and press return. (Note that the no-echo mode
is limited to 8 characters on SunOS 4.1 due to limitations in the system is limited to 8 characters on SunOS 4.1 due to limitations in the system
library. Other systems do not have this restriction.) library. Other systems do not have this restriction.)
The password is any string of characters not containing whitespace. It The password can be encoded as a string of characters not containing a space
has to match @code{chronyd's} currently defined command key (@pxref{commandkey with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
directive}). prefix. It has to match @code{chronyd's} currently defined command key
(@pxref{commandkey directive}).
@c }}} @c }}}
@c {{{ polltarget @c {{{ polltarget
@node polltarget command @node polltarget command
@@ -3897,11 +4008,11 @@ columns.
@example @example
@group @group
210 Number of sources = 3 210 Number of sources = 3
MS Name/IP address Stratum Poll LastRx Last sample MS Name/IP address Stratum Poll Reach LastRx Last sample
======================================================================= ===============================================================================
^+ a.b.c 3 6 47m -9491us[-6983us] +/- 159ms #* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^+ d.e.f 3 6 47m +32ms[ +35ms] +/- 274ms ^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
^* g.h.i 2 6 47m +8839us[ +11ms] +/- 214ms ^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
@end group @end group
@end example @end example
@@ -3942,10 +4053,18 @@ that a measurement is being made every 64 seconds.
@code{chronyd} automatically varies the polling rate in response to prevailing @code{chronyd} automatically varies the polling rate in response to prevailing
conditions. conditions.
@item Reach
This shows the source's reachability register printed as octal number. The
register has 8 bits and is updated on every received or missed packet from
the source. A value of 377 indicates that a valid reply was received for all
from the last eight transmissions.
@item LastRx @item LastRx
This column shows how long ago the last sample was received from the This column shows how long ago the last sample was received from the
source. This is normally in seconds. The letters @code{m}, @code{h}, source. This is normally in seconds. The letters @code{m}, @code{h},
@code{d} or @code{y} indicate minutes, hours, days or years. @code{d} or @code{y} indicate minutes, hours, days or years. A value
of 10 years indicates there were no samples received from this source
yet.
@item Last sample @item Last sample
This column shows the offset between the local clock and the source at This column shows the offset between the local clock and the source at
@@ -4046,13 +4165,18 @@ performance. An example of the output is shown below.
@example @example
Reference ID : 1.2.3.4 (a.b.c) Reference ID : 1.2.3.4 (a.b.c)
Stratum : 3 Stratum : 3
Ref time (UTC) : Sun May 17 06:13:11 1998 Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000000000 seconds fast of NTP time System time : 0.000001501 seconds slow of NTP time
Last offset : -0.000001632 seconds
RMS offset : 0.000002360 seconds
Frequency : 331.898 ppm fast Frequency : 331.898 ppm fast
Residual freq : 0.004 ppm Residual freq : 0.004 ppm
Skew : 0.154 ppm Skew : 0.154 ppm
Root delay : 0.373169 seconds Root delay : 0.373169 seconds
Root dispersion : 0.024780 seconds Root dispersion : 0.024780 seconds
Update interval : 64.2 seconds
Leap status : Normal
@end example @end example
The fields are explained as follows. The fields are explained as follows.
@@ -4073,7 +4197,7 @@ computer, so the computer in the example is two hops away
(i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1). (i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1).
@item Ref time @item Ref time
This is the time (GMT) at which the last measurement from the reference This is the time (UTC) at which the last measurement from the reference
source was processed. source was processed.
@item System time @item System time
@@ -4094,9 +4218,13 @@ On systems such as Solaris and SunOS, @code{chronyd} has no means to
adjust the fundamental rate of the system clock, so keeps the system adjust the fundamental rate of the system clock, so keeps the system
time correct by periodically making offsets to it as though an error had time correct by periodically making offsets to it as though an error had
been measured. The build up of these offsets will be observed in this been measured. The build up of these offsets will be observed in this
report. On systems such as Linux where @code{chronyd} can adjust the report.
fundamental rate of the system clock, this value will show zero unless a
very recent measurement has shown the system to be error. @item Last offset
This is the estimated local offset on the last clock update.
@item RMS offset
This is a long-term average of the offset value.
@item Frequency @item Frequency
The `frequency' is the rate by which the system's clock would be would The `frequency' is the rate by which the system's clock would be would
@@ -4150,6 +4278,13 @@ stratum-1 computer is correct) is given by
clock_error <= root_dispersion + (0.5 * |root_delay|) clock_error <= root_dispersion + (0.5 * |root_delay|)
@end example @end example
@item Update interval
This is the interval between the last two clock updates.
@item Leap status
This is the leap status, which can be @code{Normal}, @code{Insert second},
@code{Delete second} or @code{Not synchronised}.
@end table @end table
@c }}} @c }}}
@c {{{ trimrtc @c {{{ trimrtc

View File

@@ -40,6 +40,7 @@ struct timex {
#define ADJ_MAXERROR 0x0004 /* maximum time error */ #define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */ #define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */ #define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */ #define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */ #define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ #define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */

216
client.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +32,7 @@
#include "candm.h" #include "candm.h"
#include "nameserv.h" #include "nameserv.h"
#include "md5.h" #include "hash.h"
#include "getdate.h" #include "getdate.h"
#include "cmdparse.h" #include "cmdparse.h"
#include "pktlength.h" #include "pktlength.h"
@@ -960,17 +960,18 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
{ {
CPS_NTP_Source data; CPS_NTP_Source data;
CPS_Status status; CPS_Status status;
IPAddr ip_addr;
int result = 0; int result = 0;
status = CPS_ParseNTPSourceAdd(line, &data); status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) { switch (status) {
case CPS_Success: case CPS_Success:
/* Don't retry name resolving */ if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) {
if (data.ip_addr.family == IPADDR_UNSPEC) {
Free(data.name); Free(data.name);
fprintf(stderr, "Invalid host/IP address\n"); fprintf(stderr, "Invalid host/IP address\n");
break; break;
} }
Free(data.name);
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) { if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n"); fprintf(stderr, "Option minstratum not supported\n");
@@ -988,7 +989,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
} }
msg->data.ntp_source.port = htonl((unsigned long) data.port); msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr); UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll); msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll); msg->data.ntp_source.maxpoll = htonl(data.params.maxpoll);
msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll); msg->data.ntp_source.presend_minpoll = htonl(data.params.presend_minpoll);
@@ -1093,8 +1094,9 @@ process_cmd_delete(CMD_Request *msg, char *line)
/* ================================================== */ /* ================================================== */
static int password_seen = 0; static char *password = NULL;
static MD5_CTX md5_after_just_password; static int password_length;
static int auth_hash_id;
/* ================================================== */ /* ================================================== */
@@ -1102,8 +1104,16 @@ static int
process_cmd_password(CMD_Request *msg, char *line) process_cmd_password(CMD_Request *msg, char *line)
{ {
char *p, *q; char *p, *q;
char *password;
struct timeval now; struct timeval now;
int i, len;
/* Blank and free the old password */
if (password) {
for (i = 0; i < password_length; i++)
password[i] = 0;
free(password);
password = NULL;
}
p = line; p = line;
while (*p && isspace((unsigned char)*p)) while (*p && isspace((unsigned char)*p))
@@ -1114,26 +1124,29 @@ process_cmd_password(CMD_Request *msg, char *line)
if (isspace((unsigned char)*q)) *q = 0; if (isspace((unsigned char)*q)) *q = 0;
} }
if (*p) { if (!*p) {
password = p;
} else {
/* blank line, prompt for password */ /* blank line, prompt for password */
password = getpass("Password: "); p = getpass("Password: ");
} }
if (!*password) { if (!*p)
password_seen = 0; return 0;
} else {
password_seen = 1; len = strlen(p);
password_length = UTI_DecodePasswordFromText(p);
if (password_length > 0) {
password = malloc(password_length);
memcpy(password, p, password_length);
} }
/* Generate MD5 initial context */ /* Erase the password from the input or getpass buffer */
MD5Init(&md5_after_just_password); for (i = 0; i < len; i++)
MD5Update(&md5_after_just_password, (unsigned char *) password, strlen(password)); p[i] = 0;
/* Blank the password for security */ if (password_length <= 0) {
for (p = password; *p; p++) { fprintf(stderr, "Could not decode password\n");
*p = 0; return 0;
} }
if (gettimeofday(&now, NULL) < 0) { if (gettimeofday(&now, NULL) < 0) {
@@ -1148,43 +1161,33 @@ process_cmd_password(CMD_Request *msg, char *line)
/* ================================================== */ /* ================================================== */
static void static int
generate_auth(CMD_Request *msg) generate_auth(CMD_Request *msg)
{ {
MD5_CTX ctx; int data_len;
int pkt_len;
pkt_len = PKL_CommandLength(msg); data_len = PKL_CommandLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth)); assert(auth_hash_id >= 0);
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Request, data)); return UTI_GenerateNTPAuth(auth_hash_id, (unsigned char *)password, password_length,
} (unsigned char *)msg, data_len, ((unsigned char *)msg) + data_len, sizeof (msg->auth));
MD5Final(&ctx);
memcpy(&(msg->auth), &ctx.digest, 16);
} }
/* ================================================== */ /* ================================================== */
static int static int
check_reply_auth(CMD_Reply *msg) check_reply_auth(CMD_Reply *msg, int len)
{ {
int pkt_len; int data_len;
MD5_CTX ctx;
pkt_len = PKL_ReplyLength(msg); data_len = PKL_ReplyLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(msg->auth), 16)) { assert(auth_hash_id >= 0);
return 1;
} else { return UTI_CheckNTPAuth(auth_hash_id, (unsigned char *)password, password_length,
return 0; (unsigned char *)msg, data_len,
} ((unsigned char *)msg) + data_len, len - data_len);
} }
/* ================================================== */ /* ================================================== */
@@ -1237,6 +1240,7 @@ give_help(void)
printf("waitsync [max-tries [max-correction [max-skew]]] : Wait until synchronised\n"); printf("waitsync [max-tries [max-correction [max-skew]]] : Wait until synchronised\n");
printf("writertc : Save RTC parameters to file\n"); printf("writertc : Save RTC parameters to file\n");
printf("\n"); printf("\n");
printf("authhash <name>: Set command authentication hash function\n");
printf("dns -n|+n : Disable/enable resolving IP addresses to hostnames\n"); printf("dns -n|+n : Disable/enable resolving IP addresses to hostnames\n");
printf("dns -4|-6|-46 : Resolve hostnames only to IPv4/IPv6/both addresses\n"); printf("dns -4|-6|-46 : Resolve hostnames only to IPv4/IPv6/both addresses\n");
printf("timeout <milliseconds> : Set initial response timeout\n"); printf("timeout <milliseconds> : Set initial response timeout\n");
@@ -1272,6 +1276,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
int read_length; int read_length;
int expected_length; int expected_length;
int command_length; int command_length;
int auth_length;
struct timeval tv; struct timeval tv;
int timeout; int timeout;
int n_attempts; int n_attempts;
@@ -1294,25 +1299,32 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
do { do {
/* Decide whether to authenticate */ /* Decide whether to authenticate */
if (password_seen) { if (password) {
if (!utoken || (request->command == htons(REQ_LOGON))) { if (!utoken || (request->command == htons(REQ_LOGON))) {
/* Otherwise, the daemon won't bother authenticating our /* Otherwise, the daemon won't bother authenticating our
packet and we won't get a token back */ packet and we won't get a token back */
request->utoken = htonl(SPECIAL_UTOKEN); request->utoken = htonl(SPECIAL_UTOKEN);
} }
generate_auth(request); auth_length = generate_auth(request);
} else { } else {
memset(request->auth, 0, sizeof (request->auth)); auth_length = 0;
} }
command_length = PKL_CommandLength(request); command_length = PKL_CommandLength(request);
assert(command_length > 0); assert(command_length > 0);
/* add empty MD5 auth so older servers will not drop the request
due to bad length */
if (!auth_length) {
memset(((char *)request) + command_length, 0, 16);
auth_length = 16;
}
#if 0 #if 0
printf("Sent command length=%d bytes\n", command_length); printf("Sent command length=%d bytes auth length=%d bytes\n", command_length, auth_length);
#endif #endif
if (sendto(sock_fd, (void *) request, command_length, 0, if (sendto(sock_fd, (void *) request, command_length + auth_length, 0,
&his_addr.u, his_addr_len) < 0) { &his_addr.u, his_addr_len) < 0) {
@@ -1375,7 +1387,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
read_length = recvfrom_status; read_length = recvfrom_status;
expected_length = PKL_ReplyLength(reply); expected_length = PKL_ReplyLength(reply);
bad_length = (read_length != expected_length); bad_length = (read_length < expected_length);
bad_sender = (where_from.u.sa_family != his_addr.u.sa_family || bad_sender = (where_from.u.sa_family != his_addr.u.sa_family ||
(where_from.u.sa_family == AF_INET && (where_from.u.sa_family == AF_INET &&
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr || (where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
@@ -1429,8 +1441,8 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
ntohl(reply->token)); ntohl(reply->token));
#endif #endif
if (password_seen) { if (password) {
*reply_auth_ok = check_reply_auth(reply); *reply_auth_ok = check_reply_auth(reply, read_length);
} else { } else {
/* Assume in this case that the reply is always considered /* Assume in this case that the reply is always considered
to be authentic */ to be authentic */
@@ -1679,7 +1691,7 @@ process_cmd_sources(char *line)
IPAddr ip_addr; IPAddr ip_addr;
uint32_t latest_meas_ago; uint32_t latest_meas_ago;
uint16_t poll, stratum; uint16_t poll, stratum;
uint16_t state, mode; uint16_t state, mode, flags, reachability;
char hostname_buf[50]; char hostname_buf[50];
/* Check whether to output verbose headers */ /* Check whether to output verbose headers */
@@ -1701,10 +1713,10 @@ process_cmd_sources(char *line)
printf("|| | | \n"); printf("|| | | \n");
} }
printf("MS Name/IP address Stratum Poll LastRx Last sample\n"); printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n");
printf("============================================================================\n"); printf("===============================================================================\n");
/* "MS NNNNNNNNNNNNNNNNNNNNNNNNN SS PP RRRR SSSSSSS[SSSSSSS] +/- SSSSSS" */ /* "MS NNNNNNNNNNNNNNNNNNNNNNNNNNN SS PP RRR RRRR SSSSSSS[SSSSSSS] +/- SSSSSS" */
for (i=0; i<n_sources; i++) { for (i=0; i<n_sources; i++) {
request.command = htons(REQ_SOURCE_DATA); request.command = htons(REQ_SOURCE_DATA);
@@ -1715,6 +1727,8 @@ process_cmd_sources(char *line)
stratum = ntohs(reply.data.source_data.stratum); stratum = ntohs(reply.data.source_data.stratum);
state = ntohs(reply.data.source_data.state); state = ntohs(reply.data.source_data.state);
mode = ntohs(reply.data.source_data.mode); mode = ntohs(reply.data.source_data.mode);
flags = ntohs(reply.data.source_data.flags);
reachability = ntohs(reply.data.source_data.reachability);
latest_meas_ago = ntohl(reply.data.source_data.since_sample); latest_meas_ago = ntohl(reply.data.source_data.since_sample);
orig_latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.orig_latest_meas); orig_latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.orig_latest_meas);
latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.latest_meas); latest_meas = UTI_FloatNetworkToHost(reply.data.source_data.latest_meas);
@@ -1755,8 +1769,12 @@ process_cmd_sources(char *line)
default: default:
printf(" "); printf(" ");
} }
switch (flags) {
default:
break;
}
printf(" %-25s %2d %2d ", hostname_buf, stratum, poll); printf(" %-27s %2d %2d %3o ", hostname_buf, stratum, poll, reachability);
print_seconds(latest_meas_ago); print_seconds(latest_meas_ago);
printf(" "); printf(" ");
print_signed_nanoseconds(latest_meas); print_signed_nanoseconds(latest_meas);
@@ -1875,11 +1893,15 @@ process_cmd_tracking(char *line)
struct tm ref_time_tm; struct tm ref_time_tm;
unsigned long a, b, c, d; unsigned long a, b, c, d;
double correction; double correction;
double last_offset;
double rms_offset;
double freq_ppm; double freq_ppm;
double resid_freq_ppm; double resid_freq_ppm;
double skew_ppm; double skew_ppm;
double root_delay; double root_delay;
double root_dispersion; double root_dispersion;
double last_update_interval;
const char *leap_status;
request.command = htons(REQ_TRACKING); request.command = htons(REQ_TRACKING);
if (request_reply(&request, &reply, RPY_TRACKING, 0)) { if (request_reply(&request, &reply, RPY_TRACKING, 0)) {
@@ -1899,24 +1921,49 @@ process_cmd_tracking(char *line)
ref_ip = host; ref_ip = host;
} }
switch (ntohs(reply.data.tracking.leap_status)) {
case LEAP_Normal:
leap_status = "Normal";
break;
case LEAP_InsertSecond:
leap_status = "Insert second";
break;
case LEAP_DeleteSecond:
leap_status = "Delete second";
break;
case LEAP_Unsynchronised:
leap_status = "Not synchronised";
break;
default:
leap_status = "Unknown";
break;
}
printf("Reference ID : %lu.%lu.%lu.%lu (%s)\n", a, b, c, d, ref_ip); printf("Reference ID : %lu.%lu.%lu.%lu (%s)\n", a, b, c, d, ref_ip);
printf("Stratum : %lu\n", (unsigned long) ntohl(reply.data.tracking.stratum)); printf("Stratum : %lu\n", (unsigned long) ntohs(reply.data.tracking.stratum));
UTI_TimevalNetworkToHost(&reply.data.tracking.ref_time, &ref_time); UTI_TimevalNetworkToHost(&reply.data.tracking.ref_time, &ref_time);
ref_time_tm = *gmtime((time_t *)&ref_time.tv_sec); ref_time_tm = *gmtime((time_t *)&ref_time.tv_sec);
printf("Ref time (UTC) : %s", asctime(&ref_time_tm)); printf("Ref time (UTC) : %s", asctime(&ref_time_tm));
correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction); correction = UTI_FloatNetworkToHost(reply.data.tracking.current_correction);
last_offset = UTI_FloatNetworkToHost(reply.data.tracking.last_offset);
rms_offset = UTI_FloatNetworkToHost(reply.data.tracking.rms_offset);
printf("System time : %.9f seconds %s of NTP time\n", fabs(correction), printf("System time : %.9f seconds %s of NTP time\n", fabs(correction),
(correction > 0.0) ? "slow" : "fast"); (correction > 0.0) ? "slow" : "fast");
printf("Last offset : %.9f seconds\n", last_offset);
printf("RMS offset : %.9f seconds\n", rms_offset);
freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm); freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.freq_ppm);
resid_freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm); resid_freq_ppm = UTI_FloatNetworkToHost(reply.data.tracking.resid_freq_ppm);
skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm); skew_ppm = UTI_FloatNetworkToHost(reply.data.tracking.skew_ppm);
root_delay = UTI_FloatNetworkToHost(reply.data.tracking.root_delay); root_delay = UTI_FloatNetworkToHost(reply.data.tracking.root_delay);
root_dispersion = UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion); root_dispersion = UTI_FloatNetworkToHost(reply.data.tracking.root_dispersion);
last_update_interval = UTI_FloatNetworkToHost(reply.data.tracking.last_update_interval);
printf("Frequency : %.3f ppm %s\n", fabs(freq_ppm), (freq_ppm < 0.0) ? "slow" : "fast"); printf("Frequency : %.3f ppm %s\n", fabs(freq_ppm), (freq_ppm < 0.0) ? "slow" : "fast");
printf("Residual freq : %.3f ppm\n", resid_freq_ppm); printf("Residual freq : %.3f ppm\n", resid_freq_ppm);
printf("Skew : %.3f ppm\n", skew_ppm); printf("Skew : %.3f ppm\n", skew_ppm);
printf("Root delay : %.6f seconds\n", root_delay); printf("Root delay : %.6f seconds\n", root_delay);
printf("Root dispersion : %.6f seconds\n", root_dispersion); printf("Root dispersion : %.6f seconds\n", root_dispersion);
printf("Update interval : %.1f seconds\n", last_update_interval);
printf("Leap status : %s\n", leap_status);
return 1; return 1;
} }
return 0; return 0;
@@ -2366,11 +2413,13 @@ process_cmd_activity(const char *line)
"%ld sources online\n" "%ld sources online\n"
"%ld sources offline\n" "%ld sources offline\n"
"%ld sources doing burst (return to online)\n" "%ld sources doing burst (return to online)\n"
"%ld sources doing burst (return to offline)\n", "%ld sources doing burst (return to offline)\n"
"%ld sources with unknown address\n",
(long) ntohl(reply.data.activity.online), (long) ntohl(reply.data.activity.online),
(long) ntohl(reply.data.activity.offline), (long) ntohl(reply.data.activity.offline),
(long) ntohl(reply.data.activity.burst_online), (long) ntohl(reply.data.activity.burst_online),
(long) ntohl(reply.data.activity.burst_offline)); (long) ntohl(reply.data.activity.burst_offline),
(long) ntohl(reply.data.activity.unresolved));
return 1; return 1;
} }
return 0; return 0;
@@ -2475,6 +2524,32 @@ process_cmd_dns(const char *line)
/* ================================================== */ /* ================================================== */
static int
process_cmd_authhash(const char *line)
{
char hash_name[50];
int new_hash_id;
assert(auth_hash_id >= 0);
if (sscanf(line, "%49s", hash_name) != 1) {
fprintf(stderr, "Could not parse hash name\n");
return 0;
}
new_hash_id = HSH_GetHashId(hash_name);
if (new_hash_id < 0) {
fprintf(stderr, "Unknown hash name: %s\n", hash_name);
return 0;
}
auth_hash_id = new_hash_id;
return 1;
}
/* ================================================== */
static int static int
process_cmd_timeout(const char *line) process_cmd_timeout(const char *line)
{ {
@@ -2527,7 +2602,7 @@ process_line(char *line, int *quit)
if (!*p) { if (!*p) {
fflush(stderr); fflush(stderr);
fflush(stdout); fflush(stdout);
return ret; return 1;
}; };
if (!strncmp(p, "offline", 7)) { if (!strncmp(p, "offline", 7)) {
@@ -2633,6 +2708,9 @@ process_line(char *line, int *quit)
} else if (!strncmp(p, "waitsync", 8)) { } else if (!strncmp(p, "waitsync", 8)) {
ret = process_cmd_waitsync(p+8); ret = process_cmd_waitsync(p+8);
do_normal_submit = 0; do_normal_submit = 0;
} else if (!strncmp(p, "authhash", 8)) {
ret = process_cmd_authhash(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "dns ", 4)) { } else if (!strncmp(p, "dns ", 4)) {
ret = process_cmd_dns(p+4); ret = process_cmd_dns(p+4);
do_normal_submit = 0; do_normal_submit = 0;
@@ -2710,7 +2788,7 @@ static void
display_gpl(void) display_gpl(void)
{ {
printf("chrony version %s\n" printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2011 Richard P. Curnow and others\n" "Copyright (C) 1997-2003, 2007, 2009-2012 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n" "chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n" "you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n", "GNU General Public License version 2 for details.\n\n",
@@ -2769,6 +2847,10 @@ main(int argc, char **argv)
display_gpl(); display_gpl();
} }
/* MD5 is the default authentication hash */
auth_hash_id = HSH_GetHashId("MD5");
assert(auth_hash_id >= 0);
open_io(hostname, port); open_io(hostname, port);
if (argc > 0) { if (argc > 0) {
@@ -2787,6 +2869,8 @@ main(int argc, char **argv)
close_io(); close_io();
free(password);
return !ret; return !ret;
} }

124
cmdmon.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -328,57 +328,28 @@ CAM_Finalise(void)
rest of the packet */ rest of the packet */
static int static int
check_rx_packet_auth(CMD_Request *packet) check_rx_packet_auth(CMD_Request *packet, int packet_len)
{ {
int pkt_len, auth_len;
char *key;
int keylen;
int pkt_len;
MD5_CTX ctx;
pkt_len = PKL_CommandLength(packet); pkt_len = PKL_CommandLength(packet);
auth_len = packet_len - pkt_len;
KEY_CommandKey(&key, &keylen); return KEY_CheckAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, auth_len);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(packet->auth), 16)) {
return 1;
} else {
return 0;
}
} }
/* ================================================== */ /* ================================================== */
static void static int
generate_tx_packet_auth(CMD_Reply *packet) generate_tx_packet_auth(CMD_Reply *packet)
{ {
char *key;
int keylen;
MD5_CTX ctx;
int pkt_len; int pkt_len;
pkt_len = PKL_ReplyLength(packet); pkt_len = PKL_ReplyLength(packet);
KEY_CommandKey(&key, &keylen); return KEY_GenerateAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, sizeof (packet->auth));
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
memcpy(&(packet->auth), &ctx.digest, 16);
} }
/* ================================================== */ /* ================================================== */
@@ -720,7 +691,7 @@ print_reply_packet(CMD_Reply *pkt)
/* ================================================== */ /* ================================================== */
static void static void
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to) transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
{ {
int status; int status;
int tx_message_length; int tx_message_length;
@@ -742,7 +713,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
assert(0); assert(0);
} }
tx_message_length = PKL_ReplyLength(msg); tx_message_length = PKL_ReplyLength(msg) + auth_len;
status = sendto(sock_fd, (void *) msg, tx_message_length, 0, status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
&where_to->u, addrlen); &where_to->u, addrlen);
@@ -1091,6 +1062,18 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.source_data.mode = htons(RPY_SD_MD_REF); tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
break; break;
} }
switch (report.sel_option) {
case RPT_NORMAL:
tx_message->data.source_data.flags = htons(0);
break;
case RPT_PREFER:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
case RPT_NOSELECT:
tx_message->data.source_data.flags = htons(RPY_SD_FLAG_PREFER);
break;
}
tx_message->data.source_data.reachability = htons(report.reachability);
tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago); tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas); tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas); tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas);
@@ -1383,7 +1366,7 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
usec = (long)(ntohl(rx_message->data.doffset.usec)); usec = (long)(ntohl(rx_message->data.doffset.usec));
doffset = (double) sec + 1.0e-6 * (double) usec; doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset); LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset); LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS); tx_message->status = htons(STT_SUCCESS);
} }
@@ -1399,14 +1382,18 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->reply = htons(RPY_TRACKING); tx_message->reply = htons(RPY_TRACKING);
tx_message->data.tracking.ref_id = htonl(rpt.ref_id); tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr); UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
tx_message->data.tracking.stratum = htonl(rpt.stratum); tx_message->data.tracking.stratum = htons(rpt.stratum);
tx_message->data.tracking.leap_status = htons(rpt.leap_status);
UTI_TimevalHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time); UTI_TimevalHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time);
tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction); tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction);
tx_message->data.tracking.last_offset = UTI_FloatHostToNetwork(rpt.last_offset);
tx_message->data.tracking.rms_offset = UTI_FloatHostToNetwork(rpt.rms_offset);
tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm); tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm);
tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm); tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm);
tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm); tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm);
tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay); tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay);
tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion); tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion);
tx_message->data.tracking.last_update_interval = UTI_FloatHostToNetwork(rpt.last_update_interval);
} }
/* ================================================== */ /* ================================================== */
@@ -1708,6 +1695,7 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.activity.offline = htonl(report.offline); tx_message->data.activity.offline = htonl(report.offline);
tx_message->data.activity.burst_online = htonl(report.burst_online); tx_message->data.activity.burst_online = htonl(report.burst_online);
tx_message->data.activity.burst_offline = htonl(report.burst_offline); tx_message->data.activity.burst_offline = htonl(report.burst_offline);
tx_message->data.activity.unresolved = htonl(report.unresolved);
tx_message->status = htons(STT_SUCCESS); tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_ACTIVITY); tx_message->reply = htons(RPY_ACTIVITY);
} }
@@ -1756,7 +1744,7 @@ read_from_cmd_socket(void *anything)
{ {
int status; int status;
int read_length; /* Length of packet read */ int read_length; /* Length of packet read */
int expected_length; /* Expected length of packet */ int expected_length; /* Expected length of packet without auth data */
unsigned long flags; unsigned long flags;
CMD_Request rx_message; CMD_Request rx_message;
CMD_Reply tx_message, *prev_tx_message; CMD_Reply tx_message, *prev_tx_message;
@@ -1766,7 +1754,8 @@ read_from_cmd_socket(void *anything)
socklen_t from_length; socklen_t from_length;
IPAddr remote_ip; IPAddr remote_ip;
unsigned short remote_port; unsigned short remote_port;
int md5_ok; int auth_length;
int auth_ok;
int utoken_ok, token_ok; int utoken_ok, token_ok;
int issue_token; int issue_token;
int valid_ts; int valid_ts;
@@ -1867,7 +1856,10 @@ read_from_cmd_socket(void *anything)
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) { if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) {
tx_message.status = htons(STT_BADPKTVERSION); tx_message.status = htons(STT_BADPKTVERSION);
transmit_reply(&tx_message, &where_from); /* add empty MD5 auth so older clients will not drop
the reply due to bad length */
memset(((char *)&tx_message) + PKL_ReplyLength(&tx_message), 0, 16);
transmit_reply(&tx_message, &where_from, 16);
} }
return; return;
} }
@@ -1880,11 +1872,11 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_INVALID); tx_message.status = htons(STT_INVALID);
transmit_reply(&tx_message, &where_from); transmit_reply(&tx_message, &where_from, 0);
return; return;
} }
if (read_length != expected_length) { if (read_length < expected_length) {
if (!LOG_RateLimited()) { if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port); LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
} }
@@ -1892,7 +1884,7 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_BADPKTLENGTH); tx_message.status = htons(STT_BADPKTLENGTH);
transmit_reply(&tx_message, &where_from); transmit_reply(&tx_message, &where_from, 0);
return; return;
} }
@@ -1909,7 +1901,7 @@ read_from_cmd_socket(void *anything)
} }
tx_message.status = htons(STT_NOHOSTACCESS); tx_message.status = htons(STT_NOHOSTACCESS);
transmit_reply(&tx_message, &where_from); transmit_reply(&tx_message, &where_from, 0);
return; return;
} }
@@ -1920,18 +1912,18 @@ read_from_cmd_socket(void *anything)
clients will set their utokens to 0 to save us wasting our time clients will set their utokens to 0 to save us wasting our time
if the packet is unauthenticatable. */ if the packet is unauthenticatable. */
if (rx_message.utoken != 0) { if (rx_message.utoken != 0) {
md5_ok = check_rx_packet_auth(&rx_message); auth_ok = check_rx_packet_auth(&rx_message, read_length);
} else { } else {
md5_ok = 0; auth_ok = 0;
} }
/* All this malarky is to protect the system against various forms /* All this malarky is to protect the system against various forms
of attack. of attack.
Simple packet forgeries are blocked by requiring the packet to Simple packet forgeries are blocked by requiring the packet to
authenticate properly with MD5. (The assumption is that the authenticate properly with MD5 or other crypto hash. (The
command key is in a read-only keys file read by the daemon, and assumption is that the command key is in a read-only keys file
is known only to administrators.) read by the daemon, and is known only to administrators.)
Replay attacks are prevented by 2 fields in the packet. The Replay attacks are prevented by 2 fields in the packet. The
'token' field is where the client plays back to us a token that 'token' field is where the client plays back to us a token that
@@ -1973,13 +1965,13 @@ read_from_cmd_socket(void *anything)
rx_message_seq = ntohl(rx_message.sequence); rx_message_seq = ntohl(rx_message.sequence);
rx_attempt = ntohs(rx_message.attempt); rx_attempt = ntohs(rx_message.attempt);
if (md5_ok && utoken_ok) { if (auth_ok && utoken_ok) {
token_ok = check_token(rx_message_token); token_ok = check_token(rx_message_token);
} else { } else {
token_ok = 0; token_ok = 0;
} }
if (md5_ok && utoken_ok && !token_ok) { if (auth_ok && utoken_ok && !token_ok) {
/* This might be a resent message, due to the client not getting /* This might be a resent message, due to the client not getting
our reply to the first attempt. See if we can find the message. */ our reply to the first attempt. See if we can find the message. */
prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt); prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt);
@@ -1997,14 +1989,14 @@ read_from_cmd_socket(void *anything)
} }
if (md5_ok && utoken_ok && token_ok) { if (auth_ok && utoken_ok && token_ok) {
/* See whether we can discard the previous reply from storage */ /* See whether we can discard the previous reply from storage */
token_acknowledged(rx_message_token, &now); token_acknowledged(rx_message_token, &now);
} }
valid_ts = 0; valid_ts = 0;
if (md5_ok) { if (auth_ok) {
struct timeval ts; struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts); UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
@@ -2019,7 +2011,7 @@ read_from_cmd_socket(void *anything)
issue_token = 0; issue_token = 0;
} }
authenticated = md5_ok & utoken_ok & token_ok; authenticated = auth_ok & utoken_ok & token_ok;
if (authenticated) { if (authenticated) {
CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec); CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec);
@@ -2119,15 +2111,15 @@ read_from_cmd_socket(void *anything)
/* If the log-on fails, record the reason why */ /* If the log-on fails, record the reason why */
if (!issue_token && !LOG_RateLimited()) { if (!issue_token && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, LOG(LOGS_WARN, LOGF_CmdMon,
"Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n", "Bad command logon from %s port %d (auth_ok=%d valid_ts=%d)",
UTI_IPToString(&remote_ip), UTI_IPToString(&remote_ip),
remote_port, remote_port,
md5_ok, valid_ts); auth_ok, valid_ts);
} }
if (issue_token == 1) { if (issue_token == 1) {
tx_message.status = htons(STT_SUCCESS); tx_message.status = htons(STT_SUCCESS);
} else if (!md5_ok) { } else if (!auth_ok) {
tx_message.status = htons(STT_UNAUTH); tx_message.status = htons(STT_UNAUTH);
} else if (!valid_ts) { } else if (!valid_ts) {
tx_message.status = htons(STT_INVALIDTS); tx_message.status = htons(STT_INVALIDTS);
@@ -2298,8 +2290,10 @@ read_from_cmd_socket(void *anything)
} }
} }
if (md5_ok) { if (auth_ok) {
generate_tx_packet_auth(&tx_message); auth_length = generate_tx_packet_auth(&tx_message);
} else {
auth_length = 0;
} }
if (token_ok) { if (token_ok) {
@@ -2318,7 +2312,7 @@ read_from_cmd_socket(void *anything)
static int do_it=1; static int do_it=1;
if (do_it) { if (do_it) {
transmit_reply(&tx_message, &where_from); transmit_reply(&tx_message, &where_from, auth_length);
} }
#if 0 #if 0

View File

@@ -45,7 +45,6 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
int ok, n, done; int ok, n, done;
char cmd[MAXLEN+1], hostname[MAXLEN+1]; char cmd[MAXLEN+1], hostname[MAXLEN+1];
CPS_Status result; CPS_Status result;
DNS_Status s;
src->port = SRC_DEFAULT_PORT; src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL; src->params.minpoll = SRC_DEFAULT_MINPOLL;
@@ -66,14 +65,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
ok = 0; ok = 0;
if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) { if (sscanf(line, "%" SMAXLEN "s%n", hostname, &n) == 1) {
s = DNS_Name2IPAddress(hostname, &src->ip_addr);
if (s == DNS_Success) {
ok = 1; ok = 1;
src->name = NULL;
} else if (s == DNS_TryAgain) {
ok = 1;
src->ip_addr.family = IPADDR_UNSPEC;
}
} }
if (!ok) { if (!ok) {
@@ -199,7 +191,7 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src)
} while (!done); } while (!done);
} }
if (ok && src->ip_addr.family == IPADDR_UNSPEC) { if (ok) {
n = strlen(hostname); n = strlen(hostname);
src->name = MallocArray(char, n + 1); src->name = MallocArray(char, n + 1);
strncpy(src->name, hostname, n); strncpy(src->name, hostname, n);

View File

@@ -47,7 +47,6 @@ typedef enum {
} CPS_Status; } CPS_Status;
typedef struct { typedef struct {
IPAddr ip_addr;
char *name; char *name;
unsigned short port; unsigned short port;
SourceParameters params; SourceParameters params;

88
conf.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -76,6 +76,7 @@ static void parse_logbanner(const char *);
static void parse_logdir(const char *); static void parse_logdir(const char *);
static void parse_maxupdateskew(const char *); static void parse_maxupdateskew(const char *);
static void parse_maxclockerror(const char *); static void parse_maxclockerror(const char *);
static void parse_corrtimeratio(const char *);
static void parse_reselectdist(const char *); static void parse_reselectdist(const char *);
static void parse_stratumweight(const char *); static void parse_stratumweight(const char *);
static void parse_peer(const char *); static void parse_peer(const char *);
@@ -97,6 +98,7 @@ static void parse_noclientlog(const char *);
static void parse_clientloglimit(const char *); static void parse_clientloglimit(const char *);
static void parse_fallbackdrift(const char *); static void parse_fallbackdrift(const char *);
static void parse_makestep(const char *); static void parse_makestep(const char *);
static void parse_maxchange(const char *);
static void parse_logchange(const char *); static void parse_logchange(const char *);
static void parse_mailonchange(const char *); static void parse_mailonchange(const char *);
static void parse_bindaddress(const char *); static void parse_bindaddress(const char *);
@@ -110,6 +112,7 @@ static void parse_sched_priority(const char *);
static void parse_lockall(const char *); static void parse_lockall(const char *);
static void parse_tempcomp(const char *); static void parse_tempcomp(const char *);
static void parse_include(const char *); static void parse_include(const char *);
static void parse_leapsectz(const char *);
/* ================================================== */ /* ================================================== */
/* Configuration variables */ /* Configuration variables */
@@ -122,6 +125,7 @@ static char *drift_file = NULL;
static char *rtc_file = NULL; static char *rtc_file = NULL;
static unsigned long command_key_id; static unsigned long command_key_id;
static double max_update_skew = 1000.0; static double max_update_skew = 1000.0;
static double correction_time_ratio = 1.0;
static double max_clock_error = 1.0; /* in ppm */ static double max_clock_error = 1.0; /* in ppm */
static double reselect_distance = 1e-4; static double reselect_distance = 1e-4;
@@ -166,6 +170,12 @@ static int rtc_sync = 0;
static int make_step_limit = 0; static int make_step_limit = 0;
static double make_step_threshold = 0.0; static double make_step_threshold = 0.0;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay = -1;
static int max_offset_ignore;
static double max_offset;
/* Flag set if we should log to syslog when a time adjustment /* Flag set if we should log to syslog when a time adjustment
exceeding the threshold is initiated */ exceeding the threshold is initiated */
static int do_log_change = 0; static int do_log_change = 0;
@@ -215,6 +225,9 @@ static double linux_freq_scale;
static int sched_priority = 0; static int sched_priority = 0;
static int lock_memory = 0; static int lock_memory = 0;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leapsec_tz = NULL;
/* ================================================== */ /* ================================================== */
typedef struct { typedef struct {
@@ -239,6 +252,7 @@ static const Command commands[] = {
{"dumpdir", 7, parse_dumpdir}, {"dumpdir", 7, parse_dumpdir},
{"maxupdateskew", 13, parse_maxupdateskew}, {"maxupdateskew", 13, parse_maxupdateskew},
{"maxclockerror", 13, parse_maxclockerror}, {"maxclockerror", 13, parse_maxclockerror},
{"corrtimeratio", 13, parse_corrtimeratio},
{"commandkey", 10, parse_commandkey}, {"commandkey", 10, parse_commandkey},
{"initstepslew", 12, parse_initstepslew}, {"initstepslew", 12, parse_initstepslew},
{"local", 5, parse_local}, {"local", 5, parse_local},
@@ -254,6 +268,7 @@ static const Command commands[] = {
{"clientloglimit", 14, parse_clientloglimit}, {"clientloglimit", 14, parse_clientloglimit},
{"fallbackdrift", 13, parse_fallbackdrift}, {"fallbackdrift", 13, parse_fallbackdrift},
{"makestep", 8, parse_makestep}, {"makestep", 8, parse_makestep},
{"maxchange", 9, parse_maxchange},
{"logchange", 9, parse_logchange}, {"logchange", 9, parse_logchange},
{"mailonchange", 12, parse_mailonchange}, {"mailonchange", 12, parse_mailonchange},
{"bindaddress", 11, parse_bindaddress}, {"bindaddress", 11, parse_bindaddress},
@@ -265,6 +280,7 @@ static const Command commands[] = {
{"reselectdist", 12, parse_reselectdist}, {"reselectdist", 12, parse_reselectdist},
{"stratumweight", 13, parse_stratumweight}, {"stratumweight", 13, parse_stratumweight},
{"include", 7, parse_include}, {"include", 7, parse_include},
{"leapsectz", 9, parse_leapsectz},
{"linux_hz", 8, parse_linux_hz}, {"linux_hz", 8, parse_linux_hz},
{"linux_freq_scale", 16, parse_linux_freq_scale}, {"linux_freq_scale", 16, parse_linux_freq_scale},
{"sched_priority", 14, parse_sched_priority}, {"sched_priority", 14, parse_sched_priority},
@@ -632,6 +648,16 @@ parse_maxclockerror(const char *line)
/* ================================================== */ /* ================================================== */
static void
parse_corrtimeratio(const char *line)
{
if (sscanf(line, "%lf", &correction_time_ratio) != 1) {
LOG(LOGS_WARN, LOGF_Configure, "Could not read correction time ratio at line %d", line_number);
}
}
/* ================================================== */
static void static void
parse_reselectdist(const char *line) parse_reselectdist(const char *line)
{ {
@@ -930,6 +956,19 @@ parse_makestep(const char *line)
/* ================================================== */ /* ================================================== */
static void
parse_maxchange(const char *line)
{
if (sscanf(line, "%lf %d %d", &max_offset, &max_offset_delay, &max_offset_ignore) != 3) {
max_offset_delay = -1;
LOG(LOGS_WARN, LOGF_Configure,
"Could not read offset, check delay or ignore limit for maximum change at line %d\n",
line_number);
}
}
/* ================================================== */
static void static void
parse_logchange(const char *line) parse_logchange(const char *line)
{ {
@@ -1248,6 +1287,16 @@ parse_include(const char *line)
/* ================================================== */ /* ================================================== */
static void
parse_leapsectz(const char *line)
{
/* This must allocate enough space! */
leapsec_tz = MallocArray(char, 1 + strlen(line));
sscanf(line, "%s", leapsec_tz);
}
/* ================================================== */
static void static void
parse_linux_hz(const char *line) parse_linux_hz(const char *line)
{ {
@@ -1286,21 +1335,14 @@ CNF_ProcessInitStepSlew(void (*after_hook)(void *), void *anything)
void void
CNF_AddSources(void) { CNF_AddSources(void) {
NTP_Remote_Address server;
int i; int i;
for (i=0; i<n_ntp_sources; i++) { for (i=0; i<n_ntp_sources; i++) {
if (ntp_sources[i].params.ip_addr.family != IPADDR_UNSPEC) {
server.ip_addr = ntp_sources[i].params.ip_addr;
memset(&server.local_ip_addr, 0, sizeof (server.local_ip_addr));
server.port = ntp_sources[i].params.port;
NSR_AddSource(&server, ntp_sources[i].type, &ntp_sources[i].params.params);
} else {
NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port, NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
ntp_sources[i].type, &ntp_sources[i].params.params); ntp_sources[i].type, &ntp_sources[i].params.params);
} }
}
NSR_ResolveSources();
return; return;
@@ -1484,6 +1526,14 @@ CNF_GetMaxClockError(void)
/* ================================================== */ /* ================================================== */
double
CNF_GetCorrectionTimeRatio(void)
{
return correction_time_ratio;
}
/* ================================================== */
double double
CNF_GetReselectDistance(void) CNF_GetReselectDistance(void)
{ {
@@ -1553,6 +1603,16 @@ CNF_GetMakeStep(int *limit, double *threshold)
/* ================================================== */ /* ================================================== */
void
CNF_GetMaxChange(int *delay, int *ignore, double *offset)
{
*delay = max_offset_delay;
*ignore = max_offset_ignore;
*offset = max_offset;
}
/* ================================================== */
void void
CNF_GetLogChange(int *enabled, double *threshold) CNF_GetLogChange(int *enabled, double *threshold)
{ {
@@ -1662,6 +1722,14 @@ CNF_GetPidFile(void)
/* ================================================== */ /* ================================================== */
char *
CNF_GetLeapSecTimezone(void)
{
return leapsec_tz;
}
/* ================================================== */
void void
CNF_GetLinuxHz(int *set, int *hz) CNF_GetLinuxHz(int *set, int *hz)
{ {

3
conf.h
View File

@@ -60,6 +60,7 @@ extern int CNF_GetCommandPort(void);
extern int CNF_GetRTCOnUTC(void); extern int CNF_GetRTCOnUTC(void);
extern int CNF_GetRTCSync(void); extern int CNF_GetRTCSync(void);
extern void CNF_GetMakeStep(int *limit, double *threshold); extern void CNF_GetMakeStep(int *limit, double *threshold);
extern void CNF_GetMaxChange(int *delay, int *ignore, double *offset);
extern void CNF_GetLogChange(int *enabled, double *threshold); extern void CNF_GetLogChange(int *enabled, double *threshold);
extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user); extern void CNF_GetMailOnChange(int *enabled, double *threshold, char **user);
extern int CNF_GetNoClientLog(void); extern int CNF_GetNoClientLog(void);
@@ -68,12 +69,14 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr); extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr); extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetPidFile(void); extern char *CNF_GetPidFile(void);
extern char *CNF_GetLeapSecTimezone(void);
extern void CNF_GetLinuxHz(int *set, int *hz); extern void CNF_GetLinuxHz(int *set, int *hz);
extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale); extern void CNF_GetLinuxFreqScale(int *set, double *freq_scale);
/* Value returned in ppm, as read from file */ /* Value returned in ppm, as read from file */
extern double CNF_GetMaxUpdateSkew(void); extern double CNF_GetMaxUpdateSkew(void);
extern double CNF_GetMaxClockError(void); extern double CNF_GetMaxClockError(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetReselectDistance(void); extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void); extern double CNF_GetStratumWeight(void);

72
configure vendored
View File

@@ -4,7 +4,7 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate. # chronyd/chronyc - Programs for keeping computer clocks accurate.
# #
# Copyright (C) Richard P. Curnow 1997-2003 # Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009 # Copyright (C) Miroslav Lichvar 2009, 2012
# #
# ======================================================================= # =======================================================================
@@ -98,11 +98,13 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is --readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is --readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is --with-ncurses-library=DIR Specify where ncurses lib directory is
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-ipv6 Disable IPv6 support --disable-ipv6 Disable IPv6 support
--disable-pps Disable PPS API support --disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux --disable-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable Linux capabilities support --disable-linuxcaps Disable Linux capabilities support
--enable-forcednsretry Force retry on DNS failure --disable-forcednsretry Don't retry on permanent DNS error
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail] --with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
Fine tuning of the installation directories: Fine tuning of the installation directories:
@@ -162,6 +164,8 @@ SYSDEFS=""
feat_readline=1 feat_readline=1
try_readline=1 try_readline=1
try_editline=1 try_editline=1
try_nss=1
try_tomcrypt=1
feat_rtc=1 feat_rtc=1
try_rtc=0 try_rtc=0
feat_linuxcaps=1 feat_linuxcaps=1
@@ -173,7 +177,7 @@ feat_ipv6=1
feat_pps=1 feat_pps=1
try_setsched=0 try_setsched=0
try_lockmem=0 try_lockmem=0
feat_forcednsretry=0 feat_forcednsretry=1
mail_program="/usr/lib/sendmail" mail_program="/usr/lib/sendmail"
for option for option
@@ -239,12 +243,18 @@ do
--disable-linuxcaps) --disable-linuxcaps)
feat_linuxcaps=0 feat_linuxcaps=0
;; ;;
--enable-forcednsretry) --disable-forcednsretry)
feat_forcednsretry=1 feat_forcednsretry=0
;; ;;
--with-sendmail=* ) --with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'` mail_program=`echo $option | sed -e 's/^.*=//;'`
;; ;;
--without-nss )
try_nss=0
;;
--without-tomcrypt )
try_tomcrypt=0
;;
--host-system=* ) --host-system=* )
OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'` OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
;; ;;
@@ -365,19 +375,35 @@ if [ $feat_ipv6 = "1" ] && \
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));' return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then then
add_def HAVE_IPV6 add_def HAVE_IPV6
if ! test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' ' if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);' return sizeof(struct in6_pktinfo);'
then then
add_def HAVE_IN6_PKTINFO
else
if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \ if test_code 'in6_pktinfo with _GNU_SOURCE' 'sys/socket.h netinet/in.h' \
'-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);' '-D_GNU_SOURCE' '' 'return sizeof(struct in6_pktinfo);'
then then
add_def _GNU_SOURCE add_def _GNU_SOURCE
add_def HAVE_IN6_PKTINFO
fi fi
fi fi
fi fi
if [ $feat_pps = "1" ] && \ timepps_h=""
test_code 'PPS API' 'string.h timepps.h' '' '' ' if [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
else
if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
timepps_h="timepps.h"
add_def HAVE_TIMEPPS_H
fi
fi
fi
if [ "x$timepps_h" != "x" ] && \
test_code 'PPSAPI' "string.h $timepps_h" '' '' '
pps_handle_t h; pps_handle_t h;
pps_info_t i; pps_info_t i;
struct timespec ts; struct timespec ts;
@@ -459,6 +485,33 @@ if [ $feat_readline = "1" ]; then
fi fi
fi fi
HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $try_nss = "1" ]; then
test_cflags="`pkg-config --cflags nss`"
test_link="`pkg-config --libs-only-L nss` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
then
HASH_OBJ="hash_nss.o"
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
fi
fi
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then
HASH_OBJ="hash_tomcrypt.o"
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
fi
fi
SYSCONFDIR=/etc SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR SYSCONFDIR=$SETSYSCONFDIR
@@ -523,6 +576,9 @@ sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\ s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\ s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\ s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@HASH_LINK@%${HASH_LINK}%;\
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\ s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\ s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\ s%@SBINDIR@%${SBINDIR}%;\

41
hash.h Normal file
View File

@@ -0,0 +1,41 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for crypto hashing.
*/
#ifndef GOT_HASH_H
#define GOT_HASH_H
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
extern int HSH_GetHashId(const char *name);
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
#endif

64
hash_intmd5.c Normal file
View File

@@ -0,0 +1,64 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using internal MD5 implementation.
*/
#include "config.h"
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
return -1;
return 0;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
if (out_len < 16)
return 0;
MD5Init(&ctx);
MD5Update(&ctx, in1, in1_len);
if (in2)
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
memcpy(out, ctx.digest, 16);
return 16;
}

89
hash_nss.c Normal file
View File

@@ -0,0 +1,89 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using NSSLOWHASH API of the NSS library.
*/
#include <nss.h>
#include <hasht.h>
#include <nsslowhash.h>
/* #include "config.h" */
#include "hash.h"
static NSSLOWInitContext *ictx;
struct hash {
HASH_HashType type;
const char *name;
NSSLOWHASHContext *context;
};
static struct hash hashes[] = {
{ HASH_AlgMD5, "MD5", NULL },
{ HASH_AlgSHA1, "SHA1", NULL },
{ HASH_AlgSHA256, "SHA256", NULL },
{ HASH_AlgSHA384, "SHA384", NULL },
{ HASH_AlgSHA512, "SHA512", NULL },
{ 0, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
if (!ictx && !(ictx = NSSLOW_Init()))
return -1; /* couldn't init NSS */
if (!hashes[i].context &&
!(hashes[i].context = NSSLOWHASH_NewContext(ictx, hashes[i].type)))
return -1; /* couldn't init hash */
return i;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned int ret;
NSSLOWHASH_Begin(hashes[id].context);
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
if (in2)
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
return ret;
}

116
hash_tomcrypt.c Normal file
View File

@@ -0,0 +1,116 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using tomcrypt library.
*/
#include <tomcrypt.h>
#include "config.h"
#include "hash.h"
struct hash {
const char *name;
const char *int_name;
const struct ltc_hash_descriptor *desc;
};
static const struct hash hashes[] = {
{ "MD5", "md5", &md5_desc },
#ifdef LTC_RIPEMD128
{ "RMD128", "rmd128", &rmd128_desc },
#endif
#ifdef LTC_RIPEMD160
{ "RMD160", "rmd160", &rmd160_desc },
#endif
#ifdef LTC_RIPEMD256
{ "RMD256", "rmd256", &rmd256_desc },
#endif
#ifdef LTC_RIPEMD320
{ "RMD320", "rmd320", &rmd320_desc },
#endif
#ifdef LTC_SHA1
{ "SHA1", "sha1", &sha1_desc },
#endif
#ifdef LTC_SHA256
{ "SHA256", "sha256", &sha256_desc },
#endif
#ifdef LTC_SHA384
{ "SHA384", "sha384", &sha384_desc },
#endif
#ifdef LTC_SHA512
{ "SHA512", "sha512", &sha512_desc },
#endif
#ifdef LTC_TIGER
{ "TIGER", "tiger", &tiger_desc },
#endif
#ifdef LTC_WHIRLPOOL
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
#endif
{ NULL, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
{
int i, h;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
break;
}
if (!hashes[i].name)
return -1; /* not found */
h = find_hash(hashes[i].int_name);
if (h >= 0)
return h; /* already registered */
/* register and try again */
register_hash(hashes[i].desc);
return find_hash(hashes[i].int_name);
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
unsigned long len;
int r;
len = out_len;
if (in2)
r = hash_memory_multi(id, out, &len,
in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
else
r = hash_memory(id, in1, in1_len, out, &len);
if (r != CRYPT_OK)
return 0;
return len;
}

180
keys.c
View File

@@ -3,6 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -34,11 +35,17 @@
#include "keys.h" #include "keys.h"
#include "conf.h" #include "conf.h"
#include "memory.h" #include "memory.h"
#include "util.h"
#include "local.h"
#include "logging.h"
typedef struct { typedef struct {
unsigned long id; unsigned long id;
char *val; char *val;
int len; int len;
int hash_id;
int auth_delay;
} Key; } Key;
#define MAX_KEYS 256 #define MAX_KEYS 256
@@ -47,7 +54,7 @@ static int n_keys;
static Key keys[MAX_KEYS]; static Key keys[MAX_KEYS];
static int command_key_valid; static int command_key_valid;
static int command_key_pos; static int command_key_id;
static int cache_valid; static int cache_valid;
static unsigned long cache_key_id; static unsigned long cache_key_id;
static int cache_key_pos; static int cache_key_pos;
@@ -75,6 +82,37 @@ KEY_Finalise(void)
/* ================================================== */ /* ================================================== */
static int
determine_hash_delay(int key_id)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
#if 0
LOG(LOGS_INFO, LOGF_Keys, "authentication delay for key %d: %d useconds", key_id, min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
return min_usecs + (min_usecs >> 4);
}
/* ================================================== */
/* Compare two keys */ /* Compare two keys */
static int static int
@@ -102,16 +140,16 @@ compare_keys_by_id(const void *a, const void *b)
void void
KEY_Reload(void) KEY_Reload(void)
{ {
int i, len1; int i, len1, fields;
char *key_file; char *key_file;
FILE *in; FILE *in;
unsigned long key_id; unsigned long key_id;
char line[KEYLEN+1], keyval[KEYLEN+1]; char line[KEYLEN+1], buf1[KEYLEN+1], buf2[KEYLEN+1];
char *keyval, *hashname;
for (i=0; i<n_keys; i++) { for (i=0; i<n_keys; i++) {
Free(keys[i].val); Free(keys[i].val);
} }
n_keys = 0; n_keys = 0;
key_file = CNF_GetKeysFile(); key_file = CNF_GetKeysFile();
@@ -127,12 +165,30 @@ KEY_Reload(void)
if (line[len1] == '\n') { if (line[len1] == '\n') {
line[len1] = '\0'; line[len1] = '\0';
} }
fields = sscanf(line, "%lu%" SKEYLEN "s%" SKEYLEN "s", &key_id, buf1, buf2);
if (fields >= 2 && fields <= 3) {
if (fields == 3) {
hashname = buf1;
keyval = buf2;
} else {
hashname = "MD5";
keyval = buf1;
}
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %d", key_id);
continue;
}
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %d", key_id);
continue;
}
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
keys[n_keys].id = key_id; keys[n_keys].id = key_id;
keys[n_keys].len = strlen(keyval); keys[n_keys].val = MallocArray(char, keys[n_keys].len);
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len); memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
strcpy(keys[n_keys].val, keyval);
n_keys++; n_keys++;
} }
} }
@@ -143,12 +199,20 @@ KEY_Reload(void)
more careful! */ more careful! */
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id); qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
/* Erase the passwords from stack */
memset(line, 0, sizeof (line));
memset(buf1, 0, sizeof (buf1));
memset(buf2, 0, sizeof (buf2));
} }
} }
command_key_valid = 0; command_key_valid = 0;
cache_valid = 0; cache_valid = 0;
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
return; return;
} }
@@ -172,30 +236,8 @@ lookup_key(unsigned long id)
/* ================================================== */ /* ================================================== */
void static int
KEY_CommandKey(char **key, int *len) get_key_pos(unsigned long key_id)
{
unsigned long command_key_id;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
command_key_pos = lookup_key(command_key_id);
command_key_valid = 1;
}
if (command_key_pos >= 0) {
*key = keys[command_key_pos].val;
*len = keys[command_key_pos].len;
} else {
*key = "";
*len = 0;
}
}
/* ================================================== */
int
KEY_GetKey(unsigned long key_id, char **key, int *len)
{ {
if (!cache_valid || key_id != cache_key_id) { if (!cache_valid || key_id != cache_key_id) {
cache_valid = 1; cache_valid = 1;
@@ -203,15 +245,19 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
cache_key_id = key_id; cache_key_id = key_id;
} }
if (cache_key_pos >= 0) { return cache_key_pos;
*key = keys[cache_key_pos].val;
*len = keys[cache_key_pos].len;
return 1;
} else {
*key = "";
*len = 0;
return 0;
} }
/* ================================================== */
unsigned long
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
} }
/* ================================================== */ /* ================================================== */
@@ -239,3 +285,57 @@ KEY_KeyKnown(unsigned long key_id)
} }
} }
} }
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

8
keys.h
View File

@@ -32,9 +32,15 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void); extern void KEY_Reload(void);
extern void KEY_CommandKey(char **key, int *len); extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len); extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id); extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */ #endif /* GOT_KEYS_H */

10
local.c
View File

@@ -443,7 +443,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
/* ================================================== */ /* ================================================== */
void void
LCL_AccumulateOffset(double offset) LCL_AccumulateOffset(double offset, double corr_rate)
{ {
ChangeListEntry *ptr; ChangeListEntry *ptr;
struct timeval raw, cooked; struct timeval raw, cooked;
@@ -454,7 +454,7 @@ LCL_AccumulateOffset(double offset)
LCL_ReadRawTime(&raw); LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL); LCL_CookTime(&raw, &cooked, NULL);
(*drv_accrue_offset)(offset); (*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */ /* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) { for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -505,7 +505,7 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
/* ================================================== */ /* ================================================== */
void void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset) LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{ {
ChangeListEntry *ptr; ChangeListEntry *ptr;
struct timeval raw, cooked; struct timeval raw, cooked;
@@ -532,7 +532,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
current_freq_ppm = (*drv_set_freq)(current_freq_ppm); current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm); dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 + old_freq_ppm);
(*drv_accrue_offset)(doffset); (*drv_accrue_offset)(doffset, corr_rate);
/* Dispatch to all handlers */ /* Dispatch to all handlers */
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) { for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
@@ -598,7 +598,7 @@ LCL_MakeStep(double threshold)
return 0; return 0;
/* Cancel remaining slew and make the step */ /* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction); LCL_AccumulateOffset(correction, 0.0);
LCL_ApplyStepOffset(-correction); LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction); LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.3f seconds", correction);

View File

@@ -138,9 +138,10 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
/* Routine to apply an offset (in seconds) to the local clock. The /* Routine to apply an offset (in seconds) to the local clock. The
argument should be positive to move the clock backwards (i.e. the argument should be positive to move the clock backwards (i.e. the
local clock is currently fast of true time), or negative to move it local clock is currently fast of true time), or negative to move it
forwards (i.e. it is currently slow of true time). */ forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern void LCL_AccumulateOffset(double offset); extern void LCL_AccumulateOffset(double offset, double corr_rate);
/* Routine to apply an immediate offset by doing a sudden step if /* Routine to apply an immediate offset by doing a sudden step if
possible. (Intended for use after an initial estimate of offset has possible. (Intended for use after an initial estimate of offset has
@@ -158,7 +159,7 @@ extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cook
/* Perform the combination of modifying the frequency and applying /* Perform the combination of modifying the frequency and applying
a slew, in one easy step */ a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset); extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Routine to read the system precision as a log to base 2 value. */ /* Routine to read the system precision as a log to base 2 value. */
extern int LCL_GetSysPrecisionAsLog(void); extern int LCL_GetSysPrecisionAsLog(void);

View File

@@ -41,8 +41,9 @@ typedef double (*lcl_ReadFrequencyDriver)(void);
typedef double (*lcl_SetFrequencyDriver)(double freq_ppm); typedef double (*lcl_SetFrequencyDriver)(double freq_ppm);
/* System driver to accrue an offset. A positive argument means slew /* System driver to accrue an offset. A positive argument means slew
the clock forwards. */ the clock forwards. The suggested correction rate of time to correct the
typedef void (*lcl_AccrueOffsetDriver)(double offset); offset is given in 'corr_rate'. */
typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step /* System driver to apply a step offset. A positive argument means step
the clock forwards. */ the clock forwards. */

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011 * Copyright (C) Miroslav Lichvar 2011-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -41,6 +41,8 @@ static int initialised = 0;
static int system_log = 0; static int system_log = 0;
static int parent_fd = 0;
static time_t last_limited = 0; static time_t last_limited = 0;
#ifdef WINNT #ifdef WINNT
@@ -154,6 +156,10 @@ LOG_Fatal_Function(LOG_Facility facility, const char *format, ...)
} else { } else {
fprintf(stderr, "Fatal error : %s\n", buf); fprintf(stderr, "Fatal error : %s\n", buf);
} }
if (parent_fd) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
}
#endif #endif
MAI_CleanupAndExit(); MAI_CleanupAndExit();
@@ -196,6 +202,23 @@ LOG_OpenSystemLog(void)
/* ================================================== */ /* ================================================== */
void
LOG_SetParentFd(int fd)
{
parent_fd = fd;
}
/* ================================================== */
void
LOG_CloseParentFd()
{
if (parent_fd > 0)
close(parent_fd);
}
/* ================================================== */
int int
LOG_RateLimited(void) LOG_RateLimited(void)
{ {
@@ -282,14 +305,10 @@ LOG_CreateLogFileDir(void)
{ {
const char *logdir; const char *logdir;
if (n_filelogs <= 0)
return;
logdir = CNF_GetLogDir(); logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) { if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir); LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
n_filelogs = 0;
} }
} }

View File

@@ -54,6 +54,7 @@ typedef enum {
LOGF_CmdMon, LOGF_CmdMon,
LOGF_Acquire, LOGF_Acquire,
LOGF_Manual, LOGF_Manual,
LOGF_Keys,
LOGF_Logging, LOGF_Logging,
LOGF_Rtc, LOGF_Rtc,
LOGF_Regress, LOGF_Regress,
@@ -85,6 +86,12 @@ extern void LOG_Position(const char *filename, int line_number, const char *func
/* Log messages to syslog instead of stderr */ /* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void); extern void LOG_OpenSystemLog(void);
/* Send fatal message also to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Close the pipe to the foreground process so it can exit */
extern void LOG_CloseParentFd(void);
/* Return zero once per 10 seconds */ /* Return zero once per 10 seconds */
extern int LOG_RateLimited(void); extern int LOG_RateLimited(void);

45
main.c
View File

@@ -4,6 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009 * Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -124,6 +125,8 @@ signal_cleanup(int x)
static void static void
post_acquire_hook(void *anything) post_acquire_hook(void *anything)
{ {
/* Close the pipe to the foreground process so it can exit */
LOG_CloseParentFd();
CNF_AddSources(); CNF_AddSources();
CNF_AddBroadcasts(); CNF_AddBroadcasts();
@@ -214,7 +217,13 @@ go_daemon(void)
#else #else
int pid, fd; int pid, fd, pipefd[2];
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */ /* Does this preserve existing signal handlers? */
pid = fork(); pid = fork();
@@ -222,8 +231,22 @@ go_daemon(void)
if (pid < 0) { if (pid < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno)); LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
} else if (pid > 0) { } else if (pid > 0) {
exit(0); /* In the 'grandparent' */ /* In the 'grandparent' */
char message[1024];
int r;
close(pipefd[1]);
r = read(pipefd[0], message, sizeof (message));
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
}
exit(1);
} else
exit(0);
} else { } else {
close(pipefd[0]);
setsid(); setsid();
@@ -237,10 +260,19 @@ go_daemon(void)
} else { } else {
/* In the child we want to leave running as the daemon */ /* In the child we want to leave running as the daemon */
/* Don't keep stdin/out/err from before. */ /* Change current directory to / */
if (chdir("/") < 0) {
LOG(LOGS_ERR, LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet. */
for (fd=0; fd<1024; fd++) { for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1])
close(fd); close(fd);
} }
LOG_SetParentFd(pipefd[1]);
} }
} }
@@ -303,9 +335,6 @@ int main
} }
} }
CNF_ReadFile(conf_file);
#ifndef SYS_WINNT
if (getuid() != 0) { if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */ /* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n"); fprintf(stderr,"Not superuser\n");
@@ -323,19 +352,19 @@ int main
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION); LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
CNF_ReadFile(conf_file);
/* Check whether another chronyd may already be running. Do this after /* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in * forking, so that message logging goes to the right place (i.e. syslog), in
* case this chronyd is being run from a boot script. */ * case this chronyd is being run from a boot script. */
if (maybe_another_chronyd_running(&other_pid)) { if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)", LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile()); other_pid, CNF_GetPidFile());
exit(1);
} }
/* Write our lockfile to prevent other chronyds running. This has *GOT* to /* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */ * be done *AFTER* the daemon-creation fork() */
write_lockfile(); write_lockfile();
#endif
if (do_init_rtc) { if (do_init_rtc) {
RTC_TimePreInit(); RTC_TimePreInit();

2
md5.c
View File

@@ -37,8 +37,6 @@
*********************************************************************** ***********************************************************************
*/ */
#include "config.h"
#include "md5.h" #include "md5.h"
/* /*

8
ntp.h
View File

@@ -33,6 +33,8 @@
#include <inttypes.h> #include <inttypes.h>
#endif #endif
#include "hash.h"
typedef struct { typedef struct {
uint32_t hi; uint32_t hi;
uint32_t lo; uint32_t lo;
@@ -40,7 +42,7 @@ typedef struct {
typedef uint32_t NTP_int32; typedef uint32_t NTP_int32;
#define AUTH_DATA_LEN 16 #define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */ /* Type definition for leap bits */
typedef enum { typedef enum {
@@ -72,7 +74,7 @@ typedef struct {
NTP_int64 receive_ts; NTP_int64 receive_ts;
NTP_int64 transmit_ts; NTP_int64 transmit_ts;
NTP_int32 auth_keyid; NTP_int32 auth_keyid;
uint8_t auth_data[AUTH_DATA_LEN]; uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet; } NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the /* We have to declare a buffer type to hold a datagram read from the
@@ -89,7 +91,7 @@ typedef union {
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE]; uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer; } ReceiveBuffer;
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN)) #define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
/* ================================================== */ /* ================================================== */

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -40,7 +40,6 @@
#include "conf.h" #include "conf.h"
#include "logging.h" #include "logging.h"
#include "keys.h" #include "keys.h"
#include "md5.h"
#include "addrfilt.h" #include "addrfilt.h"
#include "clientlog.h" #include "clientlog.h"
@@ -212,13 +211,10 @@ struct NCR_Instance_Record {
static ADF_AuthTable access_auth_table; static ADF_AuthTable access_auth_table;
static int md5_offset_usecs;
/* ================================================== */ /* ================================================== */
/* Forward prototypes */ /* Forward prototypes */
static void transmit_timeout(void *arg); static void transmit_timeout(void *arg);
static void determine_md5_delay(void);
/* ================================================== */ /* ================================================== */
@@ -230,9 +226,6 @@ NCR_Initialise(void)
: -1; : -1;
access_auth_table = ADF_CreateTable(); access_auth_table = ADF_CreateTable();
determine_md5_delay();
} }
/* ================================================== */ /* ================================================== */
@@ -363,100 +356,11 @@ NCR_DestroyInstance(NCR_Instance instance)
/* ================================================== */ /* ================================================== */
/* ================================================== */
static int static int
generate_packet_auth(NTP_Packet *pkt, unsigned long keyid) check_packet_auth(NTP_Packet *pkt, unsigned long keyid, int auth_len)
{ {
int keylen; return KEY_CheckAuth(keyid, (void *)pkt, offsetof(NTP_Packet, auth_keyid),
char *keytext; (void *)&(pkt->auth_data), auth_len);
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
memcpy(&(pkt->auth_data), &ctx.digest, 16);
return 1;
} else {
pkt->auth_keyid = htonl(0);
return 0;
}
}
/* ================================================== */
static void
determine_md5_delay(void)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
MD5_CTX ctx;
static const char *example_key = "#a0,243asd=-b ds";
int slen;
int i;
slen = strlen(example_key);
for (i=0; i<10; i++) {
LCL_ReadRawTime(&before);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) example_key, slen);
MD5Update(&ctx, (unsigned const char *) &pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0) {
min_usecs = usecs;
} else {
if (usecs < min_usecs) {
min_usecs = usecs;
}
}
}
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "MD5 took %d useconds", min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
md5_offset_usecs = min_usecs + (min_usecs >> 4);
}
/* ================================================== */
static int
check_packet_auth(NTP_Packet *pkt, unsigned long keyid)
{
int keylen;
char *keytext;
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(pkt->auth_data), 16)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
} }
/* ================================================== */ /* ================================================== */
@@ -572,13 +476,21 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Authenticate */ /* Authenticate */
if (do_auth) { if (do_auth) {
int auth_len;
/* Pre-compensate the transmit time by approx. how long it will /* Pre-compensate the transmit time by approx. how long it will
take to generate the MD5 authentication bytes. */ take to generate the authentication data. */
local_transmit.tv_usec += md5_offset_usecs; local_transmit.tv_usec += KEY_GetAuthDelay(key_id);
UTI_NormaliseTimeval(&local_transmit); UTI_NormaliseTimeval(&local_transmit);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts); UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
generate_packet_auth(&message, key_id);
NIO_SendAuthenticatedPacket(&message, where_to); auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
offsetof(NTP_Packet, auth_keyid),
(unsigned char *)&message.auth_data, sizeof (message.auth_data));
if (auth_len > 0) {
message.auth_keyid = htonl(key_id);
NIO_SendAuthenticatedPacket(&message, where_to,
sizeof (message.auth_keyid) + auth_len);
}
} else { } else {
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts); UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
NIO_SendNormalPacket(&message, where_to); NIO_SendNormalPacket(&message, where_to);
@@ -723,7 +635,7 @@ transmit_timeout(void *arg)
/* ================================================== */ /* ================================================== */
static void static void
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int do_auth) receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int auth_len)
{ {
int pkt_leap; int pkt_leap;
int source_is_synchronized; int source_is_synchronized;
@@ -894,7 +806,7 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
sample_time = local_average; sample_time = local_average;
/* Calculate skew */ /* Calculate skew */
skew = source_freq_hi - source_freq_lo; skew = (source_freq_hi - source_freq_lo) / 2.0;
/* and then calculate peer dispersion */ /* and then calculate peer dispersion */
epsilon = LCL_GetSysPrecisionAsQuantum() + now_err + skew * local_interval; epsilon = LCL_GetSysPrecisionAsQuantum() + now_err + skew * local_interval;
@@ -932,7 +844,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
round trip delay to the minimum one currently in the stats data round trip delay to the minimum one currently in the stats data
register is less than an administrator-defined value */ register is less than an administrator-defined value */
if (fabs(delta/SRC_MinRoundTripDelay(inst->source)) > inst->max_delay_ratio) { if (inst->max_delay_ratio > 1.0 &&
fabs(delta/SRC_MinRoundTripDelay(inst->source)) > inst->max_delay_ratio) {
test4b = 0; /* Failed */ test4b = 0; /* Failed */
} else { } else {
test4b = 1; /* Success */ test4b = 1; /* Success */
@@ -952,12 +865,12 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* Test 5 relates to authentication. */ /* Test 5 relates to authentication. */
if (inst->do_auth) { if (inst->do_auth) {
if (do_auth) { if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid); auth_key_id = ntohl(message->auth_keyid);
if (!KEY_KeyKnown(auth_key_id)) { if (!KEY_KeyKnown(auth_key_id)) {
test5 = 0; test5 = 0;
} else { } else {
test5 = check_packet_auth(message, auth_key_id); test5 = check_packet_auth(message, auth_key_id, auth_len);
} }
} else { } else {
/* If we expect authenticated info from this peer/server and the packet /* If we expect authenticated info from this peer/server and the packet
@@ -1313,21 +1226,22 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
*/ */
/* ================================================== */ /* ================================================== */
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
static void void
process_known NCR_ProcessKnown
(NTP_Packet *message, /* the received message */ (NTP_Packet *message, /* the received message */
struct timeval *now, /* timestamp at time of receipt */ struct timeval *now, /* timestamp at time of receipt */
double now_err, double now_err,
NCR_Instance inst, /* the instance record for this peer/server */ NCR_Instance inst, /* the instance record for this peer/server */
int do_auth /* whether the received packet allegedly contains int length /* the length of the received packet */
authentication info*/
) )
{ {
int pkt_mode; int pkt_mode;
int version; int version;
int valid_auth, valid_key; int valid_auth, valid_key;
int authenticate_reply; int authenticate_reply, auth_len;
unsigned long auth_key_id; unsigned long auth_key_id;
unsigned long reply_auth_key_id; unsigned long reply_auth_key_id;
@@ -1341,6 +1255,12 @@ process_known
/* Perform tests mentioned in RFC1305 to validate packet contents */ /* Perform tests mentioned in RFC1305 to validate packet contents */
pkt_mode = (message->lvm >> 0) & 0x7; pkt_mode = (message->lvm >> 0) & 0x7;
/* Length of the authentication data, if any */
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
if (auth_len < 0) {
auth_len = 0;
}
/* Now, depending on the mode we decide what to do */ /* Now, depending on the mode we decide what to do */
switch (pkt_mode) { switch (pkt_mode) {
case MODE_CLIENT: case MODE_CLIENT:
@@ -1364,11 +1284,11 @@ process_known
CLG_LogNTPClientAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); CLG_LogNTPClientAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
if (do_auth) { if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid); auth_key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(auth_key_id); valid_key = KEY_KeyKnown(auth_key_id);
if (valid_key) { if (valid_key) {
valid_auth = check_packet_auth(message, auth_key_id); valid_auth = check_packet_auth(message, auth_key_id, auth_len);
} else { } else {
valid_auth = 0; valid_auth = 0;
} }
@@ -1407,7 +1327,7 @@ process_known
case MODE_ACTIVE: case MODE_ACTIVE:
/* Ordinary symmetric peering */ /* Ordinary symmetric peering */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_PASSIVE: case MODE_PASSIVE:
/* In this software this case should not arise, we don't /* In this software this case should not arise, we don't
@@ -1417,7 +1337,7 @@ process_known
/* This is where we have the remote configured as a server and he has /* This is where we have the remote configured as a server and he has
us configured as a peer - fair enough. */ us configured as a peer - fair enough. */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_SERVER: case MODE_SERVER:
/* Nonsense - we can't have a preconfigured server */ /* Nonsense - we can't have a preconfigured server */
@@ -1438,14 +1358,14 @@ process_known
case MODE_ACTIVE: case MODE_ACTIVE:
/* Slightly bizarre combination, but we can still process it */ /* Slightly bizarre combination, but we can still process it */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_PASSIVE: case MODE_PASSIVE:
/* We have no passive peers in this software */ /* We have no passive peers in this software */
break; break;
case MODE_CLIENT: case MODE_CLIENT:
/* Standard case where he's a server and we're the client */ /* Standard case where he's a server and we're the client */
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_SERVER: case MODE_SERVER:
/* RFC1305 error condition. */ /* RFC1305 error condition. */
@@ -1466,7 +1386,7 @@ process_known
/* This would arise if we have the remote configured as a peer and /* This would arise if we have the remote configured as a peer and
he does not have us configured */ he does not have us configured */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec); CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_PASSIVE: case MODE_PASSIVE:
/* Error condition in RFC1305. Also, we can't have any /* Error condition in RFC1305. Also, we can't have any
@@ -1475,7 +1395,7 @@ process_known
break; break;
case MODE_CLIENT: case MODE_CLIENT:
/* This is a wierd combination - how could it arise? */ /* This is a wierd combination - how could it arise? */
receive_packet(message, now, now_err, inst, do_auth); receive_packet(message, now, now_err, inst, auth_len);
break; break;
case MODE_SERVER: case MODE_SERVER:
/* Error condition in RFC1305 */ /* Error condition in RFC1305 */
@@ -1498,9 +1418,6 @@ process_known
break; break;
} }
} }
/* ================================================== */ /* ================================================== */
@@ -1508,100 +1425,18 @@ process_known
and it relates to a source we have an ongoing protocol exchange with */ and it relates to a source we have an ongoing protocol exchange with */
void void
NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst) NCR_ProcessUnknown
(NTP_Packet *message, /* the received message */
struct timeval *now, /* timestamp at time of receipt */
double now_err, /* assumed error in the timestamp */
NTP_Remote_Address *remote_addr,
int length /* the length of the received packet */
)
{ {
process_known(message, now, now_err, inst, 0);
}
/* ================================================== */
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
void
NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode; NTP_Mode his_mode;
NTP_Mode my_mode; NTP_Mode my_mode;
int my_poll, version; int my_poll, version;
int valid_key, valid_auth, auth_len;
/* Check version */
version = (message->lvm >> 3) & 0x7;
if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
/* Ignore packet, but might want to log it */
return;
}
if (ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
his_mode = message->lvm & 0x07;
if (his_mode == MODE_CLIENT) {
/* We are server */
my_mode = MODE_SERVER;
CLG_LogNTPClientAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
} else if (his_mode == MODE_ACTIVE) {
/* We are symmetric passive, even though we don't ever lock to him */
my_mode = MODE_PASSIVE;
CLG_LogNTPPeerAccess(&remote_addr->ip_addr, (time_t) now->tv_sec);
} else {
my_mode = MODE_UNDEFINED;
}
/* If we can't determine a sensible mode to reply with, it means
he has supplied a wierd mode in his request, so ignore it. */
if (my_mode != MODE_UNDEFINED) {
my_poll = message->poll; /* What should this be set to? Does the client actually care? */
transmit_packet(my_mode, my_poll,
0, 0UL,
&message->transmit_ts, /* Originate (for us) is the transmit time for the client */
now, /* Time we received the packet */
NULL, /* Don't care when we send reply, we aren't maintaining state about this client */
NULL, /* Ditto */
remote_addr);
}
} else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port);
}
return;
}
/* ================================================== */
/* This routine is called when a new authenticated packet arrives off
the network, and it relates to a source we have an ongoing protocol
exchange with */
void
NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data)
{
process_known(message, now, now_err, data, 1);
}
/* ================================================== */
/* This routine is called when a new authenticated packet arrives off
the network, and we do not recognize its source */
void
NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
NTP_Mode his_mode;
NTP_Mode my_mode;
int my_poll, version;
int valid_key, valid_auth;
unsigned long key_id; unsigned long key_id;
/* Check version */ /* Check version */
@@ -1633,23 +1468,28 @@ NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err,
he has supplied a wierd mode in his request, so ignore it. */ he has supplied a wierd mode in his request, so ignore it. */
if (my_mode != MODE_UNDEFINED) { if (my_mode != MODE_UNDEFINED) {
int do_auth = 0;
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
if (auth_len > 0) {
/* Only reply if we know the key and the packet authenticates /* Only reply if we know the key and the packet authenticates
properly. */ properly. */
key_id = ntohl(message->auth_keyid); key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(key_id); valid_key = KEY_KeyKnown(key_id);
do_auth = 1;
if (valid_key) { if (valid_key) {
valid_auth = check_packet_auth(message, key_id); valid_auth = check_packet_auth(message, key_id, auth_len);
} else { } else {
valid_auth = 0; valid_auth = 0;
} }
}
if (valid_key && valid_auth) { if (!do_auth || (valid_key && valid_auth)) {
my_poll = message->poll; /* What should this be set to? Does the client actually care? */ my_poll = message->poll; /* What should this be set to? Does the client actually care? */
transmit_packet(my_mode, my_poll, transmit_packet(my_mode, my_poll,
1, key_id, do_auth, do_auth ? key_id : 0,
&message->transmit_ts, /* Originate (for us) is the transmit time for the client */ &message->transmit_ts, /* Originate (for us) is the transmit time for the client */
now, /* Time we received the packet */ now, /* Time we received the packet */
NULL, /* Don't care when we send reply, we aren't maintaining state about this client */ NULL, /* Don't care when we send reply, we aren't maintaining state about this client */
@@ -1657,10 +1497,12 @@ NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err,
remote_addr); remote_addr);
} }
} }
} else if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_NtpCore, "NTP packet received from unauthorised host %s port %d",
UTI_IPToString(&remote_addr->ip_addr),
remote_addr->port);
} }
return; return;
} }
/* ================================================== */ /* ================================================== */
@@ -1831,20 +1673,10 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
break; break;
case MD_ONLINE: case MD_ONLINE:
inst->opmode = MD_BURST_WAS_ONLINE;
inst->burst_good_samples_to_go = n_good_samples;
inst->burst_total_samples_to_go = n_total_samples;
if (inst->timer_running) {
SCH_RemoveTimeout(inst->timeout_id);
}
inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass,
transmit_timeout, (void *) inst);
break;
case MD_OFFLINE: case MD_OFFLINE:
if (inst->opmode == MD_ONLINE)
inst->opmode = MD_BURST_WAS_ONLINE;
else
inst->opmode = MD_BURST_WAS_OFFLINE; inst->opmode = MD_BURST_WAS_OFFLINE;
inst->burst_good_samples_to_go = n_good_samples; inst->burst_good_samples_to_go = n_good_samples;
inst->burst_total_samples_to_go = n_total_samples; inst->burst_total_samples_to_go = n_total_samples;
@@ -1852,13 +1684,11 @@ NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_sampl
SCH_RemoveTimeout(inst->timeout_id); SCH_RemoveTimeout(inst->timeout_id);
} }
inst->timer_running = 1; inst->timer_running = 1;
inst->timeout_id = SCH_AddTimeoutInClass(0.0, SAMPLING_SEPARATION, inst->timeout_id = SCH_AddTimeoutInClass(INITIAL_DELAY, SAMPLING_SEPARATION,
SAMPLING_RANDOMNESS, SAMPLING_RANDOMNESS,
SCH_NtpSamplingClass, SCH_NtpSamplingClass,
transmit_timeout, (void *) inst); transmit_timeout, (void *) inst);
break; break;
default: default:
assert(0); assert(0);
break; break;

View File

@@ -54,20 +54,11 @@ extern void NCR_DestroyInstance(NCR_Instance instance);
/* This routine is called when a new packet arrives off the network, /* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */ and it relates to a source we have an ongoing protocol exchange with */
extern void NCR_ProcessNoauthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data); extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int length);
/* This routine is called when a new packet arrives off the network, /* This routine is called when a new packet arrives off the network,
and we do not recognize its source */ and we do not recognize its source */
extern void NCR_ProcessNoauthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr); extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* This routine is called when a new authenticated packet arrives off
the network, and it relates to a source we have an ongoing protocol
exchange with */
extern void NCR_ProcessAuthKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data);
/* This routine is called when a new authenticated packet arrives off
the network, and we do not recognize its source */
extern void NCR_ProcessAuthUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* Slew receive and transmit times in instance records */ /* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset); extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);

View File

@@ -355,7 +355,7 @@ read_from_socket(void *anything)
} }
#endif #endif
#ifdef IPV6_PKTINFO #if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo ipi; struct in6_pktinfo ipi;
@@ -376,13 +376,9 @@ read_from_socket(void *anything)
#endif #endif
} }
if (status == NTP_NORMAL_PACKET_SIZE) { if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr); NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr, status);
} else if (status == sizeof(NTP_Packet)) {
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
} else { } else {
@@ -466,7 +462,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr)
} }
#endif #endif
#ifdef IPV6_PKTINFO #if defined(IPV6_PKTINFO) && defined(HAVE_IN6_PKTINFO)
if (remote_addr->local_ip_addr.family == IPADDR_INET6) { if (remote_addr->local_ip_addr.family == IPADDR_INET6) {
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
struct in6_pktinfo *ipi; struct in6_pktinfo *ipi;
@@ -523,9 +519,9 @@ NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
/* Send an authenticated packet to a given address */ /* Send an authenticated packet to a given address */
void void
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr) NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len)
{ {
send_packet((void *) packet, sizeof(NTP_Packet), remote_addr); send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr);
} }
/* ================================================== */ /* ================================================== */

View File

@@ -41,7 +41,7 @@ extern void NIO_Finalise(void);
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr); extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
/* Function to transmit an authenticated packet */ /* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr); extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len);
/* Function to send a datagram to a remote machine's UDP echo port. */ /* Function to send a datagram to a remote machine's UDP echo port. */
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr); extern void NIO_SendEcho(NTP_Remote_Address *remote_addr);

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011 * Copyright (C) Miroslav Lichvar 2011-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -287,6 +287,19 @@ NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParame
/* ================================================== */ /* ================================================== */
void
NSR_ResolveSources(void)
{
/* Try to resolve unresolved sources now */
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
}
/* ================================================== */
/* Procedure to remove a source. We don't bother whether the port /* Procedure to remove a source. We don't bother whether the port
address is matched - we're only interested in removing a record for address is matched - we're only interested in removing a record for
the right IP address. Thus the caller can specify the port number the right IP address. Thus the caller can specify the port number
@@ -333,9 +346,10 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
/* ================================================== */ /* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/ /* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr) NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length)
{ {
int slot, found; int slot, found;
@@ -349,27 +363,9 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
find_slot(remote_addr, &slot, &found); find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */ if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessNoauthKnown(message, now, now_err, records[slot].data); NCR_ProcessKnown(message, now, now_err, records[slot].data, length);
} else { } else {
NCR_ProcessNoauthUnknown(message, now, now_err, remote_addr); NCR_ProcessUnknown(message, now, now_err, remote_addr, length);
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
void
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessAuthKnown(message, now, now_err, records[slot].data);
} else {
NCR_ProcessAuthUnknown(message, now, now_err, remote_addr);
} }
} }
@@ -406,12 +402,7 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int i; int i;
int any; int any;
/* Try to resolve unresolved sources now */ NSR_ResolveSources();
if (resolving_interval) {
SCH_RemoveTimeout(resolving_id);
resolving_interval--;
resolve_sources(NULL);
}
any = 0; any = 0;
for (i=0; i<N_RECORDS; i++) { for (i=0; i<N_RECORDS; i++) {
@@ -674,9 +665,10 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
} }
} }
/* Add unresolved sources to offline count */ report->unresolved = 0;
for (us = unresolved_sources; us; us = us->next) { for (us = unresolved_sources; us; us = us->next) {
report->offline++; report->unresolved++;
} }
return; return;

View File

@@ -54,14 +54,14 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type
until it succeeds or fails with a non-temporary error. */ until it succeeds or fails with a non-temporary error. */
extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params); extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params);
/* Procedure to try resolve unresolved sources immediately. */
extern void NSR_ResolveSources(void);
/* Procedure to remove a source */ /* Procedure to remove a source */
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr); extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet arrives off the network */ /* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr); extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* Initialisation function */ /* Initialisation function */
extern void NSR_Initialise(void); extern void NSR_Initialise(void);

View File

@@ -114,6 +114,11 @@ RCL_Initialise(void)
{ {
CNF_AddRefclocks(); CNF_AddRefclocks();
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks", logfileid = CNF_GetLogRefclocks() ? LOG_FileOpen("refclocks",
" Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.") " Date (UTC) Time Refid DP L P Raw offset Cooked offset Disp.")
: -1; : -1;
@@ -268,11 +273,6 @@ RCL_StartRefclocks(void)
} else } else
inst->lock_ref = -1; inst->lock_ref = -1;
} }
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
} }
void void

View File

@@ -31,7 +31,11 @@
#if HAVE_PPSAPI #if HAVE_PPSAPI
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>
#elif defined(HAVE_TIMEPPS_H)
#include <timepps.h> #include <timepps.h>
#endif
#include "logging.h" #include "logging.h"
#include "memory.h" #include "memory.h"

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -48,7 +48,6 @@ static int our_stratum;
static uint32_t our_ref_id; static uint32_t our_ref_id;
static IPAddr our_ref_ip; static IPAddr our_ref_ip;
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */ struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
static double our_offset;
static double our_skew; static double our_skew;
static double our_residual_freq; static double our_residual_freq;
static double our_root_delay; static double our_root_delay;
@@ -56,6 +55,12 @@ static double our_root_dispersion;
static double max_update_skew; static double max_update_skew;
static double last_offset;
static double avg2_offset;
static int avg2_moving;
static double correction_time_ratio;
/* Flag indicating that we are initialised */ /* Flag indicating that we are initialised */
static int initialised = 0; static int initialised = 0;
@@ -63,6 +68,12 @@ static int initialised = 0;
static int make_step_limit; static int make_step_limit;
static double make_step_threshold; static double make_step_threshold;
/* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */
static int max_offset_delay;
static int max_offset_ignore;
static double max_offset;
/* Flag and threshold for logging clock changes to syslog */ /* Flag and threshold for logging clock changes to syslog */
static int do_log_change; static int do_log_change;
static double log_change_threshold; static double log_change_threshold;
@@ -78,6 +89,11 @@ static double drift_file_age;
static void update_drift_file(double, double); static void update_drift_file(double, double);
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
static time_t last_tz_leap_check;
static NTP_Leap tz_leap;
/* ================================================== */ /* ================================================== */
static LOG_FileID logfileid; static LOG_FileID logfileid;
@@ -110,6 +126,25 @@ static double last_ref_update_interval;
/* ================================================== */ /* ================================================== */
static NTP_Leap get_tz_leap(time_t when);
/* ================================================== */
static void
handle_slew(struct timeval *raw,
struct timeval *cooked,
double dfreq,
double doffset,
int is_step_change,
void *anything)
{
if (is_step_change) {
UTI_AddDoubleToTimeval(&last_ref_update, -doffset, &last_ref_update);
}
}
/* ================================================== */
void void
REF_Initialise(void) REF_Initialise(void)
{ {
@@ -139,9 +174,8 @@ REF_Initialise(void)
/* We have read valid data */ /* We have read valid data */
our_frequency_ppm = file_freq_ppm; our_frequency_ppm = file_freq_ppm;
our_skew = 1.0e-6 * file_skew_ppm; our_skew = 1.0e-6 * file_skew_ppm;
LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +- %.3f ppm read from %s", file_freq_ppm, file_skew_ppm, drift_file); LOG(LOGS_INFO, LOGF_Reference, "Frequency %.3f +/- %.3f ppm read from %s", file_freq_ppm, file_skew_ppm, drift_file);
LCL_SetAbsoluteFrequency(our_frequency_ppm); LCL_SetAbsoluteFrequency(our_frequency_ppm);
LCL_ReadCookedTime(&last_ref_update, NULL);
} else { } else {
LOG(LOGS_WARN, LOGF_Reference, "Could not parse valid frequency and skew from driftfile %s", LOG(LOGS_WARN, LOGF_Reference, "Could not parse valid frequency and skew from driftfile %s",
drift_file); drift_file);
@@ -162,14 +196,29 @@ REF_Initialise(void)
} }
logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking", logfileid = CNF_GetLogTracking() ? LOG_FileOpen("tracking",
" Date (UTC) Time IP Address St Freq ppm Skew ppm Offset") " Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L")
: -1; : -1;
max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6; max_update_skew = fabs(CNF_GetMaxUpdateSkew()) * 1.0e-6;
correction_time_ratio = CNF_GetCorrectionTimeRatio();
enable_local_stratum = CNF_AllowLocalReference(&local_stratum); enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
if (get_tz_leap(1214784000) == LEAP_Normal &&
get_tz_leap(1230681600) == LEAP_InsertSecond) {
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
leap_tzname = NULL;
}
}
CNF_GetMakeStep(&make_step_limit, &make_step_threshold); CNF_GetMakeStep(&make_step_limit, &make_step_threshold);
CNF_GetMaxChange(&max_offset_delay, &max_offset_ignore, &max_offset);
CNF_GetLogChange(&do_log_change, &log_change_threshold); CNF_GetLogChange(&do_log_change, &log_change_threshold);
CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user); CNF_GetMailOnChange(&do_mail_change, &mail_change_threshold, &mail_change_user);
@@ -180,10 +229,13 @@ REF_Initialise(void)
memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1)); memset(fb_drifts, 0, sizeof (struct fb_drift) * (fb_drift_max - fb_drift_min + 1));
next_fb_drift = 0; next_fb_drift = 0;
fb_drift_timeout_id = -1; fb_drift_timeout_id = -1;
}
last_ref_update.tv_sec = 0; last_ref_update.tv_sec = 0;
last_ref_update.tv_usec = 0; last_ref_update.tv_usec = 0;
last_ref_update_interval = 0; last_ref_update_interval = 0.0;
}
LCL_AddParameterChangeHandler(handle_slew, NULL);
/* And just to prevent anything wierd ... */ /* And just to prevent anything wierd ... */
if (do_log_change) { if (do_log_change) {
@@ -468,20 +520,109 @@ maybe_make_step()
/* ================================================== */ /* ================================================== */
static void static int
update_leap_status(NTP_Leap leap) is_offset_ok(double offset)
{
if (max_offset_delay < 0)
return 1;
if (max_offset_delay > 0) {
max_offset_delay--;
return 1;
}
offset = fabs(offset);
if (offset > max_offset) {
LOG(LOGS_WARN, LOGF_Reference,
"Adjustment of %.3f seconds exceeds the allowed maximum of %.3f seconds (%s) ",
offset, max_offset, !max_offset_ignore ? "exiting" : "ignored");
if (!max_offset_ignore)
SCH_QuitProgram();
else if (max_offset_ignore > 0)
max_offset_ignore--;
return 0;
}
return 1;
}
/* ================================================== */
static NTP_Leap
get_tz_leap(time_t when)
{
struct tm stm;
time_t t;
char *tz_env, tz_orig[128];
/* Do this check at most twice a day */
when = when / (12 * 3600) * (12 * 3600);
if (last_tz_leap_check == when)
return tz_leap;
last_tz_leap_check = when;
tz_leap = LEAP_Normal;
stm = *gmtime(&when);
/* Check for leap second only in the latter half of June and December */
if (stm.tm_mon == 5 && stm.tm_mday > 14)
stm.tm_mday = 30;
else if (stm.tm_mon == 11 && stm.tm_mday > 14)
stm.tm_mday = 31;
else
return tz_leap;
/* Temporarily switch to the timezone containing leap seconds */
tz_env = getenv("TZ");
if (tz_env) {
if (strlen(tz_env) >= sizeof (tz_orig))
return tz_leap;
strcpy(tz_orig, tz_env);
}
setenv("TZ", leap_tzname, 1);
tzset();
/* Set the time to 23:59:60 and see how it overflows in mktime() */
stm.tm_sec = 60;
stm.tm_min = 59;
stm.tm_hour = 23;
t = mktime(&stm);
if (tz_env)
setenv("TZ", tz_orig, 1);
else
unsetenv("TZ");
tzset();
if (t == -1)
return tz_leap;
if (stm.tm_sec == 60)
tz_leap = LEAP_InsertSecond;
else if (stm.tm_sec == 1)
tz_leap = LEAP_DeleteSecond;
return tz_leap;
}
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now)
{ {
time_t now;
struct tm stm; struct tm stm;
int leap_sec; int leap_sec;
leap_sec = 0; leap_sec = 0;
if (leap_tzname && now && leap == LEAP_Normal)
leap = get_tz_leap(now);
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) { if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
/* Insert/delete leap second only on June 30 or December 31 /* Insert/delete leap second only on June 30 or December 31
and in other months ignore the leap status completely */ and in other months ignore the leap status completely */
now = time(NULL);
stm = *gmtime(&now); stm = *gmtime(&now);
if (stm.tm_mon != 5 && stm.tm_mon != 11) { if (stm.tm_mon != 5 && stm.tm_mon != 11) {
@@ -507,11 +648,12 @@ update_leap_status(NTP_Leap leap)
/* ================================================== */ /* ================================================== */
static void static void
write_log(struct timeval *ref_time, char *ref, int stratum, double freq, double skew, double offset) write_log(struct timeval *ref_time, char *ref, int stratum, NTP_Leap leap, double freq, double skew, double offset)
{ {
const char leap_codes[4] = {'N', '+', '-', '?'};
if (logfileid != -1) { if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e", LOG_FileWrite(logfileid, "%s %-15s %2d %10.3f %10.3f %10.3e %1c",
UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset); UTI_TimeToLogForm(ref_time->tv_sec), ref, stratum, freq, skew, offset, leap_codes[leap]);
} }
} }
@@ -524,6 +666,7 @@ REF_SetReference(int stratum,
IPAddr *ref_ip, IPAddr *ref_ip,
struct timeval *ref_time, struct timeval *ref_time,
double offset, double offset,
double offset_sd,
double frequency, double frequency,
double skew, double skew,
double root_delay, double root_delay,
@@ -535,11 +678,13 @@ REF_SetReference(int stratum,
double old_weight, new_weight, sum_weight; double old_weight, new_weight, sum_weight;
double delta_freq1, delta_freq2; double delta_freq1, delta_freq2;
double skew1, skew2; double skew1, skew2;
double our_offset;
double our_frequency; double our_frequency;
double abs_freq_ppm; double abs_freq_ppm;
double update_interval; double update_interval;
double elapsed; double elapsed;
struct timeval now; double correction_rate;
struct timeval now, raw_now;
assert(initialised); assert(initialised);
@@ -567,6 +712,14 @@ REF_SetReference(int stratum,
} }
} }
LCL_ReadRawTime(&raw_now);
LCL_CookTime(&raw_now, &now, NULL);
UTI_DiffTimevalsToDouble(&elapsed, &now, ref_time);
our_offset = offset + elapsed * frequency;
if (!is_offset_ok(offset))
return;
are_we_synchronised = 1; are_we_synchronised = 1;
our_stratum = stratum + 1; our_stratum = stratum + 1;
@@ -579,11 +732,31 @@ REF_SetReference(int stratum,
our_root_delay = root_delay; our_root_delay = root_delay;
our_root_dispersion = root_dispersion; our_root_dispersion = root_dispersion;
LCL_ReadCookedTime(&now, NULL); update_leap_status(leap, raw_now.tv_sec);
UTI_DiffTimevalsToDouble(&elapsed, &now, ref_time);
our_offset = offset + elapsed * frequency;
update_leap_status(leap); if (last_ref_update.tv_sec) {
UTI_DiffTimevalsToDouble(&update_interval, &now, &last_ref_update);
if (update_interval < 0.0)
update_interval = 0.0;
} else {
update_interval = 0.0;
}
last_ref_update = now;
/* We want to correct the offset quickly, but we also want to keep the
frequency error caused by the correction itself low.
Define correction rate as the area of the region bounded by the graph of
offset corrected in time. Set the rate so that the time needed to correct
an offset equal to the current sourcestats stddev will be equal to the
update interval multiplied by the correction time ratio (assuming linear
adjustment). The offset and the time needed to make the correction are
inversely proportional.
This is only a suggestion and it's up to the system driver how the
adjustment will be executed. */
correction_rate = correction_time_ratio * 0.5 * offset_sd * update_interval;
/* Eliminate updates that are based on totally unreliable frequency /* Eliminate updates that are based on totally unreliable frequency
information */ information */
@@ -619,7 +792,7 @@ REF_SetReference(int stratum,
our_residual_freq = new_freq - our_frequency; our_residual_freq = new_freq - our_frequency;
maybe_log_offset(our_offset); maybe_log_offset(our_offset);
LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset); LCL_AccumulateFrequencyAndOffset(our_frequency, our_offset, correction_rate);
} else { } else {
@@ -627,7 +800,7 @@ REF_SetReference(int stratum,
LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset); LOG(LOGS_INFO, LOGF_Reference, "Skew %f too large to track, offset=%f", skew, our_offset);
#endif #endif
maybe_log_offset(our_offset); maybe_log_offset(our_offset);
LCL_AccumulateOffset(our_offset); LCL_AccumulateOffset(our_offset, correction_rate);
our_residual_freq = frequency; our_residual_freq = frequency;
} }
@@ -639,12 +812,11 @@ REF_SetReference(int stratum,
write_log(&now, write_log(&now,
our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id), our_ref_ip.family != IPADDR_UNSPEC ? UTI_IPToString(&our_ref_ip) : UTI_RefidToString(our_ref_id),
our_stratum, our_stratum,
our_leap_status,
abs_freq_ppm, abs_freq_ppm,
1.0e6*our_skew, 1.0e6*our_skew,
our_offset); our_offset);
UTI_DiffTimevalsToDouble(&update_interval, &now, &last_ref_update);
if (drift_file) { if (drift_file) {
/* Update drift file at most once per hour */ /* Update drift file at most once per hour */
drift_file_age += update_interval; drift_file_age += update_interval;
@@ -659,8 +831,17 @@ REF_SetReference(int stratum,
update_fb_drifts(abs_freq_ppm, update_interval); update_fb_drifts(abs_freq_ppm, update_interval);
} }
last_ref_update = now;
last_ref_update_interval = update_interval; last_ref_update_interval = update_interval;
last_offset = our_offset;
/* Update the moving average of squares of offset, quickly on start */
if (avg2_moving) {
avg2_offset += 0.1 * (our_offset * our_offset - avg2_offset);
} else {
if (avg2_offset > 0.0 && avg2_offset < our_offset * our_offset)
avg2_moving = 1;
avg2_offset = our_offset * our_offset;
}
/* And now set the freq and offset to zero */ /* And now set the freq and offset to zero */
our_frequency = 0.0; our_frequency = 0.0;
@@ -691,7 +872,7 @@ REF_SetManualReference
our_residual_freq = 0.0; our_residual_freq = 0.0;
maybe_log_offset(offset); maybe_log_offset(offset);
LCL_AccumulateFrequencyAndOffset(frequency, offset); LCL_AccumulateFrequencyAndOffset(frequency, offset, 0.0);
maybe_make_step(); maybe_make_step();
abs_freq_ppm = LCL_ReadAbsoluteFrequency(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();
@@ -699,9 +880,10 @@ REF_SetManualReference
write_log(ref_time, write_log(ref_time,
"127.127.1.1", "127.127.1.1",
our_stratum, our_stratum,
our_leap_status,
abs_freq_ppm, abs_freq_ppm,
1.0e6*our_skew, 1.0e6*our_skew,
our_offset); offset);
if (drift_file) { if (drift_file) {
update_drift_file(abs_freq_ppm, our_skew); update_drift_file(abs_freq_ppm, our_skew);
@@ -724,16 +906,16 @@ REF_SetUnsynchronised(void)
schedule_fb_drift(&now); schedule_fb_drift(&now);
} }
update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0;
write_log(&now, write_log(&now,
"0.0.0.0", "0.0.0.0",
0, 0,
our_leap_status,
LCL_ReadAbsoluteFrequency(), LCL_ReadAbsoluteFrequency(),
1.0e6*our_skew, 1.0e6*our_skew,
0.0); 0.0);
are_we_synchronised = 0;
update_leap_status(LEAP_Unsynchronised);
} }
/* ================================================== */ /* ================================================== */
@@ -873,6 +1055,22 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL); LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked); UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
rep->last_update_interval = last_ref_update_interval;
rep->last_offset = last_offset;
rep->rms_offset = sqrt(avg2_offset);
if (are_we_synchronised) { if (are_we_synchronised) {
UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time); UTI_DiffTimevalsToDouble(&elapsed, &now_cooked, &our_ref_time);
@@ -882,8 +1080,6 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr = our_ref_ip; rep->ip_addr = our_ref_ip;
rep->stratum = our_stratum; rep->stratum = our_stratum;
rep->ref_time = our_ref_time; rep->ref_time = our_ref_time;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 1.0e6 * our_residual_freq; rep->resid_freq_ppm = 1.0e6 * our_residual_freq;
rep->skew_ppm = 1.0e6 * our_skew; rep->skew_ppm = 1.0e6 * our_skew;
rep->root_delay = our_root_delay; rep->root_delay = our_root_delay;
@@ -895,26 +1091,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
rep->ip_addr.family = IPADDR_UNSPEC; rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum; rep->stratum = local_stratum;
rep->ref_time = now_cooked; rep->ref_time = now_cooked;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = LCL_GetSysPrecisionAsQuantum(); rep->root_dispersion = LCL_GetSysPrecisionAsQuantum();
} else {
rep->ref_id = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->ref_time.tv_sec = 0;
rep->ref_time.tv_usec = 0;
rep->current_correction = correction;
rep->freq_ppm = LCL_ReadAbsoluteFrequency();
rep->resid_freq_ppm = 0.0;
rep->skew_ppm = 0.0;
rep->root_delay = 0.0;
rep->root_dispersion = 0.0;
} }
} }

View File

@@ -109,6 +109,7 @@ extern void REF_SetReference
IPAddr *ref_ip, IPAddr *ref_ip,
struct timeval *ref_time, struct timeval *ref_time,
double offset, double offset,
double offset_sd,
double frequency, double frequency,
double skew, double skew,
double root_delay, double root_delay,

View File

@@ -300,9 +300,9 @@ RGR_FindBestRegression
nruns = n_runs_from_residuals(resid, n - resid_start); nruns = n_runs_from_residuals(resid, n - resid_start);
if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) { if (nruns > critical_runs[n - resid_start] || n - start <= MIN_SAMPLES_FOR_REGRESS) {
if (resid_start < 0) { if (start != resid_start) {
/* Ignore extra samples in returned nruns */ /* Ignore extra samples in returned nruns */
nruns = n_runs_from_residuals(resid - resid_start, n); nruns = n_runs_from_residuals(resid - resid_start + start, n - start);
} }
break; break;
} else { } else {

View File

@@ -38,7 +38,9 @@ typedef struct {
int poll; int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode; enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state; enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE} state;
enum {RPT_NORMAL, RPT_PREFER, RPT_NOSELECT} sel_option;
int reachability;
unsigned long latest_meas_ago; /* seconds */ unsigned long latest_meas_ago; /* seconds */
double orig_latest_meas; /* seconds */ double orig_latest_meas; /* seconds */
double latest_meas; /* seconds */ double latest_meas; /* seconds */
@@ -49,13 +51,17 @@ typedef struct {
uint32_t ref_id; uint32_t ref_id;
IPAddr ip_addr; IPAddr ip_addr;
unsigned long stratum; unsigned long stratum;
unsigned long leap_status;
struct timeval ref_time; struct timeval ref_time;
double current_correction; double current_correction;
double last_offset;
double rms_offset;
double freq_ppm; double freq_ppm;
double resid_freq_ppm; double resid_freq_ppm;
double skew_ppm; double skew_ppm;
double root_delay; double root_delay;
double root_dispersion; double root_dispersion;
double last_update_interval;
} RPT_TrackingReport; } RPT_TrackingReport;
typedef struct { typedef struct {
@@ -113,6 +119,7 @@ typedef struct {
int offline; int offline;
int burst_online; int burst_online;
int burst_offline; int burst_offline;
int unresolved;
} RPT_ActivityReport; } RPT_ActivityReport;
#endif /* GOT_REPORTS_H */ #endif /* GOT_REPORTS_H */

View File

@@ -3,6 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -664,7 +665,7 @@ handle_initial_trim(void)
sys_error_now = rtc_error_now - coef_seconds_fast; sys_error_now = rtc_error_now - coef_seconds_fast;
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now); LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
LCL_AccumulateOffset(sys_error_now); LCL_AccumulateOffset(sys_error_now, 0.0);
} else { } else {
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time"); LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
} }
@@ -695,6 +696,7 @@ handle_relock_after_trim(void)
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim"); LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
} }
coefs_valid = 0;
n_samples = 0; n_samples = 0;
n_samples_since_regression = 0; n_samples_since_regression = 0;
operating_mode = OM_NORMAL; operating_mode = OM_NORMAL;
@@ -934,7 +936,7 @@ RTC_Linux_TimePreInit(void)
time_t rtc_t, estimated_correct_rtc_t; time_t rtc_t, estimated_correct_rtc_t;
long interval; long interval;
double accumulated_error = 0.0; double accumulated_error = 0.0;
struct timeval new_sys_time; struct timeval new_sys_time, old_sys_time;
coefs_file_name = CNF_GetRtcFile(); coefs_file_name = CNF_GetRtcFile();
@@ -969,8 +971,6 @@ RTC_Linux_TimePreInit(void)
accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm; accumulated_error = file_ref_offset + (double)(interval) * 1.0e-6 * file_rate_ppm;
/* Correct time */ /* Correct time */
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error); estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
} else { } else {
estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error); estimated_correct_rtc_t = rtc_t - (long)(0.5 + accumulated_error);
@@ -979,10 +979,19 @@ RTC_Linux_TimePreInit(void)
new_sys_time.tv_sec = estimated_correct_rtc_t; new_sys_time.tv_sec = estimated_correct_rtc_t;
new_sys_time.tv_usec = 0; new_sys_time.tv_usec = 0;
/* Set system time only if the step is larger than 1 second */
if (!(gettimeofday(&old_sys_time, NULL) < 0) &&
(old_sys_time.tv_sec - new_sys_time.tv_sec > 1 ||
old_sys_time.tv_sec - new_sys_time.tv_sec < -1)) {
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
/* Tough luck if this fails */ /* Tough luck if this fails */
if (settimeofday(&new_sys_time, NULL) < 0) { if (settimeofday(&new_sys_time, NULL) < 0) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday"); LOG(LOGS_WARN, LOGF_RtcLinux, "Could not settimeofday");
} }
}
} else { } else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970"); LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
} }
@@ -1044,6 +1053,11 @@ RTC_Linux_Trim(void)
n_samples = 0; n_samples = 0;
operating_mode = OM_AFTERTRIM; operating_mode = OM_AFTERTRIM;
/* Estimate the offset in case writertc is called or chronyd
is terminated during rapid sampling */
coef_seconds_fast = -now.tv_usec / 1e6 + 0.5;
coef_ref_time = now.tv_sec;
/* And start rapid sampling, interrupts on now */ /* And start rapid sampling, interrupts on now */
if (timeout_running) { if (timeout_running) {
SCH_RemoveTimeout(timeout_id); SCH_RemoveTimeout(timeout_id);

11
sched.c
View File

@@ -466,11 +466,12 @@ dispatch_timeouts(struct timeval *now) {
++n_done; ++n_done;
/* If more timeouts were handled than there were in the timer queue on /* If more timeouts were handled than there were in the timer queue on
start, assume some code is scheduling timeouts with negative delays and start and there are now, assume some code is scheduling timeouts with
abort. Make the actual limit higher in case the machine is temporarily negative delays and abort. Make the actual limit higher in case the
overloaded and dispatching the handlers takes more time than was delay machine is temporarily overloaded and dispatching the handlers takes
of a scheduled timeout. */ more time than was delay of a scheduled timeout. */
if (n_done > n_entries_on_start * 4) { if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling"); LOG_FATAL(LOGF_Scheduler, "Possible infinite loop in scheduling");
} }
} }

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011 * Copyright (C) Miroslav Lichvar 2011-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -857,6 +857,7 @@ SRC_SelectSource(uint32_t match_refid)
sources[selected_source_index]->ip_addr, sources[selected_source_index]->ip_addr,
&ref_time, &ref_time,
src_offset, src_offset,
src_offset_sd,
src_frequency, src_frequency,
src_skew, src_skew,
src_root_delay, src_root_delay,
@@ -1109,6 +1110,23 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
assert(0); assert(0);
break; break;
} }
switch (src->sel_option) {
case SRC_SelectNormal:
report->sel_option = RPT_NOSELECT;
break;
case SRC_SelectPrefer:
report->sel_option = RPT_PREFER;
break;
case SRC_SelectNoselect:
report->sel_option = RPT_NOSELECT;
break;
default:
assert(0);
}
report->reachability = src->reachability;
/* Call stats module to fill out estimates */ /* Call stats module to fill out estimates */
SST_DoSourceReport(src->stats, report, now); SST_DoSourceReport(src->stats, report, now);

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011 * Copyright (C) Miroslav Lichvar 2011-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -239,10 +239,19 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
{ {
int n, m; int n, m;
/* Make room for the new sample */
if (inst->n_samples == MAX_SAMPLES) { if (inst->n_samples == MAX_SAMPLES) {
prune_register(inst, 1); prune_register(inst, 1);
} }
/* Make sure it's newer than the last sample */
if (inst->n_samples &&
UTI_CompareTimevals(&inst->sample_times[inst->last_sample], sample_time) >= 0) {
LOG(LOGS_WARN, LOGF_SourceStats, "Out of order sample detected, discarding history for %s",
inst->ip_addr ? UTI_IPToString(inst->ip_addr) : UTI_RefidToString(inst->refid));
prune_register(inst, inst->n_samples);
}
n = inst->last_sample = (inst->last_sample + 1) % n = inst->last_sample = (inst->last_sample + 1) %
(MAX_SAMPLES * REGRESS_RUNS_RATIO); (MAX_SAMPLES * REGRESS_RUNS_RATIO);
m = n % MAX_SAMPLES; m = n % MAX_SAMPLES;
@@ -528,6 +537,14 @@ SST_GetFrequencyRange(SST_Stats inst,
skew = inst->skew; skew = inst->skew;
*lo = freq - skew; *lo = freq - skew;
*hi = freq + skew; *hi = freq + skew;
/* This function is currently used only to determine the values of delta
and epsilon in the ntp_core module. Limit the skew to a reasonable maximum
to avoid failing the dispersion test too easily. */
if (skew > WORST_CASE_FREQ_BOUND) {
*lo = -WORST_CASE_FREQ_BOUND;
*hi = WORST_CASE_FREQ_BOUND;
}
} }
/* ================================================== */ /* ================================================== */

View File

@@ -50,7 +50,7 @@ typedef struct {
#define SRC_DEFAULT_MAXPOLL 10 #define SRC_DEFAULT_MAXPOLL 10
#define SRC_DEFAULT_PRESEND_MINPOLL 0 #define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 16.0 #define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAYRATIO 16384.0 #define SRC_DEFAULT_MAXDELAYRATIO 0.0
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0 #define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0 #define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6 #define SRC_DEFAULT_POLLTARGET 6

View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009 * Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2009-2011 * Copyright (C) Miroslav Lichvar 2009-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -115,6 +115,9 @@ static int have_readonly_adjtime;
adjustments. */ adjustments. */
static int have_nanopll; static int have_nanopll;
/* Flag indicating whether adjtimex() can step the clock */
static int have_setoffset;
/* ================================================== */ /* ================================================== */
static void handle_end_of_slew(void *anything); static void handle_end_of_slew(void *anything);
@@ -171,6 +174,9 @@ static SCH_TimeoutID slew_timeout_id;
a fast slew */ a fast slew */
static double delta_total_tick; static double delta_total_tick;
/* Maximum length of one fast slew */
#define MAX_FASTSLEW_TIMEOUT (3600 * 24 * 7)
/* Max amount of time that we wish to slew by using adjtime (or its /* Max amount of time that we wish to slew by using adjtime (or its
equivalent). If more than this is outstanding, we alter the value equivalent). If more than this is outstanding, we alter the value
of tick instead, for a set period. Set this according to the of tick instead, for a set period. Set this according to the
@@ -179,7 +185,7 @@ static double delta_total_tick;
#define MAX_ADJUST_WITH_ADJTIME (0.2) #define MAX_ADJUST_WITH_ADJTIME (0.2)
/* Max amount of time that should be adjusted by kernel PLL */ /* Max amount of time that should be adjusted by kernel PLL */
#define MAX_ADJUST_WITH_NANOPLL (1.0e-5) #define MAX_ADJUST_WITH_NANOPLL (0.5)
/* The amount by which we alter 'tick' when doing a large slew */ /* The amount by which we alter 'tick' when doing a large slew */
static int slew_delta_tick; static int slew_delta_tick;
@@ -206,6 +212,18 @@ static double fast_slew_error;
/* The rate at which frequency and tick values are updated in kernel. */ /* The rate at which frequency and tick values are updated in kernel. */
static int tick_update_hz; static int tick_update_hz;
#define MIN_PLL_TIME_CONSTANT 0
#define MAX_PLL_TIME_CONSTANT 10
/* PLL time constant used when adjusting offset by PLL */
static long pll_time_constant;
/* Suggested offset correction rate (correction time * offset) */
static double correction_rate;
/* Kernel time constant shift */
static int shift_pll;
/* ================================================== */ /* ================================================== */
/* These routines are used to estimate maximum error in offset correction */ /* These routines are used to estimate maximum error in offset correction */
@@ -266,9 +284,8 @@ update_nano_slew_error(long offset, int new)
if (offset == 0 && nano_slew_error == 0) if (offset == 0 && nano_slew_error == 0)
return; return;
/* maximum error in offset reported by adjtimex, assuming PLL constant 0 /* maximum error in offset reported by adjtimex */
and SHIFT_PLL = 2 */ offset /= (1 << (shift_pll + pll_time_constant)) - (new ? 0 : 1);
offset /= new ? 4 : 3;
if (offset < 0) if (offset < 0)
offset = -offset; offset = -offset;
@@ -337,6 +354,27 @@ get_fast_slew_error(struct timeval *now)
return left > 0.0 ? fast_slew_error : 0.0; return left > 0.0 ? fast_slew_error : 0.0;
} }
/* ================================================== */
/* Select PLL time constant according to the suggested correction rate. */
static long
get_pll_constant(double offset)
{
long c;
double corr_time;
if (offset < 1e-9)
return MIN_PLL_TIME_CONSTANT;
corr_time = correction_rate / offset;
for (c = MIN_PLL_TIME_CONSTANT; c < MAX_PLL_TIME_CONSTANT; c++)
if (corr_time < 1 << (c + 1 + shift_pll))
break;
return c;
}
/* ================================================== */ /* ================================================== */
/* This routine stops a fast slew, determines how long the slew has /* This routine stops a fast slew, determines how long the slew has
been running for, and consequently how much adjustment has actually been running for, and consequently how much adjustment has actually
@@ -381,7 +419,8 @@ stop_fast_slew(void)
} }
/* ================================================== */ /* ================================================== */
/* This routine reschedules fast slew timeout after frequency was changed */ /* This routine reschedules fast slew timeout according
to the current frequency and offset */
static void static void
adjust_fast_slew(double old_tick, double old_delta_tick) adjust_fast_slew(double old_tick, double old_delta_tick)
@@ -402,8 +441,8 @@ adjust_fast_slew(double old_tick, double old_delta_tick)
dseconds = -offset_register * (current_total_tick + delta_total_tick) / delta_total_tick; dseconds = -offset_register * (current_total_tick + delta_total_tick) / delta_total_tick;
if (dseconds > 3600 * 24 * 7) if (dseconds > MAX_FASTSLEW_TIMEOUT)
dseconds = 3600 * 24 * 7; dseconds = MAX_FASTSLEW_TIMEOUT;
UTI_AddDoubleToTimeval(&tv, dseconds, &end_of_slew); UTI_AddDoubleToTimeval(&tv, dseconds, &end_of_slew);
slew_start_tv = tv; slew_start_tv = tv;
@@ -450,7 +489,7 @@ initiate_slew(void)
update_nano_slew_error(offset, 0); update_nano_slew_error(offset, 0);
offset = 0; offset = 0;
if (TMX_ApplyPLLOffset(offset) < 0) { if (TMX_ApplyPLLOffset(offset, MIN_PLL_TIME_CONSTANT) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed"); LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
} }
nano_slewing = 0; nano_slewing = 0;
@@ -458,13 +497,23 @@ initiate_slew(void)
} }
if (have_nanopll && fabs(offset_register) < MAX_ADJUST_WITH_NANOPLL) { if (have_nanopll && fabs(offset_register) < MAX_ADJUST_WITH_NANOPLL) {
/* Use PLL with fixed frequency to do the shift */ /* Use the PLL with fixed frequency to do the shift. Until the kernel has a
support for linear offset adjustments with programmable rate this is the
best we can do. */
offset = 1.0e9 * -offset_register; offset = 1.0e9 * -offset_register;
if (TMX_ApplyPLLOffset(offset) < 0) { /* First adjustment after accrue_offset() sets the PLL time constant */
if (pll_time_constant < 0) {
pll_time_constant = get_pll_constant(fabs(offset_register));
}
assert(pll_time_constant >= MIN_PLL_TIME_CONSTANT &&
pll_time_constant <= MAX_PLL_TIME_CONSTANT);
if (TMX_ApplyPLLOffset(offset, pll_time_constant) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed"); LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
} }
offset_register = 0.0; offset_register = 0.0; /* Don't keep the sub-nanosecond leftover */
nano_slewing = 1; nano_slewing = 1;
update_nano_slew_error(offset, 1); update_nano_slew_error(offset, 1);
} else if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) { } else if (fabs(offset_register) < MAX_ADJUST_WITH_ADJTIME) {
@@ -539,9 +588,8 @@ initiate_slew(void)
fast_slewing = 1; fast_slewing = 1;
slew_start_tv = T0; slew_start_tv = T0;
/* Set up timeout for end of slew, limit to one week */ if (dseconds > MAX_FASTSLEW_TIMEOUT)
if (dseconds > 3600 * 24 * 7) dseconds = MAX_FASTSLEW_TIMEOUT;
dseconds = 3600 * 24 * 7;
UTI_AddDoubleToTimeval(&T0, dseconds, &end_of_slew); UTI_AddDoubleToTimeval(&T0, dseconds, &end_of_slew);
slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL); slew_timeout_id = SCH_AddTimeout(&end_of_slew, handle_end_of_slew, NULL);
@@ -587,16 +635,21 @@ abort_slew(void)
time) */ time) */
static void static void
accrue_offset(double offset) accrue_offset(double offset, double corr_rate)
{ {
/* Add the new offset to the register */ /* Add the new offset to the register */
offset_register += offset; offset_register += offset;
correction_rate = corr_rate;
/* Select a new time constant on the next adjustment */
pll_time_constant = -1;
if (!fast_slewing) { if (!fast_slewing) {
initiate_slew(); initiate_slew();
} /* Otherwise, when the fast slew completes, any other stuff } else {
in the offset register will be applied */ adjust_fast_slew(current_total_tick, delta_total_tick);
}
} }
/* ================================================== */ /* ================================================== */
@@ -612,6 +665,11 @@ apply_step_offset(double offset)
abort_slew(); abort_slew();
} }
if (have_setoffset) {
if (TMX_ApplyStepOffset(-offset) < 0) {
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
}
} else {
if (gettimeofday(&old_time, NULL) < 0) { if (gettimeofday(&old_time, NULL) < 0) {
LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed"); LOG_FATAL(LOGF_SysLinux, "gettimeofday() failed");
} }
@@ -628,6 +686,7 @@ apply_step_offset(double offset)
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time); UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err)); lcl_InvokeDispersionNotifyHandlers(fabs(err));
}
initiate_slew(); initiate_slew();
@@ -996,8 +1055,9 @@ get_version_specific_details(void)
} }
} }
/* ADJ_OFFSET_SS_READ support */ /* ADJ_OFFSET_SS_READ support. It's available since 2.6.24,
if (kernelvercmp(major, minor, patch, 2, 6, 27) < 0) { but was buggy until 2.6.28. */
if (kernelvercmp(major, minor, patch, 2, 6, 28) < 0) {
have_readonly_adjtime = 0; have_readonly_adjtime = 0;
} else { } else {
have_readonly_adjtime = 1; have_readonly_adjtime = 1;
@@ -1010,14 +1070,28 @@ get_version_specific_details(void)
have_nanopll = 1; have_nanopll = 1;
} }
/* ADJ_SETOFFSET support */
if (kernelvercmp(major, minor, patch, 2, 6, 39) < 0) {
have_setoffset = 0;
} else {
have_setoffset = 1;
}
/* PLL time constant changed in 2.6.31 */
if (kernelvercmp(major, minor, patch, 2, 6, 31) < 0) {
shift_pll = 4;
} else {
shift_pll = 2;
}
/* Override freq_scale if it appears in conf file */ /* Override freq_scale if it appears in conf file */
CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale); CNF_GetLinuxFreqScale(&set_config_freq_scale, &config_freq_scale);
if (set_config_freq_scale) { if (set_config_freq_scale) {
freq_scale = config_freq_scale; freq_scale = config_freq_scale;
} }
LOG(LOGS_INFO, LOGF_SysLinux, "hz=%d shift_hz=%d freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d", LOG(LOGS_INFO, LOGF_SysLinux, "hz=%d shift_hz=%d freq_scale=%.8f nominal_tick=%d slew_delta_tick=%d max_tick_bias=%d shift_pll=%d",
hz, shift_hz, freq_scale, nominal_tick, slew_delta_tick, max_tick_bias); hz, shift_hz, freq_scale, nominal_tick, slew_delta_tick, max_tick_bias, shift_pll);
} }
/* ================================================== */ /* ================================================== */
@@ -1049,6 +1123,11 @@ SYS_Linux_Initialise(void)
have_nanopll = 0; have_nanopll = 0;
} }
if (have_setoffset && TMX_TestStepOffset() < 0) {
LOG(LOGS_INFO, LOGF_SysLinux, "adjtimex() doesn't support ADJ_SETOFFSET");
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRTCSync()); TMX_SetSync(CNF_GetRTCSync());
/* Read current kernel frequency */ /* Read current kernel frequency */

View File

@@ -199,7 +199,7 @@ stop_adjust(void)
slew backwards */ slew backwards */
static void static void
accrue_offset(double offset) accrue_offset(double offset, double corr_rate)
{ {
stop_adjust(); stop_adjust();
offset_register += offset; offset_register += offset;

View File

@@ -212,7 +212,7 @@ stop_adjust(void)
slew backwards */ slew backwards */
static void static void
accrue_offset(double offset) accrue_offset(double offset, double corr_rate)
{ {
stop_adjust(); stop_adjust();
offset_register += offset; offset_register += offset;

View File

@@ -216,7 +216,7 @@ stop_adjust(void)
slew backwards */ slew backwards */
static void static void
accrue_offset(double offset) accrue_offset(double offset, double corr_rate)
{ {
stop_adjust(); stop_adjust();
offset_register += offset; offset_register += offset;

71
util.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009 * Copyright (C) Miroslav Lichvar 2009, 2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -30,7 +30,7 @@
#include "sysincl.h" #include "sysincl.h"
#include "util.h" #include "util.h"
#include "md5.h" #include "hash.h"
/* ================================================== */ /* ================================================== */
@@ -336,16 +336,24 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
uint32_t uint32_t
UTI_IPToRefid(IPAddr *ip) UTI_IPToRefid(IPAddr *ip)
{ {
MD5_CTX ctx; static int MD5_hash = -1;
unsigned char buf[16];
switch (ip->family) { switch (ip->family) {
case IPADDR_INET4: case IPADDR_INET4:
return ip->addr.in4; return ip->addr.in4;
case IPADDR_INET6: case IPADDR_INET6:
MD5Init(&ctx); if (MD5_hash < 0) {
MD5Update(&ctx, (unsigned const char *) ip->addr.in6, sizeof (ip->addr.in6)); MD5_hash = HSH_GetHashId("MD5");
MD5Final(&ctx); assert(MD5_hash >= 0);
return ctx.digest[0] << 24 | ctx.digest[1] << 16 | ctx.digest[2] << 8 | ctx.digest[3]; }
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
assert(0);
return 0;
};
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
} }
return 0; return 0;
} }
@@ -612,3 +620,52 @@ UTI_FdSetCloexec(int fd)
} }
/* ================================================== */ /* ================================================== */
int
UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len)
{
return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
}
/* ================================================== */
int
UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len)
{
unsigned char buf[MAX_HASH_LENGTH];
return UTI_GenerateNTPAuth(hash_id, key, key_len, data, data_len,
buf, sizeof (buf)) == auth_len && !memcmp(buf, auth, auth_len);
}
/* ================================================== */
int
UTI_DecodePasswordFromText(char *key)
{
int i, j, len = strlen(key);
char buf[3], *p;
if (!strncmp(key, "ASCII:", 6)) {
memmove(key, key + 6, len - 6);
return len - 6;
} else if (!strncmp(key, "HEX:", 4)) {
if ((len - 4) % 2)
return 0;
for (i = 0, j = 4; j + 1 < len; i++, j += 2) {
buf[0] = key[j], buf[1] = key[j + 1], buf[2] = '\0';
key[i] = strtol(buf, &p, 16);
if (p != buf + 2)
return 0;
}
return i;
} else {
/* assume ASCII */
return len;
}
}

9
util.h
View File

@@ -32,6 +32,7 @@
#include "addressing.h" #include "addressing.h"
#include "ntp.h" #include "ntp.h"
#include "candm.h" #include "candm.h"
#include "hash.h"
/* Convert a timeval into a floating point number of seconds */ /* Convert a timeval into a floating point number of seconds */
extern void UTI_TimevalToDouble(struct timeval *a, double *b); extern void UTI_TimevalToDouble(struct timeval *a, double *b);
@@ -101,6 +102,14 @@ extern Float UTI_FloatHostToNetwork(double x);
/* Set FD_CLOEXEC on descriptor */ /* Set FD_CLOEXEC on descriptor */
extern void UTI_FdSetCloexec(int fd); extern void UTI_FdSetCloexec(int fd);
extern int UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len);
extern int UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len);
/* Decode password encoded in ASCII or HEX */
extern int UTI_DecodePasswordFromText(char *key);
#if defined (INLINE_UTILITIES) #if defined (INLINE_UTILITIES)
#define INLINE_STATIC inline static #define INLINE_STATIC inline static
#include "util.c" #include "util.c"

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002 * Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2011 * Copyright (C) Miroslav Lichvar 2011-2012
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -207,13 +207,13 @@ TMX_EnableNanoPLL(void)
} }
int int
TMX_ApplyPLLOffset(long offset) TMX_ApplyPLLOffset(long offset, long constant)
{ {
struct timex txc; struct timex txc;
txc.modes = ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO; txc.modes = ADJ_OFFSET | ADJ_TIMECONST | ADJ_NANO;
txc.offset = offset; txc.offset = offset;
txc.constant = 0; txc.constant = constant;
return adjtimex(&txc); return adjtimex(&txc);
} }
@@ -229,5 +229,53 @@ TMX_GetPLLOffsetLeft(long *offset)
return result; return result;
} }
int
TMX_TestStepOffset(void)
{
struct timex txc;
/* Zero maxerror and check it's reset to a maximum after ADJ_SETOFFSET.
This seems to be the only way how to verify that the kernel really
supports the ADJ_SETOFFSET mode as it doesn't return an error on unknown
mode. */
txc.modes = ADJ_MAXERROR;
txc.maxerror = 0;
if (adjtimex(&txc) < 0 || txc.maxerror != 0)
return -1;
txc.modes = ADJ_SETOFFSET;
txc.time.tv_sec = 0;
txc.time.tv_usec = 0;
if (adjtimex(&txc) < 0 || txc.maxerror < 100000)
return -1;
return 0;
}
int
TMX_ApplyStepOffset(double offset)
{
struct timex txc;
txc.modes = ADJ_SETOFFSET;
if (offset >= 0) {
txc.time.tv_sec = offset;
} else {
txc.time.tv_sec = offset - 1;
}
/* ADJ_NANO changes the status even with ADJ_SETOFFSET, use it only when
STA_NANO is already enabled */
if (status & STA_PLL) {
txc.modes |= ADJ_NANO;
txc.time.tv_usec = 1e9 * (offset - txc.time.tv_sec);
} else {
txc.time.tv_usec = 1e6 * (offset - txc.time.tv_sec);
}
return adjtimex(&txc);
}
#endif #endif

View File

@@ -73,8 +73,10 @@ int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap); int TMX_SetLeap(int leap);
int TMX_SetSync(int sync); int TMX_SetSync(int sync);
int TMX_EnableNanoPLL(void); int TMX_EnableNanoPLL(void);
int TMX_ApplyPLLOffset(long offset); int TMX_ApplyPLLOffset(long offset, long constant);
int TMX_GetPLLOffsetLeft(long *offset); int TMX_GetPLLOffsetLeft(long *offset);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);
#endif /* GOT_WRAP_ADJTIMEX_H */ #endif /* GOT_WRAP_ADJTIMEX_H */