Compare commits

...

44 Commits

Author SHA1 Message Date
Miroslav Lichvar
2a299233b3 update NEWS 2015-06-10 14:44:54 +02:00
Miroslav Lichvar
64f83c8861 cmdmon: reply with STT_INVALID on invalid option in handle_manual() 2015-06-09 17:05:45 +02:00
Miroslav Lichvar
1009fe3d9c makefile: warn when Makefile needs to be regenerated 2015-06-09 16:43:56 +02:00
Miroslav Lichvar
ba341fe81a sources: remove unused code in SRC_SelectSource() 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
36e8cb6530 client: add smoothtime command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
273da62aec cmdmon: add smoothtime command
This adds a command to reset or activate the time smoothing process.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
41788184a7 client: add smoothing command 2015-06-09 16:15:30 +02:00
Miroslav Lichvar
fb9c2c7dc8 cmdmon: add smoothing command
This adds a new request to get a current report on time smoothing.
2015-06-09 16:15:30 +02:00
Miroslav Lichvar
43116be122 smooth: fix resetting 2015-06-08 17:22:01 +02:00
Miroslav Lichvar
ee038d5de5 cmdmon: use SCH_GetLastEventTime() to get current time
It's cheaper and accurate enough.
2015-06-08 15:07:18 +02:00
Miroslav Lichvar
ea7fae5277 sched: detect timeout overflow in SCH_AddTimeoutByDelay()
Abort when the system time gets so close to the end of 32-bit time_t
that timeouts added by delay start to overflow. This is an addition to
the loop detector in dispatch_timeouts().
2015-06-08 14:49:52 +02:00
Miroslav Lichvar
70b108ab69 array: allow arrays larger than 4 GB
It's not expected we will work with such large arrays anytime soon, but
better be safe than sorry.

Also, limit the number of elements to 2^31-1 to prevent infinite loop in
the calculation of allocated elements.
2015-06-08 14:43:16 +02:00
Miroslav Lichvar
08b152d6a2 test: add 202-prefer 2015-06-08 12:33:46 +02:00
Miroslav Lichvar
83c6213c67 test: add option to override generated server directives on client 2015-06-08 12:33:34 +02:00
Miroslav Lichvar
4253075a97 sources: fix marking of non-preferred selectable sources
When reducing the list of selectable sources to sources with the prefer
option, sources before the first preferred source were left with the
SRC_OK status, which triggered an assertion failure in the next
selection.
2015-06-08 11:54:43 +02:00
Miroslav Lichvar
0abdc2a350 smooth: add option to smooth out only leap seconds
The leaponly option can be used to enable a mode where only leap seconds
are smoothed out and normal offset/frequency changes are ignored. This
is useful to make the interval in which a leap second is smoothed out
constant and allow an NTP client to use multiple leap smearing servers
safely.
2015-06-02 15:24:01 +02:00
Miroslav Lichvar
31669f343a cmdmon: replace definitions of empty requests with null request 2015-06-01 15:00:14 +02:00
Miroslav Lichvar
438b881ab4 cmdmon: set only non-success status in command handling functions 2015-05-28 15:21:25 +02:00
Miroslav Lichvar
27863146a3 cmdmon: refactor allow/deny functions 2015-05-28 14:32:45 +02:00
Miroslav Lichvar
cd4b73612b ntp: include message precision in peer dispersion 2015-05-28 13:49:43 +02:00
Miroslav Lichvar
3c217a9e37 util: add UTI_Log2ToDouble() 2015-05-28 12:51:54 +02:00
Miroslav Lichvar
cde3a003ea util: handle NaN in UTI_FloatHostToNetwork() 2015-05-18 15:51:32 +02:00
Miroslav Lichvar
2c35f56612 client: handle empty hostname before slash in allow/deny commands 2015-05-18 15:36:52 +02:00
Miroslav Lichvar
4295db25d7 doc: remove chrony(1) man page
It's a copy of README, chrony(1) is not a program itself.
2015-05-18 13:15:43 +02:00
Miroslav Lichvar
3c06e57f24 ntp: increase minimum replacement interval to 30 minutes 2015-05-18 13:15:43 +02:00
Miroslav Lichvar
e949cf5967 ntp: replace non-pool sources when unreachable or falsetickers
Sources that are not specified as a pool and have a name (i.e. not
specified by an IP address or added from chronyc) will be replaced with
a newly resolved address of the name when they become unreachable or
falseticker too.
2015-05-18 13:15:42 +02:00
Miroslav Lichvar
4eeaf34295 ntp: add sources specified by IP directly without name resolving 2015-05-18 13:12:00 +02:00
Miroslav Lichvar
2212a90698 ntp: improve alignment of columns in banner for measurements log 2015-05-04 10:23:17 +02:00
Miroslav Lichvar
dc52b61dad doc: update NEWS 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
bbf4c3186b doc: update chrony description 2015-04-27 12:58:19 +02:00
Miroslav Lichvar
f72016a78e doc: document when smoothtime function is activated 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
29b587a9c5 sys: fix TMX_ResetOffset() to set status back correctly 2015-04-27 12:27:55 +02:00
Miroslav Lichvar
cec4f2b140 reference: use 2012 leap second in leapsectz test 2015-04-24 12:16:47 +02:00
Miroslav Lichvar
05278c3b4c sources: ignore reselect distance when combining with refclock 2015-04-20 12:59:12 +02:00
Miroslav Lichvar
1769b8ea0f use return to exit from main function 2015-04-17 17:34:02 +02:00
Miroslav Lichvar
5686bd87d7 client: improve usage line 2015-04-17 17:33:38 +02:00
Miroslav Lichvar
1cda2db45d main: print usage with -h option 2015-04-17 17:30:38 +02:00
Miroslav Lichvar
fdf9640349 ntp: don't log error when socket() fails for client only socket 2015-04-14 15:59:55 +02:00
Miroslav Lichvar
8f2d5d99f1 doc: don't mention ancient systems
Also, don't try to track working versions of supported systems, assume
current versions are ok.
2015-04-13 17:18:19 +02:00
Miroslav Lichvar
61272e7ce8 update copyright years 2015-04-10 11:06:32 +02:00
Miroslav Lichvar
88b76f49cc doc: warn that unauthenticated peers are vulnerable to DoS attack 2015-04-10 10:52:30 +02:00
Miroslav Lichvar
ad942e352d sys: clamp frequency set in generic driver on exit 2015-04-10 10:22:28 +02:00
Miroslav Lichvar
39c2bcd462 util: don't allow time too close to 32-bit time_t overflow
In UTI_IsTimeOffsetSane() consider time in one year interval before
32-bit time_t overflow (in 2038) as invalid. Hopefully everything will
be using 64-bit time_t when that time comes.
2015-04-10 10:05:15 +02:00
Miroslav Lichvar
ae10664b24 doc: fix CVE-ID in NEWS
CVE-2015-1853 is for chrony, CVE-2015-1799 is for ntp.
2015-04-08 08:44:42 +02:00
38 changed files with 756 additions and 674 deletions

View File

@@ -112,8 +112,6 @@ install: chronyd chronyc chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/COPYING
cp README $(DESTDIR)$(DOCDIR)/README
chmod 644 $(DESTDIR)$(DOCDIR)/README
cp chrony.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chrony.1
cp chronyc.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/chronyc.1
cp chronyd.8 $(DESTDIR)$(MANDIR)/man8
@@ -152,6 +150,12 @@ chrony.html : chrony.texi
chrony.info : chrony.texi
makeinfo chrony.texi
Makefile : Makefile.in configure
@echo
@echo Makefile needs to be regenerated, run ./configure
@echo
@exit 1
.deps:
@mkdir .deps

24
NEWS
View File

@@ -1,3 +1,22 @@
New in version 2.1
==================
Enhancements
------------
* Try to replace unreachable and falseticker servers/peers specified
by name like pool sources
* Add leaponly option to smoothtime directive to allow synchronised
leap smear between multiple servers
* Add smoothing command to report time smoothing status
* Add smoothtime command to activate or reset time smoothing
Bug fixes
---------
* Fix crash in source selection with preferred sources
* Fix resetting of time smoothing
* Include packet precision in peer dispersion
* Fix crash in chronyc on invalid command syntax
New in version 2.0
==================
@@ -15,7 +34,7 @@ Enhancements
* Improve source selection
* Handle offline sources as unreachable
* Open NTP server port only when necessary (client access is allowed by
allow directive/command, peer or broadcast is configured)
allow directive/command or peer/broadcast is configured)
* Change default bindcmdaddress to loopback address
* Change default maxdelay to 3 seconds
* Change default stratumweight to 0.001
@@ -30,6 +49,7 @@ Bug fixes
---------
* Add sanity checks for time and frequency offset
* Don't report synchronised status during leap second
* Don't combine reference clocks with close NTP sources
* Fix accepting requests from configured sources
* Fix initial fallback drift setting
@@ -39,7 +59,7 @@ New in version 1.31.1
Security fixes
--------------
* Protect authenticated symmetric NTP associations against DoS attacks
(CVE-2015-1799)
(CVE-2015-1853)
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)

81
README
View File

@@ -3,67 +3,35 @@ This is the README for chrony.
What is chrony?
===============
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
chronyd is a (background) daemon program that can be started at boot
time. This does most of the work.
It is designed to perform well in a wide range of conditions, including
intermittent network connections, heavily congested networks, changing
temperatures (ordinary computer clocks are sensitive to temperature),
and systems that do not run continuosly, or run on a virtual machine.
chronyc is a command-line interface program which can be used to
monitor chronyd's performance and to change various operating
parameters whilst it is running.
chronyd's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from Network Time Protocol (NTP)
servers, reference clocks, or wristwatch-and-keyboard (via chronyc).
The main source of information about the Network Time Protocol is
http://www.ntp.org.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
chronyd can also operate as an NTPv4 (RFC 5905) server, peer and broadcast
server.
Typical accuracy between two machines on a LAN is in tens, or a few
hundreds, of microseconds; over the Internet, accuracy is typically
within a few milliseconds. With a good hardware reference clock
sub-microsecond accuracy is possible.
Two programs are included in chrony, chronyd is a daemon that can be
started at boot time and chronyc is a command-line interface program
which can be used to monitor chronyd's performance and to change various
operating parameters whilst it is running.
What will chrony run on?
========================
Chrony can be successfully built and run on
1. Linux 2.2.x, 2.3.x, 2.4.x, 2.6.x, 3.x
2. Solaris 2.5/2.5.1/2.6/2.7/2.8 (various platforms)
3. SunOS 4.1.4 (Sparc 2 and Sparc 20)
4. BSD/386 v1.1 has been reported to work using the SunOS 4.1 driver.
5. NetBSD.
Any other system will require a porting exercise. You would need to
start from one of the existing system-specific drivers and look into
the quirks of certain system calls and the kernel on your target
system.
The software is known to work on Linux, FreeBSD, NetBSD and Solaris.
Closely related systems may work too. Any other system will likely
require a porting exercise. You would need to start from one of the
existing system-specific drivers and look into the quirks of certain
system calls and the kernel on your target system.
How do I set it up?
===================
@@ -116,6 +84,11 @@ chrony-dev-request@chrony.tuxfamily.org
as applicable.
License
=======
chrony is distributed under the GNU General Public License version 2.
Author
======

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
* Copyright (C) Miroslav Lichvar 2009
* Copyright (C) Miroslav Lichvar 2009, 2015
*
* 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

12
array.c
View File

@@ -44,6 +44,8 @@ ARR_CreateInstance(unsigned int elem_size)
{
ARR_Instance array;
assert(elem_size > 0);
array = MallocNew(struct ARR_Instance_Record);
array->data = NULL;
@@ -64,6 +66,9 @@ ARR_DestroyInstance(ARR_Instance array)
static void
realloc_array(ARR_Instance array, unsigned int min_size)
{
size_t data_size;
assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return;
@@ -74,7 +79,10 @@ realloc_array(ARR_Instance array, unsigned int min_size)
array->allocated = min_size;
}
array->data = Realloc(array->data, array->elem_size * array->allocated);
data_size = (size_t)array->elem_size * array->allocated;
assert(data_size / array->elem_size == array->allocated);
array->data = Realloc(array->data, data_size);
}
void *
@@ -89,7 +97,7 @@ void *
ARR_GetElement(ARR_Instance array, unsigned int index)
{
assert(index < array->used);
return (void *)((char *)array->data + index * array->elem_size);
return (void *)((char *)array->data + (size_t)index * array->elem_size);
}
void *

92
candm.h
View File

@@ -89,7 +89,9 @@
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50
#define N_REQUEST_TYPES 51
#define REQ_SMOOTHING 51
#define REQ_SMOOTHTIME 52
#define N_REQUEST_TYPES 53
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -116,6 +118,10 @@ typedef struct {
pktlength.c, to get the number of bytes that ought to be
transmitted for each packet type. */
typedef struct {
int32_t EOR;
} REQ_Null;
typedef struct {
IPAddr mask;
IPAddr address;
@@ -215,19 +221,11 @@ typedef struct {
int32_t EOR;
} REQ_Manual;
typedef struct {
int32_t EOR;
} REQ_N_Sources;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_Source_Data;
typedef struct {
int32_t EOR;
} REQ_Rekey;
typedef struct {
IPAddr ip;
int32_t subnet_bits;
@@ -264,10 +262,6 @@ typedef struct {
int32_t EOR;
} REQ_Del_Source;
typedef struct {
int32_t EOR;
} REQ_WriteRtc;
typedef struct {
Float dfreq;
int32_t EOR;
@@ -279,27 +273,11 @@ typedef struct {
int32_t EOR;
} REQ_Doffset;
typedef struct {
int32_t EOR;
} REQ_Tracking;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_Sourcestats;
typedef struct {
int32_t EOR;
} REQ_RTCReport;
typedef struct {
int32_t EOR;
} REQ_TrimRTC;
typedef struct {
int32_t EOR;
} REQ_CycleLogs;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
@@ -310,32 +288,24 @@ typedef struct {
int32_t EOR;
} REQ_ClientAccessesByIndex;
typedef struct {
int32_t EOR;
} REQ_ManualList;
typedef struct {
int32_t index;
int32_t EOR;
} REQ_ManualDelete;
typedef struct {
int32_t EOR;
} REQ_MakeStep;
typedef struct {
int32_t EOR;
} REQ_Activity;
typedef struct {
int32_t EOR;
} REQ_Reselect;
typedef struct {
Float distance;
int32_t EOR;
} REQ_ReselectDistance;
#define REQ_SMOOTHTIME_RESET 0
#define REQ_SMOOTHTIME_ACTIVATE 1
typedef struct {
int32_t option;
int32_t EOR;
} REQ_SmoothTime;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -365,7 +335,7 @@ typedef struct {
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16, new commands: modify
makestep
makestep, smoothing report, smoothtime command
*/
#define PROTO_VERSION_NUMBER 6
@@ -398,6 +368,7 @@ typedef struct {
uint32_t token; /* Command token (to prevent replay attack) */
union {
REQ_Null null;
REQ_Online online;
REQ_Offline offline;
REQ_Burst burst;
@@ -415,28 +386,18 @@ typedef struct {
REQ_Settime settime;
REQ_Local local;
REQ_Manual manual;
REQ_N_Sources n_sources;
REQ_Source_Data source_data;
REQ_Rekey rekey;
REQ_Allow_Deny allow_deny;
REQ_Ac_Check ac_check;
REQ_NTP_Source ntp_source;
REQ_Del_Source del_source;
REQ_WriteRtc writertc;
REQ_Dfreq dfreq;
REQ_Doffset doffset;
REQ_Tracking tracking;
REQ_Sourcestats sourcestats;
REQ_RTCReport rtcreport;
REQ_TrimRTC trimrtc;
REQ_CycleLogs cyclelogs;
REQ_ClientAccessesByIndex client_accesses_by_index;
REQ_ManualList manual_list;
REQ_ManualDelete manual_delete;
REQ_MakeStep make_step;
REQ_Activity activity;
REQ_Reselect reselect;
REQ_ReselectDistance reselect_distance;
REQ_SmoothTime smoothtime;
} data; /* Command specific parameters */
/* The following fields only set the maximum size of the packet.
@@ -472,7 +433,8 @@ typedef struct {
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
#define RPY_MANUAL_LIST 11
#define RPY_ACTIVITY 12
#define N_REPLY_TYPES 13
#define RPY_SMOOTHING 13
#define N_REPLY_TYPES 14
/* Status codes */
#define STT_SUCCESS 0
@@ -627,6 +589,19 @@ typedef struct {
int32_t EOR;
} RPY_Activity;
#define RPY_SMT_FLAG_ACTIVE 0x1
#define RPY_SMT_FLAG_LEAPONLY 0x2
typedef struct {
uint32_t flags;
Float offset;
Float freq_ppm;
Float wander_ppm;
Float last_update_ago;
Float remaining_time;
int32_t EOR;
} RPY_Smoothing;
typedef struct {
uint8_t version;
uint8_t pkt_type;
@@ -653,6 +628,7 @@ typedef struct {
RPY_ClientAccessesByIndex client_accesses_by_index;
RPY_ManualList manual_list;
RPY_Activity activity;
RPY_Smoothing smoothing;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data

View File

@@ -1,72 +0,0 @@
.TH CHRONY 1 "@MAN_DATE@" "chrony @VERSION@" "User's Manual"
.SH NAME
chrony \- programs for keeping computer clocks accurate
.SH SYNOPSIS
\fBchronyc\fR [\fIOPTIONS\fR]
\fBchronyd\fR [\fIOPTIONS\fR]
.SH DESCRIPTION
\fBchrony\fR is a pair of programs for keeping computer clocks accurate.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
real-time clock at boot time (Linux only). chronyd can determine the rate at
which the computer gains or loses time and compensate for it while no external
reference is present. Its use of NTP servers can be switched on and off
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
to the Internet, and it can also act as an NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
monitor \fIchronyd\fR's performance and to change various operating
parameters whilst it is running.
\fIchronyd\fR's main function is to obtain measurements of the true (UTC)
time from one of several sources, and correct the system clock
accordingly. It also works out the rate at which the system clock
gains or loses time and uses this information to keep it accurate
between measurements from the reference.
The reference time can be derived from either Network Time Protocol
(NTP) servers, reference clocks, or wristwatch-and-keyboard (via \fIchronyc\fR).
The main source of information about the Network Time Protocol is
\fIhttp://www.ntp.org\fR.
It is designed so that it can work on computers which only have
intermittent access to reference sources, for example computers which
use a dial-up account to access the Internet or laptops. Of course, it
will work well on computers with permanent connections too.
In addition, on Linux it can monitor the system's real time clock
performance, so the system can maintain accurate time even across
reboots.
Typical accuracies available between 2 machines are
On an ethernet LAN : 100-200 microseconds, often much better
On a V32bis dial-up modem connection : 10's of milliseconds (from one
session to the next)
With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
broadcast server.
.SH "SEE ALSO"
.BR chronyc(1),
.BR chrony.conf(5),
.BR chronyd(8)
.I http://chrony.tuxfamily.org/
.SH AUTHOR
Richard Curnow <rc@rc0.org.uk>
This man-page was written by Jan Schaumann <jschauma@netmeister.org> as part
of "The Missing Man Pages Project". Please see
\fIhttp://www.netmeister.org/misc/m2p2/index.html\fR for details.
The complete chrony documentation is supplied in texinfo format.

View File

@@ -40,9 +40,8 @@ useful configuration file would look something like
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the `pool' directive
instead of multiple `server' directives in order to allow \fIchronyd\fR to
replace unreachable or bad servers automatically. The configuration file could
in this case look like
instead of multiple `server' directives. The configuration file could in this
case look like
.EX
pool pool.ntp.org iburst
@@ -52,7 +51,6 @@ in this case look like
.EE
.SH "SEE ALSO"
.BR chrony(1),
.BR chronyc(1),
.BR chronyd(8)

View File

@@ -56,34 +56,30 @@ Copyright @copyright{} 2009-2014 Miroslav Lichvar
@c {{{ S:Overview
@node Overview
@section Overview
Chrony is a software package for maintaining the accuracy of computer
system clocks. It consists of a pair of programs :
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
@itemize @bullet
@item @code{chronyd}. This is a daemon which runs in background on the
system. It obtains measurements (e.g. via the network) of the system's
offset relative to other systems, and adjusts the system time
accordingly. For isolated systems, the user can periodically enter the
correct time by hand (using @code{chronyc}). In either case,
@code{chronyd} determines the rate at which the computer gains or loses
time, and compensates for this.
It is designed to perform well in a wide range of conditions, including
intermittent network connections, heavily congested networks, changing
temperatures (ordinary computer clocks are sensitive to temperature),
and systems that do not run continuosly, or run on a virtual machine.
@code{chronyd} can also act as an NTP server, and provide a time-of-day service
to other computers. A typical set-up is to run @code{chronyd} on a gateway
computer that has a dial-up link to the Internet, and use it to serve time to
computers on a private LAN sitting behind the gateway. The IP addresses that
can act as clients of @code{chronyd} can be tightly controlled. The default is
no client access.
Typical accuracy between two machines on a LAN is in tens, or a few
hundreds, of microseconds; over the Internet, accuracy is typically
within a few milliseconds. With a good hardware reference clock
sub-microsecond accuracy is possible.
@item @code{chronyc}. This is a command-line driven control and
monitoring program. An administrator can use this to fine-tune various
parameters within the daemon, add or delete servers etc whilst the
daemon is running.
Two programs are included in chrony, @code{chronyd} is a daemon that can
be started at boot time and @code{chronyc} is a command-line interface
program which can be used to monitor @code{chronyd}'s performance and to
change various operating parameters whilst it is running.
The IP addresses from which @code{chronyc} clients may connect can be tightly
controlled. The default is just the computer that @code{chronyd} itself is
running on.
@end itemize
@c }}}
@c {{{ S:Acknowledgments
@node Acknowledgements
@@ -123,24 +119,10 @@ different operating systems may provide different function calls to
achieve this, and even where the same function is used it may have
different quirks in its behaviour.
The software is known to work in the following environments:
@itemize @bullet
@item Linux 2.2 and newer
@item NetBSD
@item BSD/386
@item Solaris 2.3/2.5/2.5.1/2.6/2.7/2.8 on Sparc (Sparc 20, Ultrasparc) and
i386
@item SunOS 4.1.4 on Sparc 2 and Sparc20.
@end itemize
Closely related systems may work too, but they have not been tested.
Porting the software to other system (particularly to those supporting
an @code{adjtime} system call) should not be difficult, however it
requires access to such systems to test out the driver.
The software is known to work on Linux, FreeBSD, NetBSD and Solaris. Closely
related systems may work too. Porting the software to other systems
(particularly to those supporting an @code{adjtime} system call) should not be
difficult, however it requires access to such systems to test out the driver.
@c }}}
@c {{{ S:Other programs
@node Other time synchronisation packages
@@ -305,8 +287,7 @@ Particular areas that need addressing are :
@item Porting to other Unices
This involves creating equivalents of sys_solaris.c, sys_linux.c etc for the
new system. Note, the Linux driver has been reported as working on a range of
different architectures (Alpha, Sparc, MIPS as well as x86 of course).
new system.
@item Porting to Windows NT
@@ -600,9 +581,8 @@ rtcsync
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the @code{pool}
directive instead of multiple @code{server} directives in order to allow
@code{chronyd} to replace unreachable or bad servers automatically. The
configuration file could in this case look like
directive instead of multiple @code{server} directives. The configuration file
could in this case look like
@example
pool pool.ntp.org iburst
@@ -1012,9 +992,8 @@ configuration file. This option is useful if you want to stop and
restart @code{chronyd} briefly for any reason, e.g. to install a new
version. However, it only makes sense on systems where the kernel can
maintain clock compensation whilst not under @code{chronyd's} control.
The only version where this happens so far is Linux. On systems where
this is not the case, e.g. Solaris and SunOS the option should not be
used.
The only version where this happens so far is Linux. On other systems
this option should not be used.
@item -R
When this option is used, the @code{initstepslew} directive and the
@code{makestep} directive used with a positive limit will be ignored.
@@ -2543,6 +2522,21 @@ be reported using the @code{clients} command in @code{chronyc}.
The syntax of this directive is identical to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify
an NTP peer rather than an NTP server.
Please note that NTP peers that are not configured with a key to enable
authentication are vulnerable to a denial-of-service attack. An attacker
knowing that NTP hosts A and B are peering with each other can send a packet
with random timestamps to host A with source address of B which will set the
NTP state variables on A to the values sent by the attacker. Host A will then
send on its next poll to B a packet with originate timestamp that doesn't match
the transmit timestamp of B and the packet will be dropped. If the attacker
does this periodically for both hosts, they won't be able to synchronize to
each other.
This attack can be prevented by enabling authentication with the key option, or
using the @code{server} directive on both sides to specify the other host as a
server instead of peer, the only drawback is that it will double the network
traffic between the two hosts.
@c }}}
@c {{{ pidfile
@node pidfile directive
@@ -3054,12 +3048,18 @@ falseticker or fail to select a source completely.
The smoothing process is independent from any slewing applied to the local
system clock, but the accumulated offset and frequency for smoothing will be
reset when the clock is corrected by step, e.g. by the @code{makestep}
directive or command.
reset when the clock is corrected by stepping, e.g. by the @code{makestep}
directive or command. The process can be reset without stepping the clock
by the @code{smoothtime reset} command (@pxref{smoothtime command}).
The directive takes two arguments, the maximum frequency offset of the smoothed
time to the tracked NTP time (in ppm) and the maximum rate at which the
frequency offset is allowed to change (in ppm per second).
frequency offset is allowed to change (in ppm per second). The smoothing
process is activated automatically when 1/10000 of the estimated skew of the
local clock falls below the maximum rate of frequency change. It can be
activated explicitly by the @code{smoothtime activate} command, which is
particularly useful when the clock is synchronized only with manual input
since the skew can't be small enough to activate the process.
An example suitable for clients using @code{ntpd} and 1024 second polling
interval could be
@@ -3288,6 +3288,7 @@ password:
@item @code{password}
@item @code{quit}
@item @code{rtcdata}
@item @code{smoothing}
@item @code{sources}
@item @code{sourcestats}
@item @code{tracking}
@@ -3348,6 +3349,8 @@ interface.
* retries command:: Set maximum number of retries
* rtcdata command:: Display RTC parameters
* settime command:: Provide a manual input of the current time
* smoothing command:: Display current time smoothing state
* smoothtime command:: Reset/activate server time smoothing
* sources command:: Display information about the current set of sources
* sourcestats command:: Display the rate & offset estimation performance of sources
* timeout command:: Set initial response timeout
@@ -4165,9 +4168,7 @@ password
@end example
The computer will respond with a @samp{Password:} prompt, at which you
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
library. Other systems do not have this restriction.)
should enter the password and press return.
The password can be encoded as a string of characters not containing a space
with optional @code{ASCII:} prefix or as a hexadecimal number with @code{HEX:}
@@ -4326,6 +4327,66 @@ settime Nov 21, 1997 16:30:05
For a full description of @code{getdate}, get hold of the getdate
documentation (bundled, for example, with the source for GNU tar).
@c }}}
@c {{{ smoothing
@node smoothing command
@subsubsection smoothing
The @code{smoothing} command displays the current state of the NTP server time
smoothing. An example of the output is shown below.
@example
Active : Yes
Offset : +1.000268817 seconds
Frequency : -0.142859 ppm
Wander : -0.010000 ppm per second
Last update : 17.8 seconds ago
Remaining time : 19988.4 seconds
@end example
The fields are explained as follows.
@table @code
@item Active
This shows if the server time smoothing is currently active. Possible values
are @code{Yes} and @code{No}. If the @code{leaponly} option is included in the
@code{smoothtime} directive, @code{(leap second only)} will be shown on the
line.
@item Offset
This is the current offset applied to the time sent to NTP clients. Positive
value means the clients are getting time that's ahead of true time.
@item Frequency
The current frequency offset of the served time. Negative value means the time
observed by clients is running slower than true time.
@item Wander
The current frequency wander of the served time. Negative value means the time
observed by clients is slowing down.
@item Last update
This field shows how long ago was the time smoothing process updated, e.g.
@code{chronyd} accumulated a new measurement.
@item Remaining time
The time it would take for the smoothing process to get to zero offset and
frequency if there were no more updates.
@end table
@c }}}
@c {{{ smoothtime
@node smoothtime command
@subsubsection smoothtime
The @code{smoothtime} command can be used to reset or activate the server time
smoothing process if it is configured with the @code{smoothtime} directive
(@pxref{smoothtime directive}).
The syntax is as follows
@example
smoothtime reset
smoothtime activate
@end example
@c }}}
@c {{{ sources
@node sources command
@@ -4551,7 +4612,7 @@ true time (which it reports to NTP clients when it is operating in
server mode). The value reported on this line is the difference due to
this effect.
On systems such as Solaris and SunOS, @code{chronyd} has no means to
On systems other than Linux, @code{chronyd} doesn't
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
been measured. The build up of these offsets will be observed in this

View File

@@ -60,8 +60,7 @@ interactively.
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
.SH "SEE ALSO"
.BR chronyd(8),
.BR chrony(1)
.BR chronyd(8)
.I http://chrony.tuxfamily.org/

View File

@@ -70,8 +70,7 @@ option is useful if you want to stop and restart \fBchronyd\fR briefly for any
reason, e.g. to install a new version. However, it only makes sense on
systems where the kernel can maintain clock compensation whilst not under
\fBchronyd\fR's control. The only version where this happens so far is Linux.
On systems where this is not the case, e.g. Solaris and SunOS the option
should not be used.
On other systems this option should not be used.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
@@ -135,7 +134,6 @@ To report bugs, please visit \fIhttp://chrony.tuxfamily.org/\fR
\fBchronyd\fR is documented in detail in the documentation supplied with the
distribution (\fIchrony.txt\fR and \fIchrony.texi\fR).
.BR chrony(1),
.BR chronyc(1),
.BR chrony.conf(5),
.BR hwclock(8),

View File

@@ -640,7 +640,8 @@ process_cmd_manual(CMD_Request *msg, const char *line)
static int
parse_allow_deny(CMD_Request *msg, char *line)
{
unsigned long a, b, c, d, n;
unsigned long a, b, c, d;
int n, specified_subnet_bits;
IPAddr ip;
char *p;
@@ -657,7 +658,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
n = 0;
if (!UTI_StringToIP(p, &ip) &&
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) <= 0) {
/* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
@@ -710,7 +711,6 @@ parse_allow_deny(CMD_Request *msg, char *line)
UTI_IPHostToNetwork(&ip, &msg->data.allow_deny.ip);
if (slashpos) {
int specified_subnet_bits, n;
n = sscanf(slashpos+1, "%d", &specified_subnet_bits);
if (n == 1) {
msg->data.allow_deny.subnet_bits = htonl(specified_subnet_bits);
@@ -1184,6 +1184,8 @@ give_help(void)
printf("reselect : Reselect synchronisation source\n");
printf("rtcdata : Print current RTC performance parameters\n");
printf("settime <date/time (e.g. Nov 21, 1997 16:30:05 or 16:30:05)> : Manually set the daemon time\n");
printf("smoothing : Display current time smoothing state\n");
printf("smoothtime reset|activate : Reset/activate time smoothing\n");
printf("sources [-v] : Display information about current sources\n");
printf("sourcestats [-v] : Display estimation information about current sources\n");
printf("tracking : Display system time information\n");
@@ -1964,6 +1966,63 @@ process_cmd_tracking(char *line)
}
/* ================================================== */
static int
process_cmd_smoothing(char *line)
{
CMD_Request request;
CMD_Reply reply;
uint32_t flags;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
request.command = htons(REQ_SMOOTHING);
if (request_reply(&request, &reply, RPY_SMOOTHING, 0)) {
flags = ntohl(reply.data.smoothing.flags);
offset = UTI_FloatNetworkToHost(reply.data.smoothing.offset);
freq_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.freq_ppm);
wander_ppm = UTI_FloatNetworkToHost(reply.data.smoothing.wander_ppm);
last_update_ago = UTI_FloatNetworkToHost(reply.data.smoothing.last_update_ago);
remaining_time = UTI_FloatNetworkToHost(reply.data.smoothing.remaining_time);
printf("Active : %s%s\n",
flags & RPY_SMT_FLAG_ACTIVE ? "Yes" : "No",
flags & RPY_SMT_FLAG_LEAPONLY ? " (leap second only)" : "");
printf("Offset : %+.9f seconds\n", offset);
printf("Frequency : %+.6f ppm\n", freq_ppm);
printf("Wander : %+.6f ppm per second\n", wander_ppm);
printf("Last update : %.1f seconds ago\n", last_update_ago);
printf("Remaining time : %.1f seconds\n", remaining_time);
return 1;
}
return 0;
}
/* ================================================== */
static int
process_cmd_smoothtime(CMD_Request *msg, const char *line)
{
if (!strcmp(line, "reset")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_RESET);
} else if (!strcmp(line, "activate")) {
msg->data.smoothtime.option = htonl(REQ_SMOOTHTIME_ACTIVATE);
} else {
fprintf(stderr, "Invalid syntax for smoothtime command\n");
return 0;
}
msg->command = htons(REQ_SMOOTHTIME);
return 1;
}
/* ================================================== */
static int
process_cmd_rtcreport(char *line)
{
@@ -2535,6 +2594,11 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "settime")) {
do_normal_submit = 0;
ret = process_cmd_settime(line);
} else if (!strcmp(command, "smoothing")) {
do_normal_submit = 0;
ret = process_cmd_smoothing(line);
} else if (!strcmp(command, "smoothtime")) {
do_normal_submit = process_cmd_smoothtime(&tx_message, line);
} else if (!strcmp(command, "sources")) {
do_normal_submit = 0;
ret = process_cmd_sources(line);
@@ -2729,10 +2793,11 @@ main(int argc, char **argv)
family = IPADDR_INET6;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
exit(0);
return 0;
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);
exit(1);
fprintf(stderr, "Usage: %s [-h HOST] [-p PORT] [-n] [-4|-6] [-a] [-f FILE] [-m] [COMMAND]\n",
progname);
return 1;
} else {
break; /* And process remainder of line as a command */
}

368
cmdmon.c
View File

@@ -37,6 +37,7 @@
#include "keys.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "smooth.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
@@ -162,6 +163,8 @@ static const char permissions[] = {
PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH, /* RESELECTDISTANCE */
PERMIT_AUTH, /* MODIFY_MAKESTEP */
PERMIT_OPEN, /* SMOOTHING */
PERMIT_AUTH, /* SMOOTHTIME */
};
/* ================================================== */
@@ -712,13 +715,12 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
}
}
/* ================================================== */
static void
handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
SRC_DumpSources();
}
/* ================================================== */
@@ -726,16 +728,12 @@ handle_null(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
status = NSR_TakeSourcesOnline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOnline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -743,16 +741,12 @@ handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
status = NSR_TakeSourcesOffline(&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_TakeSourcesOffline(&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -760,19 +754,14 @@ handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address, mask;
UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
status = NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address);
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
ntohl(rx_message->data.burst.n_total_samples),
&mask, &address))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -780,17 +769,12 @@ handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -798,17 +782,12 @@ handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxpoll(&address,
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -816,16 +795,12 @@ handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
status = NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelay(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -833,16 +808,12 @@ handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
status = NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelayratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -850,16 +821,12 @@ handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
status = NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMaxdelaydevratio(&address,
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -867,17 +834,12 @@ handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
status = NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyMinstratum(&address,
ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -885,17 +847,12 @@ handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
IPAddr address;
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
status = NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target));
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NSR_ModifyPolltarget(&address,
ntohl(rx_message->data.modify_polltarget.new_poll_target)))
tx_message->status = htons(STT_NOSUCHSOURCE);
}
}
/* ================================================== */
@@ -904,7 +861,6 @@ static void
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -914,7 +870,6 @@ handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -929,7 +884,6 @@ handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
if (!MNL_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
} else if (MNL_AcceptTimestamp(&ts, &offset_cs, &dfreq_ppm, &new_afreq_ppm)) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP);
tx_message->data.manual_timestamp.centiseconds = htonl((int32_t)offset_cs);
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
@@ -952,7 +906,6 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
} else {
REF_DisableLocal();
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -972,8 +925,10 @@ handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
case 2:
MNL_Reset();
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -983,7 +938,6 @@ handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int n_sources;
n_sources = SRC_ReadNumberOfSources();
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_N_SOURCES);
tx_message->data.n_sources.n_sources = htonl(n_sources);
}
@@ -997,7 +951,7 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
struct timeval now_corr;
/* Get data */
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
case SRC_NTP:
@@ -1008,7 +962,6 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
break;
}
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCE_DATA);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
@@ -1071,136 +1024,35 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
{
tx_message->status = htons(STT_SUCCESS);
KEY_Reload();
}
/* ================================================== */
static void
handle_allow(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_allowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_allowall(CMD_Request *rx_message, CMD_Reply *tx_message)
handle_cmdallowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_deny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_denyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (NCR_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallow(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmdallowall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 1, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddeny(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 0)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
static void
handle_cmddenyall(CMD_Request *rx_message, CMD_Reply *tx_message)
{
IPAddr ip;
int subnet_bits;
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
if (CAM_AddAccessRestriction(&ip, subnet_bits, 0, 1)) {
tx_message->status = htons(STT_SUCCESS);
} else {
tx_message->status = htons(STT_BADSUBNET);
}
}
/* ================================================== */
@@ -1266,7 +1118,6 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
status = NSR_AddSource(&rem_addr, type, &params);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_AlreadyInUse:
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
@@ -1297,7 +1148,6 @@ handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
status = NSR_RemoveSource(&rem_addr);
switch (status) {
case NSR_Success:
tx_message->status = htons(STT_SUCCESS);
break;
case NSR_NoSuchSource:
tx_message->status = htons(STT_NOSUCHSOURCE);
@@ -1317,7 +1167,6 @@ handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
switch (RTC_WriteParameters()) {
case RTC_ST_OK:
tx_message->status = htons(STT_SUCCESS);
break;
case RTC_ST_NODRV:
tx_message->status = htons(STT_NORTC);
@@ -1337,7 +1186,6 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta freq of %.3fppm", dfreq);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1352,7 +1200,6 @@ handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
doffset = (double) sec + 1.0e-6 * (double) usec;
LOG(LOGS_INFO, LOGF_CmdMon, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset, 0.0);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1363,7 +1210,6 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_TrackingReport rpt;
REF_GetTrackingReport(&rpt);
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_TRACKING);
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
@@ -1383,6 +1229,60 @@ handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */
static void
handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
{
RPT_SmoothingReport report;
struct timeval now;
SCH_GetLastEventTime(&now, NULL, NULL);
if (!SMT_GetSmoothingReport(&report, &now)) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
tx_message->reply = htons(RPY_SMOOTHING);
tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
(report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
}
/* ================================================== */
static void
handle_smoothtime(CMD_Request *rx_message, CMD_Reply *tx_message)
{
struct timeval now;
int option;
if (!SMT_IsEnabled()) {
tx_message->status = htons(STT_NOTENABLED);
return;
}
option = ntohl(rx_message->data.smoothtime.option);
SCH_GetLastEventTime(&now, NULL, NULL);
switch (option) {
case REQ_SMOOTHTIME_RESET:
SMT_Reset(&now);
break;
case REQ_SMOOTHTIME_ACTIVATE:
SMT_Activate(&now);
break;
default:
tx_message->status = htons(STT_INVALID);
break;
}
}
/* ================================================== */
static void
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
{
@@ -1390,12 +1290,11 @@ handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_SourcestatsReport report;
struct timeval now_corr;
LCL_ReadCookedTime(&now_corr, NULL);
SCH_GetLastEventTime(&now_corr, NULL, NULL);
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
&report, &now_corr);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_SOURCESTATS);
tx_message->data.sourcestats.ref_id = htonl(report.ref_id);
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr);
@@ -1421,7 +1320,6 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
RPT_RTC_Report report;
status = RTC_GetReport(&report);
if (status) {
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_RTC);
UTI_TimevalHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
tx_message->data.rtc.n_samples = htons(report.n_samples);
@@ -1439,13 +1337,8 @@ handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
status = RTC_Trim();
if (status) {
tx_message->status = htons(STT_SUCCESS);
} else {
if (!RTC_Trim())
tx_message->status = htons(STT_NORTC);
}
}
/* ================================================== */
@@ -1454,8 +1347,6 @@ static void
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
{
LOG_CycleLogFiles();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1469,14 +1360,13 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
int i, j;
struct timeval now;
LCL_ReadCookedTime(&now, NULL);
SCH_GetLastEventTime(&now, NULL, NULL);
first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
n_indices = ntohl(rx_message->data.client_accesses_by_index.n_indices);
if (n_indices > MAX_CLIENT_ACCESSES)
n_indices = MAX_CLIENT_ACCESSES;
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX);
for (i = 0, j = 0; i < n_indices; i++) {
@@ -1521,7 +1411,6 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
RPY_ManualListSample *sample;
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
tx_message->status = htons(STT_SUCCESS);
tx_message->reply = htons(RPY_MANUAL_LIST);
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
@@ -1540,16 +1429,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
{
int status;
int index;
index = ntohl(rx_message->data.manual_delete.index);
status = MNL_DeleteSample(index);
if (!status) {
if (!MNL_DeleteSample(index))
tx_message->status = htons(STT_BADSAMPLE);
} else {
tx_message->status = htons(STT_SUCCESS);
}
}
/* ================================================== */
@@ -1557,11 +1441,8 @@ handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
{
if (!LCL_MakeStep()) {
if (!LCL_MakeStep())
tx_message->status = htons(STT_FAILED);
} else {
tx_message->status = htons(STT_SUCCESS);
}
}
/* ================================================== */
@@ -1576,7 +1457,6 @@ handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.activity.burst_online = htonl(report.burst_online);
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->reply = htons(RPY_ACTIVITY);
}
@@ -1588,7 +1468,6 @@ handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
double dist;
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
SRC_SetReselectDistance(dist);
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1597,7 +1476,6 @@ static void
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
{
SRC_ReselectSource();
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
@@ -1653,8 +1531,8 @@ read_from_cmd_socket(void *anything)
read_length = status;
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked_now, NULL);
/* Get current time cheaply */
SCH_GetLastEventTime(&cooked_now, NULL, &now);
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port);
@@ -1709,6 +1587,7 @@ read_from_cmd_socket(void *anything)
tx_message.command = rx_message.command;
tx_message.sequence = rx_message.sequence;
tx_message.reply = htons(RPY_NULL);
tx_message.status = htons(STT_SUCCESS);
tx_message.pad1 = 0;
tx_message.pad2 = 0;
tx_message.pad3 = 0;
@@ -1909,7 +1788,11 @@ read_from_cmd_socket(void *anything)
if (allowed) {
switch(rx_command) {
case REQ_NULL:
handle_null(&rx_message, &tx_message);
/* Do nothing */
break;
case REQ_DUMP:
handle_dump(&rx_message, &tx_message);
break;
case REQ_ONLINE:
@@ -1932,11 +1815,6 @@ read_from_cmd_socket(void *anything)
handle_modify_maxpoll(&rx_message, &tx_message);
break;
case REQ_DUMP:
SRC_DumpSources();
tx_message.status = htons(STT_SUCCESS);
break;
case REQ_MODIFY_MAXDELAY:
handle_modify_maxdelay(&rx_message, &tx_message);
break;
@@ -2004,35 +1882,35 @@ read_from_cmd_socket(void *anything)
break;
case REQ_ALLOW:
handle_allow(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_ALLOWALL:
handle_allowall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_DENY:
handle_deny(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_DENYALL:
handle_denyall(&rx_message, &tx_message);
handle_allowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_CMDALLOW:
handle_cmdallow(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
break;
case REQ_CMDALLOWALL:
handle_cmdallowall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
break;
case REQ_CMDDENY:
handle_cmddeny(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
break;
case REQ_CMDDENYALL:
handle_cmddenyall(&rx_message, &tx_message);
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
break;
case REQ_ACCHECK:
@@ -2071,6 +1949,14 @@ read_from_cmd_socket(void *anything)
handle_tracking(&rx_message, &tx_message);
break;
case REQ_SMOOTHING:
handle_smoothing(&rx_message, &tx_message);
break;
case REQ_SMOOTHTIME:
handle_smoothtime(&rx_message, &tx_message);
break;
case REQ_SOURCESTATS:
handle_sourcestats(&rx_message, &tx_message);
break;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013
* Copyright (C) Miroslav Lichvar 2013-2014
*
* 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

20
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -189,6 +189,7 @@ static char *pidfile;
/* Smoothing constants */
static double smooth_max_freq = 0.0; /* in ppm */
static double smooth_max_wander = 0.0; /* in ppm/s */
static int smooth_leap_only = 0;
/* Temperature sensor, update interval and compensation coefficients */
static char *tempcomp_sensor_file = NULL;
@@ -1174,11 +1175,23 @@ parse_broadcast(char *line)
static void
parse_smoothtime(char *line)
{
check_number_of_args(line, 2);
if (get_number_of_args(line) != 3)
check_number_of_args(line, 2);
if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) {
smooth_max_freq = 0.0;
command_parse_error();
}
line = CPS_SplitWord(CPS_SplitWord(line));
smooth_leap_only = 0;
if (*line) {
if (!strcasecmp(line, "leaponly"))
smooth_leap_only = 1;
else
command_parse_error();
}
}
/* ================================================== */
@@ -1738,10 +1751,11 @@ CNF_GetLockMemory(void)
/* ================================================== */
void
CNF_GetSmooth(double *max_freq, double *max_wander)
CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only)
{
*max_freq = smooth_max_freq;
*max_wander = smooth_max_wander;
*leap_only = smooth_leap_only;
}
/* ================================================== */

2
conf.h
View File

@@ -96,7 +96,7 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetSmooth(double *max_freq, double *max_wander);
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);

View File

@@ -45,7 +45,6 @@ cp chrony.info* $RPM_BUILD_ROOT%{_infodir}
%{_sbindir}/chronyd
%{_bindir}/chronyc
%{_infodir}/chrony.info*
%{_mandir}/man1/chrony.1.gz
%{_mandir}/man1/chronyc.1.gz
%{_mandir}/man5/chrony.conf.5.gz
%{_mandir}/man8/chronyd.8.gz

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011, 2014
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
*
* 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
@@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
/* Smooth the leap second out */
SMT_Leap(&cooked, leap);
/* Dispatch to all handlers as if the clock was stepped */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
}

9
main.c
View File

@@ -347,6 +347,7 @@ int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
char *user = NULL;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
@@ -386,7 +387,7 @@ int main
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
exit(0);
return 0;
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
@@ -405,6 +406,10 @@ int main
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
address_family = IPADDR_INET6;
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-f FILE|COMMAND...]\n",
progname);
return 0;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
@@ -417,7 +422,7 @@ int main
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
exit(1);
return 1;
}
/* Turn into a daemon */

View File

@@ -39,7 +39,7 @@ echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
for m in chrony.1 chronyc.1.in chrony.conf.5.in chronyd.8.in; do
for m in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
sed -e "s%@VERSION@%${version}%;s%@MAN_DATE@%${mandate}%" \
< $m > ${m}_
mv -f ${m}_ $m

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -316,7 +316,7 @@ NCR_Initialise(void)
do_time_checks();
logfileid = CNF_GetLogMeasurements() ? LOG_FileOpen("measurements",
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
" Date (UTC) Time IP Address L St 123 567 ABCD LP RP Score Offset Peer del. Peer disp. Root del. Root disp.")
: -1;
access_auth_table = ADF_CreateTable();
@@ -1230,7 +1230,8 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
inst->local_ntp_tx.hi = inst->local_ntp_tx.lo = 0;
if (valid_packet) {
precision = LCL_GetSysPrecisionAsQuantum();
precision = LCL_GetSysPrecisionAsQuantum() +
UTI_Log2ToDouble(message->precision);
SRC_GetFrequencyRange(inst->source, &source_freq_lo, &source_freq_hi);

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2014
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
*
* 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
@@ -97,8 +97,13 @@ prepare_socket(int family, int port_number, int client_only)
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
if (!client_only) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
} else {
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
}
return INVALID_SOCK_FD;
}

View File

@@ -49,6 +49,7 @@ typedef struct {
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
means this slot in table is in use */
NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source, may be NULL */
int pool; /* Number of the pool from which was this source
added or INVALID_POOL */
int tentative; /* Flag indicating there was no valid response
@@ -85,6 +86,7 @@ struct UnresolvedSource {
#define RESOLVE_INTERVAL_UNIT 7
#define MIN_RESOLVE_INTERVAL 2
#define MAX_RESOLVE_INTERVAL 9
#define MIN_REPLACEMENT_INTERVAL 8
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
@@ -92,15 +94,11 @@ static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
#define MIN_POOL_RESOLVE_INTERVAL 5
#define MAX_POOL_SOURCES 16
#define INVALID_POOL (-1)
/* Pool of sources, the name is expected to resolve to multiple addresses
which change over time */
/* Pool of sources with the same name */
struct SourcePool {
char *name;
int port;
/* Number of sources added from this pool (ignoring tentative sources) */
int sources;
/* Maximum number of sources */
@@ -115,6 +113,7 @@ static ARR_Instance pools;
static void resolve_sources(void *arg);
static void rehash_records(void);
static void clean_source_record(SourceRecord *record);
static void
slew_sources(struct timeval *raw,
@@ -162,16 +161,12 @@ NSR_Finalise(void)
struct UnresolvedSource *us;
unsigned int i;
for (i = 0; i < ARR_GetSize(pools); i++)
Free(((struct SourcePool *)ARR_GetElement(pools, i))->name);
ARR_DestroyInstance(pools);
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr)
continue;
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->remote_addr)
clean_source_record(record);
}
ARR_DestroyInstance(records);
@@ -296,7 +291,7 @@ rehash_records(void)
/* Procedure to add a new source */
static NSR_Status
add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, int pool)
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
{
SourceRecord *record;
int slot, found;
@@ -323,6 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
record = get_record(slot);
record->data = NCR_GetInstance(remote_addr, type, params);
record->remote_addr = NCR_GetRemoteAddress(record->data);
record->name = name ? Strdup(name) : NULL;
record->pool = pool;
record->tentative = pool != INVALID_POOL ? 1 : 0;
@@ -382,7 +378,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
break;
} else {
if (add_source(&address, us->new_source.type, &us->new_source.params,
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
us->new_source.pool) == NSR_Success)
added++;
@@ -495,7 +491,7 @@ append_unresolved_source(struct UnresolvedSource *us)
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return add_source(remote_addr, type, params, INVALID_POOL);
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
}
/* ================================================== */
@@ -505,6 +501,15 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
{
struct UnresolvedSource *us;
struct SourcePool *sp;
NTP_Remote_Address remote_addr;
/* If the name is an IP address, don't bother with full resolving now
or later when trying to replace the source */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
remote_addr.port = port;
NSR_AddSource(&remote_addr, type, params);
return;
}
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(name);
@@ -518,8 +523,6 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
us->new_source.max_new_sources = 1;
} else {
sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->name = Strdup(name);
sp->port = port;
sp->sources = 0;
sp->max_sources = params->max_sources;
us->new_source.pool = ARR_GetSize(pools) - 1;
@@ -587,6 +590,8 @@ clean_source_record(SourceRecord *record)
assert(record->remote_addr);
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->name)
Free(record->name);
n_sources--;
}
@@ -640,15 +645,18 @@ NSR_RemoveAllSources(void)
/* ================================================== */
static void
resolve_pool_replacement(struct SourcePool *sp, NTP_Remote_Address *addr)
resolve_source_replacement(SourceRecord *record)
{
struct UnresolvedSource *us;
DEBUG_LOG(LOGF_NtpSources, "trying to replace %s",
UTI_IPToString(&record->remote_addr->ip_addr));
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(sp->name);
us->port = sp->port;
us->name = Strdup(record->name);
us->port = record->remote_addr->port;
us->replacement = 1;
us->replace_source = *addr;
us->replace_source = *record->remote_addr;
append_unresolved_source(us);
NSR_ResolveSources();
@@ -662,32 +670,33 @@ NSR_HandleBadSource(IPAddr *address)
static struct timeval last_replacement;
struct timeval now;
NTP_Remote_Address remote_addr;
struct SourcePool *pool;
int pool_index, slot, found;
SourceRecord *record;
int slot, found;
double diff;
remote_addr.ip_addr = *address;
remote_addr.port = 0;
/* Only sources from a pool can be replaced */
find_slot(&remote_addr, &slot, &found);
if (!found || (pool_index = get_record(slot)->pool) == INVALID_POOL)
if (!found)
return;
pool = (struct SourcePool *)ARR_GetElement(pools, pool_index);
record = get_record(slot);
/* Don't resolve the pool name too frequently */
/* Only sources with a name can be replaced */
if (!record->name)
return;
/* Don't resolve names too frequently */
SCH_GetLastEventTime(NULL, NULL, &now);
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_POOL_RESOLVE_INTERVAL)) {
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) {
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
return;
}
last_replacement = now;
DEBUG_LOG(LOGF_NtpSources, "pool replacement for %s", UTI_IPToString(address));
resolve_pool_replacement(pool, &remote_addr);
resolve_source_replacement(record);
}
/* ================================================== */
@@ -741,7 +750,7 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
pool->sources++;
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
pool->name, pool->sources);
record->name, pool->sources);
/* If the number of sources reached the configured maximum, remove
the tentative sources added from this pool */

View File

@@ -44,9 +44,8 @@ command_unpadded_length(CMD_Request *r)
return 0;
} else {
switch (type) {
case REQ_NULL:
return offsetof(CMD_Request, data);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ONLINE:
return offsetof(CMD_Request, data.online.EOR);
case REQ_OFFLINE:
@@ -78,11 +77,11 @@ command_unpadded_length(CMD_Request *r)
case REQ_MANUAL :
return offsetof(CMD_Request, data.manual.EOR);
case REQ_N_SOURCES :
return offsetof(CMD_Request, data.n_sources.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCE_DATA :
return offsetof(CMD_Request, data.source_data.EOR);
case REQ_REKEY :
return offsetof(CMD_Request, data.rekey.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ALLOW :
return offsetof(CMD_Request, data.allow_deny.EOR);
case REQ_ALLOWALL :
@@ -110,21 +109,21 @@ command_unpadded_length(CMD_Request *r)
case REQ_DEL_SOURCE :
return offsetof(CMD_Request, data.del_source.EOR);
case REQ_WRITERTC :
return offsetof(CMD_Request, data.writertc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_DFREQ :
return offsetof(CMD_Request, data.dfreq.EOR);
case REQ_DOFFSET :
return offsetof(CMD_Request, data.doffset.EOR);
case REQ_TRACKING :
return offsetof(CMD_Request, data.tracking.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SOURCESTATS :
return offsetof(CMD_Request, data.sourcestats.EOR);
case REQ_RTCREPORT :
return offsetof(CMD_Request, data.rtcreport.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_TRIMRTC :
return offsetof(CMD_Request, data.trimrtc.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.cyclelogs.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_SUBNETS_ACCESSED :
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -132,21 +131,25 @@ command_unpadded_length(CMD_Request *r)
case REQ_CLIENT_ACCESSES_BY_INDEX:
return offsetof(CMD_Request, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return offsetof(CMD_Request, data.manual_list.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_MANUAL_DELETE:
return offsetof(CMD_Request, data.manual_delete.EOR);
case REQ_MAKESTEP:
return offsetof(CMD_Request, data.make_step.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_ACTIVITY:
return offsetof(CMD_Request, data.activity.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.reselect.EOR);
return offsetof(CMD_Request, data.null.EOR);
case REQ_RESELECTDISTANCE:
return offsetof(CMD_Request, data.reselect_distance.EOR);
case REQ_MODIFY_MINSTRATUM:
return offsetof(CMD_Request, data.modify_minstratum.EOR);
case REQ_MODIFY_POLLTARGET:
return offsetof(CMD_Request, data.modify_polltarget.EOR);
case REQ_SMOOTHING:
return offsetof(CMD_Request, data.null.EOR);
case REQ_SMOOTHTIME:
return offsetof(CMD_Request, data.smoothtime.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -228,11 +231,11 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_MANUAL:
return PADDING_LENGTH(data.manual.EOR, data.null.EOR);
case REQ_N_SOURCES:
return PADDING_LENGTH(data.n_sources.EOR, data.n_sources.EOR);
return PADDING_LENGTH(data.null.EOR, data.n_sources.EOR);
case REQ_SOURCE_DATA:
return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR);
case REQ_REKEY:
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
@@ -260,21 +263,21 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_DEL_SOURCE:
return PADDING_LENGTH(data.del_source.EOR, data.null.EOR);
case REQ_WRITERTC:
return PADDING_LENGTH(data.writertc.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_DFREQ:
return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR);
case REQ_DOFFSET:
return PADDING_LENGTH(data.doffset.EOR, data.null.EOR);
case REQ_TRACKING:
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
return PADDING_LENGTH(data.null.EOR, data.tracking.EOR);
case REQ_SOURCESTATS:
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
case REQ_RTCREPORT:
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -282,21 +285,25 @@ PKL_CommandPaddingLength(CMD_Request *r)
case REQ_CLIENT_ACCESSES_BY_INDEX:
return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR);
case REQ_MANUAL_LIST:
return PADDING_LENGTH(data.manual_list.EOR, data.manual_list.EOR);
return PADDING_LENGTH(data.null.EOR, data.manual_list.EOR);
case REQ_MANUAL_DELETE:
return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR);
case REQ_MAKESTEP:
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.reselect.EOR, data.null.EOR);
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
case REQ_RESELECTDISTANCE:
return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR);
case REQ_MODIFY_MINSTRATUM:
return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR);
case REQ_MODIFY_POLLTARGET:
return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR);
case REQ_SMOOTHING:
return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR);
case REQ_SMOOTHTIME:
return PADDING_LENGTH(data.smoothtime.EOR, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -360,7 +367,8 @@ PKL_ReplyLength(CMD_Reply *r)
}
case RPY_ACTIVITY:
return offsetof(CMD_Reply, data.activity.EOR);
case RPY_SMOOTHING:
return offsetof(CMD_Reply, data.smoothing.EOR);
default:
assert(0);
}

View File

@@ -499,15 +499,6 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 1;
}
static double
poll_interval(int poll)
{
if (poll >= 0)
return 1 << poll;
else
return 1.0 / (1 << -poll);
}
static int
valid_sample_time(RCL_Instance instance, struct timeval *tv)
{
@@ -516,7 +507,7 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
if (diff < 0.0 || diff > UTI_Log2ToDouble(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s",
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv));
return 0;
@@ -595,7 +586,7 @@ poll_timeout(void *arg)
}
}
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
}
static void

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2014
* Copyright (C) Miroslav Lichvar 2009-2015
*
* 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
@@ -248,9 +248,9 @@ REF_Initialise(void)
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) {
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
get_tz_leap(1356912000) == LEAP_Normal) {
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);

View File

@@ -112,4 +112,14 @@ typedef struct {
int unresolved;
} RPT_ActivityReport;
typedef struct {
int active;
int leap_only;
double offset;
double freq_ppm;
double wander_ppm;
double last_update_ago;
double remaining_time;
} RPT_SmoothingReport;
#endif /* GOT_REPORTS_H */

View File

@@ -330,6 +330,10 @@ SCH_AddTimeoutByDelay(double delay, SCH_TimeoutHandler handler, SCH_ArbitraryArg
LCL_ReadRawTime(&now);
UTI_AddDoubleToTimeval(&now, delay, &then);
if (UTI_CompareTimevals(&now, &then) > 0) {
LOG_FATAL(LOGF_Scheduler, "Timeout overflow");
}
return SCH_AddTimeout(&then, handler, arg);
}

111
smooth.c
View File

@@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES];
/* Enabled/disabled smoothing */
static int enabled;
/* Enabled/disabled mode where only leap seconds are smoothed out and normal
offset/frequency changes are ignored */
static int leap_only_mode;
/* Maximum skew/max_wander ratio to start updating offset and frequency */
#define UNLOCK_SKEW_WANDER_RATIO 10000
@@ -93,15 +97,17 @@ static struct timeval last_update;
static void
get_offset_freq(struct timeval *now, double *offset, double *freq)
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
double *pwander)
{
double elapsed, length;
double elapsed, length, offset, freq, wander;
int i;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
*offset = smooth_offset;
*freq = smooth_freq;
offset = smooth_offset;
freq = smooth_freq;
wander = 0.0;
for (i = 0; i < NUM_STAGES; i++) {
if (elapsed <= 0.0)
@@ -111,13 +117,21 @@ get_offset_freq(struct timeval *now, double *offset, double *freq)
if (length >= elapsed)
length = elapsed;
*offset -= length * (2.0 * *freq + stages[i].wander * length) / 2.0;
*freq += stages[i].wander * length;
wander = stages[i].wander;
offset -= length * (2.0 * freq + wander * length) / 2.0;
freq += wander * length;
elapsed -= length;
}
if (elapsed > 0.0)
*offset -= elapsed * *freq;
if (elapsed > 0.0) {
wander = 0.0;
offset -= elapsed * freq;
}
*poffset = offset;
*pfreq = freq;
if (pwander)
*pwander = wander;
}
static void
@@ -185,14 +199,12 @@ update_smoothing(struct timeval *now, double offset, double freq)
{
/* Don't accept offset/frequency until the clock has stabilized */
if (locked) {
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) {
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated");
locked = 0;
}
if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode)
SMT_Activate(now);
return;
}
get_offset_freq(now, &smooth_offset, &smooth_freq);
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
smooth_offset += offset;
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
last_update = *now;
@@ -208,15 +220,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
{
double delta;
if (change_type == LCL_ChangeAdjust)
update_smoothing(cooked, doffset, dfreq);
if (change_type == LCL_ChangeAdjust) {
if (leap_only_mode)
update_smoothing(cooked, 0.0, 0.0);
else
update_smoothing(cooked, doffset, dfreq);
}
UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset);
}
void SMT_Initialise(void)
{
CNF_GetSmooth(&max_freq, &max_wander);
CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode);
if (max_freq <= 0.0 || max_wander <= 0.0) {
enabled = 0;
return;
@@ -249,19 +265,78 @@ SMT_GetOffset(struct timeval *now)
if (!enabled)
return 0.0;
get_offset_freq(now, &offset, &freq);
get_smoothing(now, &offset, &freq, NULL);
return offset;
}
void
SMT_Activate(struct timeval *now)
{
if (!enabled || !locked)
return;
LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ?
" (leap seconds only)" : "");
locked = 0;
last_update = *now;
}
void
SMT_Reset(struct timeval *now)
{
int i;
if (!enabled)
return;
locked = 1;
smooth_offset = 0.0;
smooth_freq = 0.0;
last_update = *now;
for (i = 0; i < NUM_STAGES; i++)
stages[i].wander = stages[i].length = 0.0;
}
void
SMT_Leap(struct timeval *now, int leap)
{
/* When the leap-only mode is disabled, the leap second will be accumulated
in handle_slew() as a normal offset */
if (!enabled || !leap_only_mode)
return;
update_smoothing(now, leap, 0.0);
}
int
SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now)
{
double length, elapsed;
int i;
if (!enabled)
return 0;
report->active = !locked;
report->leap_only = leap_only_mode;
get_smoothing(now, &report->offset, &report->freq_ppm, &report->wander_ppm);
/* Convert to ppm and negate (positive values mean faster/speeding up) */
report->freq_ppm *= -1.0e6;
report->wander_ppm *= -1.0e6;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
if (!locked && elapsed >= 0.0) {
for (i = 0, length = 0.0; i < NUM_STAGES; i++)
length += stages[i].length;
report->last_update_ago = elapsed;
report->remaining_time = elapsed < length ? length - elapsed : 0.0;
} else {
report->last_update_ago = 0.0;
report->remaining_time = 0.0;
}
return 1;
}

View File

@@ -27,6 +27,8 @@
#ifndef GOT_SMOOTH_H
#define GOT_SMOOTH_H
#include "reports.h"
extern void SMT_Initialise(void);
extern void SMT_Finalise(void);
@@ -35,6 +37,12 @@ extern int SMT_IsEnabled(void);
extern double SMT_GetOffset(struct timeval *now);
extern void SMT_Activate(struct timeval *now);
extern void SMT_Reset(struct timeval *now);
extern void SMT_Leap(struct timeval *now, int leap);
extern int SMT_GetSmoothingReport(RPT_SmoothingReport *report, struct timeval *now);
#endif

View File

@@ -513,7 +513,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
{
struct timeval src_ref_time;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion, elapsed;
double src_root_delay, src_root_dispersion, sel_src_distance, elapsed;
double offset_weight, sum_offset_weight, sum_offset, sum2_offset_sd;
double frequency_weight, sum_frequency_weight, sum_frequency, inv_sum2_skew;
int i, index, combined;
@@ -524,6 +524,10 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
sum_offset_weight = sum_offset = sum2_offset_sd = 0.0;
sum_frequency_weight = sum_frequency = inv_sum2_skew = 0.0;
sel_src_distance = sources[selected_source_index]->sel_info.root_distance;
if (sources[selected_source_index]->type == SRC_NTP)
sel_src_distance += reselect_distance;
for (i = combined = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
SST_GetTrackingData(sources[index]->stats, &src_ref_time,
@@ -536,8 +540,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
are not close, or it was recently marked as distant */
if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit *
(reselect_distance + sources[selected_source_index]->sel_info.root_distance) ||
(sources[index]->sel_info.root_distance > combine_limit * sel_src_distance ||
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
/* Use a smaller penalty in first few updates */
@@ -804,43 +807,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
}
#if 0
/* We now have a list of indices for the sources which pass the
false-ticker test. Now go on to reject those whose variance is
greater than the minimum distance of any other */
/* Find minimum distance */
index = sel_sources[0];
min_distance = sources[index]->sel_info.root_distance;
for (i = 1; i < n_sel_sources; i++) {
index = sel_sources[i];
distance = sources[index]->sel_info.root_distance;
if (distance < min_distance) {
min_distance = distance;
}
}
/* Now go through and prune any NTP sources that have excessive
variance */
for (i = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) {
sel_sources[i] = INVALID_SOURCE;
sources[index]->status = SRC_JITTERY;
}
}
/* Now crunch the list and mark all sources as selectable */
for (i = j = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (index == INVALID_SOURCE)
continue;
sel_sources[j++] = index;
}
n_sel_sources = j;
#endif
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: %s selectable sources",
@@ -869,16 +835,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* If there are any sources with prefer option, reduce the list again
only to the preferred sources */
for (i = j = 0; i < n_sel_sources; i++) {
for (i = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
sel_sources[j++] = sel_sources[i];
break;
}
if (j > 0) {
for (i = 0; i < n_sel_sources; i++) {
if (i < n_sel_sources) {
for (i = j = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
else
sel_sources[j++] = sel_sources[i];
}
assert(j > 0);
n_sel_sources = j;
sel_prefer = 1;
} else {

View File

@@ -107,6 +107,18 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
}
}
/* ================================================== */
static double
clamp_freq(double freq)
{
if (freq > max_freq)
return max_freq;
if (freq < -max_freq)
return -max_freq;
return freq;
}
/* ================================================== */
/* End currently running slew and start a new one */
@@ -144,11 +156,7 @@ update_slew(void)
corr_freq = max_corr_freq;
/* Get the new real frequency and clamp it */
total_freq = base_freq + corr_freq * (1.0e6 - base_freq);
if (total_freq > max_freq)
total_freq = max_freq;
else if (total_freq < -max_freq)
total_freq = -max_freq;
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
/* Set the new frequency (the actual frequency returned by the call may be
slightly different from the requested frequency due to rounding) */
@@ -330,7 +338,7 @@ SYS_Generic_Finalise(void)
slew_timer_running = 0;
}
(*drv_set_freq)(base_freq);
(*drv_set_freq)(clamp_freq(base_freq));
}
/* ================================================== */

View File

@@ -27,18 +27,20 @@ for leapmode in system step slew; do
check_sync || test_fail
done
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC
leapsecmode slew
smoothtime 400 0.001"
client_conf="leapsecmode system"
min_sync_time=230000
max_sync_time=240000
for smoothmode in "" "leaponly"; do
server_conf="refclock SHM 0 dpoll 10 poll 10
leapsectz right/UTC
leapsecmode slew
smoothtime 400 0.001 $smoothmode"
client_conf="leapsecmode system"
min_sync_time=230000
max_sync_time=240000
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
test_pass

21
test/simulation/202-prefer Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
. test.common
# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629
test_start "prefer option"
servers=3
client_server_conf="
server 192.168.123.1
server 192.168.123.2
server 192.168.123.3 prefer"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
test_pass

View File

@@ -65,6 +65,7 @@ default_chronyc_start=1000.0
default_server_step=""
default_client_step=""
default_client_server_conf=""
default_server_server_options=""
default_client_server_options=""
default_server_peer_options=""
@@ -192,9 +193,13 @@ get_chronyd_conf() {
done
echo "$server_conf"
else
for i in $(seq 1 $servers); do
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
done
if [ -n "$client_server_conf" ]; then
echo "$client_server_conf"
else
for i in $(seq 1 $servers); do
echo "server 192.168.123.$[$servers * ($stratum - 2) + $i] $client_server_options"
done
fi
for i in $(seq 1 $peers); do
[ $i -eq $peer -o $i -gt $clients ] && continue
echo "peer 192.168.123.$[$servers * ($stratum - 1) + $i] $client_peer_options"

29
util.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009, 2012-2013
* Copyright (C) Miroslav Lichvar 2009, 2012-2014
*
* 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
@@ -609,6 +609,9 @@ UTI_Int64ToTimeval(NTP_int64 *src,
/* Maximum offset between two sane times */
#define MAX_OFFSET 4294967296.0
/* Minimum allowed distance from maximum 32-bit time_t */
#define MIN_ENDOFTIME_DISTANCE (365 * 24 * 3600)
int
UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
{
@@ -629,6 +632,10 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
/* Check if it's in the interval to which NTP time is mapped */
if (t < (double)NTP_ERA_SPLIT || t > (double)(NTP_ERA_SPLIT + (1LL << 32)))
return 0;
#else
/* Don't get too close to 32-bit time_t overflow */
if (t > (double)(0x7fffffff - MIN_ENDOFTIME_DISTANCE))
return 0;
#endif
return 1;
@@ -636,6 +643,22 @@ UTI_IsTimeOffsetSane(struct timeval *tv, double offset)
/* ================================================== */
double
UTI_Log2ToDouble(int l)
{
if (l >= 0) {
if (l > 31)
l = 31;
return 1 << l;
} else {
if (l < -31)
l = -31;
return 1.0 / (1 << -l);
}
}
/* ================================================== */
void
UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest)
{
@@ -700,7 +723,11 @@ UTI_FloatHostToNetwork(double x)
if (x < 0.0) {
x = -x;
neg = 1;
} else if (x >= 0.0) {
neg = 0;
} else {
/* Save NaN as zero */
x = 0.0;
neg = 0;
}

3
util.h
View File

@@ -107,6 +107,9 @@ extern void UTI_Int64ToTimeval(NTP_int64 *src, struct timeval *dest);
/* Check if time + offset is sane */
extern int UTI_IsTimeOffsetSane(struct timeval *tv, double offset);
/* Get 2 raised to power of a signed integer */
extern double UTI_Log2ToDouble(int l);
extern void UTI_TimevalNetworkToHost(Timeval *src, struct timeval *dest);
extern void UTI_TimevalHostToNetwork(struct timeval *src, Timeval *dest);

View File

@@ -71,7 +71,7 @@ TMX_ResetOffset(void)
/* Set status back */
txc.modes = ADJ_STATUS;
txc.modes = status;
txc.status = status;
if (adjtimex(&txc) < 0)
return -1;