Compare commits

..

8 Commits

Author SHA1 Message Date
Miroslav Lichvar
aabb564320 doc: update NEWS 2016-01-19 08:15:15 +01:00
Miroslav Lichvar
df46e5ca5d ntp: restrict authentication of server/peer to specified key
When a server/peer was specified with a key number to enable
authentication with a symmetric key, packets received from the
server/peer were accepted if they were authenticated with any of
the keys contained in the key file and not just the specified key.

This allowed an attacker who knew one key of a client/peer to modify
packets from its servers/peers that were authenticated with other
keys in a man-in-the-middle (MITM) attack. For example, in a network
where each NTP association had a separate key and all hosts had only
keys they needed, a client of a server could not attack other clients
of the server, but it could attack the server and also attack its own
clients (i.e. modify packets from other servers).

To not allow the server/peer to be authenticated with other keys
extend the authentication test to check if the key ID in the received
packet is equal to the configured key number. As a consequence, it's
no longer possible to authenticate two peers to each other with two
different keys, both peers have to be configured to use the same key.

This issue was discovered by Matt Street of Cisco ASIG.
2016-01-19 08:15:12 +01:00
Miroslav Lichvar
370ba5e8fc doc: warn that unauthenticated peers are vulnerable to DoS attack 2016-01-19 08:14:46 +01:00
Miroslav Lichvar
463093803d doc: fix CVE-ID in NEWS
CVE-2015-1853 is for chrony, CVE-2015-1799 is for ntp.
2015-04-08 08:47:13 +02:00
Miroslav Lichvar
c4bedce1f4 doc: update NEWS 2015-04-07 16:35:16 +02:00
Miroslav Lichvar
79eacdb7e6 cmdmon: fix initialization of allocated reply slots
When allocating memory to save unacknowledged replies to authenticated
command requests, the last "next" pointer was not initialized to NULL.
When all allocated reply slots were used, the next reply could be
written to an invalid memory instead of allocating a new slot for it.

An attacker that has the command key and is allowed to access cmdmon
(only localhost is allowed by default) could exploit this to crash
chronyd or possibly execute arbitrary code with the privileges of the
chronyd process.
2015-04-07 16:35:16 +02:00
Miroslav Lichvar
cf19042ecb addrfilt: fix access configuration with subnet size indivisible by 4
When NTP or cmdmon access was configured (from chrony.conf or via
authenticated cmdmon) with a subnet size that is indivisible by 4 and
an address that has nonzero bits in the 4-bit subnet remainder (e.g.
192.168.15.0/22 or f000::/3), the new setting was written to an
incorrect location, possibly outside the allocated array.

An attacker that has the command key and is allowed to access cmdmon
(only localhost is allowed by default) could exploit this to crash
chronyd or possibly execute arbitrary code with the privileges of the
chronyd process.
2015-04-07 16:35:16 +02:00
Miroslav Lichvar
d856bd34c4 ntp: protect authenticated symmetric associations against DoS attacks
An attacker knowing that NTP hosts A and B are peering with each other
(symmetric association) 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. It is a denial-of-service attack.

According to [1], NTP authentication is supposed to protect symmetric
associations against this attack, but in the NTPv3 (RFC 1305) and NTPv4
(RFC 5905) specifications the state variables are updated before the
authentication check is performed, which means the association is
vulnerable to the attack even when authentication is enabled.

To fix this problem, save the originate and local timestamps only when
the authentication check (test5) passed.

[1] https://www.eecis.udel.edu/~mills/onwire.html
2015-04-07 16:34:42 +02:00
130 changed files with 10949 additions and 8861 deletions

31
.gitignore vendored
View File

@@ -2,23 +2,20 @@
.vimrc
*.o
*.swp
*.dSYM
*.DS_Store
RELEASES
Makefile
chrony.conf.5
chrony.info
chrony.html
chrony.texi
chrony.txt
chronyc
chronyc.1
chronyd
chronyd.8
config.h
config.log
tags
/RELEASES
/Makefile
/chrony.conf.5
/chrony.info
/chrony.html
/chrony.texi
/chrony.txt
/chronyc
/chronyc.1
/chronyd
/chronyd.8
/config.h
/config.log
/getdate.c
/version.h
version.h
/test/simulation/clknetsim
/test/simulation/tmp

View File

@@ -38,13 +38,18 @@ DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o nameserv_async.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_phc.o refclock_pps.o \
refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
@@ -73,16 +78,14 @@ $(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean
-rm -f .DS_Store
-rm -f Makefile
-rm -f chrony.conf.5 chrony.texi chronyc.1 chronyd.8
clean :
-rm -f *.o *.s chronyc chronyd core *~ chrony.info chrony.html chrony.txt
-rm -rf .deps
-rm -rf *.dSYM
getdate.c : getdate.y
getdate.c :
bison -o getdate.c getdate.y
# This can be used to force regeneration of getdate.c
@@ -92,13 +95,15 @@ getdate :
# For install, don't use the install command, because its switches
# seem to vary between systems.
install: chronyd chronyc
install: chronyd chronyc chrony.txt
[ -d $(DESTDIR)$(SYSCONFDIR) ] || mkdir -p $(DESTDIR)$(SYSCONFDIR)
[ -d $(DESTDIR)$(SBINDIR) ] || mkdir -p $(DESTDIR)$(SBINDIR)
[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -d $(DESTDIR)$(MANDIR)/man1 ] || mkdir -p $(DESTDIR)$(MANDIR)/man1
[ -d $(DESTDIR)$(MANDIR)/man5 ] || mkdir -p $(DESTDIR)$(MANDIR)/man5
[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8
[ -d $(DESTDIR)$(DOCDIR) ] || mkdir -p $(DESTDIR)$(DOCDIR)
[ -d $(DESTDIR)$(CHRONYVARDIR) ] || mkdir -p $(DESTDIR)$(CHRONYVARDIR)
if [ -f $(DESTDIR)$(SBINDIR)/chronyd ]; then rm -f $(DESTDIR)$(SBINDIR)/chronyd ; fi
if [ -f $(DESTDIR)$(BINDIR)/chronyc ]; then rm -f $(DESTDIR)$(BINDIR)/chronyc ; fi
@@ -106,6 +111,14 @@ install: chronyd chronyc
chmod 755 $(DESTDIR)$(SBINDIR)/chronyd
cp chronyc $(DESTDIR)$(BINDIR)/chronyc
chmod 755 $(DESTDIR)$(BINDIR)/chronyc
cp chrony.txt $(DESTDIR)$(DOCDIR)/chrony.txt
chmod 644 $(DESTDIR)$(DOCDIR)/chrony.txt
cp COPYING $(DESTDIR)$(DOCDIR)/COPYING
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
@@ -144,12 +157,6 @@ 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

100
NEWS
View File

@@ -1,99 +1,9 @@
New in version 2.2
==================
New in version 1.31.2
=====================
Enhancements
------------
* Add support for configuration and monitoring over Unix domain socket
(accessible by root or chrony user when root privileges are dropped)
* Add support for system call filtering with seccomp on Linux (experimental)
* Add support for dropping root privileges on NetBSD
* Control frequency of system clock on FreeBSD, NetBSD, Solaris
* Add system leap second handling mode on FreeBSD, NetBSD, Solaris
* Add dynamic drift removal on Mac OS X
* Add support for setting real-time priority on Mac OS X
* Add maxdistance directive to limit source selection by root distance
* Add refresh command to get new addresses of NTP sources
* Allow wildcard patterns in include directive
* Restore time from driftfile with -s option if later than RTC time
* Add configure option to set default hwclockfile
* Add -d option to chronyc to enable debug messages
* Allow multiple addresses to be specified for chronyc with -h option
and reconnect when no valid reply is received
* Make check interval in waitsync command configurable
Bug fixes
---------
* Fix building on Solaris
* Restore time from driftfile with -s option if reading RTC failed
Removed features
----------------
* Drop support for authentication with command key (run-time configuration
is now allowed only for local users that can access the Unix domain socket)
New in version 2.1.1
====================
Bug fixes
---------
* Fix clock stepping by integer number of seconds on Linux
New in version 2.1
==================
Enhancements
------------
* Add support for Mac OS X
* 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
* Use specific reference ID when smoothing served time
* 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
==================
Enhancements
------------
* Update to NTP version 4 (RFC 5905)
* Add pool directive to specify pool of NTP servers
* Add leapsecmode directive to select how to correct clock for leap second
* Add smoothtime directive to smooth served time and enable leap smear
* Add minsources directive to set required number of selectable sources
* Add minsamples and maxsamples options for all sources
* Add tempcomp configuration with list of points
* Allow unlimited number of NTP sources, refclocks and keys
* Allow unreachable sources to remain selected
* Improve source selection
* Handle offline sources as unreachable
* Open NTP server port only when necessary (client access is allowed by
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
* Update adjtimex synchronisation status
* Use system headers for adjtimex
* Check for memory allocation errors
* Reduce memory usage
* Add configure options to compile without NTP, cmdmon, refclock support
* Extend makestep command to set automatic clock stepping
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
Security fixes
--------------
* Restrict authentication of NTP server/peer to specified key (CVE-2016-1567)
New in version 1.31.1
=====================

89
README
View File

@@ -3,35 +3,66 @@ This is the README for chrony.
What is chrony?
===============
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.
Chrony is a pair of programs for maintaining the accuracy of computer
clocks.
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.
chronyd is a (background) daemon program that can be started at boot
time. This does most of the work.
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.
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 RFC1305-compatible NTP server and peer.
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?
========================
The software is known to work on Linux, FreeBSD, NetBSD, Mac OS X 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.
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.
How do I set it up?
===================
@@ -84,11 +115,6 @@ chrony-dev-request@chrony.tuxfamily.org
as applicable.
License
=======
chrony is distributed under the GNU General Public License version 2.
Author
======
@@ -128,9 +154,6 @@ Stephan I. Boettcher <stephan@nevis1.columbia.edu>
Erik Bryer <ebryer@spots.ab.ca>
Entries in contrib directory
Bryan Christianson <bryan@whatroute.net>
Support for Mac OS X
Juliusz Chroboczek <jch@pps.jussieu.fr>
Fix install rule in Makefile if chronyd file is in use.
@@ -145,9 +168,6 @@ Alexander Gretencord <arutha@gmx.de>
Changes to installation directory system to make it easier for
package builders.
Andrew Griffiths <agriffit@redhat.com>
Patch to add support for seccomp filter
Walter Haidinger <walter.haidinger@gmx.at>
Providing me with login access to a Linux installation where v1.12
wouldn't compile, so I could develop the fixes for v1.13. Also, for
@@ -207,9 +227,6 @@ Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
Frank Otto <sandwichmacher@web.de>
Handling arbitrary HZ values
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Patch to add refresh command to chronyc
Andreas Piesk <apiesk@virbus.de>
Patch to make chronyc use the readline library if available

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997,1998,1999,2000,2001,2002,2005
* Copyright (C) Miroslav Lichvar 2009, 2015
* Copyright (C) Miroslav Lichvar 2009
*
* 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
@@ -366,44 +366,6 @@ ADF_IsAllowed(ADF_AuthTable table,
/* ================================================== */
static int
is_any_allowed(TableNode *node, State parent)
{
State state;
int i;
state = node->state != AS_PARENT ? node->state : parent;
assert(state != AS_PARENT);
if (node->extended) {
for (i = 0; i < TABLE_SIZE; i++) {
if (is_any_allowed(&node->extended[i], state))
return 1;
}
} else if (state == ALLOW) {
return 1;
}
return 0;
}
/* ================================================== */
int
ADF_IsAnyAllowed(ADF_AuthTable table, int family)
{
switch (family) {
case IPADDR_INET4:
return is_any_allowed(&table->base4, AS_PARENT);
case IPADDR_INET6:
return is_any_allowed(&table->base6, AS_PARENT);
default:
return 0;
}
}
/* ================================================== */
#if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)

View File

@@ -72,9 +72,4 @@ extern void ADF_DestroyTable(ADF_AuthTable table);
extern int ADF_IsAllowed(ADF_AuthTable table,
IPAddr *ip);
/* Check if at least one address from a given family is allowed by
the rules in the table */
extern int ADF_IsAnyAllowed(ADF_AuthTable table,
int family);
#endif /* GOT_ADDRFILT_H */

129
array.c
View File

@@ -1,129 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Functions implementing an array with automatic memory allocation.
*/
#include "config.h"
#include "sysincl.h"
#include "array.h"
#include "memory.h"
struct ARR_Instance_Record {
void *data;
unsigned int elem_size;
unsigned int used;
unsigned int allocated;
};
ARR_Instance
ARR_CreateInstance(unsigned int elem_size)
{
ARR_Instance array;
assert(elem_size > 0);
array = MallocNew(struct ARR_Instance_Record);
array->data = NULL;
array->elem_size = elem_size;
array->used = 0;
array->allocated = 0;
return array;
}
void
ARR_DestroyInstance(ARR_Instance array)
{
Free(array->data);
Free(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;
if (array->allocated < min_size) {
while (array->allocated < min_size)
array->allocated = array->allocated ? 2 * array->allocated : 1;
} else {
array->allocated = min_size;
}
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 *
ARR_GetNewElement(ARR_Instance array)
{
array->used++;
realloc_array(array, array->used);
return ARR_GetElement(array, array->used - 1);
}
void *
ARR_GetElement(ARR_Instance array, unsigned int index)
{
assert(index < array->used);
return (void *)((char *)array->data + (size_t)index * array->elem_size);
}
void *
ARR_GetElements(ARR_Instance array)
{
return array->data;
}
void
ARR_AppendElement(ARR_Instance array, void *element)
{
void *e;
e = ARR_GetNewElement(array);
memcpy(e, element, array->elem_size);
}
void
ARR_SetSize(ARR_Instance array, unsigned int size)
{
realloc_array(array, size);
array->used = size;
}
unsigned int
ARR_GetSize(ARR_Instance array)
{
return array->used;
}

56
array.h
View File

@@ -1,56 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for array functions.
*/
#ifndef GOT_ARRAY_H
#define GOT_ARRAY_H
typedef struct ARR_Instance_Record *ARR_Instance;
/* Create a new array with given element size */
extern ARR_Instance ARR_CreateInstance(unsigned int elem_size);
/* Destroy the array */
extern void ARR_DestroyInstance(ARR_Instance array);
/* Return pointer to a new element added to the end of the array */
extern void *ARR_GetNewElement(ARR_Instance array);
/* Return element with given index */
extern void *ARR_GetElement(ARR_Instance array, unsigned int index);
/* Return pointer to the internal array of elements */
extern void *ARR_GetElements(ARR_Instance array);
/* Add a new element to the end of the array */
extern void ARR_AppendElement(ARR_Instance array, void *element);
/* Set the size of the array */
extern void ARR_SetSize(ARR_Instance array, unsigned int size);
/* Return current size of the array */
extern unsigned int ARR_GetSize(ARR_Instance array);
#endif

159
broadcast.c Normal file
View File

@@ -0,0 +1,159 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Deal with broadcast server functions.
*/
#include "config.h"
#include "sysincl.h"
#include "memory.h"
#include "addressing.h"
#include "broadcast.h"
#include "sched.h"
#include "ntp.h"
#include "local.h"
#include "reference.h"
#include "util.h"
#include "ntp_io.h"
typedef struct {
NTP_Remote_Address addr;
NTP_Local_Address local_addr;
int interval;
} Destination;
static Destination *destinations = 0;
static int n_destinations = 0;
static int max_destinations = 0;
void
BRD_Initialise(void)
{
}
/* ================================================== */
void
BRD_Finalise(void)
{
}
/* ================================================== */
/* This is a cut-down version of what transmit_packet in ntp_core.c does */
static void
timeout_handler(void *arbitrary)
{
Destination *d = (Destination *) arbitrary;
NTP_Packet message;
/* Parameters read from reference module */
int version;
int leap;
int are_we_synchronised, our_stratum;
NTP_Leap leap_status;
uint32_t our_ref_id, ts_fuzz;
struct timeval our_ref_time;
double our_root_delay, our_root_dispersion;
struct timeval local_transmit;
version = 3;
LCL_ReadCookedTime(&local_transmit, NULL);
REF_GetReferenceParams(&local_transmit,
&are_we_synchronised, &leap_status,
&our_stratum,
&our_ref_id, &our_ref_time,
&our_root_delay, &our_root_dispersion);
if (are_we_synchronised) {
leap = (int) leap_status;
} else {
leap = LEAP_Unsynchronised;
}
message.lvm = ((leap << 6) &0xc0) | ((version << 3) & 0x38) | (MODE_BROADCAST & 0x07);
message.stratum = our_stratum;
message.poll = 6; /* FIXME: what should this be? */
message.precision = LCL_GetSysPrecisionAsLog();
/* If we're sending a client mode packet and we aren't synchronized yet,
we might have to set up artificial values for some of these parameters */
message.root_delay = UTI_DoubleToInt32(our_root_delay);
message.root_dispersion = UTI_DoubleToInt32(our_root_dispersion);
message.reference_id = htonl((NTP_int32) our_ref_id);
/* Now fill in timestamps */
UTI_TimevalToInt64(&our_ref_time, &message.reference_ts, 0);
message.originate_ts.hi = 0UL;
message.originate_ts.lo = 0UL;
message.receive_ts.hi = 0UL;
message.receive_ts.lo = 0UL;
ts_fuzz = UTI_GetNTPTsFuzz(message.precision);
LCL_ReadCookedTime(&local_transmit, NULL);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts, ts_fuzz);
NIO_SendNormalPacket(&message, &d->addr, &d->local_addr);
/* Requeue timeout. Don't care if interval drifts gradually, so just do it
* at the end. */
SCH_AddTimeoutInClass((double) d->interval, 1.0, 0.02,
SCH_NtpBroadcastClass,
timeout_handler, (void *) d);
}
/* ================================================== */
void
BRD_AddDestination(IPAddr *addr, unsigned short port, int interval)
{
if (max_destinations == n_destinations) {
/* Expand array */
max_destinations += 8;
if (destinations) {
destinations = ReallocArray(Destination, max_destinations, destinations);
} else {
destinations = MallocArray(Destination, max_destinations);
}
}
destinations[n_destinations].addr.ip_addr = *addr;
destinations[n_destinations].addr.port = port;
destinations[n_destinations].local_addr.ip_addr.family = IPADDR_UNSPEC;
destinations[n_destinations].local_addr.sock_fd =
NIO_GetServerSocket(&destinations[n_destinations].addr);
destinations[n_destinations].interval = interval;
SCH_AddTimeoutInClass((double) interval, 1.0, 0.0,
SCH_NtpBroadcastClass,
timeout_handler, (void *)(destinations + n_destinations));
++n_destinations;
}

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2015
* Copyright (C) Richard P. Curnow 1997-2002
*
* 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
@@ -21,28 +21,17 @@
=======================================================================
This module implements time smoothing.
Deal with broadcast server functions.
*/
#ifndef GOT_SMOOTH_H
#define GOT_SMOOTH_H
#ifndef GOT_BROADCAST_H
#define GOT_BROADCAST_H
#include "reports.h"
#include "addressing.h"
extern void SMT_Initialise(void);
extern void BRD_Initialise(void);
extern void BRD_Finalise(void);
extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
extern void SMT_Finalise(void);
#endif /* GOT_BROADCAST_H */
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

139
candm.h
View File

@@ -31,6 +31,7 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is
defined */
@@ -87,11 +88,7 @@
#define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50
#define REQ_SMOOTHING 51
#define REQ_SMOOTHTIME 52
#define REQ_REFRESH 53
#define N_REQUEST_TYPES 54
#define N_REQUEST_TYPES 50
/* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */
@@ -118,10 +115,6 @@ 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;
@@ -194,12 +187,6 @@ typedef struct {
int32_t EOR;
} REQ_Modify_Maxupdateskew;
typedef struct {
int32_t limit;
Float threshold;
int32_t EOR;
} REQ_Modify_Makestep;
typedef struct {
Timeval ts;
int32_t EOR;
@@ -221,11 +208,19 @@ 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;
@@ -262,6 +257,10 @@ typedef struct {
int32_t EOR;
} REQ_Del_Source;
typedef struct {
int32_t EOR;
} REQ_WriteRtc;
typedef struct {
Float dfreq;
int32_t EOR;
@@ -273,11 +272,32 @@ 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;
typedef struct {
IPAddr ip;
uint32_t bits_specd;
} REQ_SubnetsAccessed_Subnet;
/* This is based on the response size rather than the
request size */
#define MAX_CLIENT_ACCESSES 8
@@ -288,24 +308,32 @@ 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
@@ -334,10 +362,7 @@ typedef struct {
subnets accessed and client accesses
Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16, new commands: modify
makestep, smoothing report, smoothtime command
Authentication was removed later in version 6.
changed maximum number of samples in manual list to 16
*/
#define PROTO_VERSION_NUMBER 6
@@ -366,11 +391,10 @@ typedef struct {
(count up from zero for same sequence
number) */
uint32_t sequence; /* Client's sequence number */
uint32_t pad1;
uint32_t pad2;
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
union {
REQ_Null null;
REQ_Online online;
REQ_Offline offline;
REQ_Burst burst;
@@ -383,29 +407,43 @@ typedef struct {
REQ_Modify_Minstratum modify_minstratum;
REQ_Modify_Polltarget modify_polltarget;
REQ_Modify_Maxupdateskew modify_maxupdateskew;
REQ_Modify_Makestep modify_makestep;
REQ_Logon logon;
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 */
/* Padding used to prevent traffic amplification. It only defines the
maximum size of the packet, there is no hole after the data field. */
/* The following fields only set the maximum size of the packet.
There are no holes between them and the actual data. */
/* Padding used to prevent traffic amplification */
uint8_t padding[MAX_PADDING_LENGTH];
/* Authentication data */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
@@ -430,8 +468,7 @@ typedef struct {
#define RPY_CLIENT_ACCESSES_BY_INDEX 10
#define RPY_MANUAL_LIST 11
#define RPY_ACTIVITY 12
#define RPY_SMOOTHING 13
#define N_REPLY_TYPES 14
#define N_REPLY_TYPES 13
/* Status codes */
#define STT_SUCCESS 0
@@ -543,6 +580,12 @@ typedef struct {
int32_t EOR;
} RPY_ManualTimestamp;
typedef struct {
IPAddr ip;
uint32_t bits_specd;
uint32_t bitmap[8];
} RPY_SubnetsAccessed_Subnet;
typedef struct {
IPAddr ip;
uint32_t client_hits;
@@ -586,19 +629,6 @@ 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;
@@ -611,9 +641,9 @@ typedef struct {
uint16_t pad2;
uint16_t pad3;
uint32_t sequence; /* Echo of client's sequence number */
uint32_t pad4;
uint32_t pad5;
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@@ -625,9 +655,12 @@ 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
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

71
chrony.1 Normal file
View File

@@ -0,0 +1,71 @@
.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
RFC1305 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 RFC1305-compatible 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 RFC1305-compatible NTP server and peer.
.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

@@ -12,45 +12,33 @@ boot time.
Assuming that you have found some servers, you need to set up a
configuration file to run \fIchrony\fR. The (compiled-in) default location
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your NTP
servers are called `foo.example.net', `bar.example.net' and `baz.example.net',
your \fBchrony.conf\fR file could contain as a minimum
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your ntp servers
are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
as a minimum
.EX
server foo.example.net
server bar.example.net
server baz.example.net
.EE
server a.b.c
server d.e.f
server g.h.i
However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `makestep', `rtcsync'. Also, the `iburst'
server option is useful to speed up the initial synchronization. The smallest
useful configuration file would look something like
particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
Also, the `iburst' server option is useful to speed up the initial
synchronization. The smallest useful configuration file would look something
like
.EX
server foo.example.net iburst
server bar.example.net iburst
server baz.example.net iburst
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
.EE
makestep 10 3
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. The configuration file could in this
case look like
.EX
pool pool.ntp.org iburst
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
.EE
.SH "SEE ALSO"
.BR chrony(1),
.BR chronyc(1),
.BR chronyd(8)

File diff suppressed because it is too large Load Diff

73
chrony_timex.h Normal file
View File

@@ -0,0 +1,73 @@
/* Taken from /usr/include/linux/timex.h. Avoids the need to
* include kernel header files. */
#ifndef CHRONY_TIMEX_H
#define CHRONY_TIMEX_H
#include <sys/time.h>
struct timex {
unsigned int modes; /* mode selector */
long offset; /* time offset (usec) */
long freq; /* frequency offset (scaled ppm) */
long maxerror; /* maximum error (usec) */
long esterror; /* estimated error (usec) */
int status; /* clock command/status */
long constant; /* pll time constant */
long precision; /* clock precision (usec) (read only) */
long tolerance; /* clock frequency tolerance (ppm)
* (read only)
*/
struct timeval time; /* (read only) */
long tick; /* (modified) usecs between clock ticks */
long ppsfreq; /* pps frequency (scaled ppm) (ro) */
long jitter; /* pps jitter (us) (ro) */
int shift; /* interval duration (s) (shift) (ro) */
long stabil; /* pps stability (scaled ppm) (ro) */
long jitcnt; /* jitter limit exceeded (ro) */
long calcnt; /* calibration intervals (ro) */
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
};
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
#define STA_PLL 0x0001 /* enable PLL updates (rw) */
#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */
#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */
#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */
#define STA_INS 0x0010 /* insert leap (rw) */
#define STA_DEL 0x0020 /* delete leap (rw) */
#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */
#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */
#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */
#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */
#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
/* This doesn't seem to be in any include files !! */
extern int adjtimex(struct timex *);
#endif /* CHRONY_TIMEX_H */

View File

@@ -24,8 +24,7 @@ A summary of the options supported by \fBchronyc\fR is included below.
.TP
\fB\-h\fR \fIhostname\fR
specify hostname or comma-separated list of addresses
(default @CHRONYSOCKDIR@/chronyd.sock,127.0.0.1,::1)
specify hostname (default 127.0.0.1)
.TP
\fB\-p\fR \fIport-number\fR
specify port-number
@@ -33,9 +32,6 @@ specify port-number
\fB\-n\fR
display raw IP addresses (don't attempt to look up hostnames)
.TP
\fB\-d\fR
print debugging messages (if compiled with debugging support)
.TP
\fB\-4\fR
resolve hostnames only to IPv4 addresses
.TP
@@ -47,10 +43,14 @@ allow multiple commands to be specified on the command line. Each argument
will be interpreted as a whole command.
.TP
\fB\-f\fR \fIconf-file\fR
this option is ignored and is provided only for compatibility.
This option can be used to specify an alternate location for the
configuration file (default \fI@SYSCONFDIR@/chrony.conf\fR). The configuration file is
needed for the \fB-a\fR option.
.TP
\fB\-a\fR
this option is ignored and is provided only for compatibility.
With this option chronyc will try to authenticate automatically on
start. It will read the configuration file, read the command key from the
keyfile and run the authhash and password commands.
.TP
\fIcommand\fR
specify command. If no command is given, chronyc will read commands
@@ -60,7 +60,8 @@ interactively.
To report bugs, please visit \fIhttp://chrony.tuxfamily.org\fR
.SH "SEE ALSO"
.BR chronyd(8)
.BR chronyd(8),
.BR chrony(1)
.I http://chrony.tuxfamily.org/

View File

@@ -40,11 +40,9 @@ A summary of the options supported by \fBchronyd\fR is included below.
.TP
\fB\-P\fR \fIpriority\fR
On Linux, this option will select the SCHED_FIFO real-time scheduler at the
specified priority (which must be between 0 and 100). On Mac OS X, this
option must have either a value of 0 (the default) to disable the thread
time constraint policy or 1 for the policy to be enabled. Other systems do not
support this option.
This option will select the SCHED_FIFO real-time scheduler at the specified
priority (which must be between 0 and 100). This mode is supported only on
Linux.
.TP
.B \-m
This option will lock chronyd into RAM so that it will never be paged out.
@@ -69,9 +67,11 @@ This option will reload sample histories for each of the servers being used.
These histories are created by using the \fIdump\fR command in \fIchronyc\fR,
or by setting the \fIdumponexit\fR directive in the configuration file. This
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 should be used only on
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 (i.e. Linux, FreeBSD, NetBSD and Solaris).
\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.
.TP
.B \-R
When this option is used, the \fIinitstepslew\fR directive and the
@@ -80,9 +80,13 @@ option is useful when restarting \fBchronyd\fR and can be used in conjunction
with the \fB-r\fR option.
.TP
.B \-s
This option will set the system clock from the computer's real-time clock or
to the last modification time of the file specified by the \fIdriftfile\fR
directive. Real-time clocks are supported only on Linux.
This option will set the system clock from the computer's real-time
clock. This is analogous to supplying the \fI-s\fR flag to the
\fI/sbin/hwclock\fR program during the Linux boot sequence.
Support for real-time clocks is limited at present - the criteria
are described in the section on the \fIrtcfile\fR directive in the
documentation supplied with the distribution.
If used in conjunction with the \fB-r\fR flag, \fBchronyd\fR will attempt
to preserve the old samples after setting the system clock from
@@ -93,23 +97,16 @@ not in use. For this to work well, it relies on \fBchronyd\fR having
been able to determine accurate statistics for the difference
between the RTC and system clock last time the computer was on.
If the last modification time of the drift file is later than the current time
and the RTC time, the system time will be set to it to restore the time when
\fBchronyd\fR was previously stopped. This is useful on computers that have no
RTC or the RTC is broken (e.g. it has no battery).
If \fBchronyd\fR doesn't support the RTC on your computer or there is no RTC
installed, the system clock will be set with this option forward to the time of
the last modification of the drift file (specified by the \fIdriftfile\fR
directive) to restore the system time at which \fBchronyd\fR was previously
stopped.
.TP
\fB\-u\fR \fIuser\fR
This option sets the name of the system user to which \fBchronyd\fR will switch
after start in order to drop root privileges. It overrides the \fBuser\fR
directive (default \fB@DEFAULT_USER@\fR). It may be set to a non-root user
only when \fBchronyd\fR is compiled with support for Linux capabilities
(libcap) or on NetBSD with the \fB/dev/clockctl\fR device.
.TP
\fB\-F\fR \fIlevel\fR
This option configures a system call filter when \fBchronyd\fR is compiled with
support for the Linux secure computing (seccomp) facility. In level 1 the
process is killed when a forbidden system call is made, in level -1 the SYSSIG
signal is thrown instead and in level 0 the filter is disabled (default 0).
This option sets the name of the user to which will \fBchronyd\fR switch to
drop root privileges if compiled with Linux capabilities support (default
\fB@DEFAULT_USER@\fR).
.TP
.B \-q
When run in this mode, chronyd will set the system clock once
@@ -138,6 +135,7 @@ 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),

1056
client.c

File diff suppressed because it is too large Load Diff

View File

@@ -174,11 +174,6 @@ CLG_Initialise(void)
void
CLG_Finalise(void)
{
int i;
for (i = 0; i < n_nodes; i++)
Free(nodes[i]);
Free(nodes);
}
/* ================================================== */
@@ -261,21 +256,28 @@ find_subnet(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
}
}
/* ================================================== */
/* Search for the record for a particular subnet, but return NULL if
one of the parents does not exist - never open a node out */
static Node *
get_node(IPAddr *ip)
static void *
find_subnet_dont_open(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
{
uint32_t ip6[4];
uint32_t this_subnet;
switch (ip->family) {
case IPADDR_INET4:
return (Node *)find_subnet(&top_subnet4, &ip->addr.in4, 1, 0);
case IPADDR_INET6:
split_ip6(ip, ip6);
return (Node *)find_subnet(&top_subnet6, ip6, 4, 0);
default:
if (bits_consumed >= 32 * addr_len) {
return subnet;
} else {
this_subnet = get_subnet(addr, bits_consumed);
bits_consumed += NBITS;
if (!subnet->entry[this_subnet]) {
return NULL;
} else {
return find_subnet_dont_open((Subnet *) subnet->entry[this_subnet], addr, addr_len, bits_consumed);
}
}
}
@@ -284,10 +286,22 @@ get_node(IPAddr *ip)
void
CLG_LogNTPClientAccess (IPAddr *client, time_t now)
{
uint32_t ip6[4];
Node *node;
if (active) {
node = get_node(client);
switch (client->family) {
case IPADDR_INET4:
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(client, ip6);
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
break;
default:
assert(0);
}
if (node == NULL)
return;
@@ -302,10 +316,22 @@ CLG_LogNTPClientAccess (IPAddr *client, time_t now)
void
CLG_LogNTPPeerAccess(IPAddr *client, time_t now)
{
uint32_t ip6[4];
Node *node;
if (active) {
node = get_node(client);
switch (client->family) {
case IPADDR_INET4:
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(client, ip6);
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
break;
default:
assert(0);
}
if (node == NULL)
return;
@@ -320,10 +346,22 @@ CLG_LogNTPPeerAccess(IPAddr *client, time_t now)
void
CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now)
{
uint32_t ip6[4];
Node *node;
if (active) {
node = get_node(client);
switch (client->family) {
case IPADDR_INET4:
node = (Node *) find_subnet(&top_subnet4, &client->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(client, ip6);
node = (Node *) find_subnet(&top_subnet6, ip6, 4, 0);
break;
default:
assert(0);
}
if (node == NULL)
return;
@@ -348,6 +386,95 @@ CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now)
/* ================================================== */
CLG_Status
CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result)
{
Subnet *s;
uint32_t ip6[4];
unsigned long i;
unsigned long word, bit, mask;
if (bits >= 0 && bits % 8 == 0) {
memset (result, 0, TABLE_SIZE/8);
if (active) {
switch (subnet->family) {
case IPADDR_INET4:
if (bits >= 32)
return CLG_BADSUBNET;
s = find_subnet_dont_open(&top_subnet4, &subnet->addr.in4, 1, 32 - bits);
break;
case IPADDR_INET6:
if (bits >= 128)
return CLG_BADSUBNET;
split_ip6(subnet, ip6);
s = find_subnet_dont_open(&top_subnet6, ip6, 4, 128 - bits);
break;
default:
return CLG_BADSUBNET;
}
if (s) {
for (i=0; i<256; i++) {
if (s->entry[i]) {
word = i / 32;
bit = i % 32;
mask = 1UL << bit;
result[word] |= mask;
}
}
return CLG_SUCCESS;
} else {
return CLG_EMPTYSUBNET;
}
} else {
return CLG_INACTIVE;
}
} else {
return CLG_BADSUBNET;
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now)
{
uint32_t ip6[4];
Node *node;
if (!active) {
return CLG_INACTIVE;
} else {
switch (ip->family) {
case IPADDR_INET4:
node = (Node *) find_subnet_dont_open(&top_subnet4, &ip->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(ip, ip6);
node = (Node *) find_subnet_dont_open(&top_subnet6, ip6, 4, 0);
break;
default:
return CLG_EMPTYSUBNET;
}
if (!node) {
return CLG_EMPTYSUBNET;
} else {
report->client_hits = node->client_hits;
report->peer_hits = node->peer_hits;
report->cmd_hits_auth = node->cmd_hits_auth;
report->cmd_hits_normal = node->cmd_hits_normal;
report->cmd_hits_bad = node->cmd_hits_bad;
report->last_ntp_hit_ago = now - node->last_ntp_hit;
report->last_cmd_hit_ago = now - node->last_cmd_hit;
return CLG_SUCCESS;
}
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices)

View File

@@ -31,6 +31,9 @@
#include "sysincl.h"
#include "reports.h"
/* Enough to hold flags for 256 hosts in a class C */
typedef uint32_t CLG_Bitmap[8];
extern void CLG_Initialise(void);
extern void CLG_Finalise(void);
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now);
@@ -57,8 +60,26 @@ typedef enum {
CLG_INDEXTOOLARGE /* Node index is higher than number of nodes present */
} CLG_Status;
/* For bits=0, 8, 16, flag which immediate subnets of that subnet are
known. For bits=24, flag which hosts in that subnet are known.
Other values, return 0 (failed) */
extern CLG_Status CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result);
extern CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now);
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices);
/* And an iterating function, to call 'fn' for each client or peer
that has accessed us since 'since'. */
extern void CLG_IterateNTPClients
(void (*fn)(IPAddr *client, void *arb),
void *arb,
time_t since);
#endif /* GOT_CLIENTLOG_H */

1153
cmdmon.c

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,6 @@ extern void CAM_Initialise(int family);
extern void CAM_Finalise(void);
extern void CAM_OpenUnixSocket(void);
extern int CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
extern int CAM_CheckAccessRestriction(IPAddr *ip_addr);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013-2014
* Copyright (C) Miroslav Lichvar 2013
*
* 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
@@ -34,7 +34,6 @@
#include "cmdparse.h"
#include "memory.h"
#include "nameserv.h"
#include "ntp.h"
#include "util.h"
/* ================================================== */
@@ -43,7 +42,7 @@ CPS_Status
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
int n, done;
int ok, n, done;
CPS_Status result;
src->port = SRC_DEFAULT_PORT;
@@ -59,10 +58,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
src->params.version = NTP_VERSION;
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
src->params.sel_option = SRC_SelectNormal;
result = CPS_Success;
@@ -72,10 +67,10 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!*hostname) {
result = CPS_BadHost;
ok = 0;
} else {
src->name = hostname;
/* Parse subfields */
ok = 1;
done = 0;
do {
cmd = line;
@@ -85,6 +80,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort;
ok = 0;
done = 1;
} else {
line += n;
@@ -92,6 +88,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll;
ok = 0;
done = 1;
} else {
line += n;
@@ -99,6 +96,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll;
ok = 0;
done = 1;
} else {
line += n;
@@ -106,6 +104,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend;
ok = 0;
done = 1;
} else {
line += n;
@@ -113,6 +112,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1;
} else {
line += n;
@@ -120,6 +120,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio;
ok = 0;
done = 1;
} else {
line += n;
@@ -127,14 +128,16 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay;
ok = 0;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
if (sscanf(line, "%lu%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY) {
result = CPS_BadKey;
ok = 0;
done = 1;
} else {
line += n;
@@ -151,6 +154,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum;
ok = 0;
done = 1;
} else {
line += n;
@@ -159,6 +163,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget;
ok = 0;
done = 1;
} else {
line += n;
@@ -170,40 +175,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer;
} else if (!strcasecmp(cmd, "version")) {
if (sscanf(line, "%d%n", &src->params.version, &n) != 1) {
result = CPS_BadVersion;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxsources")) {
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1) {
result = CPS_BadMaxsources;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "minsamples")) {
if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1) {
result = CPS_BadMinsamples;
done = 1;
} else {
line += n;
}
} else if (!strcasecmp(cmd, "maxsamples")) {
if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1) {
result = CPS_BadMaxsamples;
done = 1;
} else {
line += n;
}
} else {
result = CPS_BadOption;
ok = 0;
done = 1;
}
} else {
@@ -212,73 +186,12 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} while (!done);
}
return result;
}
/* ================================================== */
void
CPS_StatusToString(CPS_Status status, char *dest, int len)
{
const char *s = NULL;
if (len > 0)
dest[0] = '\0';
switch (status) {
case CPS_Success:
return;
case CPS_BadOption:
s = "server/peer/pool option";
break;
case CPS_BadHost:
s = "address";
break;
case CPS_BadPort:
s = "port";
break;
case CPS_BadMinpoll:
s = "minpoll";
break;
case CPS_BadMaxpoll:
s = "maxpoll";
break;
case CPS_BadPresend:
s = "presend";
break;
case CPS_BadMaxdelaydevratio:
s = "maxdelaydevratio";
break;
case CPS_BadMaxdelayratio:
s = "maxdelayratio";
break;
case CPS_BadMaxdelay:
s = "maxdelay";
break;
case CPS_BadKey:
s = "key";
break;
case CPS_BadMinstratum:
s = "minstratum";
break;
case CPS_BadPolltarget:
s = "polltarget";
break;
case CPS_BadVersion:
s = "version";
break;
case CPS_BadMaxsources:
s = "maxsources";
break;
case CPS_BadMinsamples:
s = "minsamples";
break;
case CPS_BadMaxsamples:
s = "maxsamples";
break;
if (ok) {
src->name = strdup(hostname);
}
snprintf(dest, len, "Invalid %s", s);
return result;
}
/* ================================================== */
@@ -341,7 +254,7 @@ CPS_SplitWord(char *line)
/* ================================================== */
int
CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key)
{
char *s1, *s2, *s3, *s4;
@@ -354,7 +267,7 @@ CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
if (!*s2 || *s4)
return 0;
if (sscanf(s1, "%"SCNu32, id) != 1)
if (sscanf(s1, "%lu", id) != 1)
return 0;
if (*s3) {

View File

@@ -43,11 +43,7 @@ typedef enum {
CPS_BadMaxdelay,
CPS_BadKey,
CPS_BadMinstratum,
CPS_BadPolltarget,
CPS_BadVersion,
CPS_BadMaxsources,
CPS_BadMinsamples,
CPS_BadMaxsamples,
CPS_BadPolltarget
} CPS_Status;
typedef struct {
@@ -59,9 +55,6 @@ typedef struct {
/* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Get a string describing error status */
extern void CPS_StatusToString(CPS_Status status, char *dest, int len);
/* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line);
@@ -69,6 +62,6 @@ extern void CPS_NormalizeLine(char *line);
extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */
extern int CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key);
extern int CPS_ParseKey(char *line, unsigned long *id, const char **hash, char **key);
#endif /* GOT_CMDPARSE_H */

613
conf.c

File diff suppressed because it is too large Load Diff

16
conf.h
View File

@@ -29,18 +29,14 @@
#define GOT_CONF_H
#include "addressing.h"
#include "reference.h"
extern void CNF_Initialise(int restarted);
extern void CNF_Finalise(void);
extern void CNF_SetRestarted(int);
extern char *CNF_GetRtcDevice(void);
extern void CNF_ReadFile(const char *filename);
extern void CNF_ParseLine(const char *filename, int number, char *line);
extern void CNF_CreateDirs(uid_t uid, gid_t gid);
extern void CNF_AddInitSources(void);
extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
@@ -60,6 +56,8 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
@@ -75,9 +73,7 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetBindCommandPath(void);
extern char *CNF_GetPidFile(void);
extern REF_LeapMode CNF_GetLeapSecMode(void);
extern char *CNF_GetLeapSecTimezone(void);
/* Value returned in ppm, as read from file */
@@ -86,7 +82,6 @@ extern double CNF_GetMaxClockError(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetMaxSlewRate(void);
extern double CNF_GetMaxDistance(void);
extern double CNF_GetReselectDistance(void);
extern double CNF_GetStratumWeight(void);
extern double CNF_GetCombineLimit(void);
@@ -98,16 +93,13 @@ 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, int *leap_only);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
extern int CNF_GetMinSources(void);
extern double CNF_GetRtcAutotrim(void);
extern char *CNF_GetHwclockFile(void);

310
configure vendored
View File

@@ -4,12 +4,34 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
# Copyright (C) Miroslav Lichvar 2009, 2012-2014
#
# =======================================================================
rm -f config.h config.log
# This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then
MYCC="gcc"
else
MYCC="${CC}"
fi
if [ "x${CFLAGS}" = "x" ]; then
MYCFLAGS="-O2 -g"
else
MYCFLAGS="${CFLAGS}"
fi
MYCPPFLAGS="${CPPFLAGS}"
if [ "x${MYCC}" = "xgcc" ]; then
MYCFLAGS="${MYCFLAGS} -Wmissing-prototypes -Wall"
fi
MYLDFLAGS="${LDFLAGS}"
# ======================================================================
# FUNCTIONS
@@ -21,7 +43,7 @@ test_code () {
ldflags=$4
code=$5
printf "%s" "Checking for $name : "
echo -n "Checking for $name : "
(
for h in $headers; do
@@ -83,26 +105,18 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is
--disable-sechash Disable support for hashes other than MD5
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-cmdmon Disable command and monitoring support
--disable-ntp Disable NTP support
--disable-refclock Disable reference clock support
--disable-phc Disable PHC refclock driver
--disable-pps Disable PPS refclock driver
--disable-ipv6 Disable IPv6 support
--disable-phc Disable PHC support
--disable-pps Disable PPS API support
--disable-rtc Don't include RTC even on Linux
--disable-privdrop Disable support for dropping root privileges
--without-libcap Don't use libcap even if it is available
--disable-scfilter Disable support for system call filtering
--without-seccomp Don't use seccomp even if it is available
--disable-linuxcaps Disable Linux capabilities support
--disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
since 1970-01-01 [50*365 days ago]
--with-user=USER Specify default chronyd user [root]
--with-hwclockfile=PATH Specify default path to hwclock(8) adjtime file
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
--enable-debug Enable debugging support
@@ -115,7 +129,6 @@ Fine tuning of the installation directories:
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/chrony]
--localstatedir=DIR modifiable single-machine data [/var]
--chronysockdir=DIR location for chrony sockets [LOCALSTATEDIR/run/chrony]
--chronyvardir=DIR location for chrony data [LOCALSTATEDIR/lib/chrony]
Overriding system detection when cross-compiling:
@@ -154,22 +167,6 @@ pkg_config () {
pkg-config $@ 2> /dev/null
}
#}}}
#{{{ get_features
get_features () {
ff=1
for f; do
if [ "$ff" = "0" ]; then
printf " "
fi
if grep "define FEAT_$f" config.h > /dev/null; then
printf "%s" "+$f"
else
printf "%s" "-$f"
fi
ff=0
done
}
#}}}
# ======================================================================
@@ -185,23 +182,16 @@ EXTRA_OBJECTS=""
EXTRA_DEFS=""
SYSDEFS=""
feat_debug=0
feat_cmdmon=1
feat_ntp=1
feat_refclock=1
debug=0
feat_readline=1
try_readline=1
try_editline=1
feat_sechash=1
try_nss=1
try_tomcrypt=1
feat_rtc=1
try_rtc=0
feat_droproot=1
try_libcap=-1
try_clockctl=0
feat_scfilter=1
try_seccomp=-1
feat_linuxcaps=1
try_linuxcaps=0
readline_lib=""
readline_inc=""
ncurses_lib=""
@@ -215,14 +205,13 @@ feat_asyncdns=1
feat_forcednsretry=1
ntp_era_split=""
default_user="root"
default_hwclockfile=""
mail_program="/usr/lib/sendmail"
for option
do
case "$option" in
--enable-debug )
feat_debug=1
debug=1
;;
--disable-readline )
feat_readline=0
@@ -272,21 +261,9 @@ do
--localstatedir=* )
SETLOCALSTATEDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--chronysockdir=* )
SETCHRONYSOCKDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--chronyvardir=* )
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-cmdmon)
feat_cmdmon=0
;;
--disable-ntp)
feat_ntp=0
;;
--disable-refclock)
feat_refclock=0
;;
--disable-rtc)
feat_rtc=0
;;
@@ -299,17 +276,8 @@ do
--disable-pps)
feat_pps=0
;;
--disable-privdrop)
feat_droproot=0
;;
--without-libcap|--disable-linuxcaps)
try_libcap=0
;;
--disable-scfilter)
feat_scfilter=0
;;
--without-seccomp)
try_seccomp=0
--disable-linuxcaps)
feat_linuxcaps=0
;;
--disable-asyncdns)
feat_asyncdns=0
@@ -323,15 +291,9 @@ do
--with-user=* )
default_user=`echo $option | sed -e 's/^.*=//;'`
;;
--with-hwclockfile=* )
default_hwclockfile=`echo $option | sed -e 's/^.*=//;'`
;;
--with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'`
;;
--disable-sechash )
feat_sechash=0
;;
--without-nss )
try_nss=0
;;
@@ -356,115 +318,77 @@ do
esac
done
rm -f config.h config.log
SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
case $OPERATINGSYSTEM in
Linux)
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o"
[ $try_libcap != "0" ] && try_libcap=1
case $SYSTEM in
SunOS-sun4* )
case $VERSION in
4.* )
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
add_def SUNOS
echo "Configuring for SunOS (" $SYSTEM "version" $VERSION ")"
;;
5.* )
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
add_def SOLARIS
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
;;
esac
;;
Linux* )
EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o"
try_linuxcaps=1
try_rtc=1
[ $try_seccomp != "0" ] && try_seccomp=1
try_setsched=1
try_lockmem=1
try_phc=1
add_def LINUX
echo "Configuring for " $SYSTEM
if [ "${MACHINE}" = "alpha" ]; then
echo "Enabling -mieee"
# FIXME: Should really test for GCC
MYCFLAGS="$MYCFLAGS -mieee"
fi
;;
FreeBSD)
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
add_def FREEBSD
BSD/386-i[3456]86|FreeBSD-i386|FreeBSD-amd64 )
# Antti Jrvinen <costello@iki.fi> reported that this system can
# be supported with the SunOS 4.x driver files.
EXTRA_OBJECTS="sys_sunos.o strerror.o"
EXTRA_LIBS="-lkvm"
add_def SUNOS
echo "Configuring for $SYSTEM (using SunOS driver)"
;;
NetBSD-* )
EXTRA_OBJECTS="sys_netbsd.o"
EXTRA_LIBS="-lkvm"
SYSDEFS=""
echo "Configuring for $SYSTEM"
;;
NetBSD)
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
try_clockctl=1
add_def NETBSD
echo "Configuring for $SYSTEM"
;;
Darwin)
EXTRA_OBJECTS="sys_macosx.o"
EXTRA_LIBS="-lresolv"
EXTRA_CLI_LIBS="-lresolv"
add_def MACOSX
echo "Configuring for MacOS X (" $SYSTEM "MacOS X version" $VERSION ")"
;;
SunOS)
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o"
EXTRA_LIBS="-lsocket -lnsl -lresolv"
EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv"
SunOS-i86pc* )
# Doug Woodward <dougw@whistler.com> reported that this configuration
# works for Solaris 2.8 / SunOS 5.8 on x86 platforms
EXTRA_OBJECTS="sys_solaris.o"
EXTRA_LIBS="-lsocket -lnsl -lkvm -lelf"
EXTRA_CLI_LIBS="-lsocket -lnsl"
add_def SOLARIS
# These are needed to have msg_control in struct msghdr
add_def __EXTENSIONS__
add_def _XOPEN_SOURCE 1
add_def _XOPEN_SOURCE_EXTENDED 1
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
;;
CYGWIN32_NT-i[3456]86 )
EXTRA_OBJECTS="sys_winnt.o"
EXTRA_LIBS=""
add_def WINNT
echo "Configuring for Windows NT (Cygwin32)"
;;
* )
echo "error: $SYSTEM is not supported (yet?)"
echo "Sorry, I don't know how to build this software on your system."
exit 1
;;
esac
if [ $feat_debug = "1" ]; then
add_def FEAT_DEBUG
fi
add_def DEBUG $feat_debug
if [ $feat_cmdmon = "1" ]; then
add_def FEAT_CMDMON
EXTRA_OBJECTS="$EXTRA_OBJECTS cmdmon.o manual.o pktlength.o"
fi
if [ $feat_ntp = "1" ]; then
add_def FEAT_NTP
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_core.o ntp_io.o ntp_sources.o"
else
feat_asyncdns=0
fi
if [ "$feat_cmdmon" = "1" ] || [ $feat_ntp = "1" ]; then
EXTRA_OBJECTS="$EXTRA_OBJECTS addrfilt.o clientlog.o keys.o nameserv.o"
else
feat_ipv6=0
fi
if [ $feat_refclock = "1" ]; then
add_def FEAT_REFCLOCK
EXTRA_OBJECTS="$EXTRA_OBJECTS refclock.o refclock_phc.o refclock_pps.o refclock_shm.o refclock_sock.o"
fi
MYCC="$CC"
MYCFLAGS="$CFLAGS"
MYCPPFLAGS="$CPPFLAGS"
MYLDFLAGS="$LDFLAGS"
if [ "x$MYCC" = "x" ]; then
MYCC=gcc
if ! test_code "$MYCC" '' '' '' ''; then
MYCC=cc
if ! test_code "$MYCC" '' '' '' ''; then
echo "error: no C compiler found"
exit 1
fi
fi
else
if ! test_code "$MYCC" '' '' '' ''; then
echo "error: C compiler $MYCC cannot create executables"
exit 1
fi
fi
if [ "x$MYCFLAGS" = "x" ]; then
MYCFLAGS="-O2 -g"
fi
if [ "x$MYCC" = "xgcc" ]; then
MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
fi
if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];'
@@ -477,7 +401,7 @@ then
else
split_seconds=`date '+%s'`
if [ "x$split_seconds" = "" ]; then
echo "error: could not get current time, --with-ntp-era option is needed"
echo "Could not get current time, --with-ntp-era option is needed"
exit 1
fi
split_days=$((50 * 365))
@@ -506,27 +430,27 @@ else
if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
LIBS="-lm"
else
echo "error: could not compile/link a program which uses sqrt(), log(), pow()"
echo "Can't compile/link a program which uses sqrt(), log(), pow(), bailing out"
exit 1
fi
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
add_def HAVE_STDINT_H
add_def HAS_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
add_def HAVE_INTTYPES_H
add_def HAS_INTTYPES_H
fi
if [ $feat_ipv6 = "1" ] && \
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' "$EXTRA_LIBS" '
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' '' '
struct sockaddr_in6 n;
char p[100];
n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
add_def FEAT_IPV6
add_def HAVE_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);'
then
@@ -541,7 +465,7 @@ then
fi
fi
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$EXTRA_LIBS" \
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' '' \
'return getaddrinfo(0, 0, 0, 0);'
then
add_def HAVE_GETADDRINFO
@@ -553,12 +477,11 @@ if [ $feat_asyncdns = "1" ] && \
then
add_def FEAT_ASYNCDNS
add_def USE_PTHREAD_ASYNCDNS
EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
MYCFLAGS="$MYCFLAGS -pthread"
fi
timepps_h=""
if [ $feat_refclock = "1" ] && [ $feat_pps = "1" ]; then
if [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
@@ -577,34 +500,20 @@ if [ "x$timepps_h" != "x" ] && \
struct timespec ts;
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
add_def FEAT_PPS
add_def HAVE_PPSAPI
fi
if [ $feat_droproot = "1" ] && [ $try_libcap = "1" ] && \
if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
test_code \
libcap \
linuxcaps \
'sys/types.h pwd.h sys/prctl.h sys/capability.h grp.h' \
'' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then
add_def FEAT_PRIVDROP
add_def FEAT_LINUXCAPS
EXTRA_LIBS="$EXTRA_LIBS -lcap"
fi
if [ $feat_droproot = "1" ] && [ $try_clockctl = "1" ] && \
test_code '<sys/clockctl.h>' 'sys/clockctl.h' '' '' ''
then
add_def FEAT_PRIVDROP
fi
if [ $feat_scfilter = "1" ] && [ $try_seccomp = "1" ] && \
test_code seccomp 'seccomp.h' '' '-lseccomp' \
'seccomp_init(SCMP_ACT_KILL);'
then
add_def FEAT_SCFILTER
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
fi
if [ $feat_rtc = "1" ] && [ $try_rtc = "1" ] && \
test_code '<linux/rtc.h>' 'sys/ioctl.h linux/rtc.h' '' '' \
'ioctl(1, RTC_UIE_ON&RTC_UIE_OFF&RTC_RD_TIME&RTC_SET_TIME, 0&RTC_UF);'
@@ -613,7 +522,7 @@ then
add_def FEAT_RTC
fi
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
if [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
then
@@ -701,7 +610,7 @@ HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
if [ $try_nss = "1" ]; then
test_cflags="`pkg_config --cflags nss`"
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
@@ -712,11 +621,11 @@ if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link"
LIBS="$LIBS $HASH_LINK"
add_def FEAT_SECHASH
add_def GENERATE_SHA1_KEY
fi
fi
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then
@@ -724,7 +633,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]
HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt"
LIBS="$LIBS $HASH_LINK"
add_def FEAT_SECHASH
add_def GENERATE_SHA1_KEY
fi
fi
@@ -778,29 +687,16 @@ if [ "x$SETLOCALSTATEDIR" != "x" ]; then
LOCALSTATEDIR=$SETLOCALSTATEDIR
fi
CHRONYSOCKDIR=${LOCALSTATEDIR}/run/chrony
if [ "x$SETCHRONYSOCKDIR" != "x" ]; then
CHRONYSOCKDIR=$SETCHRONYSOCKDIR
fi
CHRONYVARDIR=${LOCALSTATEDIR}/lib/chrony
if [ "x$SETCHRONYVARDIR" != "x" ]; then
CHRONYVARDIR=$SETCHRONYVARDIR
fi
add_def DEBUG $debug
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
add_def DEFAULT_HWCLOCK_FILE "\"$default_hwclockfile\""
add_def DEFAULT_USER "\"$default_user\""
add_def DEFAULT_COMMAND_SOCKET "\"$CHRONYSOCKDIR/chronyd.sock\""
add_def MAIL_PROGRAM "\"$mail_program\""
common_features="`get_features IPV6 DEBUG`"
chronyc_features="`get_features READLINE`"
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH ASYNCDNS`"
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
echo "Features : $chronyd_features $chronyc_features $common_features"
if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\""
else
@@ -828,9 +724,7 @@ do
s%@MANDIR@%${MANDIR}%;\
s%@INFODIR@%${INFODIR}%;\
s%@LOCALSTATEDIR@%${LOCALSTATEDIR}%;\
s%@CHRONYSOCKDIR@%${CHRONYSOCKDIR}%;\
s%@CHRONYVARDIR@%${CHRONYVARDIR}%;\
s%@DEFAULT_HWCLOCK_FILE@%${default_hwclockfile}%;\
s%@DEFAULT_USER@%${default_user}%;"\
< ${f}.in > $f
done

339
contrib/DNSchrony/COPYING Normal file
View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

583
contrib/DNSchrony/DNSchrony.pl Executable file
View File

@@ -0,0 +1,583 @@
#!/usr/bin/perl
# Copyright (C) Paul Elliott 2002
my($copyrighttext) = <<'EOF';
# Copyright (C) Paul Elliott 2002
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# SEE COPYING FOR DETAILS
EOF
#modules we use.
use Socket;
use Getopt::Std;
use Net::DNS;
use Tie::Syslog;
use File::Temp qw/ :mktemp /;
use File::Copy;
local($res) = new Net::DNS::Resolver;
#dns lookup of IP address.
#returns ip or errorstring.
sub gethostaddr($) #get ip address from host
{
my($host) = shift;
$query = $res->search($host);
if ($query) {
foreach $rr ($query->answer) {
next unless $rr->type eq "A";
print $rr->address, "\n" if $pedebug;
return $rr->address;
}
} else {
print "query failed: ", $res->errorstring, "\n" if $pedebug;
return $res->errorstring;
}
}
#send messages to syslog
sub Log($$)
{
if ($log) {
my($level) = shift;
my($mess) =shift;
tie *MYLOG, 'Tie::Syslog',$level,$0,'pid','unix';
print MYLOG $mess;
untie *MYLOG;
}
}
#send message to output or syslog
#and die.
sub BadDie($)
{
my($myerr) =$!;
my($mess)=shift;
if($log){
tie *MYLOG, 'Tie::Syslog','local0.err',$0,'pid','unix';
print MYLOG $mess;
print MYLOG $myerr;
untie *MYLOG;
} else {
print "$mess\n$myerr\n";
}
die $mess;
}
sub isIpAddr($) #return true if looks like ip address
{
my($ip) = shift;
return 1 if ( $ip =~ m/$ipOnlyPAT/ );
return 0;
}
sub isHostname($) #return true if looks like ip address
{
my($ip) = shift;
return 1 if ( $ip =~ m/$hostnameOnlyPAT/ );
return 0;
}
#send commands to chronyc by piping.
sub chronyc($) #send commands to chronyc
{
my($command) = shift;
my($err) = "/var/tmp/chronyc.log";
my($chronyP) = "/usr/local/bin/chronyc";
open(CHRONY, "| $chronyP 1>$err 2>&1");
print CHRONY "$passwd$command\n";
close(CHRONY);
Log('local0.info',"chronyc command issued=$command");
#look at status lines till return bad.
open( IN, "<$err");
my($status);
while (<IN>) {
$status = $_;
unless ( m/\A200 OK/ ) {
last;
}
}
$status ="" if ( $status =~ m/\A200 OK/ );
close(IN);
unlink $err;
Log('local0.info',"chronyc results=$status");
return $status;
}
#common patterns
# an ip address patern
local($ipPAT) = qr/\d{1,3}(?:\.\d{1,3}){3}/;
# an hostname pattern
local($hostnamePAT) = qr/\w+(?:\.\w+)*/;
#line with hostname only
local($hostnameOnlyPAT) = qr/\A$hostnamePAT\Z/;
#line with ip address only
local($ipOnlyPAT) =qr/\A$ipPAT\Z/;
#options hash
my(%opts);
getopts('nuadslPSC', \%opts);
local($log) = ( $opts{'l'} ) ? 1 : 0;
my($offline) = !( $opts{'n'} ) ;
my($offlineS) = ( $opts{'n'} ) ? " " : " offline" ;
# paul elliotts secret debug var. no one will ever find out about it.
local($pedebug)=( ($ENV{"PAULELLIOTTDEBUG"}) or ($opts{P}) );
if ($opts{C}) {
print $copyrighttext;
exit 0;
}
print <<"EOF" unless $opts{'S'};
$0, Copyright (C) 2002 Paul Elliott
$0 comes with ABSOLUTELY NO WARRANTY; for details
invoke $0 -C. This is free software, and you are welcome
to redistribute it under certain conditions; invoke $0 -C
for details.
EOF
local($passwd);
# password to send to chronyc
my($pl) = $ENV{"CHRONYPASSWORD"};
#password comand to send to chronyc
if ( $pl ) {
$passwd = "password $pl\n";
} else {
$passwd = "";
}
print "passwd=$passwd\n" if ($pedebug);
my(%host2ip);
# hash of arrays. host2ip{$host}[0] is ip address for this host
# host2ip{$host}[1] is rest of paramenters for this host exc offline.
#if debuging do chrony.conf in current directory.
my($listfile) =( ($pedebug) ? "./chrony.conf" : "/etc/chrony.conf") ;
# This section reads in the old data about
# hostnames IP addresses and server parameters
# data is stored as it would be in chrony.conf
# file i.e.:
#># HOSTNAME
#>server IPADDR minpoll 5 maxpoll 10 maxdelay 0.4 offline
#
# the parameter offline is omitted if the -n switch is specified.
# first parameter is the filename of the file usually
# is /etc/DNSchrony.conf
# this is where we store the list of DNS hosts.
# hosts with static IP address shold be kept in chrony.conf
# this is header that marks dnyamic host section
my($noedithead)=<<'EOF';
## DNSchrony dynamic dns server section. DO NOT EDIT
## per entry FORMAT:
## |--------------------------------------------|
## |#HOSTNAME |
## |server IP-ADDRESS extra-params [ offline ] |
## |--------------------------------------------|
EOF
#patern that recognizes above.
my($noeditheadPAT) =
qr/\#\#\s+DNSchrony\s+dynamic\s+dns\s+server\s+section\.\s+DO\s+NOT\s+EDIT\s*/;
#end of header marker.
my($noeditheadend)=<<'EOF';
## END OF DNSchrony dynamic dns server section.
EOF
#pattern that matches above.
my($noeditheadendPAT)=
qr/\#\#\s+END\s+OF\s+DNSchrony\s+dynamic\s+dns\s+server\s+section.\s*/;
#array to hold non dns portion of chrony.conf
my(@chronyDconf);
my($ip);
my($rest);
my($host);
# for each entry in the list of hosts....
open(READIN, "<$listfile") or BadDie("Can not open $listfile");
# read till dynamic patern read save in @chronyDconf
while ( <READIN> ) {
my($line) = $_;
last if ( m/\A$noeditheadPAT\Z/ );
push(@chronyDconf,$line);
}
while ( <READIN> ) {
#end loop when end of header encountered
last if ( m/\A$noeditheadendPAT/ );
# parse the line giving ip address, extra pamamters, and host
#do host comment line first
($host) = m{
\A\#\s*
($hostnamePAT)
\s*\z
}xio;
#no match skip this line.
next unless ( $host );
# read next line
$_ = <READIN>;
# parse out ip address extra parameters.
($ip,$rest) =
m{
\A
\s*
server #server comand
\s+
($ipPAT) #ip address
(?ixo: \s )
\s*
(
(?(?!
(?iox: offline )? #skip to offline #
\s* #or #
\Z
).)*
)
(?ixo:
\s*
(?ixo: offline )? #consume to #
\s*
\Z
)
}xio ;
#if failure again.
next unless ( $ip );
$rest =~ s/\s*\z//; #remove trail blanks
#from parameters
# store the data in the list
# key is host name value is
# array [0] is ip address
# [1] is other parameters
$host2ip{$host} = [$ip,$rest] ;
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
}
#read trailing line into @chronyDconf
while ( <READIN> ) {
push(@chronyDconf,$_);
}
close(READIN) or BadDie("can not close $listfile");
#if the add command:
# command can be HOST=IPADDRESS OTHER_PARAMETERS
# means add the server trust the ip address geven with out a dns lookup
# good for when dns is down but we know the ip addres
# or
# HOST OTHER_PARAMETERS
#we lookup the ip address with dns.
if ($opts{'a'}) {
my($param)= shift;
# parse the param is it hostname
if ( ($host,$ip) = $param =~ m/\A($hostnamePAT)=($ipPAT)\Z/ ) {
printf "ip=$ip host=$host\n" if ($pedebug);
} else {
$host = $param;
# get the ip address
$ip = gethostaddr($host);
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
print "query failed: ", $ip, "host=$host\n" if $pedebug;
exit 1;
}
}
printf "ip=$ip host=$host\n" if ($pedebug);
# add the server using chronyc
my($status) = chronyc("add server $ip $rest");
if ($status) { #chronyc error
print "chronyc failed, status=$status\n";
exit 1;
}
# get rest of arguements
$rest = join( ' ', @ARGV);
print "rest=$rest\n" if ($pedebug);
#save node in hash
$host2ip{$host} = [$ip,$rest] ;
print "ip=$ip rest=$rest host=$host<\n" if $pedebug;
}
#delete command if arguement is ip address
#just delete it
#if a hostname look it up
#then delete it.
if ($opts{'d'}) {
$host = shift;
#get host name is it ap address
if ( isIpAddr($host) ) { # if ip address
my($hostIT);
my($found) =0;
foreach $hostIT (keys(%host2ip) ) { #search for match
if ( $host2ip{$hostIT}[0] eq $host) {
$found=1; #record match
}
} #end of search
if ($found) { #if match found
my($status) = chronyc("delete $host"); #chronyc
if ($status) { #chronyc error
print "chronyc failed, status=$status\n";
exit 1;
} else { #reiterate
foreach $hostIT (keys(%host2ip) ) {
if ( $host2ip{$hostIT}[0] eq $host) {
delete $host2ip{$hostIT}; #deleting match hosts
}
}
}
}
} else { #else not ip address
#must be hostname
if ( ! $host2ip{$host} ) {
print "No such host as $host listed\n";
exit 1;
}
#get ip address
$ip=gethostaddr($host);
if ( ! isIpAddr($ip) ) { #no ip address
print "query failed: ", $ip, "\n" if $pedebug;
exit 1;
}
printf "ip=$ip host=$host\n" if ($pedebug);
my($listed_host_ip) = $host2ip{$host}[0]; # get the ip address saved
if ( $ip ne $listed_host_ip) {
print
"Info: listed host ip=>$listed_host_ip".
"< is different from DNS ip=>$ip<\n";
$ip = $listed_host_ip;
}
# delete the server
my($status) = chronyc("delete $listed_host_ip\n");
if ($status) {
print "chronyc failed, status=$status\n";
exit 1;
}
#delete table entry
delete$host2ip{$host};
}
}
#update for each host who's dns ip address has changed
#delete the old server and add the new. update the record.
if ($opts{'u'}) {
my($command);
my(%prospective); # store new IP address we
#are thinking of changing.
Log('local0.info',
"Now searching for modified DNS entries.");
foreach $host (keys(%host2ip)) { #for each listed host
my($old_ip) = $host2ip{$host}[0]; #get old ip
$rest = $host2ip{$host}[1]; #extra params
$ip = gethostaddr($host); #get new ip from dns
#if error
if ( ! isIpAddr($ip) or ! isHostname($host) ) {
print "query failed: ", $ip, "host=$host\n";
Log('local0.err',"query failed: ". $ip . "host=$host");
exit 1;
}
next if($ip eq $old_ip); #if ip not changed, skip
Log('local0.info',"Ip address for $host has changed. Old IP address=".
"$old_ip, new IP address=$ip");
# add command to delete old host, add the new.
$command = $command . "delete $old_ip\n" .
"add server $ip $rest\n";
# we are now thinking about changing this host ip
$prospective{$host} = [$ip,$rest];
}
# submit all the accumulated chronyc commands if any.
if ($command) {
$status = chronyc($command);
if ($status) {
print "chronyc failed, status=$status\n";
Log('local0.err',"query failed: ". $ip . "host=$host");
exit 1;
}
} else { #if no commands exit
exit 0; #because no rewrite of file needed
}
#copy prospective modifications back into main table.
#we now know that all these mods were done with chronyc
foreach $host (keys(%prospective)) {
my($ip) = $prospective{$host}[0];
$rest = $prospective{$host}[1];
$host2ip{$host} = [$ip,$rest];
}
}
#starting for each entry we have read in from the old list
# add the server in chronyc
# this option is seldom used.
if ($opts{'s'}) {
my($command)="";
foreach $host (keys(%host2ip)) {
$command = $command . "add server $host2ip{$host}[0] ".
"$host2ip{$host}[1]\n";
}
my($status) = chronyc($command);
if ($status) {
print "chronyc failed, status=$status\n";
exit 1;
}
}
# write out the data file in format
#># HOSTNAME
#>server IPADDRESS extra parameters [offline]
# offline is omitted if -n switch is specified.
my(@value);
my($such);
{
# to start out we write to temporary file.
(my($writeout) , my($outname)) = mkstemp( "${listfile}.outXXXXXXX");
$outname or BadDie("can not open for $listfile");
# save the chrony.conf part!
# and write the DYNAMIC header
print $writeout @chronyDconf, $noedithead;
# for each entry
foreach $host (keys(%host2ip) ){
#write the record
# write the comment that indicates the hostname
# and the server command.
print $writeout
"\# $host\nserver $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\n" ;
print
"server $host2ip{$host}[0] $host2ip{$host}[1]${offlineS}\# $host\n"
if $pedebug;
}
#WRITE THE end of dnyamic marker comment
print $writeout $noeditheadend;
# close the output file which was a temporary file.
close($writeout) or BadDie("can not close $outname");
# we now begin a intracate dance to make the the temporary
# the main chrony.conf
#
# if there is a chrony.conf.BAK save it to a temporary.
# rename chrony.conf to chrony.conf.BAK
# rename the temporary to chrony.conf
# if there already was a chrony.conf.BAK, unlink the copy of this.
my($backname) = "$listfile\.BAK";
my($backplain) = ( -f $backname );
my($saveback);
#if chrony.conf.BAK exists rename to a temporary.
if ($backplain ) {
$saveback = mktemp("${backname}.bakXXXXXXX");
move($backname,$saveback) or
BadDie "unable to move $backname to $savename";
}
# rename old chrony.conf to chrony.conf.BAK
move($listfile,$backname) or
BadDie "unable to move $listfile to $backname";
# rename our output to chrony.conf
move($outname,$listfile) or
BadDie "unable to move $outname to $listfile";
#if there was a temporary chrony.conf.BAK that we saved to temp
#unlink it
unlink($saveback) or BadDie "unable to unlink $saveback" if($backplain);
}

21
contrib/DNSchrony/DNSchronyADD Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/bash
# $1 is chrony password.
# $2 is hostname to add or hostname=ipaddres
# $3-$9 is rest of extra server parameters
FIRST="$1"
HOST="$2"
shift 2
#remaining parameters a the other paramaters to server command
#excluding "offline"
ARGS="$*"
#if none use default taken from chrony documentation.
DEF="minpoll 5 maxpoll 10 maxdelay 0.4"
DARGS=${ARGS:-$DEF}
CHRONYPASSWORD=$FIRST \
/usr/local/bin/DNSchrony.pl -a "$HOST" "$DARGS"

View File

@@ -0,0 +1,7 @@
#!/usr/bin/bash
# $1 is chrony password.
# $2 host to be deleted if ip nn.n.n.n then no DNS used
CHRONYPASSWORD=$1 \
/usr/local/bin/DNSchrony.pl -d $2

View File

@@ -0,0 +1,7 @@
#!/usr/bin/bash
# $1 is chrony password.
CHRONYPASSWORD=$1 \
/usr/local/bin/DNSchrony.pl -ulS

166
contrib/DNSchrony/README Normal file
View File

@@ -0,0 +1,166 @@
Copyright (C) Paul Elliott 2002
DNSchrony.pl version -2.0
Problem: If you look at the list of secondary NTP servers:
http://www.eecis.udel.edu/~mills/ntp/clock2.htm
you will find statements like this:
"Note: IP addresses are subject to change; please use DNS"
These servers represent a problem for chrony. Chrony is a program
designed to work on hosts with an intermittent connection to the
internet. Often no DNS is available when chrony starts. As chrony
is currently designed, chronyd never sees a DNS host name. If a
user specifies one when using chronyc's "add server" command, the
DNS lookup is done by chronyc and an IP address is passed to chronyd.
One can imagine I suppose, a redesign to chrony in which chronyd
keeps track of DNS changes. But this has problems, all the time
chronyd is fooling around with DNS, it would not be keeping track
of its prime function, what the clocks and NTP servers are saying.
This could result in poorer performance. Or perhaps you say that
chronyd should be multi threaded. One thread to fool with DNS
and another to keep track of time. But this introduces a great
deal of complexity, and complexity is the enemy of elegant robust
code. Besides, Richard probably has better things to do.
I have attempted to address this problem with a humble perl script,
which I now release under the GPL: DNSchrony.pl
PLEA FOR HELP FROM EXPERIENCED PERL HACKERS.
Please go thru the code and find errors and improvements.
I am not quite an polished perl hacker. Please fix bugs and
make improvements. It needs better documentation. Someone
who knows how, put in some POD.
END OF PLEA
Philosophy of DNSchrony.pl: keep a list of servers that use
DNS. From time to time, hopefully when DNS is up, go thru
the list lookup all the hostnames and see if any ip addresses have
changed. If any have changed, update our list and do chronyc
"delete" and "add server" commands so that chronyd now talks to
the right NTP server.
Additional nuance: keep the list in /etc/chrony.conf in the
form of comments starting with "#" and "server" commands
legal in a chrony.conf file. Format of a list entry:
# hostname
server IP-ADDRESS extra server parameters
These entries are delimited by special comments that allow
DNSchrony.pl to find them and also tell humans not to mess with them.
Example of such a section of a chrony.conf file:
dumpdir /var/log/chrony
rtcfile /etc/chrony.rtc
## DNSchrony dynamic dns server section. DO NOT EDIT
## per entry FORMAT:
## |--------------------------------------------|
## |#HOSTNAME |
## |server IP-ADDRESS extra-params [ offline ] |
## |--------------------------------------------|
# tock.greyware.com
server 208.14.208.44 minpoll 5 maxpoll 10 maxdelay 0.4 offline
# tick.greyware.com
server 208.14.208.19 minpoll 5 maxpoll 10 maxdelay 0.4 offline
# ntppub.tamu.edu
server 128.194.254.9 minpoll 5 maxpoll 10 maxdelay 0.4 offline
## END OF DNSchrony dynamic dns server section.
This allows the list of dynamic DNS servers to be preserved
when chronyd is stoped/started.
All servers that do not have ip addresses subject to change
should be put in the regular part of chrony.conf as described
in the chrony documentation.
Security philosophy: DNSchrony does no security checking but
relies on other security factors.
Users without the privilege to modify /etc/chrony.conf and the
directory /etc will be unable to use DNSchrony to do so, because
of file protections. DNSchrony passes thru passwords to chronyc.
Users that do not know the correct chronyc password will be
unable to get chronyd do do anything. Thus, DNSchrony passes
the buck to these other security features.
INSTALLATION:
copy the files: DNSchronyADD DNSchronyUPDATE DNSchronyDELETE DNSchrony.pl
to /usr/local/bin. Backup the file /etc/chrony.conf leave hosts
with static ip addresses in this file.
DNSchrony uses the following perl modules. See that they are installed.
Get them from CPAN if needed.
Net::DNS, Tie::Syslog, Getopt::Std, Socket, File.
Cause DNSchronyUPDATE bash script to run from time to time when DNS
is working. If you have a dialup, one way to do this would be to
modify your /etc/ppp/ip-up.local file as follows:
cat <<EOF | /usr/local/bin/chronyc
password mysecret
online
EOF
# update all of the dynamic servers and save the result.
# do not wait for response
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
Since this file contains the chronyc password you will want to set the
file permissions so that just everybody will not be able to read
it. But you already did that when you put in the chronyc command. Any
other way to make DNSchronyUPDATE run perodicly when DNS is up will
also work.
To add a server with a varying IP address one could run:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com
or if you want to specify different server parameters you
could say:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com "minpoll 10 maxpoll 20 maxdelay 0.8"
The DNSchronyADD's default for these parameters is:
"minpoll 5 maxpoll 10 maxdelay 0.4" values that are often shown
as examples in the chrony documentation.
If DNS is not running now but you know the IP address, you can say:
/usr/local/bin/DNSchronyADD mysecret tock.greyware.com=208.14.208.44
Of course, the IP address will be checked next time DNSchronyUPDATE
runs.
To delete dynamic DNS a server:
/usr/local/bin/DNSchronyDELETE mysecret tock.greyware.com
To change parameters delete and re-add.
Of course, in all of the above "mysecret" is your chronyc password
which SHOULD NOT BE "mysecret".
----------------------------------------------
DNSchrony.pl is covered by the GPL
# Copyright (C) Paul Elliott 2002
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# SEE COPYING FOR DETAILS

View File

@@ -0,0 +1,22 @@
#example file /etc/ppp/ip-up.local
#originally from SuSE distribution
#modified for chrony
cat <<EOF | /usr/local/bin/chronyc
password mysecret
online
EOF
# update all of the dynamic servers and save the result.
# do not wait for response
nohup /usr/local/bin/DNSchronyUPDATE mysecret >/dev/null 2>&1 &
#other stuff who knows?
# The following lines added for Linux-HA support # Heartbeat
DEVFILE=`echo $DEVICE | sed -e 's!^/dev/!!' -e 's!/!.!g'` # Heartbeat
OUTFILE=/var/run/ppp.d/$DEVFILE # Heartbeat
( # Heartbeat
echo "$IPREMOTE" # Heartbeat
echo "$IFNAME" # Heartbeat
echo "$PPPD_PID" # Heartbeat
echo "$IPLOCAL" # Heartbeat
) > $OUTFILE # Heartbeat

View File

@@ -1,103 +0,0 @@
Notes for installing chrony on MacOS X
Author: Bryan Christianson (bryan@whatroute.net)
------------------------------------------------
These files are for those admins/users who would prefer to install chrony
from the source distribution and are intended as guidelines rather than
being definitive. They can be edited with a plain text editor, such as
vi, emacs or your favourite IDE (xcode)
It is assumed you are comfortable with installing software from the
terminal command line and know how to use sudo to acquire root access.
If you are not familiar with the MacOS X command line then
please consider using ChronyControl from http://whatroute.net/chronycontrol.html
ChronyControl provides a gui wrapper for installing these files and sets the
necessary permissions on each file.
Install the chrony software
---------------------------
You will need xcode and the commandline additions to build and install chrony.
These can be obtained from Apple's website via the App Store.
cd to the chrony directory
./configure
make
sudo make install
chrony is now installed in default locations (/usr/local/sbin/chronyd,
/usr/local/bin/chronyc)
Create a chrony.conf file - see the chrony website for details
The support files here assume the following directives are specified in the
chrony.conf file
keyfile /etc/chrony.d/chrony.keys
driftfile /var/db/chrony/chrony.drift
bindcmdaddress /var/db/chrony/chronyd.sock
logdir /var/log/chrony
dumpdir /var/db/chrony
Install this file as /etc/chrony.d/chrony.conf and create
the directories specified in the above directives if they don't exist.
You will need root permissions to create the directories.
Running chronyd
---------------
At this point chronyd *could* be run as a daemon. Apple discourage running
daemons and their preferred method uses the launchd facility. The
support files here provide a launchd configuration file for chronyd and also
a shell script and launchd configuration file to rotate the chronyd logs on a daily basis.
Support files
-------------
Dates and sizes may differ
-rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt
-rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh
-rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.tuxfamily.chronyc.plist
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.tuxfamily.chronyd.plist
If you have used chrony support directories other than those suggested, you
will need to edit each file and make the appropriate changes.
Installing the support files
----------------------------
1. chronylogrotate.sh
This is a simple shell script that deletes old log files. Unfortunately because
of the need to run chronyc, the standard MacOS X logrotation does not work with
chrony logs.
This script runs on a daily basis under control of launchd and should be
installed in the /usr/local/bin directory
sudo cp chronylogrotate.sh /usr/local/bin
sudo chmod +x /usr/local/bin/chronylogrotate.sh
sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
2. org.tuxfamily.chronyc.plist
This file is the launchd plist that runs logrotation each day. You may
wish to edit this file to change the time of day at which the rotation
will run, currently 04:05 am
sudo cp org.tuxfamily.chronyc.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyc.plist
3. org.tuxfamily.chronyd.plist
This file is the launchd plist that runs chronyd when the Macintosh starts.
sudo cp org.tuxfamily.chronyd.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyd.plist
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyd.plist

View File

@@ -1,45 +0,0 @@
#!/bin/sh
# chronylogrotate.sh
# ChronyControl
#
# Created by Bryan Christianson on 12/07/15.
#
LOGDIR=/var/log/chrony
if [ ! -e "$LOGDIR" ]; then
echo "missing directory: $LOGDIR"
exit 1
fi
cd $LOGDIR
rotate () {
prefix=$1
rm -f $prefix.log.10
for (( count=9; count>= 0; count-- ))
do
next=$(( $count+1 ))
if [ -f $prefix.log.$count ]; then
mv $prefix.log.$count $prefix.log.$next
fi
done
if [ -f $prefix.log ]; then
mv $prefix.log $prefix.log.0
fi
}
rotate measurements
rotate statistics
rotate tracking
#
# signal chronyd via chronyc
/usr/local/bin/chronyc -a -f /etc/chrony.d/chrony.conf cyclelogs > /dev/null
exit $?

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.tuxfamily.logrotate</string>
<key>KeepAlive</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>/usr/local/bin/chronylogrotate.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>5</integer>
<key>Hour</key>
<integer>4</integer>
</dict>
</dict>
</plist>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.tuxfamily.chronyd</string>
<key>Program</key>
<string>/usr/local/sbin/chronyd</string>
<key>ProgramArguments</key>
<array>
<string>chronyd</string>
<string>-n</string>
<string>-f</string>
<string>/private/etc/chrony.d/chrony.conf</string>
</array>
<key>KeepAlive</key>
<true/>
</dict>
</plist>

View File

@@ -1,341 +0,0 @@
:toc:
:numbered:
Frequently Asked Questions
==========================
== +chrony+ compared to other programs
=== How does +chrony+ compare to +ntpd+?
+chronyd+ was designed to work well in a wide range of conditions and it can
usually synchronise the system clock faster and with better time accuracy. It
doesn't implement some of the less useful NTP modes like broadcast client or
multicast server/client.
For a more detailed comparison of features and performance, see the
http://chrony.tuxfamily.org/comparison.html[comparison page] on the +chrony+
website and the
http://chrony.tuxfamily.org/manual.html#Comparison-with-ntpd[Comparison with
ntpd] section in the manual.
If your computer is connected to the internet only for few minutes at a time,
the network connection is often congested, you turn your computer off or
suspend it frequently, the clock is not very stable (e.g. there are rapid
changes in the temperature or it's a virtual machine), or you want to use NTP
on an isolated network with no hardware reference clocks in sight, +chrony+
will probably work much better for you.
The original reason +chrony+ was written was that +ntpd+ (called +xntpd+ at the
time) could not to do anything sensible on a PC which was connected to the 'net
only for about 5 minutes once or twice a day, mainly to upload/download email
and news. The requirements were
* slew the time to correct it when going online and NTP servers
become visible
* determine the rate at which the computer gains or loses time and
use this information to keep it reasonably correct between connects
to the 'net. This has to be done using a method that does not care
about the intermittent availability of the references or the fact
the computer is turned off between groups of measurements.
* maintain the time across reboots, by working out the error and
drift rate of the computer's real-time clock and using this
information to set the system clock correctly at boot up.
Also, when working with isolated networks with no true time references at all
+ntpd+ was found to give no help with managing the local clock's gain/loss rate
on the NTP master node (which was set from watch). Some automated support was
added to +chrony+ to deal with this.
== Configuration issues
=== I have several computers on a LAN. Should be all clients of an external server?
The best configuration is usually to make one computer the master, with
the others as clients of it. Add a +local+ directive to the master's
'chrony.conf' file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN
will maintain a common time with each other.
=== Must I specify servers by IP address if DNS is not available on chronyd start?
No. Starting from version 1.25, +chronyd+ will keep trying to resolve
the hostnames specified in the +server+ and +peer+ directives in
increasing intervals until it succeeds. The +online+ command can be
issued from +chronyc+ to try to resolve them immediately.
=== How can I make +chronyd+ more secure?
If you don't need to serve time to NTP clients or peers, you can add +port 0+
to the 'chrony.conf' file to completely disable the NTP server functionality
and prevent NTP requests from reaching +chronyd+. Starting from version 2.0,
the NTP server port is open only when client access is allowed by the +allow+
directive or command, an NTP peer is configured, or the +broadcast+ directive
is used.
If you don't need to use +chronyc+ remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0.
----
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
----
If you don't need to use +chronyc+ at all or you need to run +chronyc+ only
under the root or chrony user (which can access +chronyd+ through a Unix domain
socket since version 2.2), you can disable the internet command sockets
completely by adding +cmdport 0+ to the configuration file.
On Linux, if +chronyd+ is compiled with support for Linux capabilities
(available in the libcap library), or on NetBSD with the +/dev/clockctl+
device, you can specify an unprivileged user with the +-u+ option or +user+
directive in the 'chrony.conf' file to drop root privileges after start. The
configure option +--with-user+ can be used to drop the privileges by default.
Also, if +chronyd+ is compiled with support for the Linux secure computing
(seccomp) facility, you can enable a system call filter with the +-F+ option.
It will significantly reduce the kernel attack surface and possibly prevent
kernel exploits from the +chronyd+ process if compromised. The filter
shouldn't be enabled without testing that it allows all system calls needed
with the specific configuration and libraries that +chronyd+ is using (e.g.
libc and its NSS configuration). If +chronyd+ is getting killed, some system
call is missing and the filter has to be disabled until it's patched to allow
that call.
=== How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your
network. It's better to use more than one server, three or four is usually
recommended as the minimum, so +chronyd+ can detect falsetickers and combine
measurements from multiple sources.
There are also useful options which can be set in the +server+ directive, they
are +minpoll+, +maxpoll+, +polltarget+, +maxdelay+, +maxdelayratio+ and
+maxdelaydevratio+.
The first three options set the minimum and maximum allowed polling interval,
and how should be the actual interval adjusted in the specified range. Their
default values are 6 (64 seconds) for +minpoll+, 10 (1024 seconds) for
+maxpoll+ and 6 (samples) for +polltarget+. The default values should be used
for general servers on the internet. With your own NTP servers or if have
permission to poll some servers more frequently, setting these options for
shorter polling intervals may significantly improve the accuracy of the system
clock.
The optimal polling interval depends on many factors, including the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature.
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
----
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
----
An example using very short polling intervals for a server located in the same
LAN could be
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30
----
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The +maxdelaydevratio+ option could be added to the example
with local NTP server
----
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
----
=== What happened to the +commandkey+ and +generatecommandkey+ directives?
They were removed in version 2.2. Authentication is no longer supported in the
command protocol. Commands that required authentication are now allowed only
through a Unix domain socket, which is accessible only by the root and chrony
users. If you need to configure +chronyd+ remotely or locally without the root
password, please consider using ssh and/or sudo to run +chronyc+ under the root
or chrony user on the same host as +chronyd+ is running.
== Computer is not synchronising
This is the most common problem. There are a number of reasons, see the
following questions.
=== Behind a firewall?
If there is a firewall between you and the NTP server you're trying to use, the
packets may be blocked. Try using a tool like +wireshark+ or +tcpdump+ to see if
you're getting responses from the server. If you have an external modem, see
if the receive light blinks straight after the transmit light (when the link is
quiet apart from the NTP traffic.) Try adding +log measurements+ to the
'chrony.conf' file and look in the 'measurements.log' file after +chronyd+ has
been running for a short period. See if any measurements appear.
=== Are NTP servers specified with the +offline+ option?
Check that you're using +chronyc+\'s +online+ and +offline+ commands
appropriately. Again, check in 'measurements.log' to see if you're getting any
data back from the server.
=== Is +chronyd+ allowed to step the system clock?
By default, +chronyd+ adjusts the clock gradually by slowing it down or
speeding it up. If the clock is too far from the correct time, it will take
a long time to correct the error. The +System time+ value printed by the
+chronyc+'s +tracking+ command is the remaining correction that needs to be
applied to the system clock.
The +makestep+ directive can be used to allow +chronyd+ to step the clock. For
example, if 'chrony.conf' had
----
makestep 1 3
----
the clock would be stepped in the first three updates if its offset was larger
than one second. Normally, it's recommended to allow the step only in the
first few updates, but in some cases (e.g. a computer without RTC or virtual
machine which can be suspended and resumed with incorrect time) it may be
necessary to allow the step at any clock update. The example above would
change to
----
makestep 1 -1
----
== Issues with +chronyc+
=== I keep getting the error +506 Cannot talk to daemon+
When accessing +chronyd+ remotely, make sure that the 'chrony.conf' file (on
the computer where +chronyd+ is running) has a 'cmdallow' entry for the
computer you are running +chronyc+ on and an appropriate 'bindcmdaddress'
directive. This isn't necessary for localhost.
Perhaps +chronyd+ is not running. Try using the +ps+ command (e.g. on Linux,
+ps -auxw+) to see if it's running. Or try +netstat -a+ and see if the ports
123/udp and 323/udp are listening. If +chronyd+ is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
=== I keep getting the error +501 Not authorised+
Since version 2.2, the +password+ command doesn't do anything and +chronyc+
needs to run under the root or chrony user, which are allowed to access the
Unix domain command socket.
=== Is the +chronyc+ / +chronyd+ protocol documented anywhere?
Only by the source code :-) See 'cmdmon.c' (+chronyd+ side) and 'client.c'
(+chronyc+ side).
== Real-time clock issues
=== What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It is used to initialize the system clock on boot. It normally doesn't drift
more than few seconds per day.
There are two approaches how +chronyd+ can work with it. One is to use the
+rtcsync+ directive, which tells +chronyd+ to enable a kernel mode which sets
the RTC from the system clock every 11 minutes. +chronyd+ itself won't touch
the RTC. If the computer is not turned off for a long time, the RTC should
still be close to the true time when the system clock will be initialized from
it on the next boot.
The other option is to use the +rtcfile+ directive, which will tell +chronyd+
to monitor the rate at which the RTC gains or loses time. When +chronyd+ is
started with the +-s+ option on the next boot, it will set the system time from
the RTC and also compensate for the drift it has measured previously. The
+rtcautotrim+ directive can be used to keep the RTC close to the true time, but
it's not strictly necessary if its only purpose is to set the system clock when
+chronyd+ is started on boot. See the documentation for details.
=== I want to use +chronyd+'s RTC support. Must I disable +hwclock+?
The +hwclock+ program is often set-up by default in the boot and shutdown
scripts with many Linux installations. With the kernel RTC synchronisation
(+rtcsync+ directive), the RTC will be set also every 11 minutes as long as the
system clock is synchronised. If you want to use +chronyd+'s RTC monitoring
(+rtcfile+ directive), it's important to disable +hwclock+ in the shutdown
procedure. If you don't, it will over-write the RTC with a new value, unknown
to +chronyd+. At the next reboot, +chronyd+ started with the +-s+ option will
compensate this (wrong) time with its estimate of how far the RTC has drifted
whilst the power was off, giving a meaningless initial system time.
There is no need to remove +hwclock+ from the boot process, as long as +chronyd+
is started after it has run.
=== I just keep getting the +513 RTC driver not running+ message
For the real time clock support to work, you need the following three
things
* a kernel that is supported (e.g. 2.2 onwards)
* enhanced RTC support compiled into the kernel
* an +rtcfile+ directive in your 'chrony.conf' file
== NTP-specific issues
=== Can +chronyd+ be driven from broadcast NTP servers?
No, the broadcast client mode is not supported and there is currently no plan
to implement it. The broadcast and multicast modes are inherently less
accurate and less secure (even with authentication) than the ordinary
server/client mode and they are not as useful as they used to be. Even with
very modest hardware a single NTP server can serve time to hundreds of
thousands of clients using the ordinary mode.
=== Can +chronyd+ transmit broadcast NTP packets?
Yes, the +broadcast+ directive can be used to enable the broadcast server mode
to serve time to clients in the network which support the broadcast client mode
(it's not supported in +chronyd+, see the previous question).
=== Can +chronyd+ keep the system clock a fixed offset away from real time?
This is not possible as the program currently stands.
=== What happens if the network connection is dropped without using +chronyc+'s +offline+ command first?
+chronyd+ will keep trying to access the server(s) that it thinks are online.
When the network is connected again, it will take some time (on average half of
the current polling interval) before new measurements are made and the clock is
corrected. If the servers were set to offline and the +online+ command was
issued when the network was connected, +chronyd+ would make new measurements
immediately.
The +auto_offline+ option to the +server+ entry in the 'chrony.conf' file may
be useful to switch the servers to the offline state automatically.
== Linux-specific issues
=== I get +Could not open /dev/rtc, Device or resource busy+ in my syslog file
Some other program running on the system may be using the device.
== Microsoft Windows
=== Does +chrony+ support Windows?
No. The +chronyc+ program (the command-line client used for configuring
+chronyd+ while it is running) has been successfully built and run under
Cygwin in the past. +chronyd+ is not portable, because part of it is
very system-dependent. It needs adapting to work with Windows'
equivalent of the adjtimex() call, and it needs to be made to work as a
service.
=== Are there any plans to support Windows?
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.

View File

@@ -9,7 +9,7 @@ Wants=time-sync.target
Type=oneshot
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
# clock correction to be less than 0.1 seconds
ExecStart=/usr/bin/chronyc waitsync 600 0.1 0.0 1
ExecStart=/usr/bin/chronyc waitsync 60 0.1
RemainAfterExit=yes
StandardOutput=null

View File

@@ -43,29 +43,25 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server foo.example.net iburst
! server bar.example.net iburst
! server baz.example.net iburst
! pool pool.ntp.org iburst
! server 0.pool.ntp.org iburst
! server 1.pool.ntp.org iburst
! server 2.pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server foo.example.net offline
! server bar.example.net offline
! server baz.example.net offline
! pool pool.ntp.org offline
! server 0.pool.ntp.org offline
! server 1.pool.ntp.org offline
! server 2.pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
# have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness.
! peer foo.example.net
! peer ntp0.my-company.com
# There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose
@@ -95,10 +91,23 @@
driftfile /var/lib/chrony/drift
# If you want to enable NTP authentication with symmetric keys, you will need
# to uncomment the following line and edit the file to set up the keys.
# If you want to use the program called chronyc to configure aspects of
# chronyd's operation once it is running (e.g. tell it the Internet link
# has gone up or down), you need a password. This is stored in the
# following keys file. (You also need keys to support authenticated NTP
# exchanges between cooperating machines.) Again, this option is
# assumed by default.
! keyfile /etc/chrony.keys
keyfile /etc/chrony.keys
# Tell chronyd which numbered key in the file is used as the password
# for chronyc. (You can pick any integer up to 2**32-1. '1' is just a
# default. Using another value will _NOT_ increase security.)
commandkey 1
# With this directive a random password will be generated automatically.
generatecommandkey
# chronyd can save the measurement history for the servers to files when
# it it exits. This is useful in 2 situations:
@@ -128,15 +137,15 @@ driftfile /var/lib/chrony/drift
#######################################################################
### INITIAL CLOCK CORRECTION
# This option is useful to quickly correct the clock on start if it's
# off by a large amount. The value '1.0' means that if the error is less
# than 1 second, it will be gradually removed by speeding up or slowing
# down your computer's clock until it is correct. If the error is above
# 1 second, an immediate time jump will be applied to correct it. The
# value '3' means the step is allowed only in the first three updates of
# the clock. Some software can get upset if the system clock jumps
# off by a large amount. The value '10' means that if the error is less
# than 10 seconds, it will be gradually removed by speeding up or
# slowing down your computer's clock until it is correct. If the error
# is above 10 seconds, an immediate time jump will be applied to correct
# it. The value '1' means the step is allowed only on the first update
# of the clock. Some software can get upset if the system clock jumps
# (especially backwards), so be careful!
! makestep 1.0 3
! makestep 10 1
#######################################################################
### LOGGING
@@ -224,18 +233,13 @@ driftfile /var/lib/chrony/drift
# several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.)
! mailonchange wibble@foo.example.net 0.5
! mailonchange wibble@foobar.org 0.5
#######################################################################
### COMMAND ACCESS
# The program chronyc is used to show the current operation of chronyd
# and to change parts of its configuration whilst it is running.
# By default chronyd binds to the loopback interface. Uncomment the
# following lines to allow receiving command packets from remote hosts.
! bindcmdaddress 0.0.0.0
! bindcmdaddress ::
# Normally, chronyd will only allow connections from chronyc on the same
# machine as itself. This is for security. If you have a subnet
# 192.168.*.* and you want to be able to use chronyc from any machine on
@@ -248,6 +252,11 @@ driftfile /var/lib/chrony/drift
# syntax and meaning is the same as for 'allow' and 'deny', except that
# 'cmdallow' and 'cmddeny' control access to the chronyd's command port.
# NOTE, even if the host where you run chronyc is granted access, you
# still need a command key set up and you have to know the password to
# put into chronyc to allow you to modify chronyd's parameters. By
# default all you can do is view information about chronyd's operation.
#######################################################################
### REAL TIME CLOCK
# chronyd can characterise the system's real-time clock. This is the

View File

@@ -1,12 +0,0 @@
# Use public NTP servers from the pool.ntp.org project.
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

View File

@@ -1,34 +1,46 @@
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
pool pool.ntp.org iburst
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
# Ignore stratum in source selection.
stratumweight 0
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
# Enable kernel RTC synchronization.
rtcsync
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds.
makestep 10 3
# Allow NTP client access from local network.
#allow 192.168/16
# Listen for commands only on localhost.
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
# Serve time even if not synchronized to any NTP server.
#local stratum 10
# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys
keyfile /etc/chrony.keys
# Specify the key used as password for chronyc.
commandkey 1
# Generate command key if missing.
generatecommandkey
# Disable logging of client accesses.
noclientlog
# Send message to syslog when clock adjustment is larger than 0.5 seconds.
# Send a message to syslog if a clock adjustment is larger than 0.5 seconds.
logchange 0.5
# Specify directory for log files.
logdir /var/log/chrony
# Select which information is logged.
#log measurements statistics tracking

View File

@@ -1,15 +1,29 @@
# This is an example chrony keys file. It is used for NTP authentication with
# symmetric keys. It should be readable only by root or the user to which
# chronyd is configured to switch to.
#######################################################################
#
# Don't use the example keys! The keys need to be random for maximum security.
# These shell commands can be used to generate random MD5 and SHA1 keys on
# systems which have the /dev/urandom device:
# echo "1 MD5 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 32)"
# echo "1 SHA1 HEX:$(tr -d -c '[:xdigit:]' < /dev/urandom | head -c 40)"
# This is an example chrony keys file. You should copy it to /etc/chrony.keys
# after editing it to set up the key(s) you want to use. It should be readable
# only by root or the user chronyd drops the root privileges to. In most
# situations, you will require a single key (the 'commandkey') so that you can
# supply a password to chronyc to enable you to modify chronyd's operation
# whilst it is running.
#
# Copyright 2002 Richard P. Curnow
#
######################################################################
# Examples of valid keys:
#1 ALongAndRandomPassword
#2 MD5 HEX:B028F91EA5C38D06C2E140B26C7F41EC
#3 SHA1 HEX:1DC764E0791B11FA67EFC7ECBC4B0D73F68A070C
# The keys should be random for maximum security. If you wanted to use a key
# with ID 1 as your commandkey (i.e. chronyc password) you would put
# "commandkey 1" into chrony.conf. If no commandkey is present in the keys
# file and the generatecommandkey directive is specified in chrony.conf,
# a random commandkey will be generated and added to the keys file
# automatically on chronyd start.
# You might want to define more keys if you use the authentication facility
# in the network time protocol to authenticate request/response packets between
# trusted clients and servers.

View File

@@ -3,6 +3,6 @@
nocreate
sharedscripts
postrotate
/usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
/usr/bin/chronyc -a cyclelogs > /dev/null 2>&1 || true
endscript
}

View File

@@ -6,12 +6,12 @@ export LC_ALL=C
if [ "$2" = "up" ]; then
/sbin/ip route list dev "$1" | grep -q '^default' &&
/usr/bin/chronyc online > /dev/null 2>&1
/usr/bin/chronyc -a online > /dev/null 2>&1
fi
if [ "$2" = "down" ]; then
/sbin/ip route list | grep -q '^default' ||
/usr/bin/chronyc offline > /dev/null 2>&1
/usr/bin/chronyc -a offline > /dev/null 2>&1
fi
exit 0

View File

@@ -45,6 +45,7 @@ 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

2870
getdate.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,12 @@
** This code is in the public domain and has no copyright.
*/
#include "config.h"
#ifdef HAVE_CONFIG_H
# include <config.h>
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
/* Since the code of getdate.y is not included in the Emacs executable
itself, there is no need to #define static in this file. Even if

2
hash.h
View File

@@ -38,6 +38,4 @@ extern unsigned int HSH_Hash(int id,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
extern void HSH_Finalise(void);
#endif

View File

@@ -62,8 +62,3 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return 16;
}
void
HSH_Finalise(void)
{
}

View File

@@ -25,12 +25,11 @@
*/
#include "config.h"
#include <nss.h>
#include <hasht.h>
#include <nsslowhash.h>
/* #include "config.h" */
#include "hash.h"
static NSSLOWInitContext *ictx;
@@ -88,17 +87,3 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return ret;
}
void
HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (hashes[i].context)
NSSLOWHASH_Destroy(hashes[i].context);
}
if (ictx)
NSSLOW_Shutdown(ictx);
}

View File

@@ -114,8 +114,3 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return len;
}
void
HSH_Finalise(void)
{
}

215
keys.c
View File

@@ -30,7 +30,6 @@
#include "sysincl.h"
#include "array.h"
#include "keys.h"
#include "cmdparse.h"
#include "conf.h"
@@ -41,31 +40,80 @@
typedef struct {
uint32_t id;
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
static ARR_Instance keys;
#define MAX_KEYS 256
static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_id;
static int cache_valid;
static uint32_t cache_key_id;
static unsigned long cache_key_id;
static int cache_key_pos;
/* ================================================== */
static void
free_keys(void)
static int
generate_key(unsigned long key_id)
{
unsigned int i;
#ifdef GENERATE_SHA1_KEY
unsigned char key[20];
const char *hashname = "SHA1";
#else
unsigned char key[16];
const char *hashname = "MD5";
#endif
const char *key_file, *rand_dev = "/dev/urandom";
FILE *f;
struct stat st;
int i;
for (i = 0; i < ARR_GetSize(keys); i++)
Free(((Key *)ARR_GetElement(keys, i))->val);
key_file = CNF_GetKeysFile();
ARR_SetSize(keys, 0);
cache_valid = 0;
if (!key_file)
return 0;
f = fopen(rand_dev, "r");
if (!f || fread(key, sizeof (key), 1, f) != 1) {
if (f)
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not read %s", rand_dev);
return 0;
}
fclose(f);
f = fopen(key_file, "a");
if (!f) {
LOG_FATAL(LOGF_Keys, "Could not open keyfile %s for writing", key_file);
return 0;
}
/* Make sure the keyfile is not world-readable */
if (stat(key_file, &st) || chmod(key_file, st.st_mode & 0770)) {
fclose(f);
LOG_FATAL(LOGF_Keys, "Could not change permissions of keyfile %s", key_file);
return 0;
}
fprintf(f, "\n%lu %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n");
fclose(f);
/* Erase the key from stack */
memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
return 1;
}
/* ================================================== */
@@ -73,9 +121,15 @@ free_keys(void)
void
KEY_Initialise(void)
{
keys = ARR_CreateInstance(sizeof (Key));
n_keys = 0;
command_key_valid = 0;
cache_valid = 0;
KEY_Reload();
if (CNF_GetGenerateCommandKey() && !KEY_KeyKnown(KEY_GetCommandKey())) {
if (generate_key(KEY_GetCommandKey()))
KEY_Reload();
}
}
/* ================================================== */
@@ -83,22 +137,12 @@ KEY_Initialise(void)
void
KEY_Finalise(void)
{
free_keys();
ARR_DestroyInstance(keys);
}
/* ================================================== */
static Key *
get_key(unsigned int index)
{
return ((Key *)ARR_GetElements(keys)) + index;
}
/* ================================================== */
static int
determine_hash_delay(uint32_t key_id)
determine_hash_delay(unsigned long key_id)
{
NTP_Packet pkt;
struct timeval before, after;
@@ -107,7 +151,7 @@ determine_hash_delay(uint32_t key_id)
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
@@ -121,7 +165,7 @@ determine_hash_delay(uint32_t key_id)
/* Add on a bit extra to allow for copying, conversions etc */
min_usecs += min_usecs >> 4;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %"PRIu32": %ld useconds", key_id, min_usecs);
DEBUG_LOG(LOGF_Keys, "authentication delay for key %lu: %ld useconds", key_id, min_usecs);
return min_usecs;
}
@@ -151,14 +195,18 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
unsigned int i, line_number;
int i, line_number;
FILE *in;
uint32_t key_id;
unsigned long key_id;
char line[2048], *keyval, *key_file;
const char *hashname;
Key key;
free_keys();
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
command_key_valid = 0;
cache_valid = 0;
key_file = CNF_GetKeysFile();
line_number = 0;
@@ -184,22 +232,22 @@ KEY_Reload(void)
continue;
}
key.hash_id = HSH_GetHashId(hashname);
if (key.hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, key_id);
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %lu", key_id);
continue;
}
key.len = UTI_DecodePasswordFromText(keyval);
if (!key.len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, key_id);
keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %lu", key_id);
continue;
}
key.id = key_id;
key.val = MallocArray(char, key.len);
memcpy(key.val, keyval, key.len);
ARR_AppendElement(keys, &key);
keys[n_keys].id = key_id;
keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
n_keys++;
}
fclose(in);
@@ -207,50 +255,50 @@ KEY_Reload(void)
/* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been
more careful! */
qsort(ARR_GetElements(keys), ARR_GetSize(keys), sizeof (Key), compare_keys_by_id);
qsort((void *) keys, n_keys, sizeof(Key), compare_keys_by_id);
/* Check for duplicates */
for (i = 1; i < ARR_GetSize(keys); i++) {
if (get_key(i - 1)->id == get_key(i)->id)
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
for (i = 1; i < n_keys; i++) {
if (keys[i - 1].id == keys[i].id) {
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %lu", keys[i].id);
}
}
/* Erase any passwords from stack */
memset(line, 0, sizeof (line));
for (i = 0; i < ARR_GetSize(keys); i++)
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
}
/* ================================================== */
static int
lookup_key(uint32_t id)
lookup_key(unsigned long id)
{
Key specimen, *where, *keys_ptr;
Key specimen, *where;
int pos;
keys_ptr = ARR_GetElements(keys);
specimen.id = id;
where = (Key *)bsearch((void *)&specimen, keys_ptr, ARR_GetSize(keys),
sizeof (Key), compare_keys_by_id);
where = (Key *) bsearch((void *)&specimen, (void *)keys, n_keys, sizeof(Key), compare_keys_by_id);
if (!where) {
return -1;
} else {
pos = where - keys_ptr;
pos = where - keys;
return pos;
}
}
/* ================================================== */
static Key *
get_key_by_id(uint32_t key_id)
static int
get_key_pos(unsigned long key_id)
{
int position;
if (cache_valid && key_id == cache_key_id)
return get_key(cache_key_pos);
return cache_key_pos;
position = lookup_key(key_id);
@@ -258,66 +306,81 @@ get_key_by_id(uint32_t key_id)
cache_valid = 1;
cache_key_pos = position;
cache_key_id = key_id;
return get_key(position);
}
return NULL;
return position;
}
/* ================================================== */
unsigned long
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
}
/* ================================================== */
int
KEY_KeyKnown(uint32_t key_id)
KEY_KeyKnown(unsigned long key_id)
{
return get_key_by_id(key_id) != NULL;
return get_key_pos(key_id) >= 0;
}
/* ================================================== */
int
KEY_GetAuthDelay(uint32_t key_id)
KEY_GetAuthDelay(unsigned long key_id)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
}
return key->auth_delay;
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(key->hash_id, (unsigned char *)key->val,
key->len, data, data_len, auth, auth_len);
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
Key *key;
int key_pos;
key = get_key_by_id(key_id);
key_pos = get_key_pos(key_id);
if (!key)
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(key->hash_id, (unsigned char *)key->val,
key->len, data, data_len, auth, auth_len);
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

14
keys.h
View File

@@ -27,20 +27,20 @@
#ifndef GOT_KEYS_H
#define GOT_KEYS_H
#include "sysincl.h"
extern void KEY_Initialise(void);
extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
extern int KEY_KeyKnown(uint32_t key_id);
extern int KEY_GetAuthDelay(uint32_t key_id);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data,
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

120
local.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011, 2014-2015
* Copyright (C) Miroslav Lichvar 2011, 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
@@ -36,16 +36,11 @@
#include "local.h"
#include "localp.h"
#include "memory.h"
#include "smooth.h"
#include "util.h"
#include "logging.h"
/* ================================================== */
/* Maximum allowed frequency offset in ppm, the time must not stop
or run backwards */
#define MAX_FREQ 500000.0
/* Variable to store the current frequency, in ppm */
static double current_freq_ppm;
@@ -61,7 +56,6 @@ static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
static lcl_OffsetCorrectionDriver drv_offset_convert;
static lcl_SetLeapDriver drv_set_leap;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* ================================================== */
@@ -174,13 +168,6 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
while (change_list.next != &change_list)
LCL_RemoveParameterChangeHandler(change_list.next->handler,
change_list.next->anything);
while (dispersion_notify_list.next != &dispersion_notify_list)
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
dispersion_notify_list.next->anything);
}
/* ================================================== */
@@ -260,7 +247,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
Free(ptr);
free(ptr);
}
/* ================================================== */
@@ -337,7 +324,7 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
Free(ptr);
free(ptr);
}
/* ================================================== */
@@ -402,33 +389,6 @@ LCL_ReadAbsoluteFrequency(void)
}
/* ================================================== */
static double
clamp_freq(double freq)
{
if (freq <= MAX_FREQ && freq >= -MAX_FREQ)
return freq;
LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
return freq >= MAX_FREQ ? MAX_FREQ : -MAX_FREQ;
}
/* ================================================== */
static int
check_offset(struct timeval *now, double offset)
{
/* Check if the time will be still sane with accumulated offset */
if (UTI_IsTimeOffsetSane(now, -offset))
return 1;
LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
return 0;
}
/* ================================================== */
/* This involves both setting the absolute frequency with the
system-specific driver, as well as calling all notify handlers */
@@ -438,8 +398,6 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
struct timeval raw, cooked;
double dfreq;
afreq_ppm = clamp_freq(afreq_ppm);
/* Apply temperature compensation */
if (temp_comp_ppm != 0.0) {
afreq_ppm = afreq_ppm * (1.0 - 1.0e-6 * temp_comp_ppm) - temp_comp_ppm;
@@ -477,8 +435,6 @@ LCL_AccumulateDeltaFrequency(double dfreq)
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
/* Call the system-specific driver for setting the frequency */
current_freq_ppm = (*drv_set_freq)(current_freq_ppm);
dfreq = (current_freq_ppm - old_freq_ppm) / (1.0e6 - old_freq_ppm);
@@ -503,9 +459,6 @@ LCL_AccumulateOffset(double offset, double corr_rate)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, offset))
return;
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
@@ -514,7 +467,7 @@ LCL_AccumulateOffset(double offset, double corr_rate)
/* ================================================== */
int
void
LCL_ApplyStepOffset(double offset)
{
struct timeval raw, cooked;
@@ -525,21 +478,10 @@ LCL_ApplyStepOffset(double offset)
LCL_ReadRawTime(&raw);
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&raw, offset))
return 0;
if (!(*drv_apply_step_offset)(offset)) {
LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
return 0;
}
/* Reset smoothing on all clock steps */
SMT_Reset(&cooked);
(*drv_apply_step_offset)(offset);
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeStep);
return 1;
}
/* ================================================== */
@@ -556,23 +498,6 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
/* ================================================== */
void
LCL_NotifyLeap(int leap)
{
struct timeval raw, cooked;
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);
}
/* ================================================== */
void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
@@ -584,9 +509,6 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
to the change we are about to make */
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, doffset))
return;
old_freq_ppm = current_freq_ppm;
/* Work out new absolute frequency. Note that absolute frequencies
@@ -594,8 +516,6 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
terms of the gradient of the (offset) v (local time) function. */
current_freq_ppm += dfreq * (1.0e6 - current_freq_ppm);
current_freq_ppm = clamp_freq(current_freq_ppm);
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
@@ -630,8 +550,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status)
lcl_SetLeapDriver set_leap)
{
drv_read_freq = read_freq;
drv_set_freq = set_freq;
@@ -639,7 +558,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert;
drv_set_leap = set_leap;
drv_set_sync_status = set_sync_status;
current_freq_ppm = (*drv_read_freq)();
@@ -659,13 +577,9 @@ LCL_MakeStep(void)
LCL_ReadRawTime(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL);
if (!check_offset(&raw, -correction))
return 0;
/* Cancel remaining slew and make the step */
LCL_AccumulateOffset(correction, 0.0);
if (!LCL_ApplyStepOffset(-correction))
return 0;
LCL_ApplyStepOffset(-correction);
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
@@ -674,16 +588,8 @@ LCL_MakeStep(void)
/* ================================================== */
int
LCL_CanSystemLeap(void)
{
return drv_set_leap ? 1 : 0;
}
/* ================================================== */
void
LCL_SetSystemLeap(int leap)
LCL_SetLeap(int leap)
{
if (drv_set_leap) {
(drv_set_leap)(leap);
@@ -719,13 +625,3 @@ LCL_SetTempComp(double comp)
}
/* ================================================== */
void
LCL_SetSyncStatus(int synchronised, double est_error, double max_error)
{
if (drv_set_sync_status) {
(drv_set_sync_status)(synchronised, est_error, max_error);
}
}
/* ================================================== */

22
local.h
View File

@@ -159,17 +159,13 @@ extern void LCL_AccumulateOffset(double offset, double corr_rate);
the system clock is fast on true time, i.e. it needs to be stepped
backwards. (Same convention as for AccumulateOffset routine). */
extern int LCL_ApplyStepOffset(double offset);
extern void LCL_ApplyStepOffset(double offset);
/* Routine to invoke notify handlers on an unexpected time jump
in system clock */
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
double offset, double dispersion);
/* Routine to invoke notify handlers on leap second when the system clock
doesn't correct itself */
extern void LCL_NotifyLeap(int leap);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
@@ -198,14 +194,10 @@ extern void LCL_Finalise(void);
to a timezone problem. */
extern int LCL_MakeStep(void);
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
does something */
extern int LCL_CanSystemLeap(void);
/* Routine to set the system clock to correct itself for a leap second if
supported. Leap second will be inserted at the end of the day if the
argument is positive, deleted if negative, and zero resets the setting. */
extern void LCL_SetSystemLeap(int leap);
/* Routine to schedule a leap second. Leap second will be inserted
at the end of the day if argument is positive, deleted if negative,
and zero cancels scheduled leap second. */
extern void LCL_SetLeap(int leap);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive
@@ -214,8 +206,4 @@ extern void LCL_SetSystemLeap(int leap);
due to clamping or rounding). */
extern double LCL_SetTempComp(double comp);
/* Routine to update the synchronisation status in the kernel to allow other
applications to know if the system clock is synchronised and error bounds */
extern void LCL_SetSyncStatus(int synchronised, double est_error, double max_error);
#endif /* GOT_LOCAL_H */

View File

@@ -47,7 +47,7 @@ typedef void (*lcl_AccrueOffsetDriver)(double offset, double corr_rate);
/* System driver to apply a step offset. A positive argument means step
the clock forwards. */
typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
typedef void (*lcl_ApplyStepOffsetDriver)(double offset);
/* System driver to convert a raw time to an adjusted (cooked) time.
The number of seconds returned in 'corr' have to be added to the
@@ -57,9 +57,6 @@ typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, do
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);
/* System driver to set the synchronisation status */
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
extern void
@@ -68,7 +65,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status);
lcl_SetLeapDriver set_leap);
#endif /* GOT_LOCALP_H */

View File

@@ -31,6 +31,7 @@
#include "conf.h"
#include "logging.h"
#include "mkdirpp.h"
#include "util.h"
/* This is used by DEBUG_LOG macro */
@@ -48,6 +49,10 @@ static int parent_fd = 0;
#define DEBUG_LEVEL_PRINT_DEBUG 2
static int debug_level = 0;
#ifdef WINNT
static FILE *logfile;
#endif
struct LogFile {
const char *name;
const char *banner;
@@ -69,6 +74,10 @@ void
LOG_Initialise(void)
{
initialised = 1;
#ifdef WINNT
logfile = fopen("./chronyd.err", "a");
#endif
}
/* ================================================== */
@@ -77,9 +86,15 @@ LOG_Initialise(void)
void
LOG_Finalise(void)
{
#ifdef WINNT
if (logfile) {
fclose(logfile);
}
#else
if (system_log) {
closelog();
}
#endif
LOG_CycleLogFiles();
@@ -90,6 +105,11 @@ LOG_Finalise(void)
static void log_message(int fatal, LOG_Severity severity, const char *message)
{
#ifdef WINNT
if (logfile) {
fprintf(logfile, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#else
if (system_log) {
int priority;
switch (severity) {
@@ -115,33 +135,32 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
} else {
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
#endif
}
/* ================================================== */
void LOG_Message(LOG_Severity severity,
#if DEBUG > 0
LOG_Facility facility, int line_number,
const char *filename, const char *function_name,
#endif
const char *format, ...)
void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
const char *function_name, const char *format, ...)
{
char buf[2048];
va_list other_args;
time_t t;
struct tm stm;
#ifdef WINNT
#else
if (!system_log) {
/* Don't clutter up syslog with timestamps and internal debugging info */
time(&t);
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
fprintf(stderr, "%s ", buf);
#if DEBUG > 0
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
#endif
}
#endif
va_start(other_args, format);
vsnprintf(buf, sizeof(buf), format, other_args);
@@ -179,8 +198,11 @@ void LOG_Message(LOG_Severity severity,
void
LOG_OpenSystemLog(void)
{
#ifdef WINNT
#else
system_log = 1;
openlog("chronyd", LOG_PID, LOG_DAEMON);
#endif
}
/* ================================================== */
@@ -189,6 +211,8 @@ void LOG_SetDebugLevel(int level)
{
debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
if (!DEBUG)
LOG(LOGS_WARN, LOGF_Logging, "Not compiled with full debugging support");
log_debug_enabled = 1;
}
}
@@ -278,6 +302,20 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
/* ================================================== */
void
LOG_CreateLogFileDir(void)
{
const char *logdir;
logdir = CNF_GetLogDir();
if (!mkdir_and_parents(logdir)) {
LOG(LOGS_ERR, LOGF_Logging, "Could not create directory %s", logdir);
}
}
/* ================================================== */
void
LOG_CycleLogFiles(void)
{

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* Copyright (C) Miroslav Lichvar 2013-2015
* 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
@@ -45,28 +45,18 @@ extern int log_debug_enabled;
#define FORMAT_ATTRIBUTE_PRINTF(str, first)
#endif
#if DEBUG > 0
#define LOG_MESSAGE(severity, facility, ...) \
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__);
#else
#define LOG_MESSAGE(severity, facility, ...) \
LOG_Message(severity, __VA_ARGS__);
#endif
#define DEBUG_LOG(facility, ...) \
do { \
if (DEBUG && log_debug_enabled) \
LOG_MESSAGE(LOGS_DEBUG, facility, __VA_ARGS__); \
LOG_Message(LOGS_DEBUG, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
} while (0)
#define LOG(severity, facility, ...) LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_FATAL(facility, ...) \
do { \
LOG_MESSAGE(LOGS_FATAL, facility, __VA_ARGS__); \
LOG_Message(LOGS_FATAL, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__); \
exit(1); \
} while (0)
#define LOG(severity, facility, ...) LOG_MESSAGE(severity, facility, __VA_ARGS__)
/* Definition of severity */
typedef enum {
LOGS_INFO,
@@ -90,8 +80,6 @@ typedef enum {
LOGF_Local,
LOGF_Util,
LOGF_Main,
LOGF_Memory,
LOGF_Client,
LOGF_ClientLog,
LOGF_Configure,
LOGF_CmdMon,
@@ -105,16 +93,13 @@ typedef enum {
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysMacOSX,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysSunOS,
LOGF_SysTimex,
LOGF_SysWinnt,
LOGF_TempComp,
LOGF_RtcLinux,
LOGF_Refclock,
LOGF_Smooth,
LOGF_Refclock
} LOG_Facility;
/* Init function */
@@ -124,15 +109,10 @@ extern void LOG_Initialise(void);
extern void LOG_Finalise(void);
/* Line logging function */
#if DEBUG > 0
FORMAT_ATTRIBUTE_PRINTF(6, 7)
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
const char *function_name, const char *format, ...);
#else
FORMAT_ATTRIBUTE_PRINTF(2, 3)
extern void LOG_Message(LOG_Severity severity, const char *format, ...);
#endif
/* Set debug level:
0, 1 - only non-debug messages are logged
@@ -159,6 +139,7 @@ extern LOG_FileID LOG_FileOpen(const char *name, const char *banner);
FORMAT_ATTRIBUTE_PRINTF(2, 3)
extern void LOG_FileWrite(LOG_FileID id, const char *format, ...);
extern void LOG_CreateLogFileDir(void);
extern void LOG_CycleLogFiles(void);
#endif /* GOT_LOGGING_H */

91
main.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2015
* Copyright (C) Miroslav Lichvar 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
@@ -48,10 +48,9 @@
#include "rtc.h"
#include "refclock.h"
#include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h"
#include "smooth.h"
#include "tempcomp.h"
#include "util.h"
/* ================================================== */
@@ -87,34 +86,28 @@ MAI_CleanupAndExit(void)
SRC_DumpSources();
}
/* Don't update clock when removing sources */
REF_SetMode(REF_ModeIgnore);
SMT_Finalise();
TMC_Finalise();
MNL_Finalise();
CLG_Finalise();
NSR_Finalise();
SST_Finalise();
NCR_Finalise();
NIO_Finalise();
CAM_Finalise();
BRD_Finalise();
SST_Finalise();
REF_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
REF_Finalise();
RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
SYS_Finalise();
SCH_Finalise();
LCL_Finalise();
delete_pidfile();
CNF_Finalise();
LOG_Finalise();
HSH_Finalise();
exit(exit_status);
}
@@ -265,7 +258,7 @@ write_lockfile(void)
if (!out) {
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
} else {
fprintf(out, "%d\n", (int)getpid());
fprintf(out, "%d\n", getpid());
fclose(out);
}
}
@@ -275,6 +268,11 @@ write_lockfile(void)
static void
go_daemon(void)
{
#ifdef WINNT
#else
int pid, fd, pipefd[2];
/* Create pipe which will the daemon use to notify the grandparent
@@ -333,6 +331,8 @@ go_daemon(void)
LOG_SetParentFd(pipefd[1]);
}
}
#endif
}
/* ================================================== */
@@ -341,13 +341,11 @@ int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
char *user = NULL;
struct passwd *pw;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0;
int other_pid;
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
int lock_memory = 0, sched_priority = 0;
int system_log = 1;
int config_args = 0;
@@ -377,16 +375,12 @@ int main
} else {
user = *argv;
}
} else if (!strcmp("-F", *argv)) {
++argv, --argc;
if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
LOG_FATAL(LOGF_Main, "Bad syscall filter level");
} else if (!strcmp("-s", *argv)) {
do_init_rtc = 1;
} 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);
return 0;
printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0);
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
@@ -405,10 +399,6 @@ 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 {
@@ -421,7 +411,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");
return 1;
exit(1);
}
/* Turn into a daemon */
@@ -435,12 +425,11 @@ int main
LOG_SetDebugLevel(debug);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
CHRONY_VERSION, CHRONYD_FEATURES);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
DNS_SetAddressFamily(address_family);
CNF_Initialise(restarted);
CNF_SetRestarted(restarted);
/* Parse the config file or the remaining command line arguments */
if (!config_args) {
@@ -466,17 +455,13 @@ int main
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();
/* Open privileged ports before dropping root */
CAM_Initialise(address_family);
NIO_Initialise(address_family);
NCR_Initialise();
CNF_SetupAccessRestrictions();
/* Command-line switch must have priority */
if (!sched_priority) {
sched_priority = CNF_GetSchedPriority();
@@ -492,34 +477,25 @@ int main
if (!user) {
user = CNF_GetUser();
}
if (user && strcmp(user, "root")) {
SYS_DropRoot(user);
}
if ((pw = getpwnam(user)) == NULL)
LOG_FATAL(LOGF_Main, "Could not get %s uid/gid", user);
/* Create all directories before dropping root */
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
/* Drop root privileges if the user has non-zero uid or gid */
if (pw->pw_uid || pw->pw_gid)
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
LOG_CreateLogFileDir();
REF_Initialise();
SST_Initialise();
BRD_Initialise();
NCR_Initialise();
NSR_Initialise();
CLG_Initialise();
MNL_Initialise();
TMC_Initialise();
SMT_Initialise();
/* From now on, it is safe to do finalisation on exit */
initialised = 1;
UTI_SetQuitSignalsHandler(signal_cleanup);
CAM_OpenUnixSocket();
if (scfilter_level)
SYS_EnableSystemCallFilter(scfilter_level);
CNF_SetupAccessRestrictions();
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
ref_mode = REF_ModeInitStepSlew;
@@ -534,6 +510,13 @@ int main
post_init_rtc_hook(NULL);
}
signal(SIGINT, signal_cleanup);
signal(SIGTERM, signal_cleanup);
#if !defined(WINNT)
signal(SIGQUIT, signal_cleanup);
signal(SIGHUP, signal_cleanup);
#endif /* WINNT */
/* The program normally runs under control of the main loop in
the scheduler. */
SCH_MainLoop();

View File

@@ -39,13 +39,16 @@ echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
for m in chronyc.1.in chrony.conf.5.in chronyd.8.in; do
for m in chrony.1 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
done
./configure && make chrony.txt getdate.c || exit 1
./configure && make chrony.txt || exit 1
mv chrony.txt chrony.txt_
make distclean
mv chrony.txt_ chrony.txt
awk '/^[1-9] Installation$/{p=1}
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
@@ -56,11 +59,16 @@ if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
exit 3
fi
a2x --lynx -f text doc/faq.adoc || exit 1
mv doc/faq.text FAQ
rm -rf doc
awk '/^[1-9] Frequently asked questions$/{p=1}
/^Appendix A GNU General Public License$/{exit}; p' chrony.txt | \
tail -n +4 | sed 's/^[1-9]\.\([1-9]\)/\1/' | sed 's/^----/--/' | \
sed 's/^====/==/' > FAQ
if [ $(wc -l < FAQ) -gt 400 -o $(wc -l < FAQ) -lt 200 ]; then
echo "FAQ generated incorrectly?"
exit 3
fi
make distclean
rm -f config.h config.log make_release .gitignore
cd ..

View File

@@ -54,8 +54,6 @@ typedef struct {
(measured-predicted)) */
} Sample;
#define MIN_SAMPLE_SEPARATION 1.0
#define MAX_SAMPLES 16
static Sample samples[16];
@@ -176,24 +174,14 @@ int
MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timeval now;
double offset, diff;
double offset;
int i;
if (enabled) {
/* Check whether timestamp is within margin of old one */
LCL_ReadCookedTime(&now, NULL);
/* Make sure the provided timestamp is sane and the sample
is not too close to the last one */
if (!UTI_IsTimeOffsetSane(ts, 0.0))
return 0;
if (n_samples) {
UTI_DiffTimevalsToDouble(&diff, &now, &samples[n_samples - 1].when);
if (diff < MIN_SAMPLE_SEPARATION)
return 0;
}
UTI_DiffTimevalsToDouble(&offset, &now, ts);
/* Check if buffer full up */
@@ -270,14 +258,6 @@ MNL_Reset(void)
n_samples = 0;
}
/* ================================================== */
int
MNL_IsEnabled(void)
{
return enabled;
}
/* ================================================== */
/* Generate report data for the REQ_MANUAL_LIST command/monitoring
protocol */

View File

@@ -38,7 +38,6 @@ extern int MNL_AcceptTimestamp(struct timeval *ts, long *offset_cs, double *dfre
extern void MNL_Enable(void);
extern void MNL_Disable(void);
extern void MNL_Reset(void);
extern int MNL_IsEnabled(void);
extern void MNL_ReportSamples(RPT_ManualSamplesReport *report, int max, int *n);
extern int MNL_DeleteSample(int index);

View File

@@ -27,15 +27,11 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
/* Wrappers checking for errors */
extern void *Malloc(size_t size);
extern void *Realloc(void *ptr, size_t size);
extern char *Strdup(const char *s);
/* Convenient macros */
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
#define Malloc(x) malloc(x)
#define MallocNew(T) ((T *) malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) malloc((n) * sizeof(T)))
#define Realloc(x,y) realloc(x,y)
#define ReallocArray(T,n,x) ((T *) realloc((void *)(x), (n)*sizeof(T)))
#define Free(x) free(x)
#endif /* GOT_MEMORY_H */

134
mkdirpp.c Normal file
View File

@@ -0,0 +1,134 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
A function for creating a directory and any parent directories that
don't exist.
*/
#include "config.h"
#include "sysincl.h"
#include "mkdirpp.h"
static int
do_dir(char *p)
{
int status;
struct stat buf;
#if defined(TEST)
fprintf(stderr, "do_dir(%s)\n", p);
#endif
/* See if directory exists */
status = stat(p, &buf);
if (status < 0) {
if (errno == ENOENT) {
/* Try to create directory */
status = mkdir(p, 0755);
return status;
} else {
return status;
}
}
if (!S_ISDIR(buf.st_mode)) {
return -1;
}
return 0;
}
/* ================================================== */
/* Return 0 if the directory couldn't be created, 1 if it could (or
already existed) */
int
mkdir_and_parents(const char *path)
{
char *p;
int len;
int i, j, k, last;
len = strlen(path);
p = (char *) malloc(1 + len);
i = k = 0;
while (1) {
p[i++] = path[k++];
if (path[k] == '/' || !path[k]) {
p[i] = 0;
if (do_dir(p) < 0) {
free(p);
return 0;
}
if (!path[k]) {
/* End of the string */
break;
}
/* check whether its a trailing / or group of / */
last = 1;
j = k+1;
while (path[j]) {
if (path[j] != '/') {
k = j - 1; /* Pick up a / into p[] thru the assignment at the top of the loop */
last = 0;
break;
}
j++;
}
if (last) {
break;
}
}
if (!path[k]) break;
}
free(p);
return 1;
}
/* ================================================== */
#if defined(TEST)
int main(int argc, char **argv) {
if (argc > 1) {
/* Invert sense of result */
return mkdir_and_parents(argv[1]) ? 0 : 1;
} else {
return 1;
}
}
#endif

31
mkdirpp.h Normal file
View File

@@ -0,0 +1,31 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
*/
#ifndef GOT_MKDIRPP_H
#define GOT_MKDIRPP_H
extern int mkdir_and_parents(const char *path);
#endif

View File

@@ -44,11 +44,11 @@ DNS_SetAddressFamily(int family)
}
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
DNS_Name2IPAddress(const char *name, IPAddr *addr)
{
#ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai;
int i, result;
int result;
memset(&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC;
@@ -64,40 +64,29 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
#endif
}
for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) {
for (ai = res; !result && ai != NULL; ai = ai->ai_next) {
switch (ai->ai_family) {
case AF_INET:
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
continue;
ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
i++;
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
result = 1;
break;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case AF_INET6:
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
continue;
ip_addrs[i].family = IPADDR_INET6;
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
sizeof (ip_addrs->addr.in6));
i++;
addr->family = IPADDR_INET6;
memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6));
result = 1;
break;
#endif
}
if (result && address_family != IPADDR_UNSPEC && address_family != addr->family)
result = 0;
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
freeaddrinfo(res);
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
return result ? DNS_Success : DNS_Failure;
#else
struct hostent *host;
int i;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
return DNS_Failure;
host = gethostbyname(name);
@@ -105,17 +94,8 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
if (h_errno == TRY_AGAIN)
return DNS_TryAgain;
} else {
if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
return DNS_Failure;
for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
addr->family = IPADDR_INET4;
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]);
return DNS_Success;
}
@@ -135,14 +115,33 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{
char *result = NULL;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
struct sockaddr_in in4;
struct sockaddr_in6 in6;
socklen_t slen;
char hbuf[NI_MAXHOST];
slen = UTI_IPAndPortToSockaddr(ip_addr, 0, (struct sockaddr *)&in6);
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
switch (ip_addr->family) {
case IPADDR_INET4:
memset(&in4, 0, sizeof (in4));
#ifdef SIN6_LEN
in4.sin_len = sizeof (in4);
#endif
in4.sin_family = AF_INET;
in4.sin_addr.s_addr = htonl(ip_addr->addr.in4);
if (!getnameinfo((const struct sockaddr *)&in4, sizeof (in4), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
case IPADDR_INET6:
memset(&in6, 0, sizeof (in6));
#ifdef SIN6_LEN
in6.sin6_len = sizeof (in6);
#endif
in6.sin6_family = AF_INET6;
memcpy(&in6.sin6_addr.s6_addr, ip_addr->addr.in6, sizeof (in6.sin6_addr.s6_addr));
if (!getnameinfo((const struct sockaddr *)&in6, sizeof (in6), hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
break;
}
#else
struct hostent *host;
uint32_t addr;
@@ -152,7 +151,7 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
addr = htonl(ip_addr->addr.in4);
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
break;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case IPADDR_INET6:
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
break;

View File

@@ -39,7 +39,7 @@ typedef enum {
/* Resolve names only to selected address family */
extern void DNS_SetAddressFamily(int family);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *addr);
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);

View File

@@ -34,17 +34,17 @@
#include "sched.h"
#include "util.h"
#ifdef FEAT_ASYNCDNS
#ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h>
#define MAX_ADDRESSES 16
/* ================================================== */
struct DNS_Async_Instance {
const char *name;
DNS_Status status;
IPAddr addresses[MAX_ADDRESSES];
IPAddr addr;
DNS_NameResolveHandler handler;
void *arg;
@@ -61,7 +61,7 @@ start_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
inst->status = DNS_Name2IPAddress(inst->name, inst->addresses, MAX_ADDRESSES);
inst->status = DNS_Name2IPAddress(inst->name, &inst->addr);
/* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0)
@@ -76,7 +76,6 @@ static void
end_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
int i;
if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
@@ -88,11 +87,7 @@ end_resolving(void *anything)
close(inst->pipe[0]);
close(inst->pipe[1]);
for (i = 0; inst->status == DNS_Success && i < MAX_ADDRESSES &&
inst->addresses[i].family != IPADDR_UNSPEC; i++)
;
(inst->handler)(inst->status, i, inst->addresses, inst->arg);
(inst->handler)(inst->status, &inst->addr, inst->arg);
Free(inst);
}
@@ -129,3 +124,21 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
#else
#error
#endif
#else
/* This is a blocking implementation used when nothing else is available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addr;
DNS_Status status;
status = DNS_Name2IPAddress(name, &addr);
(handler)(status, &addr, anything);
}
/* ================================================== */
#endif

View File

@@ -31,10 +31,11 @@
#include "nameserv.h"
/* Function type for callback to process the result */
typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
typedef void (*DNS_NameResolveHandler)(DNS_Status status, IPAddr *ip_addr, void *anything);
/* Request resolving of a name to IP address. The handler will be
called when the result is available. */
called when the result is available, but it may be also called
directly from this function call. */
extern void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything);
#endif

53
ntp.h
View File

@@ -38,23 +38,7 @@ typedef struct {
typedef uint32_t NTP_int32;
/* The NTP protocol version that we support */
#define NTP_VERSION 4
/* Maximum stratum number (infinity) */
#define NTP_MAX_STRATUM 16
/* The minimum valid length of an extension field */
#define NTP_MIN_EXTENSION_LENGTH 16
/* The maximum assumed length of all extension fields in received
packets (RFC 5905 doesn't specify a limit on length or number of
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH 1024
/* The minimum and maximum supported length of MAC */
#define NTP_MIN_MAC_LENGTH 16
#define NTP_MAX_MAC_LENGTH MAX_HASH_LENGTH
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@@ -85,33 +69,24 @@ typedef struct {
NTP_int64 originate_ts;
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
/* Optional extension fields, we don't send packets with them yet */
/* uint8_t extensions[] */
/* Optional message authentication code (MAC) */
NTP_int32 auth_keyid;
uint8_t auth_data[NTP_MAX_MAC_LENGTH];
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
/* We have to declare a buffer type to hold a datagram read from the
network. Even though we won't be using them (yet?!), this must be
large enough to hold NTP control messages. */
/* The buffer used to hold a datagram read from the network */
typedef struct {
/* Define the maximum number of bytes that can be read in a single
message. (This is cribbed from ntp.h in the xntpd source code). */
#define MAX_NTP_MESSAGE_SIZE (468+12+16+4)
typedef union {
NTP_Packet ntp_pkt;
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
} NTP_Receive_Buffer;
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
/* Macros to work with the lvm field */
#define NTP_LVM_TO_LEAP(lvm) (((lvm) >> 6) & 0x3)
#define NTP_LVM_TO_VERSION(lvm) (((lvm) >> 3) & 0x7)
#define NTP_LVM_TO_MODE(lvm) ((lvm) & 0x7)
#define NTP_LVM(leap, version, mode) \
((((leap) << 6) & 0xc0) | (((version) << 3) & 0x38) | ((mode) & 0x07))
/* Special NTP reference IDs */
#define NTP_REFID_UNSYNC 0x0UL
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
#endif /* GOT_NTP_H */

1137
ntp_core.c

File diff suppressed because it is too large Load Diff

View File

@@ -58,12 +58,9 @@ extern void NCR_StartInstance(NCR_Instance instance);
/* Reset an instance */
extern void NCR_ResetInstance(NCR_Instance inst);
/* Change the remote address of an instance */
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr);
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
extern int NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, NTP_Local_Address *local_addr, int length);
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int sock_fd, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
@@ -107,6 +104,4 @@ extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
extern int NCR_IsSyncPeer(NCR_Instance instance);
extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
#endif /* GOT_NTP_CORE_H */

209
ntp_io.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2015
* Copyright (C) Miroslav Lichvar 2009, 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
@@ -43,7 +43,7 @@
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
@@ -52,27 +52,15 @@ union sockaddr_in46 {
/* The server/peer and client sockets for IPv4 and IPv6 */
static int server_sock_fd4;
static int client_sock_fd4;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
static int server_sock_fd6;
static int client_sock_fd6;
#endif
/* Reference counters for server sockets to keep them open only when needed */
static int server_sock_ref4;
#ifdef FEAT_IPV6
static int server_sock_ref6;
#endif
/* Flag indicating we create a new connected client socket for each
server instead of sharing client_sock_fd4 and client_sock_fd6 */
static int separate_client_sockets;
/* Flag indicating the server sockets are not created dynamically when needed,
either to have a socket for client requests when separate client sockets
are disabled and client port is equal to server port, or the server port is
disabled */
static int permanent_server_sockets;
/* Flag indicating that we have been initialised */
static int initialised=0;
@@ -97,13 +85,8 @@ prepare_socket(int family, int port_number, int client_only)
sock_fd = socket(family, SOCK_DGRAM, 0);
if (sock_fd < 0) {
if (!client_only) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not open %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
} else {
DEBUG_LOG(LOGF_NtpIO, "Could not open %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
}
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
return INVALID_SOCK_FD;
}
@@ -133,7 +116,7 @@ prepare_socket(int family, int port_number, int client_only)
my_addr_len = sizeof (my_addr.in4);
break;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case AF_INET6:
if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address);
@@ -191,13 +174,14 @@ prepare_socket(int family, int port_number, int client_only)
if (family == AF_INET) {
#ifdef IP_PKTINFO
/* We want the local IP info on server sockets */
if (setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
if (!client_only &&
setsockopt(sock_fd, IPPROTO_IP, IP_PKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
/* Don't quit - we might survive anyway */
}
#endif
}
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
else if (family == AF_INET6) {
#ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */
@@ -206,6 +190,7 @@ prepare_socket(int family, int port_number, int client_only)
}
#endif
if (!client_only) {
#ifdef IPV6_RECVPKTINFO
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
@@ -216,12 +201,13 @@ prepare_socket(int family, int port_number, int client_only)
}
#endif
}
}
#endif
/* Bind the socket if a port or address was specified */
if (my_addr_len > 0 && bind(sock_fd, &my_addr.u, my_addr_len) < 0) {
LOG(LOGS_ERR, LOGF_NtpIO, "Could not bind %s NTP socket : %s",
UTI_SockaddrFamilyToString(family), strerror(errno));
family == AF_INET ? "IPv4" : "IPv6", strerror(errno));
close(sock_fd);
return INVALID_SOCK_FD;
}
@@ -240,7 +226,7 @@ prepare_separate_client_socket(int family)
switch (family) {
case IPADDR_INET4:
return prepare_socket(AF_INET, 0, 1);
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case IPADDR_INET6:
return prepare_socket(AF_INET6, 0, 1);
#endif
@@ -257,9 +243,27 @@ connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
union sockaddr_in46 addr;
socklen_t addr_len;
addr_len = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port, &addr.u);
memset(&addr, 0, sizeof (addr));
assert(addr_len);
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
addr_len = sizeof (addr.in4);
addr.in4.sin_family = AF_INET;
addr.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
addr.in4.sin_port = htons(remote_addr->port);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
addr_len = sizeof (addr.in6);
addr.in6.sin6_family = AF_INET6;
memcpy(addr.in6.sin6_addr.s6_addr, remote_addr->ip_addr.addr.in6,
sizeof (addr.in6.sin6_addr.s6_addr));
addr.in6.sin6_port = htons(remote_addr->port);
break;
#endif
default:
assert(0);
}
if (connect(sock_fd, &addr.u, addr_len) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
@@ -300,20 +304,15 @@ NIO_Initialise(int family)
if (client_port < 0)
client_port = 0;
permanent_server_sockets = !server_port || (!separate_client_sockets &&
client_port == server_port);
server_sock_fd4 = INVALID_SOCK_FD;
client_sock_fd4 = INVALID_SOCK_FD;
server_sock_ref4 = 0;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
server_sock_fd6 = INVALID_SOCK_FD;
client_sock_fd6 = INVALID_SOCK_FD;
server_sock_ref6 = 0;
#endif
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) {
if (permanent_server_sockets && server_port)
if (server_port)
server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
@@ -322,9 +321,9 @@ NIO_Initialise(int family)
client_sock_fd4 = server_sock_fd4;
}
}
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) {
if (permanent_server_sockets && server_port)
if (server_port)
server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
if (!separate_client_sockets) {
if (client_port != server_port || !server_port)
@@ -335,13 +334,12 @@ NIO_Initialise(int family)
}
#endif
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD &&
permanent_server_sockets
#ifdef FEAT_IPV6
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
#ifdef HAVE_IPV6
&& server_sock_fd6 == INVALID_SOCK_FD
#endif
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
&& client_sock_fd6 == INVALID_SOCK_FD
#endif
)) {
@@ -358,7 +356,7 @@ NIO_Finalise(void)
close_socket(client_sock_fd4);
close_socket(server_sock_fd4);
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
if (server_sock_fd6 != client_sock_fd6)
close_socket(client_sock_fd6);
close_socket(server_sock_fd6);
@@ -370,7 +368,7 @@ NIO_Finalise(void)
/* ================================================== */
int
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
{
if (separate_client_sockets) {
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
@@ -388,7 +386,7 @@ NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
return client_sock_fd4;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case IPADDR_INET6:
return client_sock_fd6;
#endif
@@ -401,25 +399,13 @@ NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
/* ================================================== */
int
NIO_OpenServerSocket(NTP_Remote_Address *remote_addr)
NIO_GetServerSocket(NTP_Remote_Address *remote_addr)
{
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
if (permanent_server_sockets)
return server_sock_fd4;
if (server_sock_fd4 == INVALID_SOCK_FD)
server_sock_fd4 = prepare_socket(AF_INET, CNF_GetNTPPort(), 0);
if (server_sock_fd4 != INVALID_SOCK_FD)
server_sock_ref4++;
return server_sock_fd4;
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
case IPADDR_INET6:
if (permanent_server_sockets)
return server_sock_fd6;
if (server_sock_fd6 == INVALID_SOCK_FD)
server_sock_fd6 = prepare_socket(AF_INET6, CNF_GetNTPPort(), 0);
if (server_sock_fd6 != INVALID_SOCK_FD)
server_sock_ref6++;
return server_sock_fd6;
#endif
default:
@@ -438,39 +424,12 @@ NIO_CloseClientSocket(int sock_fd)
/* ================================================== */
void
NIO_CloseServerSocket(int sock_fd)
{
if (permanent_server_sockets || sock_fd == INVALID_SOCK_FD)
return;
if (sock_fd == server_sock_fd4) {
if (--server_sock_ref4 <= 0) {
close_socket(server_sock_fd4);
server_sock_fd4 = INVALID_SOCK_FD;
}
}
#ifdef FEAT_IPV6
else if (sock_fd == server_sock_fd6) {
if (--server_sock_ref6 <= 0) {
close_socket(server_sock_fd6);
server_sock_fd6 = INVALID_SOCK_FD;
}
}
#endif
else {
assert(0);
}
}
/* ================================================== */
int
NIO_IsServerSocket(int sock_fd)
{
return sock_fd != INVALID_SOCK_FD &&
(sock_fd == server_sock_fd4
#ifdef FEAT_IPV6
#ifdef HAVE_IPV6
|| sock_fd == server_sock_fd6
#endif
);
@@ -485,7 +444,7 @@ read_from_socket(void *anything)
to read, otherwise it will block. */
int status, sock_fd;
NTP_Receive_Buffer message;
ReceiveBuffer message;
union sockaddr_in46 where_from;
unsigned int flags = 0;
struct timeval now;
@@ -501,7 +460,7 @@ read_from_socket(void *anything)
SCH_GetLastEventTime(&now, &now_err, NULL);
iov.iov_base = &message.ntp_pkt;
iov.iov_base = message.arbitrary;
iov.iov_len = sizeof(message);
msg.msg_name = &where_from;
msg.msg_namelen = sizeof(where_from);
@@ -525,7 +484,23 @@ read_from_socket(void *anything)
if (msg.msg_namelen > sizeof (where_from))
LOG_FATAL(LOGF_NtpIO, "Truncated source address");
UTI_SockaddrToIPAndPort(&where_from.u, &remote_addr.ip_addr, &remote_addr.port);
switch (where_from.u.sa_family) {
case AF_INET:
remote_addr.ip_addr.family = IPADDR_INET4;
remote_addr.ip_addr.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr);
remote_addr.port = ntohs(where_from.in4.sin_port);
break;
#ifdef HAVE_IPV6
case AF_INET6:
remote_addr.ip_addr.family = IPADDR_INET6;
memcpy(&remote_addr.ip_addr.addr.in6, where_from.in6.sin6_addr.s6_addr,
sizeof (remote_addr.ip_addr.addr.in6));
remote_addr.port = ntohs(where_from.in6.sin6_port);
break;
#endif
default:
assert(0);
}
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.sock_fd = sock_fd;
@@ -562,11 +537,14 @@ read_from_socket(void *anything)
#endif
}
if (status > 0) {
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d",
status, UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
status,
UTI_IPToString(&remote_addr.ip_addr), remote_addr.port,
UTI_IPToString(&local_addr.ip_addr), local_addr.sock_fd);
}
if (status >= NTP_NORMAL_PACKET_LENGTH) {
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
&remote_addr, &local_addr, status);
@@ -580,7 +558,7 @@ read_from_socket(void *anything)
}
/* ================================================== */
/* Send a packet to remote address from local address */
/* Send a packet to given address */
static int
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
@@ -600,15 +578,31 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0;
}
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
/* Don't set address with connected socket */
if (local_addr->sock_fd == server_sock_fd4 ||
#ifdef FEAT_IPV6
local_addr->sock_fd == server_sock_fd6 ||
if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
break;
memset(&remote.in4, 0, sizeof (remote.in4));
addrlen = sizeof (remote.in4);
remote.in4.sin_family = AF_INET;
remote.in4.sin_port = htons(remote_addr->port);
remote.in4.sin_addr.s_addr = htonl(remote_addr->ip_addr.addr.in4);
break;
#ifdef HAVE_IPV6
case IPADDR_INET6:
/* Don't set address with connected socket */
if (local_addr->sock_fd != server_sock_fd6 && separate_client_sockets)
break;
memset(&remote.in6, 0, sizeof (remote.in6));
addrlen = sizeof (remote.in6);
remote.in6.sin6_family = AF_INET6;
remote.in6.sin6_port = htons(remote_addr->port);
memcpy(&remote.in6.sin6_addr.s6_addr, &remote_addr->ip_addr.addr.in6,
sizeof (remote.in6.sin6_addr.s6_addr));
break;
#endif
!separate_client_sockets) {
addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
&remote.u);
if (!addrlen)
default:
return 0;
}
@@ -679,7 +673,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0;
}
DEBUG_LOG(LOGF_NtpIO, "Sent %d bytes to %s:%d from %s fd %d", packetlen,
DEBUG_LOG(LOGF_NtpIO, "Sent to %s:%d from %s fd %d",
UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
@@ -687,10 +681,19 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
}
/* ================================================== */
/* Send a packet to a given address */
/* Send an unauthenticated packet to a given address */
int
NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
return send_packet((void *) packet, length, remote_addr, local_addr);
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE, remote_addr, local_addr);
}
/* ================================================== */
/* Send an authenticated packet to a given address */
int
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len)
{
return send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr, local_addr);
}

View File

@@ -39,21 +39,21 @@ extern void NIO_Initialise(int family);
extern void NIO_Finalise(void);
/* Function to obtain a socket for sending client packets */
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
extern int NIO_GetClientSocket(NTP_Remote_Address *remote_addr);
/* Function to obtain a socket for sending server/peer packets */
extern int NIO_OpenServerSocket(NTP_Remote_Address *remote_addr);
extern int NIO_GetServerSocket(NTP_Remote_Address *remote_addr);
/* Function to close a socket returned by NIO_OpenClientSocket() */
/* Function to close a socket returned by NIO_GetClientSocket() */
extern void NIO_CloseClientSocket(int sock_fd);
/* Function to close a socket returned by NIO_OpenServerSocket() */
extern void NIO_CloseServerSocket(int sock_fd);
/* Function to check if socket is a server socket */
extern int NIO_IsServerSocket(int sock_fd);
/* Function to transmit a packet */
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
extern int NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
/* Function to transmit an authenticated packet */
extern int NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int auth_len);
#endif /* GOT_NTP_IO_H */

View File

@@ -31,7 +31,6 @@
#include "sysincl.h"
#include "array.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "util.h"
@@ -49,20 +48,20 @@ 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
yet and the source may be removed if other
sources from the pool respond first */
} SourceRecord;
/* Hash table of SourceRecord, the size should be a power of two */
static ARR_Instance records;
#define N_RECORDS 256
/* Fixed size table, because we use a hard coded hash algorithm. It
is rather unlikely we would have anything approaching this number
of sources. */
static SourceRecord records[N_RECORDS];
/* Number of sources in the hash table */
static int n_sources;
/* The largest number of sources we want to have stored in the hash table */
#define MAX_SOURCES 64
/* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0;
@@ -70,23 +69,14 @@ static int auto_start_sources = 0;
struct UnresolvedSource {
char *name;
int port;
int replacement;
union {
struct {
NTP_Source_Type type;
SourceParameters params;
int pool;
int max_new_sources;
} new_source;
NTP_Remote_Address replace_source;
};
struct UnresolvedSource *next;
};
#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;
@@ -94,26 +84,10 @@ static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
#define MAX_POOL_SOURCES 16
#define INVALID_POOL (-1)
/* Pool of sources with the same name */
struct SourcePool {
/* Number of sources added from this pool (ignoring tentative sources) */
int sources;
/* Maximum number of sources */
int max_sources;
};
/* Array of SourcePool */
static ARR_Instance pools;
/* ================================================== */
/* Forward prototypes */
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,
@@ -130,25 +104,16 @@ static int initialised = 0;
/* ================================================== */
static SourceRecord *
get_record(unsigned index)
{
return (SourceRecord *)ARR_GetElement(records, index);
}
/* ================================================== */
void
NSR_Initialise(void)
{
int i;
for (i=0; i<N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
n_sources = 0;
initialised = 1;
records = ARR_CreateInstance(sizeof (SourceRecord));
rehash_records();
pools = ARR_CreateInstance(sizeof (struct SourcePool));
LCL_AddParameterChangeHandler(slew_sources, NULL);
}
@@ -157,27 +122,6 @@ NSR_Initialise(void)
void
NSR_Finalise(void)
{
SourceRecord *record;
struct UnresolvedSource *us;
unsigned int i;
ARR_DestroyInstance(pools);
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr)
clean_source_record(record);
}
ARR_DestroyInstance(records);
while (unresolved_sources) {
us = unresolved_sources;
unresolved_sources = us->next;
Free(us->name);
Free(us);
}
initialised = 0;
}
@@ -198,24 +142,23 @@ NSR_Finalise(void)
static void
find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
{
SourceRecord *record;
uint32_t hash;
unsigned int i, size;
unsigned long hash;
unsigned long ip;
unsigned short port;
uint8_t *ip6;
size = ARR_GetSize(records);
assert(N_RECORDS == 256);
switch (remote_addr->ip_addr.family) {
case IPADDR_INET6:
ip6 = remote_addr->ip_addr.addr.in6;
hash = (ip6[0] ^ ip6[4] ^ ip6[8] ^ ip6[12]) |
ip = (ip6[0] ^ ip6[4] ^ ip6[8] ^ ip6[12]) |
(ip6[1] ^ ip6[5] ^ ip6[9] ^ ip6[13]) << 8 |
(ip6[2] ^ ip6[6] ^ ip6[10] ^ ip6[14]) << 16 |
(ip6[3] ^ ip6[7] ^ ip6[11] ^ ip6[15]) << 24;
break;
case IPADDR_INET4:
hash = remote_addr->ip_addr.addr.in4;
ip = remote_addr->ip_addr.addr.in4;
break;
default:
*found = *slot = 0;
@@ -223,77 +166,36 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
}
port = remote_addr->port;
/* Compute hash value just by xor'ing the 4 bytes of the address together */
hash = ip ^ (ip >> 16);
hash = (hash ^ (hash >> 8)) & 0xff;
for (i = 0; i < size / 2; i++) {
/* Use quadratic probing */
*slot = (hash + (i + i * i) / 2) % size;
record = get_record(*slot);
if (!record->remote_addr)
break;
if (!UTI_CompareIPs(&record->remote_addr->ip_addr,
while (records[hash].remote_addr &&
UTI_CompareIPs(&records[hash].remote_addr->ip_addr,
&remote_addr->ip_addr, NULL)) {
*found = record->remote_addr->port == port ? 2 : 1;
return;
}
hash++;
if (hash == 256) hash = 0;
}
if (records[hash].remote_addr) {
if (records[hash].remote_addr->port == port) {
*found = 2;
} else {
*found = 1;
}
*slot = hash;
} else {
*found = 0;
}
/* ================================================== */
/* Check if hash table of given size is sufficient to contain sources */
static int
check_hashtable_size(unsigned int sources, unsigned int size)
{
return sources * 2 + 1 < size;
}
/* ================================================== */
static void
rehash_records(void)
{
SourceRecord *temp_records;
unsigned int i, old_size, new_size;
int slot, found;
old_size = ARR_GetSize(records);
temp_records = MallocArray(SourceRecord, old_size);
memcpy(temp_records, ARR_GetElements(records), old_size * sizeof (SourceRecord));
/* The size of the hash table is always a power of two */
for (new_size = 4; !check_hashtable_size(n_sources, new_size); new_size *= 2)
;
ARR_SetSize(records, new_size);
for (i = 0; i < new_size; i++)
get_record(i)->remote_addr = NULL;
for (i = 0; i < old_size; i++) {
if (!temp_records[i].remote_addr)
continue;
find_slot(temp_records[i].remote_addr, &slot, &found);
assert(!found);
*get_record(slot) = temp_records[i];
*slot = hash;
}
Free(temp_records);
}
/* ================================================== */
/* Procedure to add a new source */
static NSR_Status
add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool)
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
SourceRecord *record;
int slot, found;
assert(initialised);
@@ -303,28 +205,17 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So
if (found) {
return NSR_AlreadyInUse;
} else {
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
if (n_sources == MAX_SOURCES) {
return NSR_TooManySources;
} else if (remote_addr->ip_addr.family != IPADDR_INET4 &&
remote_addr->ip_addr.family != IPADDR_INET6) {
return NSR_InvalidAF;
} else {
n_sources++;
if (!check_hashtable_size(n_sources, ARR_GetSize(records))) {
rehash_records();
find_slot(remote_addr, &slot, &found);
}
assert(!found);
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;
records[slot].data = NCR_GetInstance(remote_addr, type, params); /* Will need params passing through */
records[slot].remote_addr = NCR_GetRemoteAddress(records[slot].data);
if (auto_start_sources)
NCR_StartInstance(record->data);
NCR_StartInstance(records[slot].data);
return NSR_Success;
}
}
@@ -332,80 +223,24 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So
/* ================================================== */
static NSR_Status
replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
{
int slot1, slot2, found;
SourceRecord *record;
find_slot(old_addr, &slot1, &found);
if (!found)
return NSR_NoSuchSource;
find_slot(new_addr, &slot2, &found);
if (found)
return NSR_AlreadyInUse;
record = get_record(slot1);
NCR_ChangeRemoteAddress(record->data, new_addr);
record->remote_addr = NCR_GetRemoteAddress(record->data);
/* The hash table must be rebuilt for the new address */
rehash_records();
LOG(LOGS_INFO, LOGF_NtpSources, "Source %s replaced with %s",
UTI_IPToString(&old_addr->ip_addr),
UTI_IPToString(&new_addr->ip_addr));
return NSR_Success;
}
/* ================================================== */
static void
process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs)
{
NTP_Remote_Address address;
int i, added;
for (i = added = 0; i < n_addrs; i++) {
DEBUG_LOG(LOGF_NtpSources, "(%d) %s", i + 1, UTI_IPToString(&ip_addrs[i]));
address.ip_addr = ip_addrs[i];
address.port = us->port;
if (us->replacement) {
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse)
break;
} else {
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params,
us->new_source.pool) == NSR_Success)
added++;
if (added >= us->new_source.max_new_sources)
break;
}
}
}
/* ================================================== */
static void
name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything)
name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
{
struct UnresolvedSource *us, **i, *next;
NTP_Remote_Address address;
us = (struct UnresolvedSource *)anything;
assert(us == resolving_source);
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %d addrs", us->name, n_addrs);
switch (status) {
case DNS_TryAgain:
break;
case DNS_Success:
process_resolved_name(us, ip_addrs, n_addrs);
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr));
address.ip_addr = *ip_addr;
address.port = us->port;
NSR_AddSource(&address, us->type, &us->params);
break;
case DNS_Failure:
LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
@@ -416,9 +251,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
next = us->next;
/* Remove the source from the list on success or failure, replacements
are removed on any status */
if (us->replacement || status != DNS_TryAgain) {
if (status != DNS_TryAgain) {
/* Remove the source from the list */
for (i = &unresolved_sources; *i; i = &(*i)->next) {
if (*i == us) {
*i = us->next;
@@ -477,61 +311,24 @@ resolve_sources(void *arg)
/* ================================================== */
static void
append_unresolved_source(struct UnresolvedSource *us)
/* Procedure to add a new server or peer source, but instead of an IP address
only a name is provided */
void
NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params)
{
struct UnresolvedSource **i;
struct UnresolvedSource *us, **i;
us = MallocNew(struct UnresolvedSource);
us->name = name;
us->port = port;
us->type = type;
us->params = *params;
us->next = NULL;
for (i = &unresolved_sources; *i; i = &(*i)->next)
;
*i = us;
us->next = NULL;
}
/* ================================================== */
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return add_source(remote_addr, NULL, type, params, INVALID_POOL);
}
/* ================================================== */
void
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
{
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);
us->port = port;
us->replacement = 0;
us->new_source.type = type;
us->new_source.params = *params;
if (!pool) {
us->new_source.pool = INVALID_POOL;
us->new_source.max_new_sources = 1;
} else {
sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->sources = 0;
sp->max_sources = params->max_sources;
us->new_source.pool = ARR_GetSize(pools) - 1;
us->new_source.max_new_sources = MAX_POOL_SOURCES;
}
append_unresolved_source(us);
}
/* ================================================== */
@@ -568,12 +365,12 @@ NSR_ResolveSources(void)
void NSR_StartSources(void)
{
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(records); i++) {
if (!get_record(i)->remote_addr)
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
continue;
NCR_StartInstance(get_record(i)->data);
NCR_StartInstance(records[i].data);
}
}
@@ -586,20 +383,6 @@ void NSR_AutoStartSources(void)
/* ================================================== */
static void
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--;
}
/* ================================================== */
/* Procedure to remove a source. We don't bother whether the port
address is matched - we're only interested in removing a record for
the right IP address. Thus the caller can specify the port number
@@ -607,7 +390,8 @@ clean_source_record(SourceRecord *record)
NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{
int slot, found;
int i, slot, found;
SourceRecord temp_records[N_RECORDS];
assert(initialised);
@@ -616,12 +400,29 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
return NSR_NoSuchSource;
}
clean_source_record(get_record(slot));
n_sources--;
records[slot].remote_addr = NULL;
NCR_DestroyInstance(records[slot].data);
/* Rehash the table to make sure there are no broken probe sequences.
This is costly, but it's not expected to happen frequently. */
rehash_records();
memcpy(temp_records, records, sizeof (records));
for (i = 0; i < N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
for (i = 0; i < N_RECORDS; i++) {
if (!temp_records[i].remote_addr)
continue;
find_slot(temp_records[i].remote_addr, &slot, &found);
assert(!found);
records[slot].remote_addr = temp_records[i].remote_addr;
records[slot].data = temp_records[i].data;
}
return NSR_Success;
}
@@ -631,151 +432,31 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
void
NSR_RemoveAllSources(void)
{
SourceRecord *record;
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr)
for (i = 0; i < N_RECORDS; i++) {
if (!records[i].remote_addr)
continue;
clean_source_record(record);
}
rehash_records();
}
/* ================================================== */
static void
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(record->name);
us->port = record->remote_addr->port;
us->replacement = 1;
us->replace_source = *record->remote_addr;
append_unresolved_source(us);
NSR_ResolveSources();
}
/* ================================================== */
void
NSR_HandleBadSource(IPAddr *address)
{
static struct timeval last_replacement;
struct timeval now;
NTP_Remote_Address remote_addr;
SourceRecord *record;
int slot, found;
double diff;
remote_addr.ip_addr = *address;
remote_addr.port = 0;
find_slot(&remote_addr, &slot, &found);
if (!found)
return;
record = get_record(slot);
/* 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_REPLACEMENT_INTERVAL)) {
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
return;
}
last_replacement = now;
resolve_source_replacement(record);
}
/* ================================================== */
void
NSR_RefreshAddresses(void)
{
SourceRecord *record;
unsigned int i;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr || !record->name)
continue;
resolve_source_replacement(record);
NCR_DestroyInstance(records[i].data);
records[i].remote_addr = NULL;
}
}
/* ================================================== */
static void remove_tentative_pool_sources(int pool)
{
SourceRecord *record;
unsigned int i, removed;
for (i = removed = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr || record->pool != pool || !record->tentative)
continue;
DEBUG_LOG(LOGF_NtpSources, "removing tentative source %s",
UTI_IPToString(&record->remote_addr->ip_addr));
clean_source_record(record);
removed++;
}
if (removed)
rehash_records();
}
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
{
SourceRecord *record;
struct SourcePool *pool;
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
record = get_record(slot);
if (!NCR_ProcessKnown(message, now, now_err, record->data, local_addr, length))
return;
if (record->tentative) {
/* First reply from a pool source */
record->tentative = 0;
assert(record->pool != INVALID_POOL);
pool = (struct SourcePool *)ARR_GetElement(pools, record->pool);
pool->sources++;
DEBUG_LOG(LOGF_NtpSources, "pool %s has %d confirmed sources",
record->name, pool->sources);
/* If the number of sources reached the configured maximum, remove
the tentative sources added from this pool */
if (pool->sources >= pool->max_sources)
remove_tentative_pool_sources(record->pool);
}
NCR_ProcessKnown(message, now, now_err, records[slot].data,
local_addr->sock_fd, length);
} else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length);
}
@@ -791,16 +472,14 @@ slew_sources(struct timeval *raw,
LCL_ChangeType change_type,
void *anything)
{
SourceRecord *record;
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
if (change_type == LCL_ChangeUnknownStep) {
NCR_ResetInstance(record->data);
NCR_ResetInstance(records[i].data);
} else {
NCR_SlewTimes(record->data, cooked, dfreq, doffset);
NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
}
}
}
@@ -811,20 +490,18 @@ slew_sources(struct timeval *raw,
int
NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
{
SourceRecord *record;
unsigned int i;
int i;
int any;
NSR_ResolveSources();
any = 0;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
any = 1;
NCR_TakeSourceOnline(record->data);
NCR_TakeSourceOnline(records[i].data);
}
}
}
@@ -833,10 +510,8 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1;
us->new_source.params.online = 1;
us->params.online = 1;
}
}
@@ -848,39 +523,35 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{
SourceRecord *record, *syncpeer;
unsigned int i, any;
int i, any, syncpeer;
any = 0;
syncpeer = NULL;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
syncpeer = -1;
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
any = 1;
if (NCR_IsSyncPeer(record->data)) {
syncpeer = record;
if (NCR_IsSyncPeer(records[i].data)) {
syncpeer = i;
continue;
}
NCR_TakeSourceOffline(record->data);
NCR_TakeSourceOffline(records[i].data);
}
}
}
/* Take sync peer offline as last to avoid reference switching */
if (syncpeer) {
NCR_TakeSourceOffline(syncpeer->data);
if (syncpeer >= 0) {
NCR_TakeSourceOffline(records[syncpeer].data);
}
if (address->family == IPADDR_UNSPEC) {
struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1;
us->new_source.params.online = 0;
us->params.online = 0;
}
}
@@ -901,7 +572,7 @@ NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
if (found == 0) {
return 0;
} else {
NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll);
NCR_ModifyMinpoll(records[slot].data, new_minpoll);
return 1;
}
}
@@ -920,7 +591,7 @@ NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll);
NCR_ModifyMaxpoll(records[slot].data, new_maxpoll);
return 1;
}
}
@@ -939,7 +610,7 @@ NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay);
NCR_ModifyMaxdelay(records[slot].data, new_max_delay);
return 1;
}
}
@@ -958,7 +629,7 @@ NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio);
NCR_ModifyMaxdelayratio(records[slot].data, new_max_delay_ratio);
return 1;
}
}
@@ -977,7 +648,7 @@ NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
if (found == 0) {
return 0;
} else {
NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio);
NCR_ModifyMaxdelaydevratio(records[slot].data, new_max_delay_dev_ratio);
return 1;
}
}
@@ -996,7 +667,7 @@ NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
if (found == 0) {
return 0;
} else {
NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum);
NCR_ModifyMinstratum(records[slot].data, new_min_stratum);
return 1;
}
}
@@ -1015,7 +686,7 @@ NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
if (found == 0) {
return 0;
} else {
NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target);
NCR_ModifyPolltarget(records[slot].data, new_poll_target);
return 1;
}
}
@@ -1026,18 +697,16 @@ int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address)
{
SourceRecord *record;
unsigned int i;
int i;
int any;
any = 0;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
if (address->family == IPADDR_UNSPEC ||
!UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) {
!UTI_CompareIPs(&records[i].remote_addr->ip_addr, address, mask)) {
any = 1;
NCR_InitiateSampleBurst(record->data, n_good_samples, n_total_samples);
NCR_InitiateSampleBurst(records[i].data, n_good_samples, n_total_samples);
}
}
}
@@ -1060,7 +729,7 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
rem_addr.port = 0;
find_slot(&rem_addr, &slot, &found);
if (found) {
NCR_ReportSource(get_record(slot)->data, report, now);
NCR_ReportSource(records[slot].data, report, now);
} else {
report->poll = 0;
report->latest_meas_ago = 0;
@@ -1072,8 +741,7 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
SourceRecord *record;
unsigned int i;
int i;
struct UnresolvedSource *us;
report->online = 0;
@@ -1081,10 +749,9 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
report->burst_online = 0;
report->burst_offline = 0;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr) {
NCR_IncrementActivityCounters(record->data, &report->online, &report->offline,
for (i=0; i<N_RECORDS; i++) {
if (records[i].remote_addr) {
NCR_IncrementActivityCounters(records[i].data, &report->online, &report->offline,
&report->burst_online, &report->burst_offline);
}
}

View File

@@ -50,10 +50,10 @@ typedef enum {
/* Procedure to add a new server or peer source. */
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
/* Procedure to add a new server, peer source, or pool of servers specified by
name instead of address. The name is resolved in exponentially increasing
intervals until it succeeds or fails with a non-temporary error. */
extern void NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params);
/* Procedure to add a new server or peer source with currently unknown address.
The name will be periodically resolved in exponentially increasing intervals
until it succeeds or fails with a non-temporary error. */
extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params);
/* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */
@@ -77,12 +77,6 @@ extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* Procedure to remove all sources */
extern void NSR_RemoveAllSources(void);
/* Procedure to try to find a replacement for a bad source */
extern void NSR_HandleBadSource(IPAddr *address);
/* Procedure to resolve all names again */
extern void NSR_RefreshAddresses(void);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);

View File

@@ -44,8 +44,9 @@ command_unpadded_length(CMD_Request *r)
return 0;
} else {
switch (type) {
case REQ_NULL:
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data);
case REQ_ONLINE:
return offsetof(CMD_Request, data.online.EOR);
case REQ_OFFLINE:
@@ -66,8 +67,6 @@ command_unpadded_length(CMD_Request *r)
return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return offsetof(CMD_Request, data.modify_maxupdateskew.EOR);
case REQ_MODIFY_MAKESTEP:
return offsetof(CMD_Request, data.modify_makestep.EOR);
case REQ_LOGON :
return offsetof(CMD_Request, data.logon.EOR);
case REQ_SETTIME :
@@ -77,11 +76,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.null.EOR);
return offsetof(CMD_Request, data.n_sources.EOR);
case REQ_SOURCE_DATA :
return offsetof(CMD_Request, data.source_data.EOR);
case REQ_REKEY :
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.rekey.EOR);
case REQ_ALLOW :
return offsetof(CMD_Request, data.allow_deny.EOR);
case REQ_ALLOWALL :
@@ -109,21 +108,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.null.EOR);
return offsetof(CMD_Request, data.writertc.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.null.EOR);
return offsetof(CMD_Request, data.tracking.EOR);
case REQ_SOURCESTATS :
return offsetof(CMD_Request, data.sourcestats.EOR);
case REQ_RTCREPORT :
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.rtcreport.EOR);
case REQ_TRIMRTC :
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.trimrtc.EOR);
case REQ_CYCLELOGS :
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.cyclelogs.EOR);
case REQ_SUBNETS_ACCESSED :
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -131,27 +130,21 @@ 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.null.EOR);
return offsetof(CMD_Request, data.manual_list.EOR);
case REQ_MANUAL_DELETE:
return offsetof(CMD_Request, data.manual_delete.EOR);
case REQ_MAKESTEP:
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.make_step.EOR);
case REQ_ACTIVITY:
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.activity.EOR);
case REQ_RESELECT:
return offsetof(CMD_Request, data.null.EOR);
return offsetof(CMD_Request, data.reselect.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);
case REQ_REFRESH:
return offsetof(CMD_Request, data.null.EOR);
default:
/* If we fall through the switch, it most likely means we've forgotten to implement a new case */
assert(0);
@@ -222,8 +215,6 @@ PKL_CommandPaddingLength(CMD_Request *r)
return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXUPDATESKEW:
return PADDING_LENGTH(data.modify_maxupdateskew.EOR, data.null.EOR);
case REQ_MODIFY_MAKESTEP:
return PADDING_LENGTH(data.modify_makestep.EOR, data.null.EOR);
case REQ_LOGON:
return PADDING_LENGTH(data.logon.EOR, data.null.EOR);
case REQ_SETTIME:
@@ -233,11 +224,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.null.EOR, data.n_sources.EOR);
return PADDING_LENGTH(data.n_sources.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.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.rekey.EOR, data.null.EOR);
case REQ_ALLOW:
return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR);
case REQ_ALLOWALL:
@@ -265,21 +256,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.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.writertc.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.null.EOR, data.tracking.EOR);
return PADDING_LENGTH(data.tracking.EOR, data.tracking.EOR);
case REQ_SOURCESTATS:
return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR);
case REQ_RTCREPORT:
return PADDING_LENGTH(data.null.EOR, data.rtc.EOR);
return PADDING_LENGTH(data.rtcreport.EOR, data.rtc.EOR);
case REQ_TRIMRTC:
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.trimrtc.EOR, data.null.EOR);
case REQ_CYCLELOGS:
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.cyclelogs.EOR, data.null.EOR);
case REQ_SUBNETS_ACCESSED:
case REQ_CLIENT_ACCESSES:
/* No longer supported */
@@ -287,27 +278,21 @@ 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.null.EOR, data.manual_list.EOR);
return PADDING_LENGTH(data.manual_list.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.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.make_step.EOR, data.null.EOR);
case REQ_ACTIVITY:
return PADDING_LENGTH(data.null.EOR, data.activity.EOR);
return PADDING_LENGTH(data.activity.EOR, data.activity.EOR);
case REQ_RESELECT:
return PADDING_LENGTH(data.null.EOR, data.null.EOR);
return PADDING_LENGTH(data.reselect.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);
case REQ_REFRESH:
return PADDING_LENGTH(data.null.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);
@@ -371,8 +356,7 @@ 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

@@ -27,7 +27,6 @@
#include "config.h"
#include "array.h"
#include "refclock.h"
#include "reference.h"
#include "conf.h"
@@ -87,8 +86,10 @@ struct RCL_Instance_Record {
SRC_Instance source;
};
/* Array of RCL_Instance_Record */
static ARR_Instance refclocks;
#define MAX_RCL_SOURCES 8
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
static int n_sources = 0;
static LOG_FileID logfileid;
@@ -111,20 +112,12 @@ static int filter_get_sample(struct MedianFilter *filter, struct timeval *sample
static void filter_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
static void filter_add_dispersion(struct MedianFilter *filter, double dispersion);
static RCL_Instance
get_refclock(unsigned int index)
{
return (RCL_Instance)ARR_GetElement(refclocks, index);
}
void
RCL_Initialise(void)
{
refclocks = ARR_CreateInstance(sizeof (struct RCL_Instance_Record));
CNF_AddRefclocks();
if (ARR_GetSize(refclocks) > 0) {
if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
}
@@ -137,25 +130,22 @@ RCL_Initialise(void)
void
RCL_Finalise(void)
{
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(refclocks); i++) {
RCL_Instance inst = get_refclock(i);
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = (RCL_Instance)&refclocks[i];
if (inst->driver->fini)
inst->driver->fini(inst);
filter_fini(&inst->filter);
Free(inst->driver_parameter);
SRC_DestroyInstance(inst->source);
}
if (ARR_GetSize(refclocks) > 0) {
if (n_sources > 0) {
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
}
ARR_DestroyInstance(refclocks);
}
int
@@ -163,7 +153,10 @@ RCL_AddRefclock(RefclockParameters *params)
{
int pps_source = 0;
RCL_Instance inst = ARR_GetNewElement(refclocks);
RCL_Instance inst = &refclocks[n_sources];
if (n_sources == MAX_RCL_SOURCES)
return 0;
if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver;
@@ -226,13 +219,8 @@ RCL_AddRefclock(RefclockParameters *params)
inst->ref_id = params->ref_id;
else {
unsigned char ref[5] = { 0, 0, 0, 0, 0 };
unsigned int index = ARR_GetSize(refclocks) - 1;
snprintf((char *)ref, sizeof (ref), "%3.3s", params->driver_name);
ref[3] = index % 10 + '0';
if (index >= 10)
ref[2] = (index / 10) % 10 + '0';
snprintf((char *)ref, 5, "%3.3s%d", params->driver_name, n_sources % 10);
inst->ref_id = ref[0] << 24 | ref[1] << 16 | ref[2] << 8 | ref[3];
}
@@ -260,12 +248,11 @@ RCL_AddRefclock(RefclockParameters *params)
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL,
params->min_samples, params->max_samples);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL);
DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id),
inst->poll, inst->driver_poll, params->filter_length);
DEBUG_LOG(LOGF_Refclock, "refclock %s added poll=%d dpoll=%d filter=%d",
params->driver_name, inst->poll, inst->driver_poll, params->filter_length);
n_sources++;
Free(params->driver_name);
@@ -275,21 +262,20 @@ RCL_AddRefclock(RefclockParameters *params)
void
RCL_StartRefclocks(void)
{
unsigned int i, j, n;
int i, j;
n = ARR_GetSize(refclocks);
for (i = 0; i < n; i++) {
RCL_Instance inst = get_refclock(i);
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
SRC_SetSelectable(inst->source);
SRC_SetActive(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
/* Replace lock refid with index to refclocks */
for (j = 0; j < n && get_refclock(j)->ref_id != inst->lock_ref; j++)
for (j = 0; j < n_sources && refclocks[j].ref_id != inst->lock_ref; j++)
;
inst->lock_ref = j < n ? j : -1;
inst->lock_ref = (j < n_sources) ? j : -1;
} else
inst->lock_ref = -1;
}
@@ -298,14 +284,14 @@ RCL_StartRefclocks(void)
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
unsigned int i;
int i;
uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4;
for (i = 0; i < ARR_GetSize(refclocks); i++) {
RCL_Instance inst = get_refclock(i);
for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
if (inst->ref_id == ref_id) {
report->poll = inst->poll;
report->mode = RPT_LOCAL_REFERENCE;
@@ -367,9 +353,7 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
UTI_AddDoubleToTimeval(sample_time, correction, &cooked_time);
dispersion += instance->precision;
/* Make sure the timestamp and offset provided by the driver are sane */
if (!UTI_IsTimeOffsetSane(sample_time, offset) ||
!valid_sample_time(instance, sample_time))
if (!valid_sample_time(instance, sample_time))
return 0;
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
@@ -409,8 +393,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
dispersion += instance->precision;
if (!UTI_IsTimeOffsetSane(pulse_time, 0.0) ||
!valid_sample_time(instance, pulse_time))
if (!valid_sample_time(instance, pulse_time))
return 0;
rate = instance->pps_rate;
@@ -426,19 +409,16 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
offset -= 1.0 / rate;
if (instance->lock_ref != -1) {
RCL_Instance lock_refclock;
struct timeval ref_sample_time;
double sample_diff, ref_offset, ref_dispersion, shift;
lock_refclock = get_refclock(instance->lock_ref);
if (!filter_get_last_sample(&lock_refclock->filter,
if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
&ref_sample_time, &ref_offset, &ref_dispersion)) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample");
return 0;
}
ref_dispersion += filter_get_avg_sample_dispersion(&lock_refclock->filter);
ref_dispersion += filter_get_avg_sample_dispersion(&refclocks[instance->lock_ref].filter);
UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= 2.0 / rate) {
@@ -461,7 +441,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 0;
}
leap = lock_refclock->leap_status;
leap = refclocks[instance->lock_ref].leap_status;
DEBUG_LOG(LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
second, offset, ref_offset - offset, sample_diff);
@@ -499,6 +479,15 @@ 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)
{
@@ -507,9 +496,9 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
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));
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "refclock sample not valid age=%.6f tv=%s",
diff, UTI_TimevalToString(tv));
return 0;
}
return 1;
@@ -519,12 +508,10 @@ static int
pps_stratum(RCL_Instance instance, struct timeval *tv)
{
struct timeval ref_time;
int is_synchronised, stratum;
unsigned int i;
int is_synchronised, stratum, i;
double root_delay, root_dispersion;
NTP_Leap leap;
uint32_t ref_id;
RCL_Instance refclock;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion);
@@ -535,10 +522,9 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
return stratum - 1;
/* Or the current source is another PPS refclock */
for (i = 0; i < ARR_GetSize(refclocks); i++) {
refclock = get_refclock(i);
if (refclock->ref_id == ref_id &&
refclock->pps_active && refclock->lock_ref == -1)
for (i = 0; i < n_sources; i++) {
if (refclocks[i].ref_id == ref_id &&
refclocks[i].pps_active && refclocks[i].lock_ref == -1)
return stratum - 1;
}
@@ -586,30 +572,30 @@ poll_timeout(void *arg)
}
}
inst->timeout_id = SCH_AddTimeoutByDelay(UTI_Log2ToDouble(poll), poll_timeout, arg);
inst->timeout_id = SCH_AddTimeoutByDelay(poll_interval(poll), poll_timeout, arg);
}
static void
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(refclocks); i++) {
for (i = 0; i < n_sources; i++) {
if (change_type == LCL_ChangeUnknownStep)
filter_reset(&get_refclock(i)->filter);
filter_reset(&refclocks[i].filter);
else
filter_slew_samples(&get_refclock(i)->filter, cooked, dfreq, doffset);
filter_slew_samples(&refclocks[i].filter, cooked, dfreq, doffset);
}
}
static void
add_dispersion(double dispersion, void *anything)
{
unsigned int i;
int i;
for (i = 0; i < ARR_GetSize(refclocks); i++)
filter_add_dispersion(&get_refclock(i)->filter, dispersion);
for (i = 0; i < n_sources; i++)
filter_add_dispersion(&refclocks[i].filter, dispersion);
}
static void

View File

@@ -38,8 +38,6 @@ typedef struct {
int poll;
int filter_length;
int pps_rate;
int min_samples;
int max_samples;
uint32_t ref_id;
uint32_t lock_ref_id;
double offset;

View File

@@ -29,7 +29,7 @@
#include "refclock.h"
#if FEAT_PPS
#if HAVE_PPSAPI
#if defined(HAVE_SYS_TIMEPPS_H)
#include <sys/timepps.h>

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2015
* Copyright (C) Miroslav Lichvar 2009-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
@@ -50,7 +50,7 @@ static int our_leap_sec;
static int our_stratum;
static uint32_t our_ref_id;
static IPAddr our_ref_ip;
struct timeval our_ref_time;
struct timeval our_ref_time; /* Stored relative to reference, NOT local time */
static double our_skew;
static double our_residual_freq;
static double our_root_delay;
@@ -98,17 +98,6 @@ static double drift_file_age;
static void update_drift_file(double, double);
/* Leap second handling mode */
static REF_LeapMode leap_mode;
/* Flag indicating the clock was recently corrected for leap second and it may
not have correct time yet (missing 23:59:60 in the UTC time scale) */
static int leap_in_progress;
/* Timer for the leap second handler */
static int leap_timer_running;
static SCH_TimeoutID leap_timeout_id;
/* Name of a system timezone containing leap seconds occuring at midnight */
static char *leap_tzname;
static time_t last_tz_leap_check;
@@ -120,6 +109,11 @@ static LOG_FileID logfileid;
/* ================================================== */
/* Reference ID supplied when we are locally referenced */
#define LOCAL_REFERENCE_ID 0x7f7f0101UL
/* ================================================== */
/* Exponential moving averages of absolute clock frequencies
used as a fallback when synchronisation is lost. */
@@ -142,7 +136,6 @@ static double last_ref_update_interval;
/* ================================================== */
static NTP_Leap get_tz_leap(time_t when);
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
/* ================================================== */
@@ -155,9 +148,6 @@ handle_slew(struct timeval *raw,
void *anything)
{
double delta;
struct timeval now;
UTI_AdjustTimeval(&our_ref_time, cooked, &our_ref_time, &delta, dfreq, doffset);
if (change_type == LCL_ChangeUnknownStep) {
last_ref_update.tv_sec = 0;
@@ -165,13 +155,6 @@ handle_slew(struct timeval *raw,
} else if (last_ref_update.tv_sec) {
UTI_AdjustTimeval(&last_ref_update, cooked, &last_ref_update, &delta, dfreq, doffset);
}
/* When the clock was stepped, check if that doesn't change our leap status
and also reset the leap timeout to undo the shift in the scheduler */
if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
LCL_ReadRawTime(&now);
update_leap_status(our_leap_status, now.tv_sec, 1);
}
}
/* ================================================== */
@@ -234,18 +217,11 @@ REF_Initialise(void)
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
leap_timer_running = 0;
leap_in_progress = 0;
leap_mode = CNF_GetLeapSecMode();
/* Switch to step mode if the system driver doesn't support leap */
if (leap_mode == REF_LeapModeSystem && !LCL_CanSystemLeap())
leap_mode = REF_LeapModeStep;
leap_tzname = CNF_GetLeapSecTimezone();
if (leap_tzname) {
/* 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) {
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
if (get_tz_leap(1214784000) == LEAP_Normal &&
get_tz_leap(1230681600) == LEAP_InsertSecond) {
LOG(LOGS_INFO, LOGF_Reference, "Using %s timezone to obtain leap second data", leap_tzname);
} else {
LOG(LOGS_WARN, LOGF_Reference, "Timezone %s failed leap second check, ignoring", leap_tzname);
@@ -287,7 +263,9 @@ REF_Initialise(void)
void
REF_Finalise(void)
{
update_leap_status(LEAP_Unsynchronised, 0, 0);
if (our_leap_sec) {
LCL_SetLeap(0);
}
if (drift_file) {
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
@@ -323,14 +301,6 @@ REF_SetModeEndHandler(REF_ModeEndHandler handler)
/* ================================================== */
REF_LeapMode
REF_GetLeapMode(void)
{
return leap_mode;
}
/* ================================================== */
static double
Sqr(double x)
{
@@ -433,10 +403,14 @@ update_fb_drifts(double freq_ppm, double update_interval)
fb_drift_timeout_id = -1;
}
if (update_interval < 1.0 || update_interval > last_ref_update_interval * 4.0)
if (update_interval < 0.0 || update_interval > last_ref_update_interval * 4.0)
return;
for (i = 0; i < fb_drift_max - fb_drift_min + 1; i++) {
/* Don't allow differences larger than 10 ppm */
if (fabs(freq_ppm - fb_drifts[i].freq) > 10.0)
fb_drifts[i].secs = 0.0;
secs = 1 << (i + fb_drift_min);
if (fb_drifts[i].secs < secs) {
/* Calculate average over 2 * secs interval before switching to
@@ -462,12 +436,11 @@ update_fb_drifts(double freq_ppm, double update_interval)
static void
fb_drift_timeout(void *arg)
{
assert(are_we_synchronised == 0);
assert(next_fb_drift >= fb_drift_min && next_fb_drift <= fb_drift_max);
fb_drift_timeout_id = -1;
DEBUG_LOG(LOGF_Reference, "Fallback drift %d active: %f ppm",
next_fb_drift, fb_drifts[next_fb_drift - fb_drift_min].freq);
LCL_SetAbsoluteFrequency(fb_drifts[next_fb_drift - fb_drift_min].freq);
REF_SetUnsynchronised();
}
@@ -684,89 +657,7 @@ get_tz_leap(time_t when)
/* ================================================== */
static void
leap_end_timeout(void *arg)
{
leap_timer_running = 0;
leap_in_progress = 0;
our_leap_sec = 0;
if (leap_mode == REF_LeapModeSystem)
LCL_SetSystemLeap(0);
if (our_leap_status == LEAP_InsertSecond ||
our_leap_status == LEAP_DeleteSecond)
our_leap_status = LEAP_Normal;
}
/* ================================================== */
static void
leap_start_timeout(void *arg)
{
leap_in_progress = 1;
switch (leap_mode) {
case REF_LeapModeSystem:
DEBUG_LOG(LOGF_Reference, "Waiting for system clock leap second correction");
break;
case REF_LeapModeSlew:
LCL_NotifyLeap(our_leap_sec);
LCL_AccumulateOffset(our_leap_sec, 0.0);
LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
break;
case REF_LeapModeStep:
LCL_NotifyLeap(our_leap_sec);
LCL_ApplyStepOffset(our_leap_sec);
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
break;
case REF_LeapModeIgnore:
LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
break;
default:
break;
}
/* Wait until the leap second is over with some extra room to be safe */
leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
}
/* ================================================== */
static void
set_leap_timeout(time_t now)
{
struct timeval when;
/* Stop old timer if there is one */
if (leap_timer_running) {
SCH_RemoveTimeout(leap_timeout_id);
leap_timer_running = 0;
leap_in_progress = 0;
}
if (!our_leap_sec)
return;
/* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC. If the clock
will be corrected by the system, timeout slightly sooner to be sure it
will happen before the system correction. */
when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
when.tv_usec = 0;
if (our_leap_sec < 0)
when.tv_sec--;
if (leap_mode == REF_LeapModeSystem) {
when.tv_sec--;
when.tv_usec = 500000;
}
leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
leap_timer_running = 1;
}
/* ================================================== */
static void
update_leap_status(NTP_Leap leap, time_t now, int reset)
update_leap_status(NTP_Leap leap, time_t now)
{
int leap_sec;
@@ -790,23 +681,8 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
}
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
LCL_SetLeap(leap_sec);
our_leap_sec = leap_sec;
switch (leap_mode) {
case REF_LeapModeSystem:
LCL_SetSystemLeap(our_leap_sec);
/* Fall through */
case REF_LeapModeSlew:
case REF_LeapModeStep:
case REF_LeapModeIgnore:
set_leap_timeout(now);
break;
default:
assert(0);
break;
}
} else if (reset) {
set_leap_timeout(now);
}
our_leap_status = leap;
@@ -1044,16 +920,14 @@ REF_SetReference(int stratum,
our_residual_freq = frequency;
}
update_leap_status(leap, raw_now.tv_sec, 0);
update_leap_status(leap, raw_now.tv_sec);
maybe_log_offset(our_offset, raw_now.tv_sec);
if (step_offset != 0.0) {
if (LCL_ApplyStepOffset(step_offset))
LCL_ApplyStepOffset(step_offset);
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
}
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(&now,
@@ -1079,7 +953,6 @@ REF_SetReference(int stratum,
/* Update fallback drifts */
if (fb_drifts) {
update_fb_drifts(abs_freq_ppm, update_interval);
schedule_fb_drift(&now);
}
last_ref_update_interval = update_interval;
@@ -1106,10 +979,12 @@ REF_SetManualReference
double skew
)
{
uint32_t manual_refid = 0x4D414E55; /* MANU */
/* We are not synchronised to an external source, as such. This is
only supposed to be used with the local source option, really.
Log as MANU in the tracking log, packets will have NTP_REFID_LOCAL. */
REF_SetReference(0, LEAP_Unsynchronised, 1, 0x4D414E55UL, NULL,
only supposed to be used with the local source option, really
... */
REF_SetReference(0, LEAP_Unsynchronised, 1, manual_refid, NULL,
ref_time, offset, 0.0, frequency, skew, 0.0, 0.0);
}
@@ -1138,11 +1013,9 @@ REF_SetUnsynchronised(void)
schedule_fb_drift(&now);
}
update_leap_status(LEAP_Unsynchronised, 0, 0);
update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0;
LCL_SetSyncStatus(0, 0.0, 0.0);
write_log(&now,
"0.0.0.0",
0,
@@ -1184,7 +1057,7 @@ REF_GetReferenceParams
UTI_DiffTimevalsToDouble(&elapsed, local_time, &our_ref_time);
extra_dispersion = (our_skew + fabs(our_residual_freq) + LCL_GetMaxClockError()) * elapsed;
*leap_status = !leap_in_progress ? our_leap_status : LEAP_Unsynchronised;
*leap_status = our_leap_status;
*ref_id = our_ref_id;
*ref_time = our_ref_time;
*root_delay = our_root_delay;
@@ -1195,10 +1068,10 @@ REF_GetReferenceParams
*is_synchronised = 1;
*stratum = local_stratum;
*ref_id = NTP_REFID_LOCAL;
*ref_id = LOCAL_REFERENCE_ID;
/* Make the reference time be now less a second - this will
scarcely affect the client, but will ensure that the transmit
timestamp cannot come before this (which would cause test 7 to
timestamp cannot come before this (which would cause test 6 to
fail in the client's read routine) if the local system clock's
read routine is broken in any way. */
*ref_time = *local_time;
@@ -1216,8 +1089,8 @@ REF_GetReferenceParams
*is_synchronised = 0;
*leap_status = LEAP_Unsynchronised;
*stratum = NTP_MAX_STRATUM;
*ref_id = NTP_REFID_UNSYNC;
*stratum = 0;
*ref_id = 0;
ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and
any peer or client of ours will ignore them anyway because
@@ -1238,20 +1111,12 @@ REF_GetOurStratum(void)
} else if (enable_local_stratum) {
return local_stratum;
} else {
return NTP_MAX_STRATUM;
return 16;
}
}
/* ================================================== */
double
REF_GetSkew(void)
{
return our_skew;
}
/* ================================================== */
void
REF_ModifyMaxupdateskew(double new_max_update_skew)
{
@@ -1260,15 +1125,6 @@ REF_ModifyMaxupdateskew(double new_max_update_skew)
/* ================================================== */
void
REF_ModifyMakestep(int limit, double threshold)
{
make_step_limit = limit;
make_step_threshold = threshold;
}
/* ================================================== */
void
REF_EnableLocal(int stratum)
{
@@ -1331,7 +1187,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
LCL_GetOffsetCorrection(&now_raw, &correction, NULL);
UTI_AddDoubleToTimeval(&now_raw, correction, &now_cooked);
rep->ref_id = NTP_REFID_UNSYNC;
rep->ref_id = 0;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = 0;
rep->leap_status = our_leap_status;
@@ -1363,7 +1219,7 @@ REF_GetTrackingReport(RPT_TrackingReport *rep)
} else if (enable_local_stratum) {
rep->ref_id = NTP_REFID_LOCAL;
rep->ref_id = LOCAL_REFERENCE_ID;
rep->ip_addr.family = IPADDR_UNSPEC;
rep->stratum = local_stratum;
rep->ref_time = now_cooked;

View File

@@ -35,14 +35,6 @@
#include "ntp.h"
#include "reports.h"
/* Leap second handling modes */
typedef enum {
REF_LeapModeSystem,
REF_LeapModeSlew,
REF_LeapModeStep,
REF_LeapModeIgnore,
} REF_LeapMode;
/* Init function */
extern void REF_Initialise(void);
@@ -69,9 +61,6 @@ typedef void (*REF_ModeEndHandler)(int result);
/* Set the handler for being notified of mode ending */
extern void REF_SetModeEndHandler(REF_ModeEndHandler handler);
/* Get leap second handling mode */
extern REF_LeapMode REF_GetLeapMode(void);
/* Function which takes a local cooked time and returns the estimated
time of the reference. It also returns the other parameters
required for forming the outgoing NTP packet.
@@ -165,15 +154,9 @@ REF_SetUnsynchronised(void);
synchronised */
extern int REF_GetOurStratum(void);
/* Return the current skew */
extern double REF_GetSkew(void);
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
/* Modify makestep settings */
extern void REF_ModifyMakestep(int limit, double threshold);
extern void REF_EnableLocal(int stratum);
extern void REF_DisableLocal(void);
extern int REF_IsLocalActive(void);

View File

@@ -86,6 +86,16 @@ typedef struct {
double rtc_gain_rate_ppm;
} RPT_RTC_Report;
typedef struct {
unsigned long client_hits;
unsigned long peer_hits;
unsigned long cmd_hits_auth;
unsigned long cmd_hits_normal;
unsigned long cmd_hits_bad;
unsigned long last_ntp_hit_ago;
unsigned long last_cmd_hit_ago;
} RPT_ClientAccess_Report;
typedef struct {
IPAddr ip_addr;
unsigned long client_hits;
@@ -112,14 +122,4 @@ 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 */

62
rtc.c
View File

@@ -39,12 +39,11 @@
/* ================================================== */
static int driver_initialised = 0;
static int driver_preinit_ok = 0;
static struct {
int (*init)(void);
void (*fini)(void);
int (*time_pre_init)(time_t driftfile_time);
int (*time_pre_init)(void);
void (*time_init)(void (*after_hook)(void*), void *anything);
void (*start_measurements)(void);
int (*write_parameters)(void);
@@ -74,37 +73,29 @@ static struct {
};
/* ================================================== */
/* Get the last modification time of the driftfile */
/* Set the system clock to the time of last modification of driftfile
if it's in the future */
static time_t
get_driftfile_time(void)
static void
fallback_time_init(void)
{
struct timeval now;
struct stat buf;
char *drift_file;
drift_file = CNF_GetDriftFile();
if (!drift_file)
return 0;
return;
if (stat(drift_file, &buf))
return 0;
return buf.st_mtime;
}
/* ================================================== */
/* Set the system time to the driftfile time if it's in the future */
static void
apply_driftfile_time(time_t t)
{
struct timeval now;
return;
LCL_ReadCookedTime(&now, NULL);
if (now.tv_sec < t) {
if (LCL_ApplyStepOffset(now.tv_sec - t))
LOG(LOGS_INFO, LOGF_Rtc, "System time restored from driftfile");
if (now.tv_sec < buf.st_mtime) {
LCL_ApplyStepOffset(now.tv_sec - buf.st_mtime);
LOG(LOGS_INFO, LOGF_Rtc,
"System clock set from driftfile %s", drift_file);
}
}
@@ -113,24 +104,15 @@ apply_driftfile_time(time_t t)
void
RTC_Initialise(int initial_set)
{
time_t driftfile_time;
char *file_name;
/* If the -s option was specified, try to do an initial read of the RTC and
set the system time to it. Also, read the last modification time of the
driftfile (i.e. system time when chronyd was previously stopped) and set
the system time to it if it's in the future to bring the clock closer to
the true time when the RTC is broken (e.g. it has no battery), is missing,
or there is no RTC driver. */
/* Do an initial read of the RTC and set the system time to it. This
is analogous to what /sbin/hwclock -s would do on Linux. If that fails
or RTC is not supported, set the clock to the time of the last
modification of driftfile, so we at least get closer to the truth. */
if (initial_set) {
driftfile_time = get_driftfile_time();
if (driver.time_pre_init && driver.time_pre_init(driftfile_time)) {
driver_preinit_ok = 1;
} else {
driver_preinit_ok = 0;
if (driftfile_time)
apply_driftfile_time(driftfile_time);
if (!driver.time_pre_init || !driver.time_pre_init()) {
fallback_time_init();
}
}
@@ -168,9 +150,9 @@ RTC_Finalise(void)
/* ================================================== */
/* Start the processing to get a single measurement from the real time
clock, and use it to trim the system time, based on knowing the
drift rate of the RTC and the error the last time we set it. If the
TimePreInit routine has succeeded, we can be sure that the trim required
is not *too* large.
drift rate of the RTC and the error the last time we set it. The
TimePreInit routine has already run, so we can be sure that the
trim required is not *too* large.
We are called with a hook to a function to be called after the
initialisation is complete. We also call this if we cannot do the
@@ -179,7 +161,7 @@ RTC_Finalise(void)
void
RTC_TimeInit(void (*after_hook)(void *), void *anything)
{
if (driver_initialised && driver_preinit_ok) {
if (driver_initialised) {
(driver.time_init)(after_hook, anything);
} else {
(after_hook)(anything);

View File

@@ -86,8 +86,8 @@ static int skip_interrupts;
measured, together with a 'trim' that compensates these values for
any steps made to the RTC to bring it back into line
occasionally. The trim is in seconds. */
static time_t *rtc_sec = NULL;
static double *rtc_trim = NULL;
static time_t rtc_sec[MAX_SAMPLES];
static double rtc_trim[MAX_SAMPLES];
/* Reference time, against which delta times on the RTC scale are measured */
static time_t rtc_ref;
@@ -95,7 +95,7 @@ static time_t rtc_ref;
/* System clock (gettimeofday) samples associated with the above
samples. */
static struct timeval *system_times = NULL;
static struct timeval system_times[MAX_SAMPLES];
/* Number of samples currently stored. */
static int n_samples;
@@ -367,9 +367,6 @@ t_from_rtc(struct tm *stm) {
t2 = mktime(&temp2);
diff = t2 - t1;
if (t1 - diff == -1)
DEBUG_LOG(LOGF_RtcLinux, "Could not convert RTC time");
return t1 - diff;
}
@@ -382,13 +379,13 @@ read_hwclock_file(const char *hwclock_file)
char line[256];
int i;
if (!hwclock_file || !hwclock_file[0])
if (!hwclock_file)
return;
in = fopen(hwclock_file, "r");
if (!in) {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open %s : %s",
hwclock_file, strerror(errno));
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not open hwclockfile %s",
hwclock_file);
return;
}
@@ -405,7 +402,7 @@ read_hwclock_file(const char *hwclock_file)
} else if (i == 3 && !strncmp(line, "UTC", 3)) {
rtc_on_utc = 1;
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read RTC LOCAL/UTC setting from %s",
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read LOCAL/UTC setting from hwclockfile %s",
hwclock_file);
}
}
@@ -448,7 +445,7 @@ read_coefs_from_file(void)
&file_ref_offset,
&file_rate_ppm) == 4) {
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from %s",
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not read coefficients from RTC file %s",
coefs_file_name);
}
fclose(in);
@@ -533,10 +530,6 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int
RTC_Linux_Initialise(void)
{
rtc_sec = MallocArray(time_t, MAX_SAMPLES);
rtc_trim = MallocArray(double, MAX_SAMPLES);
system_times = MallocArray(struct timeval, MAX_SAMPLES);
/* Setup details depending on configuration options */
setup_config();
@@ -595,9 +588,6 @@ RTC_Linux_Finalise(void)
(void) RTC_Linux_WriteParameters();
}
Free(rtc_sec);
Free(rtc_trim);
Free(system_times);
}
/* ================================================== */
@@ -610,16 +600,14 @@ switch_interrupts(int onoff)
if (onoff) {
status = ioctl(fd, RTC_UIE_ON, 0);
if (status < 0) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
"enable", strerror(errno));
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not start measurement : %s", strerror(errno));
return;
}
skip_interrupts = 1;
} else {
status = ioctl(fd, RTC_UIE_OFF, 0);
if (status < 0) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not %s RTC interrupt : %s",
"disable", strerror(errno));
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not stop measurement : %s", strerror(errno));
return;
}
}
@@ -699,11 +687,10 @@ handle_initial_trim(void)
/* sys_error_now is positive if the system clock is fast */
sys_error_now = rtc_error_now - coef_seconds_fast;
LOG(LOGS_INFO, LOGF_RtcLinux, "System trim from RTC = %f", sys_error_now);
LCL_AccumulateOffset(sys_error_now, 0.0);
LOG(LOGS_INFO, LOGF_RtcLinux, "System clock off from RTC by %f seconds (slew)",
sys_error_now);
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid rtcfile coefficients");
LOG(LOGS_WARN, LOGF_RtcLinux, "No valid file coefficients, cannot trim system time");
}
coefs_valid = 0;
@@ -728,7 +715,7 @@ handle_relock_after_trim(void)
if (valid) {
write_coefs_to_file(1,ref,fast,saved_coef_gain_rate);
} else {
DEBUG_LOG(LOGF_RtcLinux, "Could not do regression after trim");
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not do regression after trim");
}
coefs_valid = 0;
@@ -863,6 +850,7 @@ read_from_device(void *any)
rtc_t = t_from_rtc(&rtc_tm);
if (rtc_t == (time_t)(-1)) {
LOG(LOGS_ERR, LOGF_RtcLinux, "Could not convert RTC time to timeval");
error = 1;
goto turn_off_interrupt;
}
@@ -888,7 +876,7 @@ turn_off_interrupt:
switch (operating_mode) {
case OM_INITIAL:
if (error) {
DEBUG_LOG(LOGF_RtcLinux, "Could not complete initial step due to errors");
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not complete initial step due to errors");
operating_mode = OM_NORMAL;
(after_init_hook)(after_init_hook_arg);
@@ -902,7 +890,7 @@ turn_off_interrupt:
case OM_AFTERTRIM:
if (error) {
DEBUG_LOG(LOGF_RtcLinux, "Could not complete after trim relock due to errors");
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not complete after trim relock due to errors");
operating_mode = OM_NORMAL;
switch_interrupts(0);
@@ -979,7 +967,7 @@ RTC_Linux_WriteParameters(void)
RTC behaviour than we do for the rest of the module. */
int
RTC_Linux_TimePreInit(time_t driftfile_time)
RTC_Linux_TimePreInit(void)
{
int fd, status;
struct rtc_time rtc_raw, rtc_raw_retry;
@@ -1044,23 +1032,18 @@ RTC_Linux_TimePreInit(time_t driftfile_time)
UTI_AddDoubleToTimeval(&new_sys_time, -accumulated_error, &new_sys_time);
if (new_sys_time.tv_sec < driftfile_time) {
LOG(LOGS_WARN, LOGF_RtcLinux, "RTC time before last driftfile modification (ignored)");
return 0;
}
UTI_DiffTimevalsToDouble(&sys_offset, &old_sys_time, &new_sys_time);
/* Set system time only if the step is larger than 1 second */
if (fabs(sys_offset) >= 1.0) {
if (LCL_ApplyStepOffset(sys_offset))
LOG(LOGS_INFO, LOGF_RtcLinux, "System time set from RTC");
LOG(LOGS_INFO, LOGF_RtcLinux, "Set system time, error in RTC = %f",
accumulated_error);
LCL_ApplyStepOffset(sys_offset);
}
} else {
LOG(LOGS_WARN, LOGF_RtcLinux, "Could not convert RTC reading to seconds since 1/1/1970");
return 0;
}
} else {
return 0;
}
return 1;
@@ -1100,8 +1083,7 @@ RTC_Linux_Trim(void)
if (fabs(coef_seconds_fast) > 1.0) {
LOG(LOGS_INFO, LOGF_RtcLinux, "RTC wrong by %.3f seconds (step)",
coef_seconds_fast);
LOG(LOGS_INFO, LOGF_RtcLinux, "Trimming RTC, error = %.3f seconds", coef_seconds_fast);
/* Do processing to set clock. Let R be the value we set the
RTC to, then in 500ms the RTC ticks (R+1) (see comments in

View File

@@ -30,7 +30,7 @@
extern int RTC_Linux_Initialise(void);
extern void RTC_Linux_Finalise(void);
extern int RTC_Linux_TimePreInit(time_t driftile_time);
extern int RTC_Linux_TimePreInit(void);
extern void RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything);
extern void RTC_Linux_StartMeasurements(void);

24
sched.c
View File

@@ -30,7 +30,6 @@
#include "sysincl.h"
#include "array.h"
#include "sched.h"
#include "memory.h"
#include "util.h"
@@ -69,7 +68,7 @@ typedef struct {
SCH_ArbitraryArgument arg;
} FileHandlerEntry;
static ARR_Instance file_handlers;
static FileHandlerEntry file_handlers[FD_SETSIZE];
/* Timestamp when last select() returned */
static struct timeval last_select_ts, last_select_ts_raw;
@@ -135,8 +134,6 @@ SCH_Initialise(void)
FD_ZERO(&read_fds);
n_read_fds = 0;
file_handlers = ARR_CreateInstance(sizeof (FileHandlerEntry));
n_timer_queue_entries = 0;
next_tqe_id = 0;
@@ -160,8 +157,6 @@ SCH_Initialise(void)
void
SCH_Finalise(void) {
ARR_DestroyInstance(file_handlers);
initialised = 0;
}
@@ -171,7 +166,6 @@ void
SCH_AddInputFileHandler
(int fd, SCH_FileHandler handler, SCH_ArbitraryArgument arg)
{
FileHandlerEntry *ptr;
assert(initialised);
@@ -185,12 +179,8 @@ SCH_AddInputFileHandler
++n_read_fds;
if (ARR_GetSize(file_handlers) < fd + 1)
ARR_SetSize(file_handlers, fd + 1);
ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
ptr->handler = handler;
ptr->arg = arg;
file_handlers[fd].handler = handler;
file_handlers[fd].arg = arg;
FD_SET(fd, &read_fds);
@@ -330,10 +320,6 @@ 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);
}
@@ -496,15 +482,13 @@ dispatch_timeouts(struct timeval *now) {
static void
dispatch_filehandlers(int nfh, fd_set *fhs)
{
FileHandlerEntry *ptr;
int fh = 0;
while (nfh > 0) {
if (FD_ISSET(fh, fhs)) {
/* This descriptor can be read from, dispatch its handler */
ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fh);
(ptr->handler)(ptr->arg);
(file_handlers[fh].handler)(file_handlers[fh].arg);
/* Decrement number of readable files still to find */
--nfh;

342
smooth.c
View File

@@ -1,342 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing time smoothing.
*/
#include "config.h"
#include "sysincl.h"
#include "conf.h"
#include "local.h"
#include "logging.h"
#include "reference.h"
#include "smooth.h"
#include "util.h"
/*
Time smoothing determines an offset that needs to be applied to the cooked
time to make it smooth for external observers. Observed offset and frequency
change slowly and there are no discontinuities. This can be used on an NTP
server to make it easier for the clients to track the time and keep their
clocks close together even when large offset or frequency corrections are
applied to the server's clock (e.g. after being offline for longer time).
Accumulated offset and frequency are smoothed out in three stages. In the
first stage, the frequency is changed at a constant rate (wander) up to a
maximum, in the second stage the frequency stays at the maximum for as long
as needed and in the third stage the frequency is brought back to zero.
|
max_freq +-------/--------\-------------
| /| |\
freq | / | | \
| / | | \
| / | | \
0 +--/----+--------+----\--------
| / | | | time
|/ | | |
stage 1 2 3
Integral of this function is the smoothed out offset. It's a continuous
piecewise polynomial with two quadratic parts and one linear.
*/
struct stage {
double wander;
double length;
};
#define NUM_STAGES 3
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
static int locked;
/* Maximum wander and frequency offset */
static double max_wander;
static double max_freq;
/* Frequency offset, time offset and the time of the last smoothing update */
static double smooth_freq;
static double smooth_offset;
static struct timeval last_update;
static void
get_smoothing(struct timeval *now, double *poffset, double *pfreq,
double *pwander)
{
double elapsed, length, offset, freq, wander;
int i;
UTI_DiffTimevalsToDouble(&elapsed, now, &last_update);
offset = smooth_offset;
freq = smooth_freq;
wander = 0.0;
for (i = 0; i < NUM_STAGES; i++) {
if (elapsed <= 0.0)
break;
length = stages[i].length;
if (length >= elapsed)
length = elapsed;
wander = stages[i].wander;
offset -= length * (2.0 * freq + wander * length) / 2.0;
freq += wander * length;
elapsed -= length;
}
if (elapsed > 0.0) {
wander = 0.0;
offset -= elapsed * freq;
}
*poffset = offset;
*pfreq = freq;
if (pwander)
*pwander = wander;
}
static void
update_stages(void)
{
double s1, s2, s, l1, l2, l3, lc, f, f2;
int i, dir;
/* Prepare the three stages so that the integral of the frequency offset
is equal to the offset that should be smoothed out */
s1 = smooth_offset / max_wander;
s2 = smooth_freq * smooth_freq / (2.0 * max_wander * max_wander);
l1 = l2 = l3 = 0.0;
/* Calculate the lengths of the 1st and 3rd stage assuming there is no
frequency limit. If length of the 1st stage comes out negative, switch
its direction. */
for (dir = -1; dir <= 1; dir += 2) {
s = dir * s1 + s2;
if (s >= 0.0) {
l3 = sqrt(s);
l1 = l3 - dir * smooth_freq / max_wander;
if (l1 >= 0.0)
break;
}
}
assert(dir <= 1 && l1 >= 0.0 && l3 >= 0.0);
/* If the limit was reached, shorten 1st+3rd stages and set a 2nd stage */
f = dir * smooth_freq + l1 * max_wander - max_freq;
if (f > 0.0) {
lc = f / max_wander;
/* No 1st stage if the frequency is already above the maximum */
if (lc > l1) {
lc = l1;
f2 = dir * smooth_freq;
} else {
f2 = max_freq;
}
l2 = lc * (2.0 + f / f2);
l1 -= lc;
l3 -= lc;
}
stages[0].wander = dir * max_wander;
stages[0].length = l1;
stages[1].wander = 0.0;
stages[1].length = l2;
stages[2].wander = -dir * max_wander;
stages[2].length = l3;
for (i = 0; i < NUM_STAGES; i++) {
DEBUG_LOG(LOGF_Smooth, "Smooth stage %d wander %e length %f",
i + 1, stages[i].wander, stages[i].length);
}
}
static void
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 || leap_only_mode)
SMT_Activate(now);
return;
}
get_smoothing(now, &smooth_offset, &smooth_freq, NULL);
smooth_offset += offset;
smooth_freq = (smooth_freq - freq) / (1.0 - freq);
last_update = *now;
update_stages();
DEBUG_LOG(LOGF_Smooth, "Smooth offset %e freq %e", smooth_offset, smooth_freq);
}
static void
handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
double delta;
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, &leap_only_mode);
if (max_freq <= 0.0 || max_wander <= 0.0) {
enabled = 0;
return;
}
enabled = 1;
locked = 1;
/* Convert from ppm */
max_freq *= 1e-6;
max_wander *= 1e-6;
LCL_AddParameterChangeHandler(handle_slew, NULL);
}
void SMT_Finalise(void)
{
}
int SMT_IsEnabled(void)
{
return enabled;
}
double
SMT_GetOffset(struct timeval *now)
{
double offset, freq;
if (!enabled)
return 0.0;
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;
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;
}

639
sources.c

File diff suppressed because it is too large Load Diff

View File

@@ -65,7 +65,7 @@ typedef enum {
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples);
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -74,11 +74,6 @@ extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_Se
extern void SRC_DestroyInstance(SRC_Instance instance);
/* Function to reset a source */
extern void SRC_ResetInstance(SRC_Instance instance);
/* Function to change the sources's reference ID and IP address */
extern void SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr);
/* Function to get the range of frequencies, relative to the given
source, that we believe the local clock lies within. The return
@@ -109,7 +104,7 @@ extern void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
indicates that the local clock is FAST relative to it.
root_delay and root_dispersion are in seconds, and are as per
RFC 5905. root_dispersion only includes the peer's root dispersion
RFC1305. root_dispersion only includes the peer's root dispersion
+ local sampling precision + skew dispersion accrued during the
measurement. It is the job of the source statistics algorithms +
track.c to add on the extra dispersion due to the residual standard
@@ -129,6 +124,14 @@ extern void SRC_SetActive(SRC_Instance inst);
/* This routine sets the source as not receiving reachability updates */
extern void SRC_UnsetActive(SRC_Instance inst);
/* This routine indicates that packets with valid headers are being
received from the designated source */
extern void SRC_SetSelectable(SRC_Instance instance);
/* This routine indicates that we are no longer receiving packets with
valid headers from the designated source */
extern void SRC_UnsetSelectable(SRC_Instance instance);
/* This routine updates the reachability register */
extern void SRC_UpdateReachability(SRC_Instance inst, int reachable);
@@ -137,11 +140,11 @@ extern void SRC_ResetReachability(SRC_Instance inst);
/* This routine is used to select the best source from amongst those
we currently have valid data on, and use it as the tracking base
for the local time. Updates are made to the local reference only
when the selected source was updated (set as updated_inst) since
the last reference update. This avoids updating the frequency
for the local time. Updates are only made to the local reference
if a new source is selected or updated_inst is the selected
reference source. (This avoids updating the frequency
tracking for every sample from other sources - only the ones from
the selected reference make a difference. */
the selected reference make a difference) */
extern void SRC_SelectSource(SRC_Instance updated_inst);
/* Force reselecting the best source */
@@ -177,6 +180,14 @@ extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struc
extern SRC_Type SRC_GetType(int index);
typedef enum {
SRC_Skew_Decrease,
SRC_Skew_Nochange,
SRC_Skew_Increase
} SRC_Skew_Direction;
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */

View File

@@ -43,6 +43,10 @@
to store per source */
#define MAX_SAMPLES 64
/* User defined maximum and minimum number of samples */
int max_samples;
int min_samples;
/* This is the assumed worst case bound on an unknown frequency,
2000ppm, which would be pretty bad */
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
@@ -64,10 +68,6 @@ struct SST_Stats_Record {
uint32_t refid;
IPAddr *ip_addr;
/* User defined minimum and maximum number of samples */
int min_samples;
int max_samples;
/* Number of samples currently stored. The samples are stored in circular
buffer. */
int n_samples;
@@ -108,6 +108,9 @@ struct SST_Stats_Record {
about estimated_frequency */
double skew;
/* This is the direction the skew went in at the last sample */
SST_Skew_Direction skew_dirn;
/* This is the estimated residual variance of the data points */
double variance;
@@ -119,7 +122,8 @@ struct SST_Stats_Record {
sample times. In this module, we use the convention that
positive means the local clock is FAST of the source and negative
means it is SLOW. This is contrary to the convention in the NTP
stuff. */
stuff; that part of the code is written to correspond with
RFC1305 conventions. */
double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
/* This is an array of the offsets as originally measured. Local
@@ -163,6 +167,8 @@ SST_Initialise(void)
logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics",
" Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr")
: -1;
max_samples = CNF_GetMaxSamples();
min_samples = CNF_GetMinSamples();
}
/* ================================================== */
@@ -176,15 +182,13 @@ SST_Finalise(void)
/* This function creates a new instance of the statistics handler */
SST_Stats
SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples)
SST_CreateInstance(uint32_t refid, IPAddr *addr)
{
SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record);
inst->refid = refid;
inst->ip_addr = addr;
inst->min_samples = min_samples;
inst->max_samples = max_samples;
SST_SetRefid(inst, refid, addr);
SST_ResetInstance(inst);
return inst;
@@ -212,6 +216,7 @@ SST_ResetInstance(SST_Stats inst)
inst->min_delay_sample = 0;
inst->estimated_frequency = 0;
inst->skew = 2000.0e-6;
inst->skew_dirn = SST_Skew_Nochange;
inst->estimated_offset = 0.0;
inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */
inst->offset_time.tv_sec = 0;
@@ -220,15 +225,6 @@ SST_ResetInstance(SST_Stats inst)
inst->nruns = 0;
}
/* ================================================== */
void
SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr)
{
inst->refid = refid;
inst->ip_addr = addr;
}
/* ================================================== */
/* This function is called to prune the register down when it is full.
For now, just discard the oldest sample. */
@@ -263,7 +259,7 @@ SST_AccumulateSample(SST_Stats inst, struct timeval *sample_time,
/* Make room for the new sample */
if (inst->n_samples > 0 &&
(inst->n_samples == MAX_SAMPLES || inst->n_samples == inst->max_samples)) {
(inst->n_samples == MAX_SAMPLES || inst->n_samples == max_samples)) {
prune_register(inst, 1);
}
@@ -448,7 +444,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
offsets + inst->runs_samples, weights,
inst->n_samples, inst->runs_samples,
inst->min_samples,
min_samples,
&est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom);
@@ -471,6 +467,18 @@ SST_DoNewRegression(SST_Stats inst)
stress = fabs(old_freq - inst->estimated_frequency) / old_skew;
if (best_start > 0) {
/* If we are throwing old data away, retain the current
assumptions about the skew */
inst->skew_dirn = SST_Skew_Nochange;
} else {
if (inst->skew < old_skew) {
inst->skew_dirn = SST_Skew_Decrease;
} else {
inst->skew_dirn = SST_Skew_Increase;
}
}
if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d",
UTI_TimeToLogForm(inst->offset_time.tv_sec),
@@ -529,19 +537,11 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance,
double *first_sample_ago,
double *last_sample_ago,
int *select_ok)
double *variance, int *select_ok)
{
double offset, sample_elapsed;
int i, j;
if (!inst->n_samples) {
*select_ok = 0;
return;
}
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
@@ -570,16 +570,10 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
}
#endif
i = get_runsbuf_index(inst, 0);
UTI_DiffTimevalsToDouble(first_sample_ago, now, &inst->sample_times[i]);
i = get_runsbuf_index(inst, inst->n_samples - 1);
UTI_DiffTimevalsToDouble(last_sample_ago, now, &inst->sample_times[i]);
*select_ok = inst->regression_ok;
DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f first_ago=%f last_ago=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance,
*first_sample_ago, *last_sample_ago, *select_ok);
DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance, *select_ok);
}
/* ================================================== */
@@ -631,23 +625,27 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
sample = &(inst->sample_times[i]);
prev = *sample;
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = inst->offsets[i];
inst->offsets[i] += delta_time;
DEBUG_LOG(LOGF_SourceStats, "i=%d old_st=[%s] new_st=[%s] old_off=%f new_off=%f",
i, UTI_TimevalToString(&prev), UTI_TimevalToString(sample),
prev_offset, inst->offsets[i]);
}
/* Update the regression estimates */
/* Do a half-baked update to the regression estimates */
prev = inst->offset_time;
prev_offset = inst->estimated_offset;
prev_freq = inst->estimated_frequency;
UTI_AdjustTimeval(&(inst->offset_time), when, &(inst->offset_time),
&delta_time, dfreq, doffset);
inst->estimated_offset += delta_time;
inst->estimated_frequency = (inst->estimated_frequency - dfreq) / (1.0 - dfreq);
inst->estimated_frequency -= dfreq;
DEBUG_LOG(LOGF_SourceStats, "n=%d m=%d old_off_time=%s new=%s old_off=%f new_off=%f old_freq=%.3f new_freq=%.3f",
inst->n_samples, inst->runs_samples,
DEBUG_LOG(LOGF_SourceStats, "old_off_time=[%s] new=[%s] old_off=%f new_off=%f old_freq=%.3fppm new_freq=%.3fppm",
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
prev_offset, inst->estimated_offset,
1.0e6 * prev_freq, 1.0e6 * inst->estimated_frequency);
1.0e6*prev_freq, 1.0e6*inst->estimated_frequency);
}
/* ================================================== */
@@ -853,6 +851,14 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timeval *now
}
}
/* ================================================== */
SST_Skew_Direction SST_LastSkewChange(SST_Stats inst)
{
return inst->skew_dirn;
}
/* ================================================== */
int

View File

@@ -38,7 +38,7 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr, int min_samples, int max_samples);
extern SST_Stats SST_CreateInstance(uint32_t refid, IPAddr *addr);
/* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst);
@@ -46,9 +46,6 @@ extern void SST_DeleteInstance(SST_Stats inst);
/* This function resets an instance */
extern void SST_ResetInstance(SST_Stats inst);
/* This function changes the reference ID and IP address */
extern void SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr);
/* This function accumulates a single sample into the statistics handler
sample_time is the epoch at which the sample is to be considered to
@@ -58,6 +55,10 @@ extern void SST_SetRefid(SST_Stats inst, uint32_t refid, IPAddr *addr);
seconds. Positive indicates that the local clock if FAST (contrary
to the NTP parts of the software)
root_distance is the Lambda+Delta/2 term in RFC1305, but excluding
the extra dispersion due to the residual standard deviation after
we have done the regression fit.
stratum is the stratum of the source from which the sample came.
*/
@@ -82,10 +83,7 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
double *variance,
double *first_sample_ago,
double *last_sample_ago,
int *select_ok);
double *variance, int *select_ok);
/* Get data needed when setting up tracking on this source */
extern void
@@ -137,6 +135,14 @@ extern void SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct
extern void SST_DoSourcestatsReport(SST_Stats inst, RPT_SourcestatsReport *report, struct timeval *now);
typedef enum {
SST_Skew_Decrease,
SST_Skew_Nochange,
SST_Skew_Increase
} SST_Skew_Direction;
extern SST_Skew_Direction SST_LastSkewChange(SST_Stats inst);
extern int SST_Samples(SST_Stats inst);
#endif /* GOT_SOURCESTATS_H */

View File

@@ -38,11 +38,7 @@ typedef struct {
int iburst;
int min_stratum;
int poll_target;
int version;
int max_sources;
int min_samples;
int max_samples;
uint32_t authkey;
unsigned long authkey;
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
@@ -53,14 +49,11 @@ typedef struct {
#define SRC_DEFAULT_MINPOLL 6
#define SRC_DEFAULT_MAXPOLL 10
#define SRC_DEFAULT_PRESEND_MINPOLL 0
#define SRC_DEFAULT_MAXDELAY 3.0
#define SRC_DEFAULT_MAXDELAY 16.0
#define SRC_DEFAULT_MAXDELAYRATIO 0.0
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6
#define SRC_DEFAULT_MAXSOURCES 4
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
#define INACTIVE_AUTHKEY 0
#define INACTIVE_AUTHKEY 0UL
#endif /* GOT_SRCPARAMS_H */

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
* Copyright (C) Richard P. Curnow 1997-2002
*
* 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
@@ -21,47 +21,18 @@
=======================================================================
Utility functions for memory allocation.
Replacement strerror function for systems that don't have it
*/
#include "config.h"
#include "logging.h"
#include "memory.h"
#ifdef SUNOS
void *
Malloc(size_t size)
{
void *r;
#include <errno.h>
extern char *sys_errlist[];
r = malloc(size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
char *strerror(int n) {
return sys_errlist[n];
}
void *
Realloc(void *ptr, size_t size)
{
void *r;
r = realloc(ptr, size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}
char *
Strdup(const char *s)
{
void *r;
r = strdup(s);
if (!r)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}
#endif /* SUNOS */

364
stubs.c
View File

@@ -1,364 +0,0 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Function replacements needed when optional features are disabled.
*/
#include "config.h"
#include "clientlog.h"
#include "cmdmon.h"
#include "keys.h"
#include "logging.h"
#include "manual.h"
#include "memory.h"
#include "nameserv.h"
#include "nameserv_async.h"
#include "ntp_core.h"
#include "ntp_io.h"
#include "ntp_sources.h"
#include "refclock.h"
#include "sched.h"
#ifndef FEAT_ASYNCDNS
#define MAX_ADDRESSES 16
/* This is a blocking implementation used when asynchronous resolving is not available */
struct DNS_Async_Instance {
const char *name;
DNS_NameResolveHandler handler;
void *arg;
};
static void
resolve_name(void *anything)
{
struct DNS_Async_Instance *inst;
IPAddr addrs[MAX_ADDRESSES];
DNS_Status status;
int i;
inst = (struct DNS_Async_Instance *)anything;
status = DNS_Name2IPAddress(inst->name, addrs, MAX_ADDRESSES);
for (i = 0; status == DNS_Success && i < MAX_ADDRESSES &&
addrs[i].family != IPADDR_UNSPEC; i++)
;
(inst->handler)(status, i, addrs, inst->arg);
Free(inst);
}
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
struct DNS_Async_Instance *inst;
inst = MallocNew(struct DNS_Async_Instance);
inst->name = name;
inst->handler = handler;
inst->arg = anything;
SCH_AddTimeoutByDelay(0.0, resolve_name, inst);
}
#endif /* !FEAT_ASYNCDNS */
#ifndef FEAT_CMDMON
void
CAM_Initialise(int family)
{
}
void
CAM_Finalise(void)
{
}
void
CAM_OpenUnixSocket(void)
{
}
int
CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
{
return 1;
}
void
MNL_Initialise(void)
{
}
void
MNL_Finalise(void)
{
}
#endif /* !FEAT_CMDMON */
#ifndef FEAT_NTP
void
NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
{
}
void
NCR_Initialise(void)
{
}
void
NCR_Finalise(void)
{
}
int
NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
{
return 1;
}
int
NCR_CheckAccessRestriction(IPAddr *ip_addr)
{
return 0;
}
void
NIO_Initialise(int family)
{
}
void
NIO_Finalise(void)
{
}
void
NSR_Initialise(void)
{
}
void
NSR_Finalise(void)
{
}
NSR_Status
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{
return NSR_TooManySources;
}
void
NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params)
{
}
NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{
return NSR_NoSuchSource;
}
void
NSR_RemoveAllSources(void)
{
}
void
NSR_HandleBadSource(IPAddr *address)
{
}
void
NSR_RefreshAddresses(void)
{
}
void
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
{
if (handler)
(handler)();
}
void
NSR_ResolveSources(void)
{
}
void NSR_StartSources(void)
{
}
void NSR_AutoStartSources(void)
{
}
int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{
return 0;
}
int
NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
{
return 0;
}
int
NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
{
return 0;
}
int
NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
{
return 0;
}
int
NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
{
return 0;
}
int
NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
{
return 0;
}
int
NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
{
return 0;
}
int
NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
{
return 0;
}
void
NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
memset(report, 0, sizeof (*report));
}
void
NSR_GetActivityReport(RPT_ActivityReport *report)
{
memset(report, 0, sizeof (*report));
}
#ifndef FEAT_CMDMON
void
CLG_Initialise(void)
{
}
void
CLG_Finalise(void)
{
}
void
DNS_SetAddressFamily(int family)
{
}
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{
return DNS_Failure;
}
void
KEY_Initialise(void)
{
}
void
KEY_Finalise(void)
{
}
#endif /* !FEAT_CMDMON */
#endif /* !FEAT_NTP */
#ifndef FEAT_REFCLOCK
void
RCL_Initialise(void)
{
}
void
RCL_Finalise(void)
{
}
int
RCL_AddRefclock(RefclockParameters *params)
{
return 0;
}
void
RCL_StartRefclocks(void)
{
}
void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{
memset(report, 0, sizeof (*report));
}
#endif /* !FEAT_REFCLOCK */

80
sys.c
View File

@@ -27,21 +27,23 @@
#include "config.h"
#include "sysincl.h"
#include "sys.h"
#include "logging.h"
#if defined(LINUX)
#if defined (LINUX)
#include "sys_linux.h"
#elif defined(SOLARIS)
#endif
#if defined (SOLARIS)
#include "sys_solaris.h"
#elif defined(SUNOS)
#endif
#if defined (SUNOS)
#include "sys_sunos.h"
#elif defined(NETBSD) || defined(FREEBSD)
#endif
#if defined (__NetBSD__)
#include "sys_netbsd.h"
#elif defined(MACOSX)
#include "sys_macosx.h"
#endif
/* ================================================== */
@@ -49,19 +51,23 @@
void
SYS_Initialise(void)
{
#if defined(LINUX)
SYS_Linux_Initialise();
#elif defined(SOLARIS)
SYS_Solaris_Initialise();
#elif defined(SUNOS)
SYS_SunOS_Initialise();
#elif defined(NETBSD) || defined(FREEBSD)
SYS_NetBSD_Initialise();
#elif defined(MACOSX)
SYS_MacOSX_Initialise();
#else
#error Unknown system
#endif
#if defined(SOLARIS)
SYS_Solaris_Initialise();
#endif
#if defined(SUNOS)
SYS_SunOS_Initialise();
#endif
#if defined(__NetBSD__)
SYS_NetBSD_Initialise();
#endif
}
/* ================================================== */
@@ -69,29 +75,30 @@ SYS_Initialise(void)
void
SYS_Finalise(void)
{
#if defined(LINUX)
SYS_Linux_Finalise();
#elif defined(SOLARIS)
#endif
#if defined(SOLARIS)
SYS_Solaris_Finalise();
#elif defined(SUNOS)
#endif
#if defined(SUNOS)
SYS_SunOS_Finalise();
#elif defined(NETBSD) || defined(FREEBSD)
#endif
#if defined(__NetBSD__)
SYS_NetBSD_Finalise();
#elif defined(MACOSX)
SYS_MacOSX_Finalise();
#else
#error Unknown system
#endif
}
/* ================================================== */
void SYS_DropRoot(uid_t uid, gid_t gid)
void SYS_DropRoot(char *user)
{
#if defined(LINUX) && defined (FEAT_PRIVDROP)
SYS_Linux_DropRoot(uid, gid);
#elif defined(NETBSD) && defined(FEAT_PRIVDROP)
SYS_NetBSD_DropRoot(uid, gid);
#if defined(LINUX) && defined (FEAT_LINUXCAPS)
SYS_Linux_DropRoot(user);
#else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");
#endif
@@ -99,23 +106,10 @@ void SYS_DropRoot(uid_t uid, gid_t gid)
/* ================================================== */
void SYS_EnableSystemCallFilter(int level)
{
#if defined(LINUX) && defined(FEAT_SCFILTER)
SYS_Linux_EnableSystemCallFilter(level);
#else
LOG_FATAL(LOGF_Sys, "system call filter not supported");
#endif
}
/* ================================================== */
void SYS_SetScheduler(int SchedPriority)
{
#if defined(LINUX) && defined(HAVE_SCHED_SETSCHEDULER)
SYS_Linux_SetScheduler(SchedPriority);
#elif defined(MACOSX)
SYS_MacOSX_SetScheduler(SchedPriority);
#else
LOG_FATAL(LOGF_Sys, "scheduler priority setting not supported");
#endif

8
sys.h
View File

@@ -35,12 +35,8 @@ extern void SYS_Initialise(void);
/* Called at the end of the run to do final clean-up */
extern void SYS_Finalise(void);
/* Drop root privileges to the specified user and group */
extern void SYS_DropRoot(uid_t uid, gid_t gid);
/* Enable a system call filter to allow only system calls
which chronyd normally needs after initialization */
extern void SYS_EnableSystemCallFilter(int level);
/* Drop root privileges to the specified user */
extern void SYS_DropRoot(char *user);
extern void SYS_SetScheduler(int SchedPriority);
extern void SYS_LockMemory(void);

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014-2015
* Copyright (C) Miroslav Lichvar 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
@@ -39,12 +39,9 @@
/* ================================================== */
/* System clock drivers */
/* System clock frequency drivers */
static lcl_ReadFrequencyDriver drv_read_freq;
static lcl_SetFrequencyDriver drv_set_freq;
static lcl_SetSyncStatusDriver drv_set_sync_status;
static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_OffsetCorrectionDriver drv_get_offset_correction;
/* Current frequency as requested by the local module (in ppm) */
static double base_freq;
@@ -87,16 +84,6 @@ static double correction_rate;
real frequency of the clock */
static double slew_error;
/* Minimum offset that the system driver can slew faster than the maximum
frequency offset that it allows to be set directly */
static double fastslew_min_offset;
/* Maximum slew rate of the system driver */
static double fastslew_max_rate;
/* Flag indicating that the system driver is currently slewing */
static int fastslew_active;
/* ================================================== */
static void handle_end_of_slew(void *anything);
@@ -119,50 +106,6 @@ handle_step(struct timeval *raw, struct timeval *cooked, double dfreq,
}
}
/* ================================================== */
static void
start_fastslew(void)
{
if (!drv_accrue_offset)
return;
drv_accrue_offset(offset_register, 0.0);
DEBUG_LOG(LOGF_SysGeneric, "fastslew offset=%e", offset_register);
offset_register = 0.0;
fastslew_active = 1;
}
/* ================================================== */
static void
stop_fastslew(struct timeval *now)
{
double corr;
if (!drv_get_offset_correction || !fastslew_active)
return;
/* Cancel the remaining offset */
drv_get_offset_correction(now, &corr, NULL);
drv_accrue_offset(corr, 0.0);
offset_register -= corr;
}
/* ================================================== */
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 */
@@ -182,8 +125,6 @@ update_slew(void)
UTI_DiffTimevalsToDouble(&duration, &now, &slew_start);
offset_register -= slew_freq * duration;
stop_fastslew(&now);
/* Estimate how long should the next slew take */
if (fabs(offset_register) < MIN_OFFSET_CORRECTION) {
duration = MAX_SLEW_TIMEOUT;
@@ -201,16 +142,12 @@ update_slew(void)
else if (corr_freq > max_corr_freq)
corr_freq = max_corr_freq;
/* Let the system driver perform the slew if the requested frequency
offset is too large for the frequency driver */
if (drv_accrue_offset && fabs(corr_freq) >= fastslew_max_rate &&
fabs(offset_register) > fastslew_min_offset) {
start_fastslew();
corr_freq = 0.0;
}
/* Get the new real frequency and clamp it */
total_freq = clamp_freq(base_freq + corr_freq * (1.0e6 - base_freq));
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;
/* Set the new frequency (the actual frequency returned by the call may be
slightly different from the requested frequency due to rounding) */
@@ -229,8 +166,8 @@ update_slew(void)
/* Compute the duration of the slew and clamp it. If the slewing frequency
is zero or has wrong sign (e.g. due to rounding in the frequency driver or
when base_freq is larger than max_freq, or fast slew is active), use the
maximum timeout and try again on the next update. */
when base_freq is larger than max_freq), use maximum timeout and try again
on the next update. */
if (fabs(offset_register) < MIN_OFFSET_CORRECTION ||
offset_register * slew_freq <= 0.0) {
duration = MAX_SLEW_TIMEOUT;
@@ -300,31 +237,19 @@ static void
offset_convert(struct timeval *raw,
double *corr, double *err)
{
double duration, fastslew_corr, fastslew_err;
double duration;
UTI_DiffTimevalsToDouble(&duration, raw, &slew_start);
if (drv_get_offset_correction && fastslew_active) {
drv_get_offset_correction(raw, &fastslew_corr, &fastslew_err);
if (fastslew_corr == 0.0 && fastslew_err == 0.0)
fastslew_active = 0;
} else {
fastslew_corr = fastslew_err = 0.0;
}
*corr = slew_freq * duration + fastslew_corr - offset_register;
if (err) {
*err = fastslew_err;
if (fabs(duration) <= max_freq_change_delay)
*err += slew_error;
}
*corr = slew_freq * duration - offset_register;
if (err)
*err = fabs(duration) <= max_freq_change_delay ? slew_error : 0.0;
}
/* ================================================== */
/* Positive means currently fast of true time, i.e. jump backwards */
static int
static void
apply_step_offset(double offset)
{
struct timeval old_time, new_time;
@@ -334,32 +259,13 @@ apply_step_offset(double offset)
UTI_AddDoubleToTimeval(&old_time, -offset, &new_time);
if (settimeofday(&new_time, NULL) < 0) {
DEBUG_LOG(LOGF_SysGeneric, "settimeofday() failed");
return 0;
LOG_FATAL(LOGF_SysGeneric, "settimeofday() failed");
}
LCL_ReadRawTime(&old_time);
UTI_DiffTimevalsToDouble(&err, &old_time, &new_time);
lcl_InvokeDispersionNotifyHandlers(fabs(err));
return 1;
}
/* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
double offset;
offset = fabs(offset_register);
if (est_error < offset)
est_error = offset;
max_error += offset;
if (drv_set_sync_status)
drv_set_sync_status(synchronised, est_error, max_error);
}
/* ================================================== */
@@ -369,19 +275,12 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset,
double min_fastslew_offset, double max_fastslew_rate,
lcl_AccrueOffsetDriver sys_accrue_offset,
lcl_OffsetCorrectionDriver sys_get_offset_correction,
lcl_SetLeapDriver sys_set_leap,
lcl_SetSyncStatusDriver sys_set_sync_status)
lcl_SetLeapDriver sys_set_leap)
{
max_freq = max_set_freq_ppm;
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
drv_read_freq = sys_read_freq;
drv_set_freq = sys_set_freq;
drv_accrue_offset = sys_accrue_offset;
drv_get_offset_correction = sys_get_offset_correction;
drv_set_sync_status = sys_set_sync_status;
base_freq = (*drv_read_freq)();
slew_freq = 0.0;
@@ -389,14 +288,10 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
max_corr_freq = CNF_GetMaxSlewRate() / 1.0e6;
fastslew_min_offset = min_fastslew_offset;
fastslew_max_rate = max_fastslew_rate / 1.0e6;
fastslew_active = 0;
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, sys_apply_step_offset ?
sys_apply_step_offset : apply_step_offset,
offset_convert, sys_set_leap, set_sync_status);
offset_convert, sys_set_leap);
LCL_AddParameterChangeHandler(handle_step, NULL);
}
@@ -406,8 +301,6 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
void
SYS_Generic_Finalise(void)
{
struct timeval now;
/* Must *NOT* leave a slew running - clock could drift way off
if the daemon is not restarted */
if (slew_timer_running) {
@@ -415,10 +308,7 @@ SYS_Generic_Finalise(void)
slew_timer_running = 0;
}
(*drv_set_freq)(clamp_freq(base_freq));
LCL_ReadRawTime(&now);
stop_fastslew(&now);
(*drv_set_freq)(base_freq);
}
/* ================================================== */

Some files were not shown because too many files have changed in this diff Show More