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
92 changed files with 3924 additions and 4013 deletions

View File

@@ -38,9 +38,14 @@ DESTDIR=
HASH_OBJ = @HASH_OBJ@ HASH_OBJ = @HASH_OBJ@
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \ OBJS = util.o sched.o regress.o local.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \ sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sys.o tempcomp.o util.o $(HASH_OBJ) 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@ EXTRA_OBJS=@EXTRA_OBJECTS@

42
NEWS
View File

@@ -1,33 +1,19 @@
New in version 2.0 New in version 1.31.2
================== =====================
Enhancements Security fixes
------------ --------------
* Update to NTP version 4 (RFC 5905) * Restrict authentication of NTP server/peer to specified key (CVE-2016-1567)
* Add pool directive to specify pool of NTP servers
* 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, peer or broadcast is configured)
* Change default bindcmdaddress to loopback address
* 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 New in version 1.31.1
--------- =====================
* Fix accepting requests from configured sources when acquisitionport
is equal to server port Security fixes
* Fix allocation of slots saving replies to authenticated commands --------------
* Protect authenticated symmetric NTP associations against DoS attacks
(CVE-2015-1853)
* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821)
* Fix initialization of reply slots for authenticated commands (CVE-2015-1822)
New in version 1.31 New in version 1.31
=================== ===================

3
README
View File

@@ -41,8 +41,7 @@ session to the next)
With a good reference clock the accuracy can reach one microsecond. With a good reference clock the accuracy can reach one microsecond.
chronyd can also operate as an NTPv4 (RFC 5905) server, peer and broadcast chronyd can also operate as an RFC1305-compatible NTP server and peer.
server.
What will chrony run on? What will chrony run on?

View File

@@ -199,7 +199,10 @@ set_subnet(TableNode *start_node,
/* How many subnet entries to set : 1->8, 2->4, 3->2 */ /* How many subnet entries to set : 1->8, 2->4, 3->2 */
N = 1 << (NBITS-bits_to_go); N = 1 << (NBITS-bits_to_go);
subnet = get_subnet(ip, bits_consumed);
subnet = get_subnet(ip, bits_consumed) & ~(N - 1);
assert(subnet + N <= TABLE_SIZE);
if (!(node->extended)) { if (!(node->extended)) {
open_node(node); open_node(node);
} }
@@ -363,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 #if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits) 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, extern int ADF_IsAllowed(ADF_AuthTable table,
IPAddr *ip); 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 */ #endif /* GOT_ADDRFILT_H */

121
array.c
View File

@@ -1,121 +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;
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)
{
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;
}
array->data = Realloc(array->data, array->elem_size * array->allocated);
}
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 + 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. 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
@@ -21,47 +21,17 @@
======================================================================= =======================================================================
Utility functions for memory allocation. Deal with broadcast server functions.
*/ */
#include "config.h" #ifndef GOT_BROADCAST_H
#define GOT_BROADCAST_H
#include "logging.h" #include "addressing.h"
#include "memory.h"
void * extern void BRD_Initialise(void);
Malloc(size_t size) extern void BRD_Finalise(void);
{ extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
void *r;
r = malloc(size); #endif /* GOT_BROADCAST_H */
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
return r;
}
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;
}

13
candm.h
View File

@@ -88,8 +88,7 @@
#define REQ_MODIFY_MAXDELAYDEVRATIO 47 #define REQ_MODIFY_MAXDELAYDEVRATIO 47
#define REQ_RESELECT 48 #define REQ_RESELECT 48
#define REQ_RESELECTDISTANCE 49 #define REQ_RESELECTDISTANCE 49
#define REQ_MODIFY_MAKESTEP 50 #define N_REQUEST_TYPES 50
#define N_REQUEST_TYPES 51
/* Special utoken value used to log on with first exchange being the /* Special utoken value used to log on with first exchange being the
password. (This time value has long since gone by) */ password. (This time value has long since gone by) */
@@ -188,12 +187,6 @@ typedef struct {
int32_t EOR; int32_t EOR;
} REQ_Modify_Maxupdateskew; } REQ_Modify_Maxupdateskew;
typedef struct {
int32_t limit;
Float threshold;
int32_t EOR;
} REQ_Modify_Makestep;
typedef struct { typedef struct {
Timeval ts; Timeval ts;
int32_t EOR; int32_t EOR;
@@ -369,8 +362,7 @@ typedef struct {
subnets accessed and client accesses subnets accessed and client accesses
Version 6 : added padding to requests to prevent amplification attack, Version 6 : added padding to requests to prevent amplification attack,
changed maximum number of samples in manual list to 16, new commands: modify changed maximum number of samples in manual list to 16
makestep
*/ */
#define PROTO_VERSION_NUMBER 6 #define PROTO_VERSION_NUMBER 6
@@ -415,7 +407,6 @@ typedef struct {
REQ_Modify_Minstratum modify_minstratum; REQ_Modify_Minstratum modify_minstratum;
REQ_Modify_Polltarget modify_polltarget; REQ_Modify_Polltarget modify_polltarget;
REQ_Modify_Maxupdateskew modify_maxupdateskew; REQ_Modify_Maxupdateskew modify_maxupdateskew;
REQ_Modify_Makestep modify_makestep;
REQ_Logon logon; REQ_Logon logon;
REQ_Settime settime; REQ_Settime settime;
REQ_Local local; REQ_Local local;

View File

@@ -11,12 +11,12 @@ chrony \- programs for keeping computer clocks accurate
\fBchrony\fR is a pair of programs for keeping computer clocks accurate. \fBchrony\fR is a pair of programs for keeping computer clocks accurate.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a \fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be command-line interface to it. Time reference sources for chronyd can be
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's 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 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 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 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 (through \fIchronyc\fR) to support computers with dial-up/intermittent access
to the Internet, and it can also act as an NTP server. to the Internet, and it can also act as an RFC1305-compatible NTP server.
.SH USAGE .SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to \fIchronyc\fR is a command-line interface program which can be used to
@@ -51,8 +51,7 @@ session to the next)
With a good reference clock the accuracy can reach one microsecond. With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and \fIchronyd\fR can also operate as an RFC1305-compatible NTP server and peer.
broadcast server.
.SH "SEE ALSO" .SH "SEE ALSO"
.BR chronyc(1), .BR chronyc(1),

View File

@@ -12,44 +12,30 @@ boot time.
Assuming that you have found some servers, you need to set up a Assuming that you have found some servers, you need to set up a
configuration file to run \fIchrony\fR. The (compiled-in) default location configuration file to run \fIchrony\fR. The (compiled-in) default location
for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your NTP for this file is \fB@SYSCONFDIR@/chrony.conf\fR. Assuming that your ntp servers
servers are called `foo.example.net', `bar.example.net' and `baz.example.net', are called `a.b.c' and `d.e.f', your \fBchrony.conf\fR file could contain
your \fBchrony.conf\fR file could contain as a minimum as a minimum
.EX server a.b.c
server foo.example.net server d.e.f
server bar.example.net server g.h.i
server baz.example.net
.EE
However, you will probably want to include some of the other directives However, you will probably want to include some of the other directives
described in detail in the documentation supplied with the distribution described in detail in the documentation supplied with the distribution
(\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be (\fIchrony.txt\fR and \fIchrony.texi\fR). The following directives may be
particularly useful : `driftfile', `makestep', `rtcsync'. Also, the `iburst' particularly useful : `driftfile', `generatecommandkey', `keyfile', `makestep'.
server option is useful to speed up the initial synchronization. The smallest Also, the `iburst' server option is useful to speed up the initial
useful configuration file would look something like synchronization. The smallest useful configuration file would look something
like
.EX server a.b.c iburst
server foo.example.net iburst server d.e.f iburst
server bar.example.net iburst server g.h.i iburst
server baz.example.net iburst keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
makestep 10 3 makestep 10 3
rtcsync
.EE
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the `pool' directive
instead of multiple `server' directives in order to allow \fIchronyd\fR to
replace unreachable or bad servers automatically. The configuration file could
in this case look like
.EX
pool pool.ntp.org iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
rtcsync
.EE
.SH "SEE ALSO" .SH "SEE ALSO"
.BR chrony(1), .BR chrony(1),

View File

@@ -94,9 +94,10 @@ Data Security, Inc. MD5 Message-Digest Algorithm} for authenticating
messages between different machines on the network. messages between different machines on the network.
In writing the @code{chronyd} program, extensive use has been made of In writing the @code{chronyd} program, extensive use has been made of
RFC 1305 and RFC 5905, written by David Mills. The source code of RFC1305, written by David Mills. The @code{ntp} suite's source code has
the NTP reference implementation has been used to check details of the been occasionally used to check details of the protocol that the RFC did
protocol. not make absolutely clear. The core algorithms in @code{chronyd} are
all completely distinct from @code{ntp}, however.
@c }}} @c }}}
@c {{{ S:Availability @c {{{ S:Availability
@node Availability @node Availability
@@ -210,10 +211,11 @@ Things @code{ntpd} can do that @code{chronyd} can't:
@itemize @bullet @itemize @bullet
@item @item
@code{ntpd} supports all operating modes from RFC 5905, including @code{ntpd} fully supports NTP version 4 (RFC5905), including broadcast,
broadcast, multicast and manycast client / server. It supports the multicast, manycast clients / servers and the orphan mode. It also
orphan mode and it also supports authentication based on public-key supports extra authentication schemes based on public-key cryptography
cryptography described in RFC 5906. (RFC5906). @code{chronyd} uses NTP version 3 (RFC1305), which is
compatible with version 4.
@item @item
@code{ntpd} has been ported to more types of computer / operating @code{ntpd} has been ported to more types of computer / operating
@@ -430,15 +432,15 @@ install-info /usr/local/share/info/chrony.info /usr/share/info/dir
Now that the software is successfully installed, the next step is to Now that the software is successfully installed, the next step is to
set up a configuration file. The default location of the file set up a configuration file. The default location of the file
is @file{@SYSCONFDIR@/chrony.conf}. Several examples of configuration with is @file{@SYSCONFDIR@/chrony.conf}. Suppose you want to use public NTP
comments are included in the examples directory. Suppose you want to use servers from the pool.ntp.org project as your time reference. A
public NTP servers from the pool.ntp.org project as your time reference. A
minimal useful configuration file could be minimal useful configuration file could be
@example @example
pool pool.ntp.org iburst server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
makestep 10 3 makestep 10 3
rtcsync
@end example @end example
Then, @code{chronyd} can be run. Then, @code{chronyd} can be run.
@@ -573,42 +575,28 @@ use their facilities.
Assuming that you have found some servers, you need to set up a Assuming that you have found some servers, you need to set up a
configuration file to run chrony. The (compiled-in) default location configuration file to run chrony. The (compiled-in) default location
for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your NTP for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your ntp
servers are called @code{foo.example.net}, @code{bar.example.net} and servers are called @code{a.b.c} and @code{d.e.f}, your
@code{baz.example.net}, your @file{chrony.conf} file could contain as a minimum @file{chrony.conf} file could contain as a minimum
@example @example
server foo.example.net server a.b.c
server bar.example.net server d.e.f
server baz.example.net server g.h.i
@end example @end example
However, you will probably want to include some of the other directives However, you will probably want to include some of the other directives
described later. The following directives may be particularly useful : described later. The @code{driftfile} and @code{makestep} directives may be
@code{driftfile}, @code{makestep}, @code{rtcsync}. Also, the @code{iburst} particularly useful. Also, the @code{iburst} server option is useful to speed
server option is useful to speed up the initial synchronization. The smallest up the initial synchronization. The smallest useful configuration file would
useful configuration file would look something like look something like
@example @example
server foo.example.net iburst server a.b.c iburst
server bar.example.net iburst server d.e.f iburst
server baz.example.net iburst server g.h.i iburst
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
makestep 10 3 makestep 10 3
rtcsync
@end example
When using a pool of NTP servers (one name is used for multiple servers which
may change over time), it's better to specify them with the @code{pool}
directive instead of multiple @code{server} directives in order to allow
@code{chronyd} to replace unreachable or bad servers automatically. The
configuration file could in this case look like
@example
pool pool.ntp.org iburst
driftfile @CHRONYVARDIR@/drift
makestep 10 3
rtcsync
@end example @end example
@c }}} @c }}}
@c {{{ S:Infrequent connection @c {{{ S:Infrequent connection
@@ -632,14 +620,14 @@ In this case, you will need some additional configuration to tell
This saves the program from continuously trying to poll the servers when This saves the program from continuously trying to poll the servers when
they are inaccessible. they are inaccessible.
Again, assuming that your NTP servers are called @code{foo.example.net}, Again, assuming that your ntp servers are called @code{a.b.c} and
@code{bar.example.net} and @code{baz.example.net}, your @file{chrony.conf} file @code{d.e.f}, your @file{chrony.conf} file would need to contain
would need to contain something like something like
@example @example
server foo.example.net server a.b.c
server bar.example.net server d.e.f
server baz.example.net server g.h.i
@end example @end example
However, your computer will keep trying to contact the servers to obtain However, your computer will keep trying to contact the servers to obtain
@@ -651,9 +639,9 @@ For this reason, it would be better to specify this part of your
configuration file in the following way: configuration file in the following way:
@example @example
server foo.example.net offline server a.b.c offline
server bar.example.net offline server d.e.f offline
server baz.example.net offline server g.h.i offline
@end example @end example
The @code{offline} keyword indicates that the servers start The @code{offline} keyword indicates that the servers start
@@ -670,9 +658,9 @@ automatically on the first @code{chronyd} start.
The smallest useful configuration file would look something like The smallest useful configuration file would look something like
@example @example
server foo.example.net offline server a.b.c offline
server bar.example.net offline server d.e.f offline
server baz.example.net offline server g.h.i offline
keyfile @SYSCONFDIR@/chrony.keys keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey generatecommandkey
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
@@ -885,9 +873,9 @@ For the @file{@SYSCONFDIR@/chrony.conf} file, the following can be used as an
example. example.
@example @example
server foo.example.net maxdelay 0.4 offline server 0.pool.ntp.org maxdelay 0.4 offline
server bar.example.net maxdelay 0.4 offline server 1.pool.ntp.org maxdelay 0.4 offline
server baz.example.net maxdelay 0.4 offline server 2.pool.ntp.org maxdelay 0.4 offline
logdir /var/log/chrony logdir /var/log/chrony
log statistics measurements tracking log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
@@ -1174,11 +1162,9 @@ the configuration file is ignored.
* maxslewrate directive:: Set maximum slew rate * maxslewrate directive:: Set maximum slew rate
* maxupdateskew directive:: Stop bad estimates upsetting machine clock * maxupdateskew directive:: Stop bad estimates upsetting machine clock
* minsamples directive:: Set minimum number of samples per source * minsamples directive:: Set minimum number of samples per source
* minsources directive:: Set minimum number of selectable sources to update clock
* noclientlog directive:: Prevent chronyd from gathering data about clients * noclientlog directive:: Prevent chronyd from gathering data about clients
* peer directive:: Specify an NTP peer * peer directive:: Specify an NTP peer
* pidfile directive:: Specify the file where chronyd's pid is written * pidfile directive:: Specify the file where chronyd's pid is written
* pool directive:: Specify an NTP pool
* port directive:: Set NTP server port * port directive:: Set NTP server port
* refclock directive:: Specify a reference clock * refclock directive:: Specify a reference clock
* reselectdist directive:: Set improvement in distance needed to reselect a source * reselectdist directive:: Set improvement in distance needed to reselect a source
@@ -1245,7 +1231,7 @@ to other clients.
Examples of use of the command are as follows: Examples of use of the command are as follows:
@example @example
allow foo.example.net allow foo.bar.com
allow 1.2 allow 1.2
allow 3.4.5 allow 3.4.5
allow 6.7.8/22 allow 6.7.8/22
@@ -1330,32 +1316,47 @@ bindaddress 192.168.1.1
to the configuration file. to the configuration file.
For each of IPv4 and IPv6 protocols, only one @code{bindaddress} directive can This directive affects NTP (UDP port 123 by default) packets. If no
be specified. Therefore, it's not useful on computers which should serve NTP @code{bindcmdaddress} directive is present, the address supplied by
on multiple network interfaces. @code{bindaddress} will be used to control binding of the command socket (UDP
port 323 by default) as well.
The @code{bindaddress} directive has been found to cause problems when used on
computers that need to pass NTP traffic over multiple network interfaces (e.g.
firewalls). It is, therefore, not particularly useful. Use of the
@code{allow} and @code{deny} directives together with a network firewall is
more likely to be successful.
For each of IPv4 and IPv6 protocols, only one @code{bindaddress}
directive can be specified.
@c }}} @c }}}
@c {{{ bindcmdaddress @c {{{ bindcmdaddress
@node bindcmdaddress directive @node bindcmdaddress directive
@subsection bindcmdaddress @subsection bindcmdaddress
The @code{bindcmdaddress} directive allows you to specify the network The @code{bindcmdaddress} directive allows you to restrict the network
interface to which @code{chronyd} will listen for command packets (issued by interface to which @code{chronyd} will listen for command packets (issued by
@code{chronyc}). This provides an additional level of access restriction above @code{chronyc}). This provides an additional level of access restriction above
that available through @code{cmddeny} mechanism. that available through @code{cmddeny} mechanism.
By default, @code{chronyd} binds to the loopback interface (with addresses Suppose you want to block all access except from localhost. You
@code{127.0.0.1} and @code{::1}). This blocks all access except from could add the lines
localhost. To listen for command packets on all interfaces, you can add the
lines
@example @example
bindcmdaddress 0.0.0.0 bindcmdaddress 127.0.0.1
bindcmdaddress :: bindcmdaddress ::1
@end example @end example
to the configuration file. to the configuration file.
For each of IPv4 and IPv6 protocols, only one @code{bindcmdaddress} For each of IPv4 and IPv6 protocols, only one @code{bindcmdaddress}
directive can be specified. directive can be specified.
The default values are set by the @code{bindaddress} directive.
The @code{bindcmdaddress} directive has been found to cause problems when used
on computers that need to pass command traffic over multiple network
interfaces. Use of the @code{cmdallow} and @code{cmddeny} directives together
with a network firewall is more likely to be successful.
@c }}} @c }}}
@c {{{ broadcast directive @c {{{ broadcast directive
@node broadcast directive @node broadcast directive
@@ -1423,10 +1424,6 @@ The syntax is identical to the @code{allow} directive.
There is also a @code{cmdallow all} directive with similar behaviour to the There is also a @code{cmdallow all} directive with similar behaviour to the
@code{allow all} directive (but applying to control access in this case, of @code{allow all} directive (but applying to control access in this case, of
course). course).
Note that @code{chronyd} has to be configured with the @code{bindcmdaddress}
directive to not listen only on the loopback interface to actually allow remote
access.
@c }}} @c }}}
@c {{{ cmddeny @c {{{ cmddeny
@node cmddeny directive @node cmddeny directive
@@ -1725,7 +1722,7 @@ used instead. This makes it easier to restart @code{chronyd} whilst the
system is in normal operation. system is in normal operation.
The @code{initstepslew} directive takes a threshold and a list of NTP The @code{initstepslew} directive takes a threshold and a list of NTP
servers as arguments. Each of the servers servers as arguments. A maximum of 8 will be used. Each of the servers
is rapidly polled several times, and a majority voting mechanism used to is rapidly polled several times, and a majority voting mechanism used to
find the most likely range of system clock error that is present. A find the most likely range of system clock error that is present. A
step (or slew) is applied to the system clock to correct this error. step (or slew) is applied to the system clock to correct this error.
@@ -1734,7 +1731,7 @@ step (or slew) is applied to the system clock to correct this error.
An example of use of the command is An example of use of the command is
@example @example
initstepslew 30 foo.example.net bar.example.net initstepslew 30 foo.bar.com baz.quz.com
@end example @end example
where 2 NTP servers are used to make the measurement. The @code{30} where 2 NTP servers are used to make the measurement. The @code{30}
@@ -1938,7 +1935,7 @@ An example line (which actually appears as a single line in the file)
from the measurements log file is shown below. from the measurements log file is shown below.
@example @example
2014-10-13 05:40:50 158.152.1.76 N 2 111 111 1111 10 10 1.0 \ 2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03 -4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
@end example @end example
@@ -1947,7 +1944,7 @@ values from the example line above) :
@enumerate 1 @enumerate 1
@item @item
Date [2014-10-13] Date [2010-12-22]
@item @item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone. expressed in UTC, not the local time zone.
@@ -1961,13 +1958,12 @@ currently synchronised.) [N]
@item @item
Stratum of remote computer. [2] Stratum of remote computer. [2]
@item @item
RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111] RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
@item
RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
@item @item
Tests for maximum delay, maximum delay ratio and maximum delay dev ratio, Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
against defined parameters, and a test for synchronisation loop against defined parameters (1=pass, 0=fail) [111]
(1=pass, 0=fail) [1111] @item
RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
@item @item
Local poll [10] Local poll [10]
@item @item
@@ -1977,16 +1973,15 @@ Remote poll [10]
to increase or decrease the polling level. This is adjusted based on number to increase or decrease the polling level. This is adjusted based on number
of measurements currently being used for the regression algorithm). [1.0] of measurements currently being used for the regression algorithm). [1.0]
@item @item
The estimated local clock error (`theta' in RFC 5905). Positive The estimated local clock error (`theta' in RFC1305). Positive indicates that the local clock is slow. [-4.966e-03].
indicates that the local clock is slow of the remote source. [-4.966e-03].
@item @item
The peer delay (`delta' in RFC 5905). [2.296e-01] The peer delay (`delta' in RFC1305). [2.296e-01]
@item @item
The peer dispersion (`epsilon' in RFC 5905). [1.577e-05] The peer dispersion (`epsilon' in RFC1305). [1.577e-05]
@item @item
The root delay (`DELTA' in RFC 5905). [1.615e-01] The root delay (`Delta' in RFC1305). [1.615e-01]
@item @item
The root dispersion (`EPSILON' in RFC 5905). [7.446e-03] The root dispersion (`E' in RFC1305). [7.446e-03]
@end enumerate @end enumerate
A banner is periodically written to the log file to indicate the A banner is periodically written to the log file to indicate the
@@ -2378,11 +2373,9 @@ crystal oscillator.
@c {{{ maxsamples @c {{{ maxsamples
@node maxsamples directive @node maxsamples directive
@subsection maxsamples @subsection maxsamples
The @code{maxsamples} directive sets the default maximum number of samples The @code{maxsamples} directive sets the maximum number of samples
@code{chronyd} should keep for each source. This setting can be overriden for @code{chronyd} should keep for each source. The default is 0, which
individual sources in the @code{server} and @code{refclock} directives disables the configurable limit, and the useful range is 4 to 64.
(@pxref{server directive}, @pxref{refclock directive}). The default value is
0, which disables the configurable limit. The useful range is 4 to 64.
The syntax is The syntax is
@@ -2444,11 +2437,9 @@ the new master estimate.
@c {{{ minsamples @c {{{ minsamples
@node minsamples directive @node minsamples directive
@subsection minsamples @subsection minsamples
The @code{minsamples} directive sets the default minimum number of samples The @code{minsamples} directive sets the minimum number of samples
@code{chronyd} should keep for each source. This setting can be overriden for @code{chronyd} should try to keep for each source. The default is 0 and the
individual sources in the @code{server} and @code{refclock} directives useful range is 4 to 64.
(@pxref{server directive}, @pxref{refclock directive}). The default value is
0. The useful range is 4 to 64.
The syntax is The syntax is
@@ -2456,23 +2447,6 @@ The syntax is
minsamples <samples> minsamples <samples>
@end example @end example
@c }}} @c }}}
@c {{{ minsources
@node minsources directive
@subsection minsources
The @code{minsources} directive sets the minimum number of sources that need
to be considered as selectable in the source selection algorithm before the
local clock is updated. The default value is 1.
Setting this option to a larger number can be used to improve the reliability.
More sources will have to agree with each other and the clock will not be
updated when only one source (which could be serving wrong time) is reachable.
The syntax is
@example
minsources <sources>
@end example
@c }}}
@c {{{ noclientlog @c {{{ noclientlog
@node noclientlog directive @node noclientlog directive
@subsection noclientlog @subsection noclientlog
@@ -2486,6 +2460,24 @@ be reported using the @code{clients} command in @code{chronyc}.
The syntax of this directive is identical to that for the @code{server} The syntax of this directive is identical to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify directive (@pxref{server directive}), except that it is used to specify
an NTP peer rather than an NTP server. an NTP peer rather than an NTP server.
When a key is specified by the @code{key} option to enable authentication, both
peers must be configured to use the same key and the same key number.
Please note that NTP peers that are not configured with a key to enable
authentication are vulnerable to a denial-of-service attack. An attacker
knowing that NTP hosts A and B are peering with each other can send a packet
with random timestamps to host A with source address of B which will set the
NTP state variables on A to the values sent by the attacker. Host A will then
send on its next poll to B a packet with originate timestamp that doesn't match
the transmit timestamp of B and the packet will be dropped. If the attacker
does this periodically for both hosts, they won't be able to synchronize to
each other.
This attack can be prevented by enabling authentication with the key option, or
using the @code{server} directive on both sides to specify the other host as a
server instead of peer, the only drawback is that it will double the network
traffic between the two hosts.
@c }}} @c }}}
@c {{{ pidfile @c {{{ pidfile
@node pidfile directive @node pidfile directive
@@ -2496,42 +2488,14 @@ chronyd always writes its process ID (pid) to a file, and checks this file on st
pidfile /var/tmp/chronyd.pid pidfile /var/tmp/chronyd.pid
@end example @end example
@c }}} @c }}}
@c {{{ pool
@node pool directive
@subsection pool
The syntax of this directive is similar to that for the @code{server}
directive (@pxref{server directive}), except that it is used to specify a pool
of NTP servers rather than a single NTP server. The pool name is expected to
resolve to multiple addresses which may change over time.
All options valid in the @code{server} directive can be used in this directive
too. There is one option specific to @code{pool} directive: @code{maxsources}
sets the maximum number of sources that can be used from the pool, the default
value is 4.
On start, when the pool name is resolved, @code{chronyd} will add up to 16
sources, one for each resolved address. When the number of sources from which
at least one valid reply was received reaches @code{maxsources}, the other
sources will be removed. When a pool source is unreachable or marked as
falseticker, @code{chronyd} will try to replace the source with a newly
resolved address of the pool.
An example of the pool directive is
@example
pool pool.ntp.org iburst maxsources 3
@end example
@c }}}
@c {{{ port @c {{{ port
@node port directive @node port directive
@subsection port @subsection port
This option allows you to configure the port on which @code{chronyd} This option allows you to configure the port on which @code{chronyd}
will listen for NTP requests. The port will be open only when an address is will listen for NTP requests.
allowed by the @code{allow} directive or command, an NTP peer is configured, or
the broadcast server mode is enabled.
The compiled in default is udp/123, the standard NTP port. If set to 0, The compiled in default is udp/123, the standard NTP port. If set to 0,
@code{chronyd} will never open the server port and will operate strictly in a @code{chronyd} will not open the server socket and will operate strictly in a
client-only mode. The source port used in NTP client requests can be set by client-only mode. The source port used in NTP client requests can be set by
the @code{acquisitionport} directive. the @code{acquisitionport} directive.
@@ -2678,12 +2642,6 @@ Prefer this source over sources without prefer option.
@item noselect @item noselect
Never select this source. This is useful for monitoring or with sources Never select this source. This is useful for monitoring or with sources
which are not very accurate, but are locked with a PPS refclock. which are not very accurate, but are locked with a PPS refclock.
@item minsamples
Set the minimum number of samples kept for this source. This overrides the
@code{minsamples} directive (@pxref{minsamples directive}).
@item maxsamples
Set the maximum number of samples kept for this source. This overrides the
@code{maxsamples} directive (@pxref{maxsamples directive}).
@end table @end table
@c }}} @c }}}
@@ -2847,11 +2805,11 @@ required (the default is 123, the standard NTP port).
Although @code{chronyd} will trim the rate at which it samples the Although @code{chronyd} will trim the rate at which it samples the
server during normal operation, the user may wish to constrain the server during normal operation, the user may wish to constrain the
minimum polling interval. This is always defined as a power of 2, so minimum polling interval. This is always defined as a power of 2, so
@code{minpoll 5} would mean that the polling interval cannot drop below 32 <tt/minpoll 5/ would mean that the polling interval cannot drop below 32
seconds. The default is 6 (64 seconds). seconds. The default is 6 (64 seconds).
@item maxpoll @item maxpoll
In a similar way, the user may wish to constrain the maximum polling In a similar way, the user may wish to constrain the maximum polling
interval. Again this is specified as a power of 2, @code{maxpoll 9} interval. Again this is specified as a power of 2, so <tt/maxpoll 9/
indicates that the polling interval must stay at or below 512 seconds. indicates that the polling interval must stay at or below 512 seconds.
The default is 10 (1024 seconds). The default is 10 (1024 seconds).
@item maxdelay @item maxdelay
@@ -2871,7 +2829,7 @@ some sort).
If the user knows that round trip delays above a certain level should If the user knows that round trip delays above a certain level should
cause the measurement to be ignored, this level can be defined with the cause the measurement to be ignored, this level can be defined with the
maxdelay command. For example, @code{maxdelay 0.3} would indicate that maxdelay command. For example, <tt/maxdelay 0.3/ would indicate that
measurements with a round-trip delay of 0.3 seconds or more should be measurements with a round-trip delay of 0.3 seconds or more should be
ignored. ignored.
@@ -2960,25 +2918,12 @@ Target number of measurements to use for the regression algorithm which
@code{minpoll} and @code{maxpoll}. A higher target makes @code{chronyd} prefer @code{minpoll} and @code{maxpoll}. A higher target makes @code{chronyd} prefer
shorter polling intervals. The default is 6 and a useful range is 6 to 60. shorter polling intervals. The default is 6 and a useful range is 6 to 60.
@item version
This option sets the NTP version number used in packets sent to the server.
This can be useful when the server runs an old NTP implementation that doesn't
respond to newer versions. The default version number is 4.
@item prefer @item prefer
Prefer this source over sources without prefer option. Prefer this source over sources without prefer option.
@item noselect @item noselect
Never select this source. This is particularly useful for monitoring. Never select this source. This is particularly useful for monitoring.
@item minsamples
Set the minimum number of samples kept for this source. This overrides the
@code{minsamples} directive (@pxref{minsamples directive}).
@item maxsamples
Set the maximum number of samples kept for this source. This overrides the
@code{maxsamples} directive (@pxref{maxsamples directive}).
@end table @end table
@c }}} @c }}}
@c {{{ stratumweight @c {{{ stratumweight
@@ -2995,31 +2940,30 @@ The syntax is
stratumweight <dist-in-seconds> stratumweight <dist-in-seconds>
@end example @end example
By default, the weight is 0.001 seconds. This means that stratum of the By default, it is 1 second. This usually means that sources with lower stratum
sources in the selection process matters only when the differences between the will be preferred to sources with higher stratum even when their distance is
distances are in milliseconds. significantly worse. Setting @code{stratumweight} to 0 makes @code{chronyd}
ignore stratum when selecting the source.
@c }}} @c }}}
@c {{{ tempcomp @c {{{ tempcomp
@node tempcomp directive @node tempcomp directive
@subsection tempcomp @subsection tempcomp
Normally, changes in the rate of drift of the system clock are caused mainly by Normally, changes in rate of drift of the system clock are caused mainly by
changes in the temperature of the crystal oscillator on the mainboard. changes in temperature of the crystal oscillator on the mainboard.
If there are temperature measurements available from a sensor close to the If there are available temperature measurements from a sensor close to the
oscillator, the @code{tempcomp} directive can be used to compensate for the oscillator, @code{tempcomp} directive can be used to compensate for the changes
changes in the temperature and improve the stability and accuracy of the clock. in rate and possibly improve clock accuracy.
The result depends on many factors, including the resolution of the sensor, Whether it will really help depends on many factors, including resolution of
the amount of noise in the measurements, the polling interval of the time the sensor, noise in measurements, time source polling interval, compensation
source, the compensation update interval, how well is the compensation update interval, how good are the temperature coefficients, and how close is
specified, and how close is the sensor to the oscillator. When it's working the sensor to the oscillator. The frequency reported in tracking.log should
well, the frequency reported in the @file{tracking.log} file is more stable and be more stable and the offsets should be smaller.
the maximum reached offset is smaller.
There are two forms of the directive. The first one has six parameters: a The directive has six parameters: path to the file which contains current
path to the file containing the current temperature from the sensor (in temperature in text format, update interval (in seconds), and temperature
text format), the compensation update interval (in seconds), and temperature
coefficients T0, k0, k1, k2. coefficients T0, k0, k1, k2.
The frequency compensation is calculated (in ppm) as The frequency compensation is calculated (in ppm) as
@@ -3027,48 +2971,23 @@ The frequency compensation is calculated (in ppm) as
@code{k0 + (T - T0) * k1 + (T - T0)^2 * k2} @code{k0 + (T - T0) * k1 + (T - T0)^2 * k2}
The result has to be between -10 ppm and 10 ppm, otherwise the measurement is The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
considered invalid and will be ignored. The k0 coefficient can be used to get considered to be faulty and will be ignored. The k0 coefficient can be used to
the results in that range. get the results in that range.
Valid measurements and calculated corrections are logged to tempcomp.log file if
enabled with @code{log tempcomp} directive.
An example of use is An example of use is
@example @example
tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0 tempcomp /sys/class/hwmon/hwmon1/device/temp2_input 30 26000 0.0 0.000183 0.0
@end example @end example
The measured temperature will be read from the file in the Linux sysfs The measured temperature will be read from the file in Linux sysfs filesystem
filesystem every 30 seconds. When the temperature is 26000 (26 degrees every 30 seconds. When the temperature is 26 degress (26000), the system clock
Celsius), the frequency correction will be zero. When it is 27000 (27 degrees frequency will not be adjusted. When it is 27 degrees (27000), the clock will
Celsius), the clock will be set to run 0.183ppm faster, etc. be set to run 0.183ppm faster than it would be without the compensation, etc.
The second form has three parameters, the path to the sensor file, the update
interval and a path to a file containing a list of (temperature, compensation)
points, from which the compensation is linearly interpolated or extrapolated.
An example is
@example
tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 /etc/chrony.tempcomp
@end example
where the @file{chrony.tempcomp} file could have
@example
20000 1.0
21000 0.64
22000 0.36
23000 0.16
24000 0.04
25000 0.0
26000 0.04
27000 0.16
28000 0.36
29000 0.64
30000 1.0
@end example
Valid measurements with corresponding compensations are logged to the
@file{tempcomp.log} file if enabled by the @code{log tempcomp} directive.
@c }}} @c }}}
@c {{{ user @c {{{ user
@node user directive @node user directive
@@ -3236,7 +3155,7 @@ interface.
* exit command:: Exit from chronyc * exit command:: Exit from chronyc
* help command:: Generate help summary * help command:: Generate help summary
* local command:: Let computer be a server when it is unsynchronised * local command:: Let computer be a server when it is unsynchronised
* makestep command:: Correct the system clock by stepping instead of slewing * makestep command:: Immediately correct the system clock instead of slewing
* manual command:: Enable/disable/configure options for settime * manual command:: Enable/disable/configure options for settime
* maxdelay command:: Set max measurement delay for a source * maxdelay command:: Set max measurement delay for a source
* maxdelaydevratio command:: Set max measurement delay for a source as ratio to deviation * maxdelaydevratio command:: Set max measurement delay for a source as ratio to deviation
@@ -3274,7 +3193,7 @@ Examples of use, showing a named host and a numeric IP address, are as
follows: follows:
@example @example
accheck foo.example.net accheck a.b.c
accheck 1.2.3.4 accheck 1.2.3.4
accheck 2001:db8::1 accheck 2001:db8::1
@end example @end example
@@ -3315,16 +3234,13 @@ The @code{add peer} command allows a new NTP peer to be added whilst
@code{chronyd} is running. @code{chronyd} is running.
Following the words @code{add peer}, the syntax of the following Following the words @code{add peer}, the syntax of the following
parameters and options is similar to that for the @code{peer} parameters and options is identical to that for the @code{peer}
directive in the configuration file (@pxref{peer directive}). directive in the configuration file (@pxref{peer directive}).
The following peer options can be set in the command:
@code{port}, @code{minpoll}, @code{maxpoll}, @code{presend},
@code{maxdelayratio}, @code{maxdelay}, @code{key}
An example of using this command is shown below. An example of using this command is shown below.
@example @example
add peer foo.example.net minpoll 6 maxpoll 10 key 25 add peer foo.bar.com minpoll 6 maxpoll 10 authkey 25
@end example @end example
@c }}} @c }}}
@c {{{ add server @c {{{ add server
@@ -3334,16 +3250,13 @@ The @code{add server} command allows a new NTP server to be added whilst
@code{chronyd} is running. @code{chronyd} is running.
Following the words @code{add server}, the syntax of the following Following the words @code{add server}, the syntax of the following
parameters and options is similar to that for the @code{server} parameters and options is identical to that for the @code{server}
directive in the configuration file (@pxref{server directive}). directive in the configuration file (@pxref{server directive}).
The following server options can be set in the command:
@code{port}, @code{minpoll}, @code{maxpoll}, @code{presend},
@code{maxdelayratio}, @code{maxdelay}, @code{key}
An example of using this command is shown below. An example of using this command is shown below.
@example @example
add server foo.example.net minpoll 6 maxpoll 10 key 25 add server foo.bar.com minpoll 6 maxpoll 10 authkey 25
@end example @end example
@c }}} @c }}}
@c {{{ allow all @c {{{ allow all
@@ -3361,7 +3274,7 @@ the configuration file (@pxref{allow directive}).
The syntax is illustrated in the following examples: The syntax is illustrated in the following examples:
@example @example
allow foo.example.net allow foo.bar.com
allow 1.2 allow 1.2
allow 3.4.5 allow 3.4.5
allow 6.7.8/22 allow 6.7.8/22
@@ -3476,7 +3389,7 @@ whose IPv6 addresses have first 48 bits equal to @code{2001:db8:789a}.
Example of the three-argument form of the command is Example of the three-argument form of the command is
@example @example
burst 2/10 foo.example.net burst 2/10 foo.bar.com
@end example @end example
@c }}} @c }}}
@c {{{ clients @c {{{ clients
@@ -3540,7 +3453,7 @@ used to check whether command access is permitted from a named host.
Examples of use are as follows: Examples of use are as follows:
@example @example
cmdaccheck foo.example.net cmdaccheck a.b.c
cmdaccheck 1.2.3.4 cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1 cmdaccheck 2001:db8::1
@end example @end example
@@ -3598,7 +3511,7 @@ from the current set of sources.
The syntax is illustrated in the examples below. The syntax is illustrated in the examples below.
@example @example
delete foo.example.net delete foo.bar.com
delete 1.2.3.4 delete 1.2.3.4
delete 2001:db8::1 delete 2001:db8::1
@end example @end example
@@ -3621,7 +3534,7 @@ directive in the configuration file (@pxref{deny directive}).
The syntax is illustrated in the following examples: The syntax is illustrated in the following examples:
@example @example
deny foo.example.net deny foo.bar.com
deny 1.2 deny 1.2
deny 3.4.5 deny 3.4.5
deny 6.7.8/22 deny 6.7.8/22
@@ -3713,27 +3626,17 @@ offset, by slowing down or speeding up the clock as required. In
certain situations, the system clock may be so far adrift that this certain situations, the system clock may be so far adrift that this
slewing process would take a very long time to correct the system clock. slewing process would take a very long time to correct the system clock.
The @code{makestep} command can be used in this situation. There are two forms The @code{makestep} command can be used in this situation. It cancels
of the command. The first form has no parameters. It tells @code{chronyd} to any remaining correction that was being slewed, and jumps the system
cancel any remaining correction that was being slewed and jump the system clock clock by the equivalent amount, making it correct immediately.
by the equivalent amount, making it correct immediately.
The second form configures the automatic stepping, similarly to the
@code{makestep} directive (@pxref{makestep directive}). It has two parameters,
stepping threshold (in seconds) and number of future clock updates for which
will be the threshold active. This can be used with the @code{burst} command
to quickly make a new measurement and correct the clock by stepping if needed,
without waiting for @code{chronyd} to complete the measurement and update the
clock.
@example
makestep 0.1 1
burst 1/2
@end example
BE WARNED - certain software will be seriously affected by such jumps to BE WARNED - certain software will be seriously affected by such jumps to
the system time. (That is the reason why chronyd uses slewing the system time. (That is the reason why chronyd uses slewing
normally.) normally.)
The @code{makestep} directive in the configuration file can be used
to step the clock automatically when the adjustment is larger than a
specified threshold, see @ref{makestep directive}.
@c }}} @c }}}
@c {{{ manual @c {{{ manual
@node manual command @node manual command
@@ -3810,13 +3713,13 @@ directive}).
The following examples illustrate the syntax The following examples illustrate the syntax
@example @example
maxdelay foo.example.net 0.3 maxdelay foo.bar.com 0.3
maxdelay 1.2.3.4 0.0015 maxdelay 1.2.3.4 0.0015
maxdelay 2001:db8::1 0.0015 maxdelay 2001:db8::1 0.0015
@end example @end example
The first example sets the maximum network delay allowed for a The first example sets the maximum network delay allowed for a
measurement to the host @code{foo.example.net} to 0.3 seconds. The second measurement to the host @code{foo.bar.com} to 0.3 seconds. The second
and third examples set the maximum network delay for a measurement to and third examples set the maximum network delay for a measurement to
the host with IPv4 address @code{1.2.3.4} and the host with IPv6 address the host with IPv4 address @code{1.2.3.4} and the host with IPv6 address
@code{2001:db8::1} to 1.5 milliseconds. @code{2001:db8::1} to 1.5 milliseconds.
@@ -3835,7 +3738,7 @@ directive}).
The following examples illustrate the syntax The following examples illustrate the syntax
@example @example
maxdelaydevratio foo.example.net 0.1 maxdelaydevratio foo.bar.com 0.1
maxdelaydevratio 1.2.3.4 1.0 maxdelaydevratio 1.2.3.4 1.0
maxdelaydevratio 2001:db8::1 100.0 maxdelaydevratio 2001:db8::1 100.0
@end example @end example
@@ -3851,13 +3754,13 @@ directive}).
The following examples illustrate the syntax The following examples illustrate the syntax
@example @example
maxdelayratio foo.example.net 1.5 maxdelayratio foo.bar.com 1.5
maxdelayratio 1.2.3.4 2.0 maxdelayratio 1.2.3.4 2.0
maxdelayratio 2001:db8::1 2.0 maxdelayratio 2001:db8::1 2.0
@end example @end example
The first example sets the maximum network delay for a measurement to The first example sets the maximum network delay for a measurement to
the host @code{foo.example.net} to be 1.5 times the minimum delay found the host @code{foo.bar.com} to be 1.5 times the minimum delay found
amongst the previous measurements that have been retained. The second amongst the previous measurements that have been retained. The second
and third examples set the maximum network delay for a measurement to and third examples set the maximum network delay for a measurement to
the host with IPv4 address @code{1.2.3.4} and the host with IPv6 the host with IPv4 address @code{1.2.3.4} and the host with IPv6
@@ -3888,10 +3791,10 @@ sampling).
An example is An example is
@example @example
maxpoll foo.example.net 10 maxpoll foo.bar.com 10
@end example @end example
which sets the maximum polling interval for the host @code{foo.example.net} which sets the maximum polling interval for the host @code{foo.bar.com}
to 1024 seconds. to 1024 seconds.
Note that the new maximum polling interval only takes effect after the Note that the new maximum polling interval only takes effect after the
@@ -3925,10 +3828,10 @@ sampling).
An example is An example is
@example @example
minpoll foo.example.net 5 minpoll foo.bar.com 5
@end example @end example
which sets the minimum polling interval for the host @code{foo.example.net} which sets the minimum polling interval for the host @code{foo.bar.com}
to 32 seconds. to 32 seconds.
Note that the new minimum polling interval only takes effect after the Note that the new minimum polling interval only takes effect after the
@@ -3954,10 +3857,10 @@ IP address.
An example is An example is
@example @example
minpoll foo.example.net 5 minpoll foo.bar.com 5
@end example @end example
which sets the minimum stratum for the host @code{foo.example.net} which sets the minimum stratum for the host @code{foo.bar.com}
to 5. to 5.
Note that the new minimum stratum only takes effect after the Note that the new minimum stratum only takes effect after the
@@ -4023,7 +3926,7 @@ illustrated below.
offline offline
offline 255.255.255.0/1.2.3.0 offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48 offline 2001:db8:789a::/48
offline foo.example.net offline foo.bar.com
@end example @end example
The second form means that the @code{offline} command is to be applied The second form means that the @code{offline} command is to be applied
@@ -4104,10 +4007,10 @@ IP address.
An example is An example is
@example @example
polltarget foo.example.net 12 polltarget foo.bar.com 12
@end example @end example
which sets the poll target for the host @code{foo.example.net} which sets the poll target for the host @code{foo.bar.com}
to 12. to 12.
@c }}} @c }}}
@c {{{ quit @c {{{ quit
@@ -4250,8 +4153,8 @@ columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample MS Name/IP address Stratum Poll Reach LastRx Last sample
=============================================================================== ===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns #* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms ^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms ^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
@end group @end group
@end example @end example
@@ -4407,7 +4310,7 @@ The @code{tracking} command displays parameters about the system's clock
performance. An example of the output is shown below. performance. An example of the output is shown below.
@example @example
Reference ID : 1.2.3.4 (foo.example.net) Reference ID : 1.2.3.4 (a.b.c)
Stratum : 3 Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012 Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time System time : 0.000001501 seconds slow of NTP time
@@ -4438,7 +4341,7 @@ in the @file{@SYSCONFDIR@/chrony.conf} file (@pxref{local directive})).
The stratum indicates how many hops away from a computer with an The stratum indicates how many hops away from a computer with an
attached reference clock we are. Such a computer is a stratum-1 attached reference clock we are. Such a computer is a stratum-1
computer, so the computer in the example is two hops away computer, so the computer in the example is two hops away
(i.e. @code{foo.example.net} is a stratum-2 and is synchronised from a stratum-1). (i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1).
@item Ref time @item Ref time
This is the time (UTC) at which the last measurement from the reference This is the time (UTC) at which the last measurement from the reference
@@ -4502,6 +4405,11 @@ This is the estimated error bound on the the frequency.
This is the total of the network path delays to the stratum-1 computer This is the total of the network path delays to the stratum-1 computer
from which the computer is ultimately synchronised. from which the computer is ultimately synchronised.
In certain extreme situations, this value can be negative. (This can
arise in a symmetric peer arrangement where the computers' frequencies
are not tracking each other and the network delay is very short relative
to the turn-around time at each computer.)
@item Root dispersion @item Root dispersion
This is the total dispersion accumulated through all the computers back This is the total dispersion accumulated through all the computers back
to the stratum-1 computer from which the computer is ultimately to the stratum-1 computer from which the computer is ultimately
@@ -4631,9 +4539,9 @@ For the current development from the developers' version control system see the
@code{Git} link on the web site. @code{Git} link on the web site.
@subsection Are there any packaged versions of chrony? @subsection Are there any packaged versions of chrony?
We are aware of packages for Arch, CentOS, Debian, Fedora, Gentoo, Mageia, We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva, Slackware,
OpenSuse, Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how Ubuntu, FreeBSD and NetBSD. We are not involved with how these are built or
these are built or distributed. distributed.
@subsection Where is the home page? @subsection Where is the home page?
It is currently at It is currently at
@@ -4718,16 +4626,13 @@ increasing intervals until it succeeds. The @code{online} command can be
issued from @code{chronyc} to try to resolve them immediately. issued from @code{chronyc} to try to resolve them immediately.
@subsection How can I make chronyd more secure? @subsection How can I make chronyd more secure?
If you don't need to serve time to NTP clients or peers, you can add If you don't need to serve time to NTP clients, you can add @code{port 0} to
@code{port 0} to the @file{chrony.conf} file to completely disable the NTP the @file{chrony.conf} file to disable the NTP server/peer sockets and prevent
server functionality and prevent NTP requests from reaching @code{chronyd}. NTP requests from reaching @code{chronyd}.
Starting from version 2.0, the NTP server port is open only when client access
is allowed by the @code{allow} directive or command, an NTP peer is configured,
or the @code{broadcast} directive is used.
If you don't need to use @code{chronyc} remotely, you can add the following If you don't need to use @code{chronyc} remotely, you can add the following
directives to the configuration file to bind the command sockets to the directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0. loopback interface
@example @example
bindcmdaddress 127.0.0.1 bindcmdaddress 127.0.0.1
@@ -4755,27 +4660,16 @@ they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
The first three options set the minimum and maximum allowed polling interval, 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 and how should be the actual interval adjusted in the specified range. Their
default values are 6 (64 seconds) for @code{minpoll}, 10 (1024 seconds) for default values are suitable for public NTP servers, which normally don't allow
@code{maxpoll} and 6 (samples) for @code{polltarget}. The default values too frequent polling, but if you run your own NTP servers or have permission to
should be used for general servers on the internet. With your own NTP servers poll the servers frequently, setting the options for shorter polling intervals
or if have permission to poll some servers more frequently, setting these may significantly improve the accuracy of the system clock.
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 The optimal polling interval depends on many factors, this includes the ratio
between the wander of the clock and the network jitter (sometimes expressed in between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature. crystal oscillator and the maximum rate of change of the temperature. An
example of the directive for a server located in the same LAN could be
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
@example
server foo.example.net minpoll 4 maxpoll 6 polltarget 16
@end example
An example using very short polling intervals for a server located in the
same LAN could be
@example @example
server ntp.local minpoll 2 maxpoll 4 polltarget 30 server ntp.local minpoll 2 maxpoll 4 polltarget 30
@@ -4784,7 +4678,7 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30
The maxdelay options are useful to ignore measurements with larger delay (e.g. 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 due to congestion in the network) and improve the stability of the
synchronisation. The @code{maxdelaydevratio} option could be added to the synchronisation. The @code{maxdelaydevratio} option could be added to the
example with local NTP server previous example
@example @example
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2 server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
@@ -4822,10 +4716,9 @@ will arise. You should always make X quite high (e.g. 10) in this directive.
@section Issues with chronyc @section Issues with chronyc
@subsection I keep getting the error @code{506 Cannot talk to daemon} @subsection I keep getting the error @code{506 Cannot talk to daemon}
When accessing @code{chronyd} remotely, make sure that the @file{chrony.conf} Make sure that the @file{chrony.conf} file (on the computer where
file (on the computer where @code{chronyd} is running) has a @code{cmdallow} @code{chronyd} is running) has a @code{cmdallow} entry for the computer you are
entry for the computer you are running @code{chronyc} on and an appropriate running @code{chronyc} on. This isn't necessary for localhost.
@code{bindcmdaddress} directive. This isn't necessary for localhost.
Perhaps @code{chronyd} is not running. Try using the ps command (e.g. on Perhaps @code{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 Linux, 'ps -auxw') to see if it's running. Or try 'netstat -a' and see if the

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 */

172
client.c
View File

@@ -36,6 +36,7 @@
#include "getdate.h" #include "getdate.h"
#include "cmdparse.h" #include "cmdparse.h"
#include "pktlength.h" #include "pktlength.h"
#include "memory.h"
#include "util.h" #include "util.h"
#ifdef FEAT_READLINE #ifdef FEAT_READLINE
@@ -51,7 +52,7 @@
union sockaddr_in46 { union sockaddr_in46 {
struct sockaddr_in in4; struct sockaddr_in in4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
#endif #endif
struct sockaddr u; struct sockaddr u;
@@ -67,6 +68,30 @@ static int no_dns = 0;
static int recv_errqueue = 0; static int recv_errqueue = 0;
/* ================================================== */
/* Ought to extract some code from util.c to make
a new set of utilities that can be linked into either
the daemon or the client. */
static char *
time_to_log_form(time_t t)
{
struct tm stm;
static char buffer[64];
static const char *months[] = {"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
stm = *gmtime(&t);
snprintf(buffer, sizeof(buffer),
"%2d%s%02d %02d:%02d:%02d",
stm.tm_mday, months[stm.tm_mon], stm.tm_year % 100,
stm.tm_hour, stm.tm_min, stm.tm_sec);
return buffer;
}
/* ================================================== */ /* ================================================== */
/* Read a single line of commands from standard input. Eventually we /* Read a single line of commands from standard input. Eventually we
might want to use the GNU readline library. */ might want to use the GNU readline library. */
@@ -119,26 +144,37 @@ open_io(const char *hostname, int port)
int on_off = 1; int on_off = 1;
/* Note, this call could block for a while */ /* Note, this call could block for a while */
if (DNS_Name2IPAddress(hostname, &ip, 1) != DNS_Success) { if (DNS_Name2IPAddress(hostname, &ip) != DNS_Success) {
fprintf(stderr, "Could not get IP address for %s\n", hostname); fprintf(stderr, "Could not get IP address for %s\n", hostname);
exit(1); exit(1);
} }
memset(&his_addr, 0, sizeof (his_addr));
switch (ip.family) { switch (ip.family) {
case IPADDR_INET4: case IPADDR_INET4:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0); sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
his_addr.in4.sin_family = AF_INET;
his_addr.in4.sin_addr.s_addr = htonl(ip.addr.in4);
his_addr.in4.sin_port = htons(port);
his_addr_len = sizeof (his_addr.in4);
break; break;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case IPADDR_INET6: case IPADDR_INET6:
sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); sock_fd = socket(AF_INET6, SOCK_DGRAM, 0);
his_addr.in6.sin6_family = AF_INET6;
memcpy(his_addr.in6.sin6_addr.s6_addr, ip.addr.in6,
sizeof (his_addr.in6.sin6_addr.s6_addr));
his_addr.in6.sin6_port = htons(port);
his_addr_len = sizeof (his_addr.in6);
break; break;
#endif #endif
default: default:
assert(0); assert(0);
} }
his_addr_len = UTI_IPAndPortToSockaddr(&ip, port, &his_addr.u);
if (sock_fd < 0) { if (sock_fd < 0) {
perror("Can't create socket"); perror("Can't create socket");
exit(1); exit(1);
@@ -151,7 +187,7 @@ open_io(const char *hostname, int port)
recv_errqueue = 1; recv_errqueue = 1;
} }
#endif #endif
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
#ifdef IPV6_RECVERR #ifdef IPV6_RECVERR
if (ip.family == IPADDR_INET6 && if (ip.family == IPADDR_INET6 &&
!setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVERR, &on_off, sizeof(on_off))) { !setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVERR, &on_off, sizeof(on_off))) {
@@ -233,7 +269,7 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address)
} }
} }
} else { } else {
if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) { if (DNS_Name2IPAddress(p, address) == DNS_Success) {
bits_to_mask(-1, address->family, mask); bits_to_mask(-1, address->family, mask);
return 1; return 1;
} else { } else {
@@ -305,7 +341,7 @@ read_address_integer(char *line, IPAddr *address, int *value)
fprintf(stderr, "Invalid syntax for address value\n"); fprintf(stderr, "Invalid syntax for address value\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) { if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {
@@ -333,7 +369,7 @@ read_address_double(char *line, IPAddr *address, double *value)
fprintf(stderr, "Invalid syntax for address value\n"); fprintf(stderr, "Invalid syntax for address value\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) { if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {
@@ -660,7 +696,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) { (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
/* Try to parse as the name of a machine */ /* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) { if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
fprintf(stderr, "Could not read address\n"); fprintf(stderr, "Could not read address\n");
return 0; return 0;
} else { } else {
@@ -828,7 +864,7 @@ accheck_getaddr(char *line, IPAddr *addr)
addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d; addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
return 1; return 1;
} else { } else {
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) { if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
return 0; return 0;
} else { } else {
*addr = ip; *addr = ip;
@@ -930,16 +966,17 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
CPS_NTP_Source data; CPS_NTP_Source data;
CPS_Status status; CPS_Status status;
IPAddr ip_addr; IPAddr ip_addr;
char str[64];
int result = 0; int result = 0;
status = CPS_ParseNTPSourceAdd(line, &data); status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) { switch (status) {
case CPS_Success: case CPS_Success:
if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) { if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) {
Free(data.name);
fprintf(stderr, "Invalid host/IP address\n"); fprintf(stderr, "Invalid host/IP address\n");
break; break;
} }
Free(data.name);
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) { if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n"); fprintf(stderr, "Option minstratum not supported\n");
@@ -956,26 +993,6 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
break; break;
} }
if (data.params.version != NTP_VERSION) {
fprintf(stderr, "Option version not supported\n");
break;
}
if (data.params.max_sources != SRC_DEFAULT_MAXSOURCES) {
fprintf(stderr, "Option maxsources not supported\n");
break;
}
if (data.params.min_samples != SRC_DEFAULT_MINSAMPLES) {
fprintf(stderr, "Option minsamples not supported\n");
break;
}
if (data.params.max_samples != SRC_DEFAULT_MAXSAMPLES) {
fprintf(stderr, "Option maxsamples not supported\n");
break;
}
msg->data.ntp_source.port = htonl((unsigned long) data.port); msg->data.ntp_source.port = htonl((unsigned long) data.port);
UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr); UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll); msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
@@ -993,9 +1010,41 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
result = 1; result = 1;
break; break;
default: case CPS_BadOption:
CPS_StatusToString(status, str, sizeof (str)); fprintf(stderr, "Unrecognized subcommand\n");
fprintf(stderr, "%s\n", str); break;
case CPS_BadHost:
fprintf(stderr, "Invalid host/IP address\n");
break;
case CPS_BadPort:
fprintf(stderr, "Unreadable port number\n");
break;
case CPS_BadMinpoll:
fprintf(stderr, "Unreadable minpoll value\n");
break;
case CPS_BadMaxpoll:
fprintf(stderr, "Unreadable maxpoll value\n");
break;
case CPS_BadPresend:
fprintf(stderr, "Unreadable presend value\n");
break;
case CPS_BadMaxdelaydevratio:
fprintf(stderr, "Unreadable max delay dev ratio value\n");
break;
case CPS_BadMaxdelayratio:
fprintf(stderr, "Unreadable max delay ratio value\n");
break;
case CPS_BadMaxdelay:
fprintf(stderr, "Unreadable max delay value\n");
break;
case CPS_BadKey:
fprintf(stderr, "Unreadable key value\n");
break;
case CPS_BadMinstratum:
fprintf(stderr, "Unreadable minstratum value\n");
break;
case CPS_BadPolltarget:
fprintf(stderr, "Unreadable polltarget value\n");
break; break;
} }
@@ -1037,7 +1086,7 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Invalid syntax for address\n"); fprintf(stderr, "Invalid syntax for address\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) { if (DNS_Name2IPAddress(hostname, &address) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {
@@ -1167,7 +1216,7 @@ give_help(void)
printf("dump : Dump all measurements to save files\n"); printf("dump : Dump all measurements to save files\n");
printf("local off : Disable server capability for unsynchronised clock\n"); printf("local off : Disable server capability for unsynchronised clock\n");
printf("local stratum <stratum> : Enable server capability for unsynchronised clock\n"); printf("local stratum <stratum> : Enable server capability for unsynchronised clock\n");
printf("makestep [<threshold> <updates>] : Correct clock by stepping\n"); printf("makestep : Jump the time to remove any correction being slewed\n");
printf("manual off|on|reset : Disable/enable/reset settime command and statistics\n"); printf("manual off|on|reset : Disable/enable/reset settime command and statistics\n");
printf("manual list : Show previous settime entries\n"); printf("manual list : Show previous settime entries\n");
printf("maxdelay <address> <new-max-delay> : Modify maximum round-trip valid sample delay for source\n"); printf("maxdelay <address> <new-max-delay> : Modify maximum round-trip valid sample delay for source\n");
@@ -1363,7 +1412,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
(where_from.u.sa_family == AF_INET && (where_from.u.sa_family == AF_INET &&
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr || (where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
where_from.in4.sin_port != his_addr.in4.sin_port)) || where_from.in4.sin_port != his_addr.in4.sin_port)) ||
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
(where_from.u.sa_family == AF_INET6 && (where_from.u.sa_family == AF_INET6 &&
(memcmp(where_from.in6.sin6_addr.s6_addr, his_addr.in6.sin6_addr.s6_addr, (memcmp(where_from.in6.sin6_addr.s6_addr, his_addr.in6.sin6_addr.s6_addr,
sizeof (where_from.in6.sin6_addr.s6_addr)) != 0 || sizeof (where_from.in6.sin6_addr.s6_addr)) != 0 ||
@@ -1701,10 +1750,10 @@ process_cmd_sources(char *line)
printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n"); printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n"); printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n"); printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| Reachability register (octal) -. | xxxx = adjusted offset,\n"); printf("|| / xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) --. | | yyyy = measured offset,\n"); printf("|| Log2(Polling interval) -. | yyyy = measured offset,\n");
printf("|| \\ | | zzzz = estimated error.\n"); printf("|| \\ | zzzz = estimated error.\n");
printf("|| | | \\\n"); printf("|| | | \n");
} }
printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n"); printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n");
@@ -2109,14 +2158,14 @@ process_cmd_manual_list(const char *line)
n_samples = ntohl(reply.data.manual_list.n_samples); n_samples = ntohl(reply.data.manual_list.n_samples);
printf("210 n_samples = %d\n", n_samples); printf("210 n_samples = %d\n", n_samples);
printf("# Date Time(UTC) Slewed Original Residual\n" printf("# Date Time(UTC) Slewed Original Residual\n"
"=======================================================\n"); "====================================================\n");
for (i=0; i<n_samples; i++) { for (i=0; i<n_samples; i++) {
sample = &reply.data.manual_list.samples[i]; sample = &reply.data.manual_list.samples[i];
UTI_TimevalNetworkToHost(&sample->when, &when); UTI_TimevalNetworkToHost(&sample->when, &when);
slewed_offset = UTI_FloatNetworkToHost(sample->slewed_offset); slewed_offset = UTI_FloatNetworkToHost(sample->slewed_offset);
orig_offset = UTI_FloatNetworkToHost(sample->orig_offset); orig_offset = UTI_FloatNetworkToHost(sample->orig_offset);
residual = UTI_FloatNetworkToHost(sample->residual); residual = UTI_FloatNetworkToHost(sample->residual);
printf("%2d %s %10.2f %10.2f %10.2f\n", i, UTI_TimeToLogForm(when.tv_sec), slewed_offset, orig_offset, residual); printf("%2d %s %10.2f %10.2f %10.2f\n", i, time_to_log_form(when.tv_sec), slewed_offset, orig_offset, residual);
} }
return 1; return 1;
} }
@@ -2187,25 +2236,10 @@ process_cmd_rekey(CMD_Request *msg, char *line)
/* ================================================== */ /* ================================================== */
static int static void
process_cmd_makestep(CMD_Request *msg, char *line) process_cmd_makestep(CMD_Request *msg, char *line)
{ {
int limit;
double threshold;
if (*line) {
if (sscanf(line, "%lf %d", &threshold, &limit) != 2) {
fprintf(stderr, "Bad syntax for makestep command\n");
return 0;
}
msg->command = htons(REQ_MODIFY_MAKESTEP);
msg->data.modify_makestep.limit = htonl(limit);
msg->data.modify_makestep.threshold = UTI_FloatHostToNetwork(threshold);
} else {
msg->command = htons(REQ_MAKESTEP); msg->command = htons(REQ_MAKESTEP);
}
return 1;
} }
/* ================================================== */ /* ================================================== */
@@ -2484,7 +2518,7 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "local")) { } else if (!strcmp(command, "local")) {
do_normal_submit = process_cmd_local(&tx_message, line); do_normal_submit = process_cmd_local(&tx_message, line);
} else if (!strcmp(command, "makestep")) { } else if (!strcmp(command, "makestep")) {
do_normal_submit = process_cmd_makestep(&tx_message, line); process_cmd_makestep(&tx_message, line);
} else if (!strcmp(command, "manual")) { } else if (!strcmp(command, "manual")) {
if (!strncmp(line, "list", 4)) { if (!strncmp(line, "list", 4)) {
do_normal_submit = 0; do_normal_submit = 0;
@@ -2576,8 +2610,8 @@ authenticate_from_config(const char *filename)
CMD_Reply rx_message; CMD_Reply rx_message;
char line[2048], keyfile[2048], *command, *arg, *password; char line[2048], keyfile[2048], *command, *arg, *password;
const char *hashname; const char *hashname;
uint32_t key_id = 0, key_id2; unsigned long key_id = 0, key_id2 = -1;
int key_id_valid = 1, ret; int ret;
FILE *in; FILE *in;
in = fopen(filename, "r"); in = fopen(filename, "r");
@@ -2594,12 +2628,13 @@ authenticate_from_config(const char *filename)
if (!strcasecmp(command, "keyfile")) { if (!strcasecmp(command, "keyfile")) {
snprintf(keyfile, sizeof (keyfile), "%s", arg); snprintf(keyfile, sizeof (keyfile), "%s", arg);
} else if (!strcasecmp(command, "commandkey")) { } else if (!strcasecmp(command, "commandkey")) {
key_id_valid = sscanf(arg, "%"SCNu32, &key_id) == 1; if (sscanf(arg, "%lu", &key_id) != 1)
key_id = -1;
} }
} }
fclose(in); fclose(in);
if (!*keyfile || !key_id_valid) { if (!*keyfile || key_id == -1) {
fprintf(stderr, "Could not read keyfile or commandkey in file %s\n", filename); fprintf(stderr, "Could not read keyfile or commandkey in file %s\n", filename);
return 0; return 0;
} }
@@ -2610,7 +2645,6 @@ authenticate_from_config(const char *filename)
return 0; return 0;
} }
key_id2 = key_id + 1;
while (fgets(line, sizeof (line), in)) { while (fgets(line, sizeof (line), in)) {
CPS_NormalizeLine(line); CPS_NormalizeLine(line);
if (!*line || !CPS_ParseKey(line, &key_id2, &hashname, &password)) if (!*line || !CPS_ParseKey(line, &key_id2, &hashname, &password))
@@ -2628,7 +2662,7 @@ authenticate_from_config(const char *filename)
ret = 0; ret = 0;
} }
} else { } else {
fprintf(stderr, "Could not find key %"PRIu32" in keyfile %s\n", key_id, keyfile); fprintf(stderr, "Could not find key %lu in keyfile %s\n", key_id, keyfile);
ret = 0; ret = 0;
} }
@@ -2728,7 +2762,7 @@ main(int argc, char **argv)
} else if (!strcmp(*argv, "-6")) { } else if (!strcmp(*argv, "-6")) {
family = IPADDR_INET6; family = IPADDR_INET6;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) { } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES); printf("chronyc (chrony) version %s\n", CHRONY_VERSION);
exit(0); exit(0);
} else if (!strncmp(*argv, "-", 1)) { } else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname); fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);

View File

@@ -174,11 +174,6 @@ CLG_Initialise(void)
void void
CLG_Finalise(void) CLG_Finalise(void)
{ {
int i;
for (i = 0; i < n_nodes; i++)
Free(nodes[i]);
Free(nodes);
} }
/* ================================================== */ /* ================================================== */
@@ -261,6 +256,31 @@ 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 void *
find_subnet_dont_open(Subnet *subnet, uint32_t *addr, int addr_len, int bits_consumed)
{
uint32_t this_subnet;
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);
}
}
}
/* ================================================== */ /* ================================================== */
void void
@@ -366,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_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices) time_t now, unsigned long *n_indices)

View File

@@ -31,6 +31,9 @@
#include "sysincl.h" #include "sysincl.h"
#include "reports.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_Initialise(void);
extern void CLG_Finalise(void); extern void CLG_Finalise(void);
extern void CLG_LogNTPClientAccess(IPAddr *client, time_t now); 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_INDEXTOOLARGE /* Node index is higher than number of nodes present */
} CLG_Status; } 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_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices); 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 */ #endif /* GOT_CLIENTLOG_H */

View File

@@ -54,7 +54,7 @@
union sockaddr_in46 { union sockaddr_in46 {
struct sockaddr_in in4; struct sockaddr_in in4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
#endif #endif
struct sockaddr u; struct sockaddr u;
@@ -62,7 +62,7 @@ union sockaddr_in46 {
/* File descriptors for command and monitoring sockets */ /* File descriptors for command and monitoring sockets */
static int sock_fd4; static int sock_fd4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
static int sock_fd6; static int sock_fd6;
#endif #endif
@@ -110,7 +110,7 @@ static ResponseCell *free_replies;
/* ================================================== */ /* ================================================== */
/* Array of permission levels for command types */ /* Array of permission levels for command types */
static const char permissions[] = { static int permissions[] = {
PERMIT_OPEN, /* NULL */ PERMIT_OPEN, /* NULL */
PERMIT_AUTH, /* ONLINE */ PERMIT_AUTH, /* ONLINE */
PERMIT_AUTH, /* OFFLINE */ PERMIT_AUTH, /* OFFLINE */
@@ -160,8 +160,7 @@ static const char permissions[] = {
PERMIT_AUTH, /* MODIFY_POLLTARGET */ PERMIT_AUTH, /* MODIFY_POLLTARGET */
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */ PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
PERMIT_AUTH, /* RESELECT */ PERMIT_AUTH, /* RESELECT */
PERMIT_AUTH, /* RESELECTDISTANCE */ PERMIT_AUTH /* RESELECTDISTANCE */
PERMIT_AUTH, /* MODIFY_MAKESTEP */
}; };
/* ================================================== */ /* ================================================== */
@@ -208,7 +207,7 @@ prepare_socket(int family, int port_number)
} }
#endif #endif
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
if (family == AF_INET6) { if (family == AF_INET6) {
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */ /* Receive IPv6 packets only */
@@ -232,9 +231,9 @@ prepare_socket(int family, int port_number)
if (bind_address.family == IPADDR_INET4) if (bind_address.family == IPADDR_INET4)
my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4); my_addr.in4.sin_addr.s_addr = htonl(bind_address.addr.in4);
else else
my_addr.in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); my_addr.in4.sin_addr.s_addr = htonl(INADDR_ANY);
break; break;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case AF_INET6: case AF_INET6:
my_addr_len = sizeof (my_addr.in6); my_addr_len = sizeof (my_addr.in6);
my_addr.in6.sin6_family = family; my_addr.in6.sin6_family = family;
@@ -246,7 +245,7 @@ prepare_socket(int family, int port_number)
memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6, memcpy(my_addr.in6.sin6_addr.s6_addr, bind_address.addr.in6,
sizeof (my_addr.in6.sin6_addr.s6_addr)); sizeof (my_addr.in6.sin6_addr.s6_addr));
else else
my_addr.in6.sin6_addr = in6addr_loopback; my_addr.in6.sin6_addr = in6addr_any;
break; break;
#endif #endif
default: default:
@@ -305,7 +304,7 @@ CAM_Initialise(int family)
sock_fd4 = prepare_socket(AF_INET, port_number); sock_fd4 = prepare_socket(AF_INET, port_number);
else else
sock_fd4 = -1; sock_fd4 = -1;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET6)) if (port_number && (family == IPADDR_UNSPEC || family == IPADDR_INET6))
sock_fd6 = prepare_socket(AF_INET6, port_number); sock_fd6 = prepare_socket(AF_INET6, port_number);
else else
@@ -313,7 +312,7 @@ CAM_Initialise(int family)
#endif #endif
if (port_number && sock_fd4 < 0 if (port_number && sock_fd4 < 0
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
&& sock_fd6 < 0 && sock_fd6 < 0
#endif #endif
) { ) {
@@ -334,7 +333,7 @@ CAM_Finalise(void)
close(sock_fd4); close(sock_fd4);
} }
sock_fd4 = -1; sock_fd4 = -1;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
if (sock_fd6 >= 0) { if (sock_fd6 >= 0) {
SCH_RemoveInputFileHandler(sock_fd6); SCH_RemoveInputFileHandler(sock_fd6);
close(sock_fd6); close(sock_fd6);
@@ -554,7 +553,7 @@ ts_is_unique_and_not_stale(struct timeval *ts, struct timeval *now)
/* ================================================== */ /* ================================================== */
#define REPLY_EXTEND_QUANTUM 8 #define REPLY_EXTEND_QUANTUM 32
static void static void
get_more_replies(void) get_more_replies(void)
@@ -689,7 +688,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
sock_fd = sock_fd4; sock_fd = sock_fd4;
addrlen = sizeof (where_to->in4); addrlen = sizeof (where_to->in4);
break; break;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case AF_INET6: case AF_INET6:
sock_fd = sock_fd6; sock_fd = sock_fd6;
addrlen = sizeof (where_to->in6); addrlen = sizeof (where_to->in6);
@@ -707,7 +706,23 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
unsigned short port; unsigned short port;
IPAddr ip; IPAddr ip;
UTI_SockaddrToIPAndPort(&where_to->u, &ip, &port); switch (where_to->u.sa_family) {
case AF_INET:
ip.family = IPADDR_INET4;
ip.addr.in4 = ntohl(where_to->in4.sin_addr.s_addr);
port = ntohs(where_to->in4.sin_port);
break;
#ifdef HAVE_IPV6
case AF_INET6:
ip.family = IPADDR_INET6;
memcpy(ip.addr.in6, (where_to->in6.sin6_addr.s6_addr), sizeof(ip.addr.in6));
port = ntohs(where_to->in6.sin6_port);
break;
#endif
default:
assert(0);
}
DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port); DEBUG_LOG(LOGF_CmdMon, "Could not send response to %s:%hu", UTI_IPToString(&ip), port);
} }
} }
@@ -909,16 +924,6 @@ handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
/* ================================================== */ /* ================================================== */
static void
handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
{
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
tx_message->status = htons(STT_SUCCESS);
}
/* ================================================== */
static void static void
handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message) handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
{ {
@@ -1256,10 +1261,6 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
params.min_stratum = SRC_DEFAULT_MINSTRATUM; params.min_stratum = SRC_DEFAULT_MINSTRATUM;
params.poll_target = SRC_DEFAULT_POLLTARGET; params.poll_target = SRC_DEFAULT_POLLTARGET;
params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO; params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
params.version = NTP_VERSION;
params.max_sources = SRC_DEFAULT_MAXSOURCES;
params.min_samples = SRC_DEFAULT_MINSAMPLES;
params.max_samples = SRC_DEFAULT_MAXSAMPLES;
status = NSR_AddSource(&rem_addr, type, &params); status = NSR_AddSource(&rem_addr, type, &params);
switch (status) { switch (status) {
@@ -1652,17 +1653,24 @@ read_from_cmd_socket(void *anything)
LCL_ReadRawTime(&now); LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked_now, NULL); LCL_CookTime(&now, &cooked_now, NULL);
UTI_SockaddrToIPAndPort(&where_from.u, &remote_ip, &remote_port); switch (where_from.u.sa_family) {
case AF_INET:
/* Check if it's a loopback address (127.0.0.1 or ::1) */ remote_ip.family = IPADDR_INET4;
switch (remote_ip.family) { remote_ip.addr.in4 = ntohl(where_from.in4.sin_addr.s_addr);
case IPADDR_INET4: remote_port = ntohs(where_from.in4.sin_port);
localhost = remote_ip.addr.in4 == INADDR_LOOPBACK; localhost = (remote_ip.addr.in4 == 0x7f000001UL);
break; break;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case IPADDR_INET6: case AF_INET6:
localhost = !memcmp(remote_ip.addr.in6, &in6addr_loopback, remote_ip.family = IPADDR_INET6;
sizeof (in6addr_loopback)); memcpy(&remote_ip.addr.in6, where_from.in6.sin6_addr.s6_addr,
sizeof (remote_ip.addr.in6));
remote_port = ntohs(where_from.in6.sin6_port);
/* Check for ::1 */
for (localhost = 0; localhost < 16; localhost++)
if (remote_ip.addr.in6[localhost] != 0)
break;
localhost = (localhost == 15 && remote_ip.addr.in6[localhost] == 1);
break; break;
#endif #endif
default: default:
@@ -1949,10 +1957,6 @@ read_from_cmd_socket(void *anything)
handle_modify_maxupdateskew(&rx_message, &tx_message); handle_modify_maxupdateskew(&rx_message, &tx_message);
break; break;
case REQ_MODIFY_MAKESTEP:
handle_modify_makestep(&rx_message, &tx_message);
break;
case REQ_LOGON: case REQ_LOGON:
/* If the log-on fails, record the reason why */ /* If the log-on fails, record the reason why */
if (!issue_token) { if (!issue_token) {

View File

@@ -34,7 +34,6 @@
#include "cmdparse.h" #include "cmdparse.h"
#include "memory.h" #include "memory.h"
#include "nameserv.h" #include "nameserv.h"
#include "ntp.h"
#include "util.h" #include "util.h"
/* ================================================== */ /* ================================================== */
@@ -43,7 +42,7 @@ CPS_Status
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{ {
char *hostname, *cmd; char *hostname, *cmd;
int n, done; int ok, n, done;
CPS_Status result; CPS_Status result;
src->port = SRC_DEFAULT_PORT; src->port = SRC_DEFAULT_PORT;
@@ -59,10 +58,6 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.iburst = 0; src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM; src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET; 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; src->params.sel_option = SRC_SelectNormal;
result = CPS_Success; result = CPS_Success;
@@ -72,10 +67,10 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!*hostname) { if (!*hostname) {
result = CPS_BadHost; result = CPS_BadHost;
ok = 0;
} else { } else {
src->name = hostname;
/* Parse subfields */ /* Parse subfields */
ok = 1;
done = 0; done = 0;
do { do {
cmd = line; cmd = line;
@@ -85,6 +80,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!strcasecmp(cmd, "port")) { if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1) { if (sscanf(line, "%hu%n", &src->port, &n) != 1) {
result = CPS_BadPort; result = CPS_BadPort;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -92,6 +88,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minpoll")) { } else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) { if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1) {
result = CPS_BadMinpoll; result = CPS_BadMinpoll;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -99,6 +96,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxpoll")) { } else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) { if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1) {
result = CPS_BadMaxpoll; result = CPS_BadMaxpoll;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -106,6 +104,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "presend")) { } else if (!strcasecmp(cmd, "presend")) {
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) { if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1) {
result = CPS_BadPresend; result = CPS_BadPresend;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -113,6 +112,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelaydevratio")) { } else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) { if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1) {
result = CPS_BadMaxdelaydevratio; result = CPS_BadMaxdelaydevratio;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -120,6 +120,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelayratio")) { } else if (!strcasecmp(cmd, "maxdelayratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) { if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1) {
result = CPS_BadMaxdelayratio; result = CPS_BadMaxdelayratio;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -127,14 +128,16 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelay")) { } else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) { if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1) {
result = CPS_BadMaxdelay; result = CPS_BadMaxdelay;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
} }
} else if (!strcasecmp(cmd, "key")) { } 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) { src->params.authkey == INACTIVE_AUTHKEY) {
result = CPS_BadKey; result = CPS_BadKey;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -151,6 +154,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minstratum")) { } else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) { if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1) {
result = CPS_BadMinstratum; result = CPS_BadMinstratum;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -159,6 +163,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "polltarget")) { } else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) { if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1) {
result = CPS_BadPolltarget; result = CPS_BadPolltarget;
ok = 0;
done = 1; done = 1;
} else { } else {
line += n; line += n;
@@ -170,40 +175,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "prefer")) { } else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_option = SRC_SelectPrefer; 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 { } else {
result = CPS_BadOption; result = CPS_BadOption;
ok = 0;
done = 1; done = 1;
} }
} else { } else {
@@ -212,73 +186,12 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} while (!done); } while (!done);
} }
return result; if (ok) {
} src->name = strdup(hostname);
/* ================================================== */
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;
} }
snprintf(dest, len, "Invalid %s", s); return result;
} }
/* ================================================== */ /* ================================================== */
@@ -341,7 +254,7 @@ CPS_SplitWord(char *line)
/* ================================================== */ /* ================================================== */
int 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; char *s1, *s2, *s3, *s4;
@@ -354,7 +267,7 @@ CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
if (!*s2 || *s4) if (!*s2 || *s4)
return 0; return 0;
if (sscanf(s1, "%"SCNu32, id) != 1) if (sscanf(s1, "%lu", id) != 1)
return 0; return 0;
if (*s3) { if (*s3) {

View File

@@ -43,11 +43,7 @@ typedef enum {
CPS_BadMaxdelay, CPS_BadMaxdelay,
CPS_BadKey, CPS_BadKey,
CPS_BadMinstratum, CPS_BadMinstratum,
CPS_BadPolltarget, CPS_BadPolltarget
CPS_BadVersion,
CPS_BadMaxsources,
CPS_BadMinsamples,
CPS_BadMaxsamples,
} CPS_Status; } CPS_Status;
typedef struct { typedef struct {
@@ -59,9 +55,6 @@ typedef struct {
/* Parse a command to add an NTP server or peer */ /* Parse a command to add an NTP server or peer */
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src); 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 */ /* Remove extra white-space and comments */
extern void CPS_NormalizeLine(char *line); extern void CPS_NormalizeLine(char *line);
@@ -69,6 +62,6 @@ extern void CPS_NormalizeLine(char *line);
extern char *CPS_SplitWord(char *line); extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */ /* 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 */ #endif /* GOT_CMDPARSE_H */

424
conf.c
View File

@@ -29,7 +29,6 @@
#include "sysincl.h" #include "sysincl.h"
#include "array.h"
#include "conf.h" #include "conf.h"
#include "ntp_sources.h" #include "ntp_sources.h"
#include "ntp_core.h" #include "ntp_core.h"
@@ -40,6 +39,7 @@
#include "nameserv.h" #include "nameserv.h"
#include "memory.h" #include "memory.h"
#include "cmdparse.h" #include "cmdparse.h"
#include "broadcast.h"
#include "util.h" #include "util.h"
/* ================================================== */ /* ================================================== */
@@ -47,7 +47,7 @@
static int parse_string(char *line, char **result); static int parse_string(char *line, char **result);
static int parse_int(char *line, int *result); static int parse_int(char *line, int *result);
static int parse_uint32(char *, uint32_t *result); static int parse_unsignedlong(char *, unsigned long *result);
static int parse_double(char *line, double *result); static int parse_double(char *line, double *result);
static int parse_null(char *line); static int parse_null(char *line);
@@ -69,7 +69,6 @@ static void parse_mailonchange(char *);
static void parse_makestep(char *); static void parse_makestep(char *);
static void parse_maxchange(char *); static void parse_maxchange(char *);
static void parse_peer(char *); static void parse_peer(char *);
static void parse_pool(char *);
static void parse_refclock(char *); static void parse_refclock(char *);
static void parse_server(char *); static void parse_server(char *);
static void parse_tempcomp(char *); static void parse_tempcomp(char *);
@@ -79,20 +78,20 @@ static void parse_tempcomp(char *);
static int restarted = 0; static int restarted = 0;
static int generate_command_key = 0; static int generate_command_key = 0;
static char *rtc_device; static char *rtc_device = "/dev/rtc";
static int acquisition_port = -1; static int acquisition_port = -1;
static int ntp_port = 123; static int ntp_port = 123;
static char *keys_file = NULL; static char *keys_file = NULL;
static char *drift_file = NULL; static char *drift_file = NULL;
static char *rtc_file = NULL; static char *rtc_file = NULL;
static uint32_t command_key_id; static unsigned long command_key_id;
static double max_update_skew = 1000.0; static double max_update_skew = 1000.0;
static double correction_time_ratio = 3.0; static double correction_time_ratio = 3.0;
static double max_clock_error = 1.0; /* in ppm */ static double max_clock_error = 1.0; /* in ppm */
static double max_slew_rate = 1e6 / 12.0; /* in ppm */ static double max_slew_rate = 1e6 / 12.0; /* in ppm */
static double reselect_distance = 1e-4; static double reselect_distance = 1e-4;
static double stratum_weight = 1e-3; static double stratum_weight = 1.0;
static double combine_limit = 3.0; static double combine_limit = 3.0;
static int cmd_port = DEFAULT_CANDM_PORT; static int cmd_port = DEFAULT_CANDM_PORT;
@@ -105,17 +104,19 @@ static int do_log_refclocks = 0;
static int do_log_tempcomp = 0; static int do_log_tempcomp = 0;
static int do_dump_on_exit = 0; static int do_dump_on_exit = 0;
static int log_banner = 32; static int log_banner = 32;
static char *logdir; static char *logdir = ".";
static char *dumpdir; static char *dumpdir = ".";
static int enable_local=0; static int enable_local=0;
static int local_stratum; static int local_stratum;
static int n_init_srcs;
/* Threshold (in seconds) - if absolute value of initial error is less /* Threshold (in seconds) - if absolute value of initial error is less
than this, slew instead of stepping */ than this, slew instead of stepping */
static double init_slew_threshold; static double init_slew_threshold;
/* Array of IPAddr */ #define MAX_INIT_SRCS 8
static ARR_Instance init_sources; static IPAddr init_srcs_ip[MAX_INIT_SRCS];
static int enable_manual=0; static int enable_manual=0;
@@ -136,9 +137,6 @@ static double make_step_threshold = 0.0;
/* Threshold for automatic RTC trimming */ /* Threshold for automatic RTC trimming */
static double rtc_autotrim_threshold = 0.0; static double rtc_autotrim_threshold = 0.0;
/* Minimum number of selectables sources required to update the clock */
static int min_sources = 1;
/* Number of updates before offset checking, number of ignored updates /* Number of updates before offset checking, number of ignored updates
before exiting and the maximum allowed offset */ before exiting and the maximum allowed offset */
static int max_offset_delay = -1; static int max_offset_delay = -1;
@@ -177,16 +175,15 @@ static IPAddr bind_address4, bind_address6;
static IPAddr bind_acq_address4, bind_acq_address6; static IPAddr bind_acq_address4, bind_acq_address6;
/* IP addresses for binding the command socket to. UNSPEC family means /* IP addresses for binding the command socket to. UNSPEC family means
the loopback address will be used */ use the value of bind_address */
static IPAddr bind_cmd_address4, bind_cmd_address6; static IPAddr bind_cmd_address4, bind_cmd_address6;
/* Filename to use for storing pid of running chronyd, to prevent multiple /* Filename to use for storing pid of running chronyd, to prevent multiple
* chronyds being started. */ * chronyds being started. */
static char *pidfile; static char *pidfile = "/var/run/chronyd.pid";
/* Temperature sensor, update interval and compensation coefficients */ /* Temperature sensor, update interval and compensation coefficients */
static char *tempcomp_sensor_file = NULL; static char *tempcomp_file = NULL;
static char *tempcomp_point_file = NULL;
static double tempcomp_interval; static double tempcomp_interval;
static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2; static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
@@ -197,39 +194,45 @@ static int lock_memory = 0;
static char *leapsec_tz = NULL; static char *leapsec_tz = NULL;
/* Name of the user to which will be dropped root privileges. */ /* Name of the user to which will be dropped root privileges. */
static char *user; static char *user = DEFAULT_USER;
typedef struct { typedef struct {
NTP_Source_Type type; NTP_Source_Type type;
int pool;
CPS_NTP_Source params; CPS_NTP_Source params;
} NTP_Source; } NTP_Source;
/* Array of NTP_Source */ #define MAX_NTP_SOURCES 64
static ARR_Instance ntp_sources;
/* Array of RefclockParameters */ static NTP_Source ntp_sources[MAX_NTP_SOURCES];
static ARR_Instance refclock_sources; static int n_ntp_sources = 0;
#define MAX_RCL_SOURCES 8
static RefclockParameters refclock_sources[MAX_RCL_SOURCES];
static int n_refclock_sources = 0;
typedef struct _AllowDeny { typedef struct _AllowDeny {
struct _AllowDeny *next;
struct _AllowDeny *prev;
IPAddr ip; IPAddr ip;
int subnet_bits; int subnet_bits;
int all; /* 1 to override existing more specific defns */ int all; /* 1 to override existing more specific defns */
int allow; /* 0 for deny, 1 for allow */ int allow; /* 0 for deny, 1 for allow */
} AllowDeny; } AllowDeny;
/* Arrays of AllowDeny */ static AllowDeny ntp_auth_list = {&ntp_auth_list, &ntp_auth_list};
static ARR_Instance ntp_restrictions; static AllowDeny cmd_auth_list = {&cmd_auth_list, &cmd_auth_list};
static ARR_Instance cmd_restrictions;
typedef struct { typedef struct {
/* Both in host (not necessarily network) order */
IPAddr addr; IPAddr addr;
unsigned short port; unsigned short port;
int interval; int interval;
} NTP_Broadcast_Destination; } NTP_Broadcast_Destination;
/* Array of NTP_Broadcast_Destination */ static NTP_Broadcast_Destination *broadcasts = NULL;
static ARR_Instance broadcasts; static int max_broadcasts = 0;
static int n_broadcasts = 0;
/* ================================================== */ /* ================================================== */
@@ -260,31 +263,18 @@ other_parse_error(const char *message)
/* ================================================== */ /* ================================================== */
static int static void
get_number_of_args(char *line) check_number_of_args(char *line, int num)
{ {
int num = 0;
/* The line is normalized, between arguments is just one space */ /* The line is normalized, between arguments is just one space */
if (*line == ' ') if (*line == ' ')
line++; line++;
if (*line) if (*line)
num++; num--;
for (; *line; line++) { for (; *line; line++) {
if (*line == ' ') if (*line == ' ')
num++; num--;
} }
return num;
}
/* ================================================== */
static void
check_number_of_args(char *line, int num)
{
num -= get_number_of_args(line);
if (num) { if (num) {
LOG_FATAL(LOGF_Configure, "%s arguments for %s directive at line %d%s%s", LOG_FATAL(LOGF_Configure, "%s arguments for %s directive at line %d%s%s",
num > 0 ? "Missing" : "Too many", num > 0 ? "Missing" : "Too many",
@@ -296,56 +286,9 @@ check_number_of_args(char *line, int num)
/* ================================================== */ /* ================================================== */
void void
CNF_Initialise(int r) CNF_SetRestarted(int r)
{ {
restarted = r; restarted = r;
init_sources = ARR_CreateInstance(sizeof (IPAddr));
ntp_sources = ARR_CreateInstance(sizeof (NTP_Source));
refclock_sources = ARR_CreateInstance(sizeof (RefclockParameters));
broadcasts = ARR_CreateInstance(sizeof (NTP_Broadcast_Destination));
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
dumpdir = Strdup(".");
logdir = Strdup(".");
pidfile = Strdup("/var/run/chronyd.pid");
rtc_device = Strdup("/dev/rtc");
user = Strdup(DEFAULT_USER);
}
/* ================================================== */
void
CNF_Finalise(void)
{
unsigned int i;
for (i = 0; i < ARR_GetSize(ntp_sources); i++)
Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name);
ARR_DestroyInstance(init_sources);
ARR_DestroyInstance(ntp_sources);
ARR_DestroyInstance(refclock_sources);
ARR_DestroyInstance(broadcasts);
ARR_DestroyInstance(ntp_restrictions);
ARR_DestroyInstance(cmd_restrictions);
Free(drift_file);
Free(dumpdir);
Free(hwclock_file);
Free(keys_file);
Free(leapsec_tz);
Free(logdir);
Free(pidfile);
Free(rtc_device);
Free(rtc_file);
Free(user);
Free(mail_user_on_change);
Free(tempcomp_sensor_file);
Free(tempcomp_point_file);
} }
/* ================================================== */ /* ================================================== */
@@ -417,7 +360,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "combinelimit")) { } else if (!strcasecmp(command, "combinelimit")) {
parse_double(p, &combine_limit); parse_double(p, &combine_limit);
} else if (!strcasecmp(command, "commandkey")) { } else if (!strcasecmp(command, "commandkey")) {
parse_uint32(p, &command_key_id); parse_unsignedlong(p, &command_key_id);
} else if (!strcasecmp(command, "corrtimeratio")) { } else if (!strcasecmp(command, "corrtimeratio")) {
parse_double(p, &correction_time_ratio); parse_double(p, &correction_time_ratio);
} else if (!strcasecmp(command, "deny")) { } else if (!strcasecmp(command, "deny")) {
@@ -476,16 +419,12 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_double(p, &max_update_skew); parse_double(p, &max_update_skew);
} else if (!strcasecmp(command, "minsamples")) { } else if (!strcasecmp(command, "minsamples")) {
parse_int(p, &min_samples); parse_int(p, &min_samples);
} else if (!strcasecmp(command, "minsources")) {
parse_int(p, &min_sources);
} else if (!strcasecmp(command, "noclientlog")) { } else if (!strcasecmp(command, "noclientlog")) {
no_client_log = parse_null(p); no_client_log = parse_null(p);
} else if (!strcasecmp(command, "peer")) { } else if (!strcasecmp(command, "peer")) {
parse_peer(p); parse_peer(p);
} else if (!strcasecmp(command, "pidfile")) { } else if (!strcasecmp(command, "pidfile")) {
parse_string(p, &pidfile); parse_string(p, &pidfile);
} else if (!strcasecmp(command, "pool")) {
parse_pool(p);
} else if (!strcasecmp(command, "port")) { } else if (!strcasecmp(command, "port")) {
parse_int(p, &ntp_port); parse_int(p, &ntp_port);
} else if (!strcasecmp(command, "refclock")) { } else if (!strcasecmp(command, "refclock")) {
@@ -523,8 +462,7 @@ static int
parse_string(char *line, char **result) parse_string(char *line, char **result)
{ {
check_number_of_args(line, 1); check_number_of_args(line, 1);
Free(*result); *result = strdup(line);
*result = Strdup(line);
return 1; return 1;
} }
@@ -544,10 +482,10 @@ parse_int(char *line, int *result)
/* ================================================== */ /* ================================================== */
static int static int
parse_uint32(char *line, uint32_t *result) parse_unsignedlong(char *line, unsigned long *result)
{ {
check_number_of_args(line, 1); check_number_of_args(line, 1);
if (sscanf(line, "%"SCNu32, result) != 1) { if (sscanf(line, "%lu", result) != 1) {
command_parse_error(); command_parse_error();
return 0; return 0;
} }
@@ -579,24 +517,57 @@ parse_null(char *line)
/* ================================================== */ /* ================================================== */
static void static void
parse_source(char *line, NTP_Source_Type type, int pool) parse_source(char *line, NTP_Source_Type type)
{ {
CPS_Status status; CPS_Status status;
NTP_Source source;
char str[64];
source.type = type; if (n_ntp_sources >= MAX_NTP_SOURCES)
source.pool = pool;
status = CPS_ParseNTPSourceAdd(line, &source.params);
if (status != CPS_Success) {
CPS_StatusToString(status, str, sizeof (str));
other_parse_error(str);
return; return;
}
source.params.name = Strdup(source.params.name); ntp_sources[n_ntp_sources].type = type;
ARR_AppendElement(ntp_sources, &source); status = CPS_ParseNTPSourceAdd(line, &ntp_sources[n_ntp_sources].params);
switch (status) {
case CPS_Success:
n_ntp_sources++;
break;
case CPS_BadOption:
other_parse_error("Invalid server/peer parameter");
break;
case CPS_BadHost:
other_parse_error("Invalid host/IP address");
break;
case CPS_BadPort:
other_parse_error("Unreadable port");
break;
case CPS_BadMinpoll:
other_parse_error("Unreadable minpoll");
break;
case CPS_BadMaxpoll:
other_parse_error("Unreadable maxpoll");
break;
case CPS_BadPresend:
other_parse_error("Unreadable presend");
break;
case CPS_BadMaxdelaydevratio:
other_parse_error("Unreadable maxdelaydevratio");
break;
case CPS_BadMaxdelayratio:
other_parse_error("Unreadable maxdelayratio");
break;
case CPS_BadMaxdelay:
other_parse_error("Unreadable maxdelay");
break;
case CPS_BadKey:
other_parse_error("Unreadable key");
break;
case CPS_BadMinstratum:
other_parse_error("Unreadable minstratum");
break;
case CPS_BadPolltarget:
other_parse_error("Unreadable polltarget");
break;
}
} }
/* ================================================== */ /* ================================================== */
@@ -604,7 +575,7 @@ parse_source(char *line, NTP_Source_Type type, int pool)
static void static void
parse_server(char *line) parse_server(char *line)
{ {
parse_source(line, NTP_SERVER, 0); parse_source(line, NTP_SERVER);
} }
/* ================================================== */ /* ================================================== */
@@ -612,15 +583,7 @@ parse_server(char *line)
static void static void
parse_peer(char *line) parse_peer(char *line)
{ {
parse_source(line, NTP_PEER, 0); parse_source(line, NTP_PEER);
}
/* ================================================== */
static void
parse_pool(char *line)
{
parse_source(line, NTP_SERVER, 1);
} }
/* ================================================== */ /* ================================================== */
@@ -628,20 +591,21 @@ parse_pool(char *line)
static void static void
parse_refclock(char *line) parse_refclock(char *line)
{ {
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples; int i, n, poll, dpoll, filter_length, pps_rate;
uint32_t ref_id, lock_ref_id; uint32_t ref_id, lock_ref_id;
double offset, delay, precision, max_dispersion; double offset, delay, precision, max_dispersion;
char *p, *cmd, *name, *param; char *p, *cmd, *name, *param;
unsigned char ref[5]; unsigned char ref[5];
SRC_SelectOption sel_option; SRC_SelectOption sel_option;
RefclockParameters *refclock;
i = n_refclock_sources;
if (i >= MAX_RCL_SOURCES)
return;
poll = 4; poll = 4;
dpoll = 0; dpoll = 0;
filter_length = 64; filter_length = 64;
pps_rate = 0; pps_rate = 0;
min_samples = SRC_DEFAULT_MINSAMPLES;
max_samples = SRC_DEFAULT_MAXSAMPLES;
offset = 0.0; offset = 0.0;
delay = 1e-9; delay = 1e-9;
precision = 0.0; precision = 0.0;
@@ -663,11 +627,11 @@ parse_refclock(char *line)
return; return;
} }
name = Strdup(p); name = strdup(p);
p = line; p = line;
line = CPS_SplitWord(line); line = CPS_SplitWord(line);
param = Strdup(p); param = strdup(p);
while (*line) { while (*line) {
cmd = line; cmd = line;
@@ -695,12 +659,6 @@ parse_refclock(char *line)
} else if (!strcasecmp(cmd, "rate")) { } else if (!strcasecmp(cmd, "rate")) {
if (sscanf(line, "%d%n", &pps_rate, &n) != 1) if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
break; break;
} else if (!strcasecmp(cmd, "minsamples")) {
if (sscanf(line, "%d%n", &min_samples, &n) != 1)
break;
} else if (!strcasecmp(cmd, "maxsamples")) {
if (sscanf(line, "%d%n", &max_samples, &n) != 1)
break;
} else if (!strcasecmp(cmd, "offset")) { } else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &offset, &n) != 1) if (sscanf(line, "%lf%n", &offset, &n) != 1)
break; break;
@@ -730,22 +688,21 @@ parse_refclock(char *line)
return; return;
} }
refclock = (RefclockParameters *)ARR_GetNewElement(refclock_sources); refclock_sources[i].driver_name = name;
refclock->driver_name = name; refclock_sources[i].driver_parameter = param;
refclock->driver_parameter = param; refclock_sources[i].driver_poll = dpoll;
refclock->driver_poll = dpoll; refclock_sources[i].poll = poll;
refclock->poll = poll; refclock_sources[i].filter_length = filter_length;
refclock->filter_length = filter_length; refclock_sources[i].pps_rate = pps_rate;
refclock->pps_rate = pps_rate; refclock_sources[i].offset = offset;
refclock->min_samples = min_samples; refclock_sources[i].delay = delay;
refclock->max_samples = max_samples; refclock_sources[i].precision = precision;
refclock->offset = offset; refclock_sources[i].max_dispersion = max_dispersion;
refclock->delay = delay; refclock_sources[i].sel_option = sel_option;
refclock->precision = precision; refclock_sources[i].ref_id = ref_id;
refclock->max_dispersion = max_dispersion; refclock_sources[i].lock_ref_id = lock_ref_id;
refclock->sel_option = sel_option;
refclock->ref_id = ref_id; n_refclock_sources++;
refclock->lock_ref_id = lock_ref_id;
} }
/* ================================================== */ /* ================================================== */
@@ -807,7 +764,7 @@ parse_initstepslew(char *line)
return; return;
} }
ARR_SetSize(init_sources, 0); n_init_srcs = 0;
p = CPS_SplitWord(line); p = CPS_SplitWord(line);
if (sscanf(line, "%lf", &init_slew_threshold) != 1) { if (sscanf(line, "%lf", &init_slew_threshold) != 1) {
@@ -819,11 +776,16 @@ parse_initstepslew(char *line)
hostname = p; hostname = p;
p = CPS_SplitWord(p); p = CPS_SplitWord(p);
if (*hostname) { if (*hostname) {
if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) { if (DNS_Name2IPAddress(hostname, &ip_addr) == DNS_Success) {
ARR_AppendElement(init_sources, &ip_addr); init_srcs_ip[n_init_srcs] = ip_addr;
++n_init_srcs;
} else { } else {
LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname); LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname);
} }
if (n_init_srcs >= MAX_INIT_SRCS) {
other_parse_error("Too many initstepslew servers");
}
} }
} }
} }
@@ -893,9 +855,8 @@ parse_mailonchange(char *line)
check_number_of_args(line, 2); check_number_of_args(line, 2);
address = line; address = line;
line = CPS_SplitWord(line); line = CPS_SplitWord(line);
Free(mail_user_on_change);
if (sscanf(line, "%lf", &mail_change_threshold) == 1) { if (sscanf(line, "%lf", &mail_change_threshold) == 1) {
mail_user_on_change = Strdup(address); mail_user_on_change = strdup(address);
} else { } else {
mail_user_on_change = NULL; mail_user_on_change = NULL;
command_parse_error(); command_parse_error();
@@ -905,7 +866,7 @@ parse_mailonchange(char *line)
/* ================================================== */ /* ================================================== */
static void static void
parse_allow_deny(char *line, ARR_Instance restrictions, int allow) parse_allow_deny(char *line, AllowDeny *list, int allow)
{ {
char *p; char *p;
unsigned long a, b, c, d, n; unsigned long a, b, c, d, n;
@@ -922,7 +883,7 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
if (!*p) { if (!*p) {
/* Empty line applies to all addresses */ /* Empty line applies to all addresses */
new_node = (AllowDeny *)ARR_GetNewElement(restrictions); new_node = MallocNew(AllowDeny);
new_node->allow = allow; new_node->allow = allow;
new_node->all = all; new_node->all = all;
new_node->ip.family = IPADDR_UNSPEC; new_node->ip.family = IPADDR_UNSPEC;
@@ -936,7 +897,7 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
n = 0; n = 0;
if (UTI_StringToIP(p, &ip_addr) || if (UTI_StringToIP(p, &ip_addr) ||
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) { (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) >= 1) {
new_node = (AllowDeny *)ARR_GetNewElement(restrictions); new_node = MallocNew(AllowDeny);
new_node->allow = allow; new_node->allow = allow;
new_node->all = all; new_node->all = all;
@@ -987,8 +948,8 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
} }
} else { } else {
if (DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) { if (DNS_Name2IPAddress(p, &ip_addr) == DNS_Success) {
new_node = (AllowDeny *)ARR_GetNewElement(restrictions); new_node = MallocNew(AllowDeny);
new_node->allow = allow; new_node->allow = allow;
new_node->all = all; new_node->all = all;
new_node->ip = ip_addr; new_node->ip = ip_addr;
@@ -1001,6 +962,14 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
} }
} }
} }
if (new_node) {
new_node->prev = list->prev;
new_node->next = list;
list->prev->next = new_node;
list->prev = new_node;
}
} }
@@ -1009,7 +978,7 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
static void static void
parse_allow(char *line) parse_allow(char *line)
{ {
parse_allow_deny(line, ntp_restrictions, 1); parse_allow_deny(line, &ntp_auth_list, 1);
} }
@@ -1018,7 +987,7 @@ parse_allow(char *line)
static void static void
parse_deny(char *line) parse_deny(char *line)
{ {
parse_allow_deny(line, ntp_restrictions, 0); parse_allow_deny(line, &ntp_auth_list, 0);
} }
/* ================================================== */ /* ================================================== */
@@ -1026,7 +995,7 @@ parse_deny(char *line)
static void static void
parse_cmdallow(char *line) parse_cmdallow(char *line)
{ {
parse_allow_deny(line, cmd_restrictions, 1); parse_allow_deny(line, &cmd_auth_list, 1);
} }
@@ -1035,7 +1004,7 @@ parse_cmdallow(char *line)
static void static void
parse_cmddeny(char *line) parse_cmddeny(char *line)
{ {
parse_allow_deny(line, cmd_restrictions, 0); parse_allow_deny(line, &cmd_auth_list, 0);
} }
/* ================================================== */ /* ================================================== */
@@ -1098,7 +1067,6 @@ static void
parse_broadcast(char *line) parse_broadcast(char *line)
{ {
/* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */ /* Syntax : broadcast <interval> <broadcast-IP-addr> [<port>] */
NTP_Broadcast_Destination *destination;
int port; int port;
int interval; int interval;
char *p; char *p;
@@ -1133,10 +1101,20 @@ parse_broadcast(char *line)
port = 123; port = 123;
} }
destination = (NTP_Broadcast_Destination *)ARR_GetNewElement(broadcasts); if (max_broadcasts == n_broadcasts) {
destination->addr = ip; /* Expand array */
destination->port = port; max_broadcasts += 8;
destination->interval = interval; if (broadcasts) {
broadcasts = ReallocArray(NTP_Broadcast_Destination, max_broadcasts, broadcasts);
} else {
broadcasts = MallocArray(NTP_Broadcast_Destination, max_broadcasts);
}
}
broadcasts[n_broadcasts].addr = ip;
broadcasts[n_broadcasts].port = port;
broadcasts[n_broadcasts].interval = interval;
++n_broadcasts;
} }
/* ================================================== */ /* ================================================== */
@@ -1145,13 +1123,8 @@ static void
parse_tempcomp(char *line) parse_tempcomp(char *line)
{ {
char *p; char *p;
int point_form;
point_form = get_number_of_args(line) == 3;
if (!point_form)
check_number_of_args(line, 6); check_number_of_args(line, 6);
p = line; p = line;
line = CPS_SplitWord(line); line = CPS_SplitWord(line);
@@ -1160,25 +1133,12 @@ parse_tempcomp(char *line)
return; return;
} }
Free(tempcomp_point_file); if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval, &tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
if (point_form) {
if (sscanf(line, "%lf", &tempcomp_interval) != 1) {
command_parse_error(); command_parse_error();
return; return;
} }
tempcomp_point_file = Strdup(CPS_SplitWord(line));
} else {
if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval,
&tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
command_parse_error();
return;
}
tempcomp_point_file = NULL;
}
Free(tempcomp_sensor_file); tempcomp_file = strdup(p);
tempcomp_sensor_file = Strdup(p);
} }
/* ================================================== */ /* ================================================== */
@@ -1198,54 +1158,43 @@ CNF_AddInitSources(void)
CPS_NTP_Source cps_source; CPS_NTP_Source cps_source;
NTP_Remote_Address ntp_addr; NTP_Remote_Address ntp_addr;
char dummy_hostname[2] = "H"; char dummy_hostname[2] = "H";
unsigned int i; int i;
for (i = 0; i < ARR_GetSize(init_sources); i++) { for (i = 0; i < n_init_srcs; i++) {
/* Get the default NTP params */ /* Get the default NTP params */
CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source); CPS_ParseNTPSourceAdd(dummy_hostname, &cps_source);
/* Add the address as an offline iburst server */ /* Add the address as an offline iburst server */
ntp_addr.ip_addr = *(IPAddr *)ARR_GetElement(init_sources, i); ntp_addr.ip_addr = init_srcs_ip[i];
ntp_addr.port = cps_source.port; ntp_addr.port = cps_source.port;
cps_source.params.iburst = 1; cps_source.params.iburst = 1;
cps_source.params.online = 0; cps_source.params.online = 0;
NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params); NSR_AddSource(&ntp_addr, NTP_SERVER, &cps_source.params);
} }
ARR_SetSize(init_sources, 0);
} }
/* ================================================== */ /* ================================================== */
void void
CNF_AddSources(void) CNF_AddSources(void) {
{ int i;
NTP_Source *source;
unsigned int i;
for (i = 0; i < ARR_GetSize(ntp_sources); i++) { for (i=0; i<n_ntp_sources; i++) {
source = (NTP_Source *)ARR_GetElement(ntp_sources, i); NSR_AddUnresolvedSource(ntp_sources[i].params.name, ntp_sources[i].params.port,
NSR_AddSourceByName(source->params.name, source->params.port, ntp_sources[i].type, &ntp_sources[i].params.params);
source->pool, source->type, &source->params.params);
Free(source->params.name);
} }
ARR_SetSize(ntp_sources, 0);
} }
/* ================================================== */ /* ================================================== */
void void
CNF_AddRefclocks(void) CNF_AddRefclocks(void) {
{ int i;
unsigned int i;
for (i = 0; i < ARR_GetSize(refclock_sources); i++) { for (i=0; i<n_refclock_sources; i++) {
RCL_AddRefclock((RefclockParameters *)ARR_GetElement(refclock_sources, i)); RCL_AddRefclock(&refclock_sources[i]);
} }
ARR_SetSize(refclock_sources, 0);
} }
/* ================================================== */ /* ================================================== */
@@ -1253,16 +1202,12 @@ CNF_AddRefclocks(void)
void void
CNF_AddBroadcasts(void) CNF_AddBroadcasts(void)
{ {
unsigned int i; int i;
NTP_Broadcast_Destination *destination; for (i=0; i<n_broadcasts; i++) {
BRD_AddDestination(&broadcasts[i].addr,
for (i = 0; i < ARR_GetSize(broadcasts); i++) { broadcasts[i].port,
destination = (NTP_Broadcast_Destination *)ARR_GetElement(broadcasts, i); broadcasts[i].interval);
NCR_AddBroadcastDestination(&destination->addr, destination->port,
destination->interval);
} }
ARR_SetSize(broadcasts, 0);
} }
/* ================================================== */ /* ================================================== */
@@ -1395,7 +1340,7 @@ CNF_GetRtcDevice(void)
/* ================================================== */ /* ================================================== */
uint32_t unsigned long
CNF_GetCommandKey(void) CNF_GetCommandKey(void)
{ {
return command_key_id; return command_key_id;
@@ -1568,26 +1513,20 @@ CNF_SetupAccessRestrictions(void)
{ {
AllowDeny *node; AllowDeny *node;
int status; int status;
unsigned int i;
for (i = 0; i < ARR_GetSize(ntp_restrictions); i++) { for (node = ntp_auth_list.next; node != &ntp_auth_list; node = node->next) {
node = ARR_GetElement(ntp_restrictions, i);
status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); status = NCR_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) { if (!status) {
LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits); LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
} }
} }
for (i = 0; i < ARR_GetSize(cmd_restrictions); i++) { for (node = cmd_auth_list.next; node != &cmd_auth_list; node = node->next) {
node = ARR_GetElement(cmd_restrictions, i);
status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all); status = CAM_AddAccessRestriction(&node->ip, node->subnet_bits, node->allow, node->all);
if (!status) { if (!status) {
LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits); LOG_FATAL(LOGF_Configure, "Bad subnet in %s/%d", UTI_IPToString(&node->ip), node->subnet_bits);
} }
} }
ARR_SetSize(ntp_restrictions, 0);
ARR_SetSize(cmd_restrictions, 0);
} }
/* ================================================== */ /* ================================================== */
@@ -1647,9 +1586,9 @@ void
CNF_GetBindCommandAddress(int family, IPAddr *addr) CNF_GetBindCommandAddress(int family, IPAddr *addr)
{ {
if (family == IPADDR_INET4) if (family == IPADDR_INET4)
*addr = bind_cmd_address4; *addr = bind_cmd_address4.family != IPADDR_UNSPEC ? bind_cmd_address4 : bind_address4;
else if (family == IPADDR_INET6) else if (family == IPADDR_INET6)
*addr = bind_cmd_address6; *addr = bind_cmd_address6.family != IPADDR_UNSPEC ? bind_cmd_address6 : bind_address6;
else else
addr->family = IPADDR_UNSPEC; addr->family = IPADDR_UNSPEC;
} }
@@ -1689,10 +1628,9 @@ CNF_GetLockMemory(void)
/* ================================================== */ /* ================================================== */
void void
CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2) CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2)
{ {
*file = tempcomp_sensor_file; *file = tempcomp_file;
*point_file = tempcomp_point_file;
*interval = tempcomp_interval; *interval = tempcomp_interval;
*T0 = tempcomp_T0; *T0 = tempcomp_T0;
*k0 = tempcomp_k0; *k0 = tempcomp_k0;
@@ -1726,14 +1664,6 @@ CNF_GetMinSamples(void)
/* ================================================== */ /* ================================================== */
int
CNF_GetMinSources(void)
{
return min_sources;
}
/* ================================================== */
char * char *
CNF_GetHwclockFile(void) CNF_GetHwclockFile(void)
{ {
@@ -1745,7 +1675,7 @@ CNF_GetHwclockFile(void)
int int
CNF_GetInitSources(void) CNF_GetInitSources(void)
{ {
return ARR_GetSize(init_sources); return n_init_srcs;
} }
/* ================================================== */ /* ================================================== */

9
conf.h
View File

@@ -30,8 +30,7 @@
#include "addressing.h" #include "addressing.h"
extern void CNF_Initialise(int restarted); extern void CNF_SetRestarted(int);
extern void CNF_Finalise(void);
extern char *CNF_GetRtcDevice(void); extern char *CNF_GetRtcDevice(void);
@@ -57,7 +56,7 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void); extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void); extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void); extern char *CNF_GetRtcFile(void);
extern uint32_t CNF_GetCommandKey(void); extern unsigned long CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void); extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void); extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void); extern int CNF_GetManualEnabled(void);
@@ -94,15 +93,13 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void); extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void); extern int CNF_GetLockMemory(void);
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 char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void); extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void); extern int CNF_GetMinSamples(void);
extern int CNF_GetMinSources(void);
extern double CNF_GetRtcAutotrim(void); extern double CNF_GetRtcAutotrim(void);
extern char *CNF_GetHwclockFile(void); extern char *CNF_GetHwclockFile(void);

121
configure vendored
View File

@@ -8,6 +8,8 @@
# #
# ======================================================================= # =======================================================================
rm -f config.h config.log
# This configure script determines the operating system type and version # This configure script determines the operating system type and version
if [ "x${CC}" = "x" ]; then if [ "x${CC}" = "x" ]; then
@@ -103,17 +105,13 @@ For better control, use the options below.
--readline-inc-dir=DIR Specify where readline include directory is --readline-inc-dir=DIR Specify where readline include directory is
--readline-lib-dir=DIR Specify where readline lib directory is --readline-lib-dir=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is --with-ncurses-library=DIR Specify where ncurses lib directory is
--disable-sechash Disable support for hashes other than MD5
--without-nss Don't use NSS even if it is available --without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt 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-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-rtc Don't include RTC even on Linux
--disable-linuxcaps Disable libcap (Linux capabilities) support --disable-linuxcaps Disable Linux capabilities support
--disable-asyncdns Disable asynchronous name resolving --disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error --disable-forcednsretry Don't retry on permanent DNS error
--with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds --with-ntp-era=SECONDS Specify earliest assumed NTP time in seconds
@@ -169,22 +167,6 @@ pkg_config () {
pkg-config $@ 2> /dev/null pkg-config $@ 2> /dev/null
} }
#}}} #}}}
#{{{ get_features
get_features () {
ff=1
for f; do
if [ "$ff" = "0" ]; then
echo -n " "
fi
if grep "define FEAT_$f" config.h > /dev/null; then
echo -n "+$f"
else
echo -n "-$f"
fi
ff=0
done
}
#}}}
# ====================================================================== # ======================================================================
@@ -200,20 +182,16 @@ EXTRA_OBJECTS=""
EXTRA_DEFS="" EXTRA_DEFS=""
SYSDEFS="" SYSDEFS=""
feat_debug=0 debug=0
feat_cmdmon=1
feat_ntp=1
feat_refclock=1
feat_readline=1 feat_readline=1
try_readline=1 try_readline=1
try_editline=1 try_editline=1
feat_sechash=1
try_nss=1 try_nss=1
try_tomcrypt=1 try_tomcrypt=1
feat_rtc=1 feat_rtc=1
try_rtc=0 try_rtc=0
feat_droproot=1 feat_linuxcaps=1
try_libcap=0 try_linuxcaps=0
readline_lib="" readline_lib=""
readline_inc="" readline_inc=""
ncurses_lib="" ncurses_lib=""
@@ -233,7 +211,7 @@ for option
do do
case "$option" in case "$option" in
--enable-debug ) --enable-debug )
feat_debug=1 debug=1
;; ;;
--disable-readline ) --disable-readline )
feat_readline=0 feat_readline=0
@@ -286,15 +264,6 @@ do
--chronyvardir=* ) --chronyvardir=* )
SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'` SETCHRONYVARDIR=`echo $option | sed -e 's/^.*=//;'`
;; ;;
--disable-cmdmon)
feat_cmdmon=0
;;
--disable-ntp)
feat_ntp=0
;;
--disable-refclock)
feat_refclock=0
;;
--disable-rtc) --disable-rtc)
feat_rtc=0 feat_rtc=0
;; ;;
@@ -308,7 +277,7 @@ do
feat_pps=0 feat_pps=0
;; ;;
--disable-linuxcaps) --disable-linuxcaps)
feat_droproot=0 feat_linuxcaps=0
;; ;;
--disable-asyncdns) --disable-asyncdns)
feat_asyncdns=0 feat_asyncdns=0
@@ -325,9 +294,6 @@ do
--with-sendmail=* ) --with-sendmail=* )
mail_program=`echo $option | sed -e 's/^.*=//;'` mail_program=`echo $option | sed -e 's/^.*=//;'`
;; ;;
--disable-sechash )
feat_sechash=0
;;
--without-nss ) --without-nss )
try_nss=0 try_nss=0
;; ;;
@@ -352,8 +318,6 @@ do
esac esac
done done
rm -f config.h config.log
SYSTEM=${OPERATINGSYSTEM}-${MACHINE} SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
case $SYSTEM in case $SYSTEM in
@@ -376,7 +340,7 @@ case $SYSTEM in
;; ;;
Linux* ) Linux* )
EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o" EXTRA_OBJECTS="sys_generic.o sys_linux.o wrap_adjtimex.o"
try_libcap=1 try_linuxcaps=1
try_rtc=1 try_rtc=1
try_setsched=1 try_setsched=1
try_lockmem=1 try_lockmem=1
@@ -425,34 +389,6 @@ case $SYSTEM in
;; ;;
esac 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
if test_code '64-bit time_t' 'time.h' '' '' ' if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0}; char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];' return x[0];'
@@ -500,11 +436,11 @@ else
fi fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
add_def HAVE_STDINT_H add_def HAS_STDINT_H
fi fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
add_def HAVE_INTTYPES_H add_def HAS_INTTYPES_H
fi fi
if [ $feat_ipv6 = "1" ] && \ if [ $feat_ipv6 = "1" ] && \
@@ -514,7 +450,7 @@ if [ $feat_ipv6 = "1" ] && \
n.sin6_addr = in6addr_any; n.sin6_addr = in6addr_any;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));' return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then then
add_def FEAT_IPV6 add_def HAVE_IPV6
if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' ' if test_code 'in6_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
return sizeof(struct in6_pktinfo);' return sizeof(struct in6_pktinfo);'
then then
@@ -541,12 +477,11 @@ if [ $feat_asyncdns = "1" ] && \
then then
add_def FEAT_ASYNCDNS add_def FEAT_ASYNCDNS
add_def USE_PTHREAD_ASYNCDNS add_def USE_PTHREAD_ASYNCDNS
EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
MYCFLAGS="$MYCFLAGS -pthread" MYCFLAGS="$MYCFLAGS -pthread"
fi fi
timepps_h="" 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 if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h" timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H add_def HAVE_SYS_TIMEPPS_H
@@ -565,17 +500,17 @@ if [ "x$timepps_h" != "x" ] && \
struct timespec ts; struct timespec ts;
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);' return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then then
add_def FEAT_PPS add_def HAVE_PPSAPI
fi fi
if [ $feat_droproot = "1" ] && [ $try_libcap = "1" ] && \ if [ $feat_linuxcaps = "1" ] && [ $try_linuxcaps = "1" ] && \
test_code \ test_code \
libcap \ linuxcaps \
'sys/types.h pwd.h sys/prctl.h sys/capability.h grp.h' \ 'sys/types.h pwd.h sys/prctl.h sys/capability.h grp.h' \
'' '-lcap' \ '' '-lcap' \
'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));' 'prctl(PR_SET_KEEPCAPS, 1);cap_set_proc(cap_from_text("cap_sys_time=ep"));'
then then
add_def FEAT_PRIVDROP add_def FEAT_LINUXCAPS
EXTRA_LIBS="$EXTRA_LIBS -lcap" EXTRA_LIBS="$EXTRA_LIBS -lcap"
fi fi
@@ -587,7 +522,7 @@ then
add_def FEAT_RTC add_def FEAT_RTC
fi 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' '' '' \ test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);' 'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
then then
@@ -675,7 +610,7 @@ HASH_OBJ="hash_intmd5.o"
HASH_COMPILE="" HASH_COMPILE=""
HASH_LINK="" HASH_LINK=""
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then if [ $try_nss = "1" ]; then
test_cflags="`pkg_config --cflags nss`" test_cflags="`pkg_config --cflags nss`"
test_link="`pkg_config --libs-only-L nss` -lfreebl3" test_link="`pkg_config --libs-only-L nss` -lfreebl3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \ if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
@@ -686,11 +621,11 @@ if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
HASH_COMPILE="$test_cflags" HASH_COMPILE="$test_cflags"
HASH_LINK="$test_link" HASH_LINK="$test_link"
LIBS="$LIBS $HASH_LINK" LIBS="$LIBS $HASH_LINK"
add_def FEAT_SECHASH add_def GENERATE_SHA1_KEY
fi fi
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' \ if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);' 'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
then then
@@ -698,7 +633,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]
HASH_COMPILE="-I/usr/include/tomcrypt" HASH_COMPILE="-I/usr/include/tomcrypt"
HASH_LINK="-ltomcrypt" HASH_LINK="-ltomcrypt"
LIBS="$LIBS $HASH_LINK" LIBS="$LIBS $HASH_LINK"
add_def FEAT_SECHASH add_def GENERATE_SHA1_KEY
fi fi
fi fi
@@ -757,17 +692,11 @@ if [ "x$SETCHRONYVARDIR" != "x" ]; then
CHRONYVARDIR=$SETCHRONYVARDIR CHRONYVARDIR=$SETCHRONYVARDIR
fi fi
add_def DEBUG $debug
add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\"" add_def DEFAULT_CONF_FILE "\"$SYSCONFDIR/chrony.conf\""
add_def DEFAULT_USER "\"$default_user\"" add_def DEFAULT_USER "\"$default_user\""
add_def MAIL_PROGRAM "\"$mail_program\"" add_def MAIL_PROGRAM "\"$mail_program\""
common_features="`get_features ASYNCDNS IPV6 SECHASH`"
chronyc_features="`get_features READLINE`"
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP DEBUG`"
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 if [ -f version.txt ]; then
add_def CHRONY_VERSION "\"`cat version.txt`\"" add_def CHRONY_VERSION "\"`cat version.txt`\""
else else

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

@@ -43,29 +43,25 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or # you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project. # you can use servers from the pool.ntp.org project.
! server foo.example.net iburst ! server 0.pool.ntp.org iburst
! server bar.example.net iburst ! server 1.pool.ntp.org iburst
! server baz.example.net iburst ! server 2.pool.ntp.org iburst
! pool pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word # However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use # 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have # chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line. # become visible after you go on-line.
! server foo.example.net offline ! server 0.pool.ntp.org offline
! server bar.example.net offline ! server 1.pool.ntp.org offline
! server baz.example.net offline ! server 2.pool.ntp.org offline
! pool pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network # 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 # with a lot of computers and want several computers running chrony to
# have the 'front-line' interface to the public NTP servers, you can # have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness. # '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 # There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose # might want to use. For example, you can ignore measurements whose
@@ -111,7 +107,6 @@ keyfile /etc/chrony.keys
commandkey 1 commandkey 1
# With this directive a random password will be generated automatically. # With this directive a random password will be generated automatically.
generatecommandkey generatecommandkey
# chronyd can save the measurement history for the servers to files when # chronyd can save the measurement history for the servers to files when
@@ -238,18 +233,13 @@ generatecommandkey
# several people, you need to set up a mailing list or sendmail alias # several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.) # for them and use the address of that.)
! mailonchange wibble@foo.example.net 0.5 ! mailonchange wibble@foobar.org 0.5
####################################################################### #######################################################################
### COMMAND ACCESS ### COMMAND ACCESS
# The program chronyc is used to show the current operation of chronyd # The program chronyc is used to show the current operation of chronyd
# and to change parts of its configuration whilst it is running. # 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 # Normally, chronyd will only allow connections from chronyc on the same
# machine as itself. This is for security. If you have a subnet # 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 # 192.168.*.* and you want to be able to use chronyc from any machine on

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 10 seconds.
makestep 10 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

View File

@@ -1,40 +1,46 @@
# Use public servers from the pool.ntp.org project. # Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html). # 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. # Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift driftfile /var/lib/chrony/drift
# Enable kernel RTC synchronization.
rtcsync
# In first three updates step the system clock instead of slew # In first three updates step the system clock instead of slew
# if the adjustment is larger than 10 seconds. # if the adjustment is larger than 10 seconds.
makestep 10 3 makestep 10 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
# Allow NTP client access from local network. # Allow NTP client access from local network.
#allow 192.168/16 #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. # Serve time even if not synchronized to any NTP server.
#local stratum 10 #local stratum 10
# Specify file containing keys for NTP and command authentication.
keyfile /etc/chrony.keys keyfile /etc/chrony.keys
# Specify key number for command authentication. # Specify the key used as password for chronyc.
commandkey 1 commandkey 1
# Generate new command key on start if missing. # Generate command key if missing.
generatecommandkey generatecommandkey
# Disable logging of client accesses. # Disable logging of client accesses.
noclientlog 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 logchange 0.5
# Specify directory for log files.
logdir /var/log/chrony logdir /var/log/chrony
# Select which information is logged.
#log measurements statistics tracking #log measurements statistics tracking

2
hash.h
View File

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

View File

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

View File

@@ -87,17 +87,3 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return ret; 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; return len;
} }
void
HSH_Finalise(void)
{
}

164
keys.c
View File

@@ -30,7 +30,6 @@
#include "sysincl.h" #include "sysincl.h"
#include "array.h"
#include "keys.h" #include "keys.h"
#include "cmdparse.h" #include "cmdparse.h"
#include "conf.h" #include "conf.h"
@@ -41,27 +40,30 @@
typedef struct { typedef struct {
uint32_t id; unsigned long id;
char *val; char *val;
int len; int len;
int hash_id; int hash_id;
int auth_delay; int auth_delay;
} Key; } 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_valid;
static uint32_t command_key_id; static int command_key_id;
static int cache_valid; static int cache_valid;
static uint32_t cache_key_id; static unsigned long cache_key_id;
static int cache_key_pos; static int cache_key_pos;
/* ================================================== */ /* ================================================== */
static int static int
generate_key(uint32_t key_id) generate_key(unsigned long key_id)
{ {
#ifdef FEAT_SECHASH #ifdef GENERATE_SHA1_KEY
unsigned char key[20]; unsigned char key[20];
const char *hashname = "SHA1"; const char *hashname = "SHA1";
#else #else
@@ -100,7 +102,7 @@ generate_key(uint32_t key_id)
return 0; return 0;
} }
fprintf(f, "\n%"PRIu32" %s HEX:", key_id, hashname); fprintf(f, "\n%lu %s HEX:", key_id, hashname);
for (i = 0; i < sizeof (key); i++) for (i = 0; i < sizeof (key); i++)
fprintf(f, "%02hhX", key[i]); fprintf(f, "%02hhX", key[i]);
fprintf(f, "\n"); fprintf(f, "\n");
@@ -109,32 +111,17 @@ generate_key(uint32_t key_id)
/* Erase the key from stack */ /* Erase the key from stack */
memset(key, 0, sizeof (key)); memset(key, 0, sizeof (key));
LOG(LOGS_INFO, LOGF_Keys, "Generated key %"PRIu32, key_id); LOG(LOGS_INFO, LOGF_Keys, "Generated key %lu", key_id);
return 1; return 1;
} }
/* ================================================== */ /* ================================================== */
static void
free_keys(void)
{
unsigned int i;
for (i = 0; i < ARR_GetSize(keys); i++)
Free(((Key *)ARR_GetElement(keys, i))->val);
ARR_SetSize(keys, 0);
command_key_valid = 0;
cache_valid = 0;
}
/* ================================================== */
void void
KEY_Initialise(void) KEY_Initialise(void)
{ {
keys = ARR_CreateInstance(sizeof (Key)); n_keys = 0;
command_key_valid = 0; command_key_valid = 0;
cache_valid = 0; cache_valid = 0;
KEY_Reload(); KEY_Reload();
@@ -150,22 +137,12 @@ KEY_Initialise(void)
void void
KEY_Finalise(void) KEY_Finalise(void)
{ {
free_keys();
ARR_DestroyInstance(keys);
}
/* ================================================== */
static Key *
get_key(unsigned int index)
{
return ((Key *)ARR_GetElements(keys)) + index;
} }
/* ================================================== */ /* ================================================== */
static int static int
determine_hash_delay(uint32_t key_id) determine_hash_delay(unsigned long key_id)
{ {
NTP_Packet pkt; NTP_Packet pkt;
struct timeval before, after; struct timeval before, after;
@@ -174,7 +151,7 @@ determine_hash_delay(uint32_t key_id)
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before); 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)); (unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after); LCL_ReadRawTime(&after);
@@ -188,7 +165,7 @@ determine_hash_delay(uint32_t key_id)
/* Add on a bit extra to allow for copying, conversions etc */ /* Add on a bit extra to allow for copying, conversions etc */
min_usecs += min_usecs >> 4; 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; return min_usecs;
} }
@@ -218,14 +195,18 @@ compare_keys_by_id(const void *a, const void *b)
void void
KEY_Reload(void) KEY_Reload(void)
{ {
unsigned int i, line_number; int i, line_number;
FILE *in; FILE *in;
uint32_t key_id; unsigned long key_id;
char line[2048], *keyval, *key_file; char line[2048], *keyval, *key_file;
const char *hashname; 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(); key_file = CNF_GetKeysFile();
line_number = 0; line_number = 0;
@@ -251,22 +232,22 @@ KEY_Reload(void)
continue; continue;
} }
key.hash_id = HSH_GetHashId(hashname); keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (key.hash_id < 0) { if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, key_id); LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %lu", key_id);
continue; continue;
} }
key.len = UTI_DecodePasswordFromText(keyval); keys[n_keys].len = UTI_DecodePasswordFromText(keyval);
if (!key.len) { if (!keys[n_keys].len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, key_id); LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %lu", key_id);
continue; continue;
} }
key.id = key_id; keys[n_keys].id = key_id;
key.val = MallocArray(char, key.len); keys[n_keys].val = MallocArray(char, keys[n_keys].len);
memcpy(key.val, keyval, key.len); memcpy(keys[n_keys].val, keyval, keys[n_keys].len);
ARR_AppendElement(keys, &key); n_keys++;
} }
fclose(in); fclose(in);
@@ -274,50 +255,50 @@ KEY_Reload(void)
/* Sort keys into order. Note, if there's a duplicate, it is /* Sort keys into order. Note, if there's a duplicate, it is
arbitrary which one we use later - the user should have been arbitrary which one we use later - the user should have been
more careful! */ 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 */ /* Check for duplicates */
for (i = 1; i < ARR_GetSize(keys); i++) { for (i = 1; i < n_keys; i++) {
if (get_key(i - 1)->id == get_key(i)->id) if (keys[i - 1].id == keys[i].id) {
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->id); LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %lu", keys[i].id);
}
} }
/* Erase any passwords from stack */ /* Erase any passwords from stack */
memset(line, 0, sizeof (line)); memset(line, 0, sizeof (line));
for (i = 0; i < ARR_GetSize(keys); i++) for (i=0; i<n_keys; i++) {
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id); keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
} }
/* ================================================== */ /* ================================================== */
static int static int
lookup_key(uint32_t id) lookup_key(unsigned long id)
{ {
Key specimen, *where, *keys_ptr; Key specimen, *where;
int pos; int pos;
keys_ptr = ARR_GetElements(keys);
specimen.id = id; specimen.id = id;
where = (Key *)bsearch((void *)&specimen, keys_ptr, ARR_GetSize(keys), where = (Key *) bsearch((void *)&specimen, (void *)keys, n_keys, sizeof(Key), compare_keys_by_id);
sizeof (Key), compare_keys_by_id);
if (!where) { if (!where) {
return -1; return -1;
} else { } else {
pos = where - keys_ptr; pos = where - keys;
return pos; return pos;
} }
} }
/* ================================================== */ /* ================================================== */
static Key * static int
get_key_by_id(uint32_t key_id) get_key_pos(unsigned long key_id)
{ {
int position; int position;
if (cache_valid && key_id == cache_key_id) if (cache_valid && key_id == cache_key_id)
return get_key(cache_key_pos); return cache_key_pos;
position = lookup_key(key_id); position = lookup_key(key_id);
@@ -325,16 +306,14 @@ get_key_by_id(uint32_t key_id)
cache_valid = 1; cache_valid = 1;
cache_key_pos = position; cache_key_pos = position;
cache_key_id = key_id; cache_key_id = key_id;
return get_key(position);
} }
return NULL; return position;
} }
/* ================================================== */ /* ================================================== */
uint32_t unsigned long
KEY_GetCommandKey(void) KEY_GetCommandKey(void)
{ {
if (!command_key_valid) { if (!command_key_valid) {
@@ -347,56 +326,61 @@ KEY_GetCommandKey(void)
/* ================================================== */ /* ================================================== */
int 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 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 0;
}
return key->auth_delay; return keys[key_pos].auth_delay;
} }
/* ================================================== */ /* ================================================== */
int 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) 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 0;
}
return UTI_GenerateNTPAuth(key->hash_id, (unsigned char *)key->val, return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
key->len, data, data_len, auth, auth_len); (unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
} }
/* ================================================== */ /* ================================================== */
int 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) 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 0;
}
return UTI_CheckNTPAuth(key->hash_id, (unsigned char *)key->val, return UTI_CheckNTPAuth(keys[key_pos].hash_id,
key->len, data, data_len, auth, auth_len); (unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
} }

14
keys.h
View File

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

26
local.c
View File

@@ -56,7 +56,6 @@ static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_ApplyStepOffsetDriver drv_apply_step_offset; static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
static lcl_OffsetCorrectionDriver drv_offset_convert; static lcl_OffsetCorrectionDriver drv_offset_convert;
static lcl_SetLeapDriver drv_set_leap; static lcl_SetLeapDriver drv_set_leap;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* ================================================== */ /* ================================================== */
@@ -169,13 +168,6 @@ LCL_Initialise(void)
void void
LCL_Finalise(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);
} }
/* ================================================== */ /* ================================================== */
@@ -255,7 +247,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->next->prev = ptr->prev; ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next; ptr->prev->next = ptr->next;
Free(ptr); free(ptr);
} }
/* ================================================== */ /* ================================================== */
@@ -332,7 +324,7 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->next->prev = ptr->prev; ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next; ptr->prev->next = ptr->next;
Free(ptr); free(ptr);
} }
/* ================================================== */ /* ================================================== */
@@ -558,8 +550,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset, lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset, lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert, lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap, lcl_SetLeapDriver set_leap)
lcl_SetSyncStatusDriver set_sync_status)
{ {
drv_read_freq = read_freq; drv_read_freq = read_freq;
drv_set_freq = set_freq; drv_set_freq = set_freq;
@@ -567,7 +558,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_apply_step_offset = apply_step_offset; drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert; drv_offset_convert = offset_convert;
drv_set_leap = set_leap; drv_set_leap = set_leap;
drv_set_sync_status = set_sync_status;
current_freq_ppm = (*drv_read_freq)(); current_freq_ppm = (*drv_read_freq)();
@@ -635,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);
}
}
/* ================================================== */

View File

@@ -206,8 +206,4 @@ extern void LCL_SetLeap(int leap);
due to clamping or rounding). */ due to clamping or rounding). */
extern double LCL_SetTempComp(double comp); 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 */ #endif /* GOT_LOCAL_H */

View File

@@ -57,9 +57,6 @@ typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, do
/* System driver to schedule leap second */ /* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap); 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 lcl_InvokeDispersionNotifyHandlers(double dispersion);
extern void extern void
@@ -68,7 +65,6 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset, lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset, lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert, lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap, lcl_SetLeapDriver set_leap);
lcl_SetSyncStatusDriver set_sync_status);
#endif /* GOT_LOCALP_H */ #endif /* GOT_LOCALP_H */

View File

@@ -211,6 +211,8 @@ void LOG_SetDebugLevel(int level)
{ {
debug_level = level; debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) { if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
if (!DEBUG)
LOG(LOGS_WARN, LOGF_Logging, "Not compiled with full debugging support");
log_debug_enabled = 1; log_debug_enabled = 1;
} }
} }

View File

@@ -80,7 +80,6 @@ typedef enum {
LOGF_Local, LOGF_Local,
LOGF_Util, LOGF_Util,
LOGF_Main, LOGF_Main,
LOGF_Memory,
LOGF_ClientLog, LOGF_ClientLog,
LOGF_Configure, LOGF_Configure,
LOGF_CmdMon, LOGF_CmdMon,

26
main.c
View File

@@ -48,6 +48,7 @@
#include "rtc.h" #include "rtc.h"
#include "refclock.h" #include "refclock.h"
#include "clientlog.h" #include "clientlog.h"
#include "broadcast.h"
#include "nameserv.h" #include "nameserv.h"
#include "tempcomp.h" #include "tempcomp.h"
@@ -85,33 +86,28 @@ MAI_CleanupAndExit(void)
SRC_DumpSources(); SRC_DumpSources();
} }
/* Don't update clock when removing sources */
REF_SetMode(REF_ModeIgnore);
TMC_Finalise(); TMC_Finalise();
MNL_Finalise(); MNL_Finalise();
CLG_Finalise(); CLG_Finalise();
NSR_Finalise(); NSR_Finalise();
NCR_Finalise(); NCR_Finalise();
CAM_Finalise(); BRD_Finalise();
NIO_Finalise();
SST_Finalise(); SST_Finalise();
REF_Finalise();
KEY_Finalise(); KEY_Finalise();
RCL_Finalise(); RCL_Finalise();
SRC_Finalise(); SRC_Finalise();
REF_Finalise();
RTC_Finalise(); RTC_Finalise();
CAM_Finalise();
NIO_Finalise();
SYS_Finalise(); SYS_Finalise();
SCH_Finalise(); SCH_Finalise();
LCL_Finalise(); LCL_Finalise();
delete_pidfile(); delete_pidfile();
CNF_Finalise();
LOG_Finalise(); LOG_Finalise();
HSH_Finalise();
exit(exit_status); exit(exit_status);
} }
@@ -383,7 +379,7 @@ int main
do_init_rtc = 1; do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) { } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */ /* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES); printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
exit(0); exit(0);
} else if (!strcmp("-n", *argv)) { } else if (!strcmp("-n", *argv)) {
nofork = 1; nofork = 1;
@@ -429,12 +425,11 @@ int main
LOG_SetDebugLevel(debug); LOG_SetDebugLevel(debug);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)", LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
CHRONY_VERSION, CHRONYD_FEATURES);
DNS_SetAddressFamily(address_family); DNS_SetAddressFamily(address_family);
CNF_Initialise(restarted); CNF_SetRestarted(restarted);
/* Parse the config file or the remaining command line arguments */ /* Parse the config file or the remaining command line arguments */
if (!config_args) { if (!config_args) {
@@ -460,6 +455,8 @@ int main
LCL_Initialise(); LCL_Initialise();
SCH_Initialise(); SCH_Initialise();
SYS_Initialise(); SYS_Initialise();
NIO_Initialise(address_family);
CAM_Initialise(address_family);
RTC_Initialise(do_init_rtc); RTC_Initialise(do_init_rtc);
SRC_Initialise(); SRC_Initialise();
RCL_Initialise(); RCL_Initialise();
@@ -488,8 +485,7 @@ int main
REF_Initialise(); REF_Initialise();
SST_Initialise(); SST_Initialise();
NIO_Initialise(address_family); BRD_Initialise();
CAM_Initialise(address_family);
NCR_Initialise(); NCR_Initialise();
NSR_Initialise(); NSR_Initialise();
CLG_Initialise(); CLG_Initialise();

View File

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

View File

@@ -30,7 +30,6 @@
#include "sysincl.h" #include "sysincl.h"
#include "memory.h"
#include "mkdirpp.h" #include "mkdirpp.h"
static int static int
@@ -75,7 +74,7 @@ mkdir_and_parents(const char *path)
int i, j, k, last; int i, j, k, last;
len = strlen(path); len = strlen(path);
p = (char *)Malloc(1 + len); p = (char *) malloc(1 + len);
i = k = 0; i = k = 0;
while (1) { while (1) {
@@ -85,7 +84,7 @@ mkdir_and_parents(const char *path)
p[i] = 0; p[i] = 0;
if (do_dir(p) < 0) { if (do_dir(p) < 0) {
Free(p); free(p);
return 0; return 0;
} }
@@ -115,7 +114,7 @@ mkdir_and_parents(const char *path)
} }
Free(p); free(p);
return 1; return 1;
} }

View File

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

View File

@@ -39,7 +39,7 @@ typedef enum {
/* Resolve names only to selected address family */ /* Resolve names only to selected address family */
extern void DNS_SetAddressFamily(int 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); extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);

View File

@@ -34,17 +34,17 @@
#include "sched.h" #include "sched.h"
#include "util.h" #include "util.h"
#ifdef FEAT_ASYNCDNS
#ifdef USE_PTHREAD_ASYNCDNS #ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h> #include <pthread.h>
#define MAX_ADDRESSES 16
/* ================================================== */ /* ================================================== */
struct DNS_Async_Instance { struct DNS_Async_Instance {
const char *name; const char *name;
DNS_Status status; DNS_Status status;
IPAddr addresses[MAX_ADDRESSES]; IPAddr addr;
DNS_NameResolveHandler handler; DNS_NameResolveHandler handler;
void *arg; void *arg;
@@ -61,7 +61,7 @@ start_resolving(void *anything)
{ {
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)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 */ /* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0) if (write(inst->pipe[1], "", 1) < 0)
@@ -76,7 +76,6 @@ static void
end_resolving(void *anything) end_resolving(void *anything)
{ {
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
int i;
if (pthread_join(inst->thread, NULL)) { if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed"); LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
@@ -88,11 +87,7 @@ end_resolving(void *anything)
close(inst->pipe[0]); close(inst->pipe[0]);
close(inst->pipe[1]); close(inst->pipe[1]);
for (i = 0; inst->status == DNS_Success && i < MAX_ADDRESSES && (inst->handler)(inst->status, &inst->addr, inst->arg);
inst->addresses[i].family != IPADDR_UNSPEC; i++)
;
(inst->handler)(inst->status, i, inst->addresses, inst->arg);
Free(inst); Free(inst);
} }
@@ -129,3 +124,21 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
#else #else
#error #error
#endif #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,7 +31,7 @@
#include "nameserv.h" #include "nameserv.h"
/* Function type for callback to process the result */ /* 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 /* Request resolving of a name to IP address. The handler will be
called when the result is available, but it may be also called called when the result is available, but it may be also called

48
ntp.h
View File

@@ -38,23 +38,7 @@ typedef struct {
typedef uint32_t NTP_int32; typedef uint32_t NTP_int32;
/* The NTP protocol version that we support */ #define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
#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
/* Type definition for leap bits */ /* Type definition for leap bits */
typedef enum { typedef enum {
@@ -85,28 +69,24 @@ typedef struct {
NTP_int64 originate_ts; NTP_int64 originate_ts;
NTP_int64 receive_ts; NTP_int64 receive_ts;
NTP_int64 transmit_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; NTP_int32 auth_keyid;
uint8_t auth_data[NTP_MAX_MAC_LENGTH]; uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet; } 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 */ /* Define the maximum number of bytes that can be read in a single
typedef struct { 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; NTP_Packet ntp_pkt;
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH]; uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} NTP_Receive_Buffer; } ReceiveBuffer;
/* Macros to work with the lvm field */ #define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
#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))
#endif /* GOT_NTP_H */ #endif /* GOT_NTP_H */

1085
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 */ /* Reset an instance */
extern void NCR_ResetInstance(NCR_Instance inst); 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, /* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */ and it relates to a source we have an ongoing protocol exchange with */
extern 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, /* This routine is called when a new packet arrives off the network,
and we do not recognize its source */ and we do not recognize its source */
@@ -107,6 +104,4 @@ extern NTP_Remote_Address *NCR_GetRemoteAddress(NCR_Instance instance);
extern int NCR_IsSyncPeer(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 */ #endif /* GOT_NTP_CORE_H */

198
ntp_io.c
View File

@@ -43,7 +43,7 @@
union sockaddr_in46 { union sockaddr_in46 {
struct sockaddr_in in4; struct sockaddr_in in4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
#endif #endif
struct sockaddr u; struct sockaddr u;
@@ -52,27 +52,15 @@ union sockaddr_in46 {
/* The server/peer and client sockets for IPv4 and IPv6 */ /* The server/peer and client sockets for IPv4 and IPv6 */
static int server_sock_fd4; static int server_sock_fd4;
static int client_sock_fd4; static int client_sock_fd4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
static int server_sock_fd6; static int server_sock_fd6;
static int client_sock_fd6; static int client_sock_fd6;
#endif #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 /* Flag indicating we create a new connected client socket for each
server instead of sharing client_sock_fd4 and client_sock_fd6 */ server instead of sharing client_sock_fd4 and client_sock_fd6 */
static int separate_client_sockets; 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 */ /* Flag indicating that we have been initialised */
static int initialised=0; static int initialised=0;
@@ -128,7 +116,7 @@ prepare_socket(int family, int port_number, int client_only)
my_addr_len = sizeof (my_addr.in4); my_addr_len = sizeof (my_addr.in4);
break; break;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case AF_INET6: case AF_INET6:
if (!client_only) if (!client_only)
CNF_GetBindAddress(IPADDR_INET6, &bind_address); CNF_GetBindAddress(IPADDR_INET6, &bind_address);
@@ -186,13 +174,14 @@ prepare_socket(int family, int port_number, int client_only)
if (family == AF_INET) { if (family == AF_INET) {
#ifdef IP_PKTINFO #ifdef IP_PKTINFO
/* We want the local IP info on server sockets */ /* 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"); LOG(LOGS_ERR, LOGF_NtpIO, "Could not set packet info socket option");
/* Don't quit - we might survive anyway */ /* Don't quit - we might survive anyway */
} }
#endif #endif
} }
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
else if (family == AF_INET6) { else if (family == AF_INET6) {
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
/* Receive IPv6 packets only */ /* Receive IPv6 packets only */
@@ -201,6 +190,7 @@ prepare_socket(int family, int port_number, int client_only)
} }
#endif #endif
if (!client_only) {
#ifdef IPV6_RECVPKTINFO #ifdef IPV6_RECVPKTINFO
if (setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (char *)&on_off, sizeof(on_off)) < 0) { 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"); LOG(LOGS_ERR, LOGF_NtpIO, "Could not set IPv6 packet info socket option");
@@ -211,6 +201,7 @@ prepare_socket(int family, int port_number, int client_only)
} }
#endif #endif
} }
}
#endif #endif
/* Bind the socket if a port or address was specified */ /* Bind the socket if a port or address was specified */
@@ -235,7 +226,7 @@ prepare_separate_client_socket(int family)
switch (family) { switch (family) {
case IPADDR_INET4: case IPADDR_INET4:
return prepare_socket(AF_INET, 0, 1); return prepare_socket(AF_INET, 0, 1);
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case IPADDR_INET6: case IPADDR_INET6:
return prepare_socket(AF_INET6, 0, 1); return prepare_socket(AF_INET6, 0, 1);
#endif #endif
@@ -252,9 +243,27 @@ connect_socket(int sock_fd, NTP_Remote_Address *remote_addr)
union sockaddr_in46 addr; union sockaddr_in46 addr;
socklen_t addr_len; 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) { if (connect(sock_fd, &addr.u, addr_len) < 0) {
DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s", DEBUG_LOG(LOGF_NtpIO, "Could not connect NTP socket to %s:%d : %s",
@@ -295,20 +304,15 @@ NIO_Initialise(int family)
if (client_port < 0) if (client_port < 0)
client_port = 0; client_port = 0;
permanent_server_sockets = !server_port || (!separate_client_sockets &&
client_port == server_port);
server_sock_fd4 = INVALID_SOCK_FD; server_sock_fd4 = INVALID_SOCK_FD;
client_sock_fd4 = INVALID_SOCK_FD; client_sock_fd4 = INVALID_SOCK_FD;
server_sock_ref4 = 0; #ifdef HAVE_IPV6
#ifdef FEAT_IPV6
server_sock_fd6 = INVALID_SOCK_FD; server_sock_fd6 = INVALID_SOCK_FD;
client_sock_fd6 = INVALID_SOCK_FD; client_sock_fd6 = INVALID_SOCK_FD;
server_sock_ref6 = 0;
#endif #endif
if (family == IPADDR_UNSPEC || family == IPADDR_INET4) { 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); server_sock_fd4 = prepare_socket(AF_INET, server_port, 0);
if (!separate_client_sockets) { if (!separate_client_sockets) {
if (client_port != server_port || !server_port) if (client_port != server_port || !server_port)
@@ -317,9 +321,9 @@ NIO_Initialise(int family)
client_sock_fd4 = server_sock_fd4; client_sock_fd4 = server_sock_fd4;
} }
} }
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
if (family == IPADDR_UNSPEC || family == IPADDR_INET6) { 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); server_sock_fd6 = prepare_socket(AF_INET6, server_port, 0);
if (!separate_client_sockets) { if (!separate_client_sockets) {
if (client_port != server_port || !server_port) if (client_port != server_port || !server_port)
@@ -330,13 +334,12 @@ NIO_Initialise(int family)
} }
#endif #endif
if ((server_port && server_sock_fd4 == INVALID_SOCK_FD && if ((server_port && server_sock_fd4 == INVALID_SOCK_FD
permanent_server_sockets #ifdef HAVE_IPV6
#ifdef FEAT_IPV6
&& server_sock_fd6 == INVALID_SOCK_FD && server_sock_fd6 == INVALID_SOCK_FD
#endif #endif
) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD ) || (!separate_client_sockets && client_sock_fd4 == INVALID_SOCK_FD
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
&& client_sock_fd6 == INVALID_SOCK_FD && client_sock_fd6 == INVALID_SOCK_FD
#endif #endif
)) { )) {
@@ -353,7 +356,7 @@ NIO_Finalise(void)
close_socket(client_sock_fd4); close_socket(client_sock_fd4);
close_socket(server_sock_fd4); close_socket(server_sock_fd4);
server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD; server_sock_fd4 = client_sock_fd4 = INVALID_SOCK_FD;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
if (server_sock_fd6 != client_sock_fd6) if (server_sock_fd6 != client_sock_fd6)
close_socket(client_sock_fd6); close_socket(client_sock_fd6);
close_socket(server_sock_fd6); close_socket(server_sock_fd6);
@@ -365,7 +368,7 @@ NIO_Finalise(void)
/* ================================================== */ /* ================================================== */
int int
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr) NIO_GetClientSocket(NTP_Remote_Address *remote_addr)
{ {
if (separate_client_sockets) { if (separate_client_sockets) {
int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family); int sock_fd = prepare_separate_client_socket(remote_addr->ip_addr.family);
@@ -383,7 +386,7 @@ NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
switch (remote_addr->ip_addr.family) { switch (remote_addr->ip_addr.family) {
case IPADDR_INET4: case IPADDR_INET4:
return client_sock_fd4; return client_sock_fd4;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
case IPADDR_INET6: case IPADDR_INET6:
return client_sock_fd6; return client_sock_fd6;
#endif #endif
@@ -396,25 +399,13 @@ NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
/* ================================================== */ /* ================================================== */
int int
NIO_OpenServerSocket(NTP_Remote_Address *remote_addr) NIO_GetServerSocket(NTP_Remote_Address *remote_addr)
{ {
switch (remote_addr->ip_addr.family) { switch (remote_addr->ip_addr.family) {
case IPADDR_INET4: case IPADDR_INET4:
if (permanent_server_sockets)
return server_sock_fd4; return server_sock_fd4;
if (server_sock_fd4 == INVALID_SOCK_FD) #ifdef HAVE_IPV6
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
case IPADDR_INET6: 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; return server_sock_fd6;
#endif #endif
default: default:
@@ -433,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 int
NIO_IsServerSocket(int sock_fd) NIO_IsServerSocket(int sock_fd)
{ {
return sock_fd != INVALID_SOCK_FD && return sock_fd != INVALID_SOCK_FD &&
(sock_fd == server_sock_fd4 (sock_fd == server_sock_fd4
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
|| sock_fd == server_sock_fd6 || sock_fd == server_sock_fd6
#endif #endif
); );
@@ -480,7 +444,7 @@ read_from_socket(void *anything)
to read, otherwise it will block. */ to read, otherwise it will block. */
int status, sock_fd; int status, sock_fd;
NTP_Receive_Buffer message; ReceiveBuffer message;
union sockaddr_in46 where_from; union sockaddr_in46 where_from;
unsigned int flags = 0; unsigned int flags = 0;
struct timeval now; struct timeval now;
@@ -496,7 +460,7 @@ read_from_socket(void *anything)
SCH_GetLastEventTime(&now, &now_err, NULL); SCH_GetLastEventTime(&now, &now_err, NULL);
iov.iov_base = &message.ntp_pkt; iov.iov_base = message.arbitrary;
iov.iov_len = sizeof(message); iov.iov_len = sizeof(message);
msg.msg_name = &where_from; msg.msg_name = &where_from;
msg.msg_namelen = sizeof(where_from); msg.msg_namelen = sizeof(where_from);
@@ -520,7 +484,23 @@ read_from_socket(void *anything)
if (msg.msg_namelen > sizeof (where_from)) if (msg.msg_namelen > sizeof (where_from))
LOG_FATAL(LOGF_NtpIO, "Truncated source address"); 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.ip_addr.family = IPADDR_UNSPEC;
local_addr.sock_fd = sock_fd; local_addr.sock_fd = sock_fd;
@@ -557,11 +537,14 @@ read_from_socket(void *anything)
#endif #endif
} }
if (status > 0) {
DEBUG_LOG(LOGF_NtpIO, "Received %d bytes from %s:%d to %s fd %d", 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); 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, NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err,
&remote_addr, &local_addr, status); &remote_addr, &local_addr, status);
@@ -575,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 static int
send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr) send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
@@ -595,15 +578,31 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0; return 0;
} }
switch (remote_addr->ip_addr.family) {
case IPADDR_INET4:
/* Don't set address with connected socket */ /* Don't set address with connected socket */
if (local_addr->sock_fd == server_sock_fd4 || if (local_addr->sock_fd != server_sock_fd4 && separate_client_sockets)
#ifdef FEAT_IPV6 break;
local_addr->sock_fd == server_sock_fd6 || 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 #endif
!separate_client_sockets) { default:
addrlen = UTI_IPAndPortToSockaddr(&remote_addr->ip_addr, remote_addr->port,
&remote.u);
if (!addrlen)
return 0; return 0;
} }
@@ -674,7 +673,7 @@ send_packet(void *packet, int packetlen, NTP_Remote_Address *remote_addr, NTP_Lo
return 0; 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(&remote_addr->ip_addr), remote_addr->port,
UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd); UTI_IPToString(&local_addr->ip_addr), local_addr->sock_fd);
@@ -682,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 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); extern void NIO_Finalise(void);
/* Function to obtain a socket for sending client packets */ /* 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 */ /* 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); 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 */ /* Function to check if socket is a server socket */
extern int NIO_IsServerSocket(int sock_fd); extern int NIO_IsServerSocket(int sock_fd);
/* Function to transmit a packet */ /* 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 */ #endif /* GOT_NTP_IO_H */

View File

@@ -31,7 +31,6 @@
#include "sysincl.h" #include "sysincl.h"
#include "array.h"
#include "ntp_sources.h" #include "ntp_sources.h"
#include "ntp_core.h" #include "ntp_core.h"
#include "util.h" #include "util.h"
@@ -49,19 +48,20 @@ typedef struct {
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL
means this slot in table is in use */ means this slot in table is in use */
NCR_Instance data; /* Data for the protocol engine for this source */ NCR_Instance data; /* Data for the protocol engine for this source */
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; } SourceRecord;
/* Hash table of SourceRecord, the size should be a power of two */ #define N_RECORDS 256
static ARR_Instance records;
/* 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; 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 */ /* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0; static int auto_start_sources = 0;
@@ -69,16 +69,8 @@ static int auto_start_sources = 0;
struct UnresolvedSource { struct UnresolvedSource {
char *name; char *name;
int port; int port;
int replacement;
union {
struct {
NTP_Source_Type type; NTP_Source_Type type;
SourceParameters params; SourceParameters params;
int pool;
int max_new_sources;
} new_source;
NTP_Remote_Address replace_source;
};
struct UnresolvedSource *next; struct UnresolvedSource *next;
}; };
@@ -92,29 +84,10 @@ static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL; static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL; static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
#define MIN_POOL_RESOLVE_INTERVAL 5
#define MAX_POOL_SOURCES 16
#define INVALID_POOL (-1)
/* Pool of sources, the name is expected to resolve to multiple addresses
which change over time */
struct SourcePool {
char *name;
int port;
/* 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 */ /* Forward prototypes */
static void resolve_sources(void *arg); static void resolve_sources(void *arg);
static void rehash_records(void);
static void static void
slew_sources(struct timeval *raw, slew_sources(struct timeval *raw,
@@ -131,25 +104,16 @@ static int initialised = 0;
/* ================================================== */ /* ================================================== */
static SourceRecord *
get_record(unsigned index)
{
return (SourceRecord *)ARR_GetElement(records, index);
}
/* ================================================== */
void void
NSR_Initialise(void) NSR_Initialise(void)
{ {
int i;
for (i=0; i<N_RECORDS; i++) {
records[i].remote_addr = NULL;
}
n_sources = 0; n_sources = 0;
initialised = 1; initialised = 1;
records = ARR_CreateInstance(sizeof (SourceRecord));
rehash_records();
pools = ARR_CreateInstance(sizeof (struct SourcePool));
LCL_AddParameterChangeHandler(slew_sources, NULL); LCL_AddParameterChangeHandler(slew_sources, NULL);
} }
@@ -158,31 +122,6 @@ NSR_Initialise(void)
void void
NSR_Finalise(void) NSR_Finalise(void)
{ {
SourceRecord *record;
struct UnresolvedSource *us;
unsigned int i;
for (i = 0; i < ARR_GetSize(pools); i++)
Free(((struct SourcePool *)ARR_GetElement(pools, i))->name);
ARR_DestroyInstance(pools);
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr)
continue;
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
}
ARR_DestroyInstance(records);
while (unresolved_sources) {
us = unresolved_sources;
unresolved_sources = us->next;
Free(us->name);
Free(us);
}
initialised = 0; initialised = 0;
} }
@@ -203,24 +142,23 @@ NSR_Finalise(void)
static void static void
find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found) find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
{ {
SourceRecord *record; unsigned long hash;
uint32_t hash; unsigned long ip;
unsigned int i, size;
unsigned short port; unsigned short port;
uint8_t *ip6; uint8_t *ip6;
size = ARR_GetSize(records); assert(N_RECORDS == 256);
switch (remote_addr->ip_addr.family) { switch (remote_addr->ip_addr.family) {
case IPADDR_INET6: case IPADDR_INET6:
ip6 = remote_addr->ip_addr.addr.in6; 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[1] ^ ip6[5] ^ ip6[9] ^ ip6[13]) << 8 |
(ip6[2] ^ ip6[6] ^ ip6[10] ^ ip6[14]) << 16 | (ip6[2] ^ ip6[6] ^ ip6[10] ^ ip6[14]) << 16 |
(ip6[3] ^ ip6[7] ^ ip6[11] ^ ip6[15]) << 24; (ip6[3] ^ ip6[7] ^ ip6[11] ^ ip6[15]) << 24;
break; break;
case IPADDR_INET4: case IPADDR_INET4:
hash = remote_addr->ip_addr.addr.in4; ip = remote_addr->ip_addr.addr.in4;
break; break;
default: default:
*found = *slot = 0; *found = *slot = 0;
@@ -228,77 +166,36 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
} }
port = remote_addr->port; 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++) { while (records[hash].remote_addr &&
/* Use quadratic probing */ UTI_CompareIPs(&records[hash].remote_addr->ip_addr,
*slot = (hash + (i + i * i) / 2) % size;
record = get_record(*slot);
if (!record->remote_addr)
break;
if (!UTI_CompareIPs(&record->remote_addr->ip_addr,
&remote_addr->ip_addr, NULL)) { &remote_addr->ip_addr, NULL)) {
*found = record->remote_addr->port == port ? 2 : 1; hash++;
return; 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; *found = 0;
} *slot = hash;
/* ================================================== */
/* 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];
} }
Free(temp_records);
} }
/* ================================================== */ /* ================================================== */
/* Procedure to add a new source */ /* Procedure to add a new source */
static NSR_Status NSR_Status
add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, int pool) NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
{ {
SourceRecord *record;
int slot, found; int slot, found;
assert(initialised); assert(initialised);
@@ -308,27 +205,17 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
if (found) { if (found) {
return NSR_AlreadyInUse; return NSR_AlreadyInUse;
} else { } 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) { remote_addr->ip_addr.family != IPADDR_INET6) {
return NSR_InvalidAF; return NSR_InvalidAF;
} else { } else {
n_sources++; n_sources++;
records[slot].data = NCR_GetInstance(remote_addr, type, params); /* Will need params passing through */
if (!check_hashtable_size(n_sources, ARR_GetSize(records))) { records[slot].remote_addr = NCR_GetRemoteAddress(records[slot].data);
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->pool = pool;
record->tentative = pool != INVALID_POOL ? 1 : 0;
if (auto_start_sources) if (auto_start_sources)
NCR_StartInstance(record->data); NCR_StartInstance(records[slot].data);
return NSR_Success; return NSR_Success;
} }
} }
@@ -336,68 +223,11 @@ add_source(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParamete
/* ================================================== */ /* ================================================== */
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 static void
process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs) name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
{
NTP_Remote_Address address;
int i, added;
for (i = added = 0; i < n_addrs; i++) {
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, 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->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)
{ {
struct UnresolvedSource *us, **i, *next; struct UnresolvedSource *us, **i, *next;
NTP_Remote_Address address;
us = (struct UnresolvedSource *)anything; us = (struct UnresolvedSource *)anything;
@@ -407,7 +237,10 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
case DNS_TryAgain: case DNS_TryAgain:
break; break;
case DNS_Success: 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; break;
case DNS_Failure: case DNS_Failure:
LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name); LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name);
@@ -418,9 +251,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
next = us->next; next = us->next;
/* Remove the source from the list on success or failure, replacements if (status != DNS_TryAgain) {
are removed on any status */ /* Remove the source from the list */
if (us->replacement || status != DNS_TryAgain) {
for (i = &unresolved_sources; *i; i = &(*i)->next) { for (i = &unresolved_sources; *i; i = &(*i)->next) {
if (*i == us) { if (*i == us) {
*i = us->next; *i = us->next;
@@ -479,54 +311,24 @@ resolve_sources(void *arg)
/* ================================================== */ /* ================================================== */
static void /* Procedure to add a new server or peer source, but instead of an IP address
append_unresolved_source(struct UnresolvedSource *us) 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) for (i = &unresolved_sources; *i; i = &(*i)->next)
; ;
*i = us; *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, 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;
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->name = Strdup(name);
sp->port = port;
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);
} }
/* ================================================== */ /* ================================================== */
@@ -563,12 +365,12 @@ NSR_ResolveSources(void)
void NSR_StartSources(void) void NSR_StartSources(void)
{ {
unsigned int i; int i;
for (i = 0; i < ARR_GetSize(records); i++) { for (i = 0; i < N_RECORDS; i++) {
if (!get_record(i)->remote_addr) if (!records[i].remote_addr)
continue; continue;
NCR_StartInstance(get_record(i)->data); NCR_StartInstance(records[i].data);
} }
} }
@@ -581,18 +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);
n_sources--;
}
/* ================================================== */
/* Procedure to remove a source. We don't bother whether the port /* Procedure to remove a source. We don't bother whether the port
address is matched - we're only interested in removing a record for address is matched - we're only interested in removing a record for
the right IP address. Thus the caller can specify the port number the right IP address. Thus the caller can specify the port number
@@ -600,7 +390,8 @@ clean_source_record(SourceRecord *record)
NSR_Status NSR_Status
NSR_RemoveSource(NTP_Remote_Address *remote_addr) NSR_RemoveSource(NTP_Remote_Address *remote_addr)
{ {
int slot, found; int i, slot, found;
SourceRecord temp_records[N_RECORDS];
assert(initialised); assert(initialised);
@@ -609,12 +400,29 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
return NSR_NoSuchSource; 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. /* Rehash the table to make sure there are no broken probe sequences.
This is costly, but it's not expected to happen frequently. */ 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; return NSR_Success;
} }
@@ -624,130 +432,31 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
void void
NSR_RemoveAllSources(void) NSR_RemoveAllSources(void)
{ {
SourceRecord *record; int i;
unsigned int i;
for (i = 0; i < ARR_GetSize(records); i++) { for (i = 0; i < N_RECORDS; i++) {
record = get_record(i); if (!records[i].remote_addr)
if (!record->remote_addr)
continue; continue;
clean_source_record(record); NCR_DestroyInstance(records[i].data);
records[i].remote_addr = NULL;
} }
rehash_records();
} }
/* ================================================== */ /* ================================================== */
static void
resolve_pool_replacement(struct SourcePool *sp, NTP_Remote_Address *addr)
{
struct UnresolvedSource *us;
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(sp->name);
us->port = sp->port;
us->replacement = 1;
us->replace_source = *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;
struct SourcePool *pool;
int pool_index, slot, found;
double diff;
remote_addr.ip_addr = *address;
remote_addr.port = 0;
/* Only sources from a pool can be replaced */
find_slot(&remote_addr, &slot, &found);
if (!found || (pool_index = get_record(slot)->pool) == INVALID_POOL)
return;
pool = (struct SourcePool *)ARR_GetElement(pools, pool_index);
/* Don't resolve the pool name too frequently */
SCH_GetLastEventTime(NULL, NULL, &now);
UTI_DiffTimevalsToDouble(&diff, &now, &last_replacement);
if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_POOL_RESOLVE_INTERVAL)) {
DEBUG_LOG(LOGF_NtpSources, "replacement postponed");
return;
}
last_replacement = now;
DEBUG_LOG(LOGF_NtpSources, "pool replacement for %s", UTI_IPToString(address));
resolve_pool_replacement(pool, &remote_addr);
}
/* ================================================== */
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, /* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */ possibly with an authentication tail */
void void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length) 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; int slot, found;
assert(initialised); assert(initialised);
find_slot(remote_addr, &slot, &found); find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */ if (found == 2) { /* Must match IP address AND port number */
record = get_record(slot); NCR_ProcessKnown(message, now, now_err, records[slot].data,
local_addr->sock_fd, length);
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",
pool->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);
}
} else { } else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length); NCR_ProcessUnknown(message, now, now_err, remote_addr, local_addr, length);
} }
@@ -763,16 +472,14 @@ slew_sources(struct timeval *raw,
LCL_ChangeType change_type, LCL_ChangeType change_type,
void *anything) void *anything)
{ {
SourceRecord *record; int i;
unsigned int i;
for (i = 0; i < ARR_GetSize(records); i++) { for (i=0; i<N_RECORDS; i++) {
record = get_record(i); if (records[i].remote_addr) {
if (record->remote_addr) {
if (change_type == LCL_ChangeUnknownStep) { if (change_type == LCL_ChangeUnknownStep) {
NCR_ResetInstance(record->data); NCR_ResetInstance(records[i].data);
} else { } else {
NCR_SlewTimes(record->data, cooked, dfreq, doffset); NCR_SlewTimes(records[i].data, cooked, dfreq, doffset);
} }
} }
} }
@@ -783,20 +490,18 @@ slew_sources(struct timeval *raw,
int int
NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address) NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
{ {
SourceRecord *record; int i;
unsigned int i;
int any; int any;
NSR_ResolveSources(); NSR_ResolveSources();
any = 0; any = 0;
for (i = 0; i < ARR_GetSize(records); i++) { for (i=0; i<N_RECORDS; i++) {
record = get_record(i); if (records[i].remote_addr) {
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC || 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; any = 1;
NCR_TakeSourceOnline(record->data); NCR_TakeSourceOnline(records[i].data);
} }
} }
} }
@@ -805,10 +510,8 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
struct UnresolvedSource *us; struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) { for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1; any = 1;
us->new_source.params.online = 1; us->params.online = 1;
} }
} }
@@ -820,39 +523,35 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address)
int int
NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address) NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address)
{ {
SourceRecord *record, *syncpeer; int i, any, syncpeer;
unsigned int i, any;
any = 0; any = 0;
syncpeer = NULL; syncpeer = -1;
for (i = 0; i < ARR_GetSize(records); i++) { for (i=0; i<N_RECORDS; i++) {
record = get_record(i); if (records[i].remote_addr) {
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC || 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; any = 1;
if (NCR_IsSyncPeer(record->data)) { if (NCR_IsSyncPeer(records[i].data)) {
syncpeer = record; syncpeer = i;
continue; continue;
} }
NCR_TakeSourceOffline(record->data); NCR_TakeSourceOffline(records[i].data);
} }
} }
} }
/* Take sync peer offline as last to avoid reference switching */ /* Take sync peer offline as last to avoid reference switching */
if (syncpeer) { if (syncpeer >= 0) {
NCR_TakeSourceOffline(syncpeer->data); NCR_TakeSourceOffline(records[syncpeer].data);
} }
if (address->family == IPADDR_UNSPEC) { if (address->family == IPADDR_UNSPEC) {
struct UnresolvedSource *us; struct UnresolvedSource *us;
for (us = unresolved_sources; us; us = us->next) { for (us = unresolved_sources; us; us = us->next) {
if (us->replacement)
continue;
any = 1; any = 1;
us->new_source.params.online = 0; us->params.online = 0;
} }
} }
@@ -873,7 +572,7 @@ NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll); NCR_ModifyMinpoll(records[slot].data, new_minpoll);
return 1; return 1;
} }
} }
@@ -892,7 +591,7 @@ NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll); NCR_ModifyMaxpoll(records[slot].data, new_maxpoll);
return 1; return 1;
} }
} }
@@ -911,7 +610,7 @@ NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay); NCR_ModifyMaxdelay(records[slot].data, new_max_delay);
return 1; return 1;
} }
} }
@@ -930,7 +629,7 @@ NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio); NCR_ModifyMaxdelayratio(records[slot].data, new_max_delay_ratio);
return 1; return 1;
} }
} }
@@ -949,7 +648,7 @@ NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio); NCR_ModifyMaxdelaydevratio(records[slot].data, new_max_delay_dev_ratio);
return 1; return 1;
} }
} }
@@ -968,7 +667,7 @@ NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum); NCR_ModifyMinstratum(records[slot].data, new_min_stratum);
return 1; return 1;
} }
} }
@@ -987,7 +686,7 @@ NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
if (found == 0) { if (found == 0) {
return 0; return 0;
} else { } else {
NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target); NCR_ModifyPolltarget(records[slot].data, new_poll_target);
return 1; return 1;
} }
} }
@@ -998,18 +697,16 @@ int
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
IPAddr *mask, IPAddr *address) IPAddr *mask, IPAddr *address)
{ {
SourceRecord *record; int i;
unsigned int i;
int any; int any;
any = 0; any = 0;
for (i = 0; i < ARR_GetSize(records); i++) { for (i=0; i<N_RECORDS; i++) {
record = get_record(i); if (records[i].remote_addr) {
if (record->remote_addr) {
if (address->family == IPADDR_UNSPEC || 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; any = 1;
NCR_InitiateSampleBurst(record->data, n_good_samples, n_total_samples); NCR_InitiateSampleBurst(records[i].data, n_good_samples, n_total_samples);
} }
} }
} }
@@ -1032,7 +729,7 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
rem_addr.port = 0; rem_addr.port = 0;
find_slot(&rem_addr, &slot, &found); find_slot(&rem_addr, &slot, &found);
if (found) { if (found) {
NCR_ReportSource(get_record(slot)->data, report, now); NCR_ReportSource(records[slot].data, report, now);
} else { } else {
report->poll = 0; report->poll = 0;
report->latest_meas_ago = 0; report->latest_meas_ago = 0;
@@ -1044,8 +741,7 @@ NSR_ReportSource(RPT_SourceReport *report, struct timeval *now)
void void
NSR_GetActivityReport(RPT_ActivityReport *report) NSR_GetActivityReport(RPT_ActivityReport *report)
{ {
SourceRecord *record; int i;
unsigned int i;
struct UnresolvedSource *us; struct UnresolvedSource *us;
report->online = 0; report->online = 0;
@@ -1053,10 +749,9 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
report->burst_online = 0; report->burst_online = 0;
report->burst_offline = 0; report->burst_offline = 0;
for (i = 0; i < ARR_GetSize(records); i++) { for (i=0; i<N_RECORDS; i++) {
record = get_record(i); if (records[i].remote_addr) {
if (record->remote_addr) { NCR_IncrementActivityCounters(records[i].data, &report->online, &report->offline,
NCR_IncrementActivityCounters(record->data, &report->online, &report->offline,
&report->burst_online, &report->burst_offline); &report->burst_online, &report->burst_offline);
} }
} }

View File

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

@@ -67,8 +67,6 @@ command_unpadded_length(CMD_Request *r)
return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR); return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR);
case REQ_MODIFY_MAXUPDATESKEW: case REQ_MODIFY_MAXUPDATESKEW:
return offsetof(CMD_Request, data.modify_maxupdateskew.EOR); return offsetof(CMD_Request, data.modify_maxupdateskew.EOR);
case REQ_MODIFY_MAKESTEP:
return offsetof(CMD_Request, data.modify_makestep.EOR);
case REQ_LOGON : case REQ_LOGON :
return offsetof(CMD_Request, data.logon.EOR); return offsetof(CMD_Request, data.logon.EOR);
case REQ_SETTIME : case REQ_SETTIME :
@@ -217,8 +215,6 @@ PKL_CommandPaddingLength(CMD_Request *r)
return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR); return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR);
case REQ_MODIFY_MAXUPDATESKEW: case REQ_MODIFY_MAXUPDATESKEW:
return PADDING_LENGTH(data.modify_maxupdateskew.EOR, data.null.EOR); 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: case REQ_LOGON:
return PADDING_LENGTH(data.logon.EOR, data.null.EOR); return PADDING_LENGTH(data.logon.EOR, data.null.EOR);
case REQ_SETTIME: case REQ_SETTIME:

View File

@@ -27,7 +27,6 @@
#include "config.h" #include "config.h"
#include "array.h"
#include "refclock.h" #include "refclock.h"
#include "reference.h" #include "reference.h"
#include "conf.h" #include "conf.h"
@@ -87,8 +86,10 @@ struct RCL_Instance_Record {
SRC_Instance source; SRC_Instance source;
}; };
/* Array of RCL_Instance_Record */ #define MAX_RCL_SOURCES 8
static ARR_Instance refclocks;
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
static int n_sources = 0;
static LOG_FileID logfileid; 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_slew_samples(struct MedianFilter *filter, struct timeval *when, double dfreq, double doffset);
static void filter_add_dispersion(struct MedianFilter *filter, double dispersion); 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 void
RCL_Initialise(void) RCL_Initialise(void)
{ {
refclocks = ARR_CreateInstance(sizeof (struct RCL_Instance_Record));
CNF_AddRefclocks(); CNF_AddRefclocks();
if (ARR_GetSize(refclocks) > 0) { if (n_sources > 0) {
LCL_AddParameterChangeHandler(slew_samples, NULL); LCL_AddParameterChangeHandler(slew_samples, NULL);
LCL_AddDispersionNotifyHandler(add_dispersion, NULL); LCL_AddDispersionNotifyHandler(add_dispersion, NULL);
} }
@@ -137,25 +130,22 @@ RCL_Initialise(void)
void void
RCL_Finalise(void) RCL_Finalise(void)
{ {
unsigned int i; int i;
for (i = 0; i < ARR_GetSize(refclocks); i++) { for (i = 0; i < n_sources; i++) {
RCL_Instance inst = get_refclock(i); RCL_Instance inst = (RCL_Instance)&refclocks[i];
if (inst->driver->fini) if (inst->driver->fini)
inst->driver->fini(inst); inst->driver->fini(inst);
filter_fini(&inst->filter); filter_fini(&inst->filter);
Free(inst->driver_parameter); Free(inst->driver_parameter);
SRC_DestroyInstance(inst->source);
} }
if (ARR_GetSize(refclocks) > 0) { if (n_sources > 0) {
LCL_RemoveParameterChangeHandler(slew_samples, NULL); LCL_RemoveParameterChangeHandler(slew_samples, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL); LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
} }
ARR_DestroyInstance(refclocks);
} }
int int
@@ -163,7 +153,10 @@ RCL_AddRefclock(RefclockParameters *params)
{ {
int pps_source = 0; 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) { if (strcmp(params->driver_name, "SHM") == 0) {
inst->driver = &RCL_SHM_driver; inst->driver = &RCL_SHM_driver;
@@ -226,13 +219,8 @@ RCL_AddRefclock(RefclockParameters *params)
inst->ref_id = params->ref_id; inst->ref_id = params->ref_id;
else { else {
unsigned char ref[5] = { 0, 0, 0, 0, 0 }; unsigned char ref[5] = { 0, 0, 0, 0, 0 };
unsigned int index = ARR_GetSize(refclocks);
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]; 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); filter_init(&inst->filter, params->filter_length, params->max_dispersion);
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL, inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, params->sel_option, NULL);
params->min_samples, params->max_samples);
DEBUG_LOG(LOGF_Refclock, "refclock %s refid=%s poll=%d dpoll=%d filter=%d", DEBUG_LOG(LOGF_Refclock, "refclock %s added poll=%d dpoll=%d filter=%d",
params->driver_name, UTI_RefidToString(inst->ref_id), params->driver_name, inst->poll, inst->driver_poll, params->filter_length);
inst->poll, inst->driver_poll, params->filter_length); n_sources++;
Free(params->driver_name); Free(params->driver_name);
@@ -275,21 +262,20 @@ RCL_AddRefclock(RefclockParameters *params)
void void
RCL_StartRefclocks(void) RCL_StartRefclocks(void)
{ {
unsigned int i, j, n; int i, j;
n = ARR_GetSize(refclocks); for (i = 0; i < n_sources; i++) {
RCL_Instance inst = &refclocks[i];
for (i = 0; i < n; i++) {
RCL_Instance inst = get_refclock(i);
SRC_SetSelectable(inst->source);
SRC_SetActive(inst->source); SRC_SetActive(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst); inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) { if (inst->lock_ref) {
/* Replace lock refid with index to refclocks */ /* 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 } else
inst->lock_ref = -1; inst->lock_ref = -1;
} }
@@ -298,14 +284,14 @@ RCL_StartRefclocks(void)
void void
RCL_ReportSource(RPT_SourceReport *report, struct timeval *now) RCL_ReportSource(RPT_SourceReport *report, struct timeval *now)
{ {
unsigned int i; int i;
uint32_t ref_id; uint32_t ref_id;
assert(report->ip_addr.family == IPADDR_INET4); assert(report->ip_addr.family == IPADDR_INET4);
ref_id = report->ip_addr.addr.in4; ref_id = report->ip_addr.addr.in4;
for (i = 0; i < ARR_GetSize(refclocks); i++) { for (i = 0; i < n_sources; i++) {
RCL_Instance inst = get_refclock(i); RCL_Instance inst = &refclocks[i];
if (inst->ref_id == ref_id) { if (inst->ref_id == ref_id) {
report->poll = inst->poll; report->poll = inst->poll;
report->mode = RPT_LOCAL_REFERENCE; report->mode = RPT_LOCAL_REFERENCE;
@@ -423,19 +409,16 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
offset -= 1.0 / rate; offset -= 1.0 / rate;
if (instance->lock_ref != -1) { if (instance->lock_ref != -1) {
RCL_Instance lock_refclock;
struct timeval ref_sample_time; struct timeval ref_sample_time;
double sample_diff, ref_offset, ref_dispersion, shift; double sample_diff, ref_offset, ref_dispersion, shift;
lock_refclock = get_refclock(instance->lock_ref); if (!filter_get_last_sample(&refclocks[instance->lock_ref].filter,
if (!filter_get_last_sample(&lock_refclock->filter,
&ref_sample_time, &ref_offset, &ref_dispersion)) { &ref_sample_time, &ref_offset, &ref_dispersion)) {
DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample"); DEBUG_LOG(LOGF_Refclock, "refclock pulse ignored no ref sample");
return 0; 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); UTI_DiffTimevalsToDouble(&sample_diff, &cooked_time, &ref_sample_time);
if (fabs(sample_diff) >= 2.0 / rate) { if (fabs(sample_diff) >= 2.0 / rate) {
@@ -458,7 +441,7 @@ RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
return 0; 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", DEBUG_LOG(LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f offdiff=%.9f samplediff=%.9f",
second, offset, ref_offset - offset, sample_diff); second, offset, ref_offset - offset, sample_diff);
@@ -514,8 +497,8 @@ valid_sample_time(RCL_Instance instance, struct timeval *tv)
LCL_ReadRawTime(&raw_time); LCL_ReadRawTime(&raw_time);
UTI_DiffTimevalsToDouble(&diff, &raw_time, tv); UTI_DiffTimevalsToDouble(&diff, &raw_time, tv);
if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) { if (diff < 0.0 || diff > poll_interval(instance->poll + 1)) {
DEBUG_LOG(LOGF_Refclock, "%s refclock sample not valid age=%.6f tv=%s", DEBUG_LOG(LOGF_Refclock, "refclock sample not valid age=%.6f tv=%s",
UTI_RefidToString(instance->ref_id), diff, UTI_TimevalToString(tv)); diff, UTI_TimevalToString(tv));
return 0; return 0;
} }
return 1; return 1;
@@ -525,12 +508,10 @@ static int
pps_stratum(RCL_Instance instance, struct timeval *tv) pps_stratum(RCL_Instance instance, struct timeval *tv)
{ {
struct timeval ref_time; struct timeval ref_time;
int is_synchronised, stratum; int is_synchronised, stratum, i;
unsigned int i;
double root_delay, root_dispersion; double root_delay, root_dispersion;
NTP_Leap leap; NTP_Leap leap;
uint32_t ref_id; uint32_t ref_id;
RCL_Instance refclock;
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum, REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
&ref_id, &ref_time, &root_delay, &root_dispersion); &ref_id, &ref_time, &root_delay, &root_dispersion);
@@ -541,10 +522,9 @@ pps_stratum(RCL_Instance instance, struct timeval *tv)
return stratum - 1; return stratum - 1;
/* Or the current source is another PPS refclock */ /* Or the current source is another PPS refclock */
for (i = 0; i < ARR_GetSize(refclocks); i++) { for (i = 0; i < n_sources; i++) {
refclock = get_refclock(i); if (refclocks[i].ref_id == ref_id &&
if (refclock->ref_id == ref_id && refclocks[i].pps_active && refclocks[i].lock_ref == -1)
refclock->pps_active && refclock->lock_ref == -1)
return stratum - 1; return stratum - 1;
} }
@@ -599,23 +579,23 @@ static void
slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything) 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) if (change_type == LCL_ChangeUnknownStep)
filter_reset(&get_refclock(i)->filter); filter_reset(&refclocks[i].filter);
else else
filter_slew_samples(&get_refclock(i)->filter, cooked, dfreq, doffset); filter_slew_samples(&refclocks[i].filter, cooked, dfreq, doffset);
} }
} }
static void static void
add_dispersion(double dispersion, void *anything) add_dispersion(double dispersion, void *anything)
{ {
unsigned int i; int i;
for (i = 0; i < ARR_GetSize(refclocks); i++) for (i = 0; i < n_sources; i++)
filter_add_dispersion(&get_refclock(i)->filter, dispersion); filter_add_dispersion(&refclocks[i].filter, dispersion);
} }
static void static void

View File

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

View File

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

View File

@@ -928,8 +928,6 @@ REF_SetReference(int stratum,
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -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(); abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(&now, write_log(&now,
@@ -1018,8 +1016,6 @@ REF_SetUnsynchronised(void)
update_leap_status(LEAP_Unsynchronised, 0); update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0; are_we_synchronised = 0;
LCL_SetSyncStatus(0, 0.0, 0.0);
write_log(&now, write_log(&now,
"0.0.0.0", "0.0.0.0",
0, 0,
@@ -1075,7 +1071,7 @@ REF_GetReferenceParams
*ref_id = LOCAL_REFERENCE_ID; *ref_id = LOCAL_REFERENCE_ID;
/* Make the reference time be now less a second - this will /* Make the reference time be now less a second - this will
scarcely affect the client, but will ensure that the transmit 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 fail in the client's read routine) if the local system clock's
read routine is broken in any way. */ read routine is broken in any way. */
*ref_time = *local_time; *ref_time = *local_time;
@@ -1093,7 +1089,7 @@ REF_GetReferenceParams
*is_synchronised = 0; *is_synchronised = 0;
*leap_status = LEAP_Unsynchronised; *leap_status = LEAP_Unsynchronised;
*stratum = NTP_MAX_STRATUM; *stratum = 0;
*ref_id = 0; *ref_id = 0;
ref_time->tv_sec = ref_time->tv_usec = 0; ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and /* These values seem to be standard for a client, and
@@ -1115,7 +1111,7 @@ REF_GetOurStratum(void)
} else if (enable_local_stratum) { } else if (enable_local_stratum) {
return local_stratum; return local_stratum;
} else { } else {
return NTP_MAX_STRATUM; return 16;
} }
} }
@@ -1129,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 void
REF_EnableLocal(int stratum) REF_EnableLocal(int stratum)
{ {

View File

@@ -157,9 +157,6 @@ extern int REF_GetOurStratum(void);
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */ /* 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); 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_EnableLocal(int stratum);
extern void REF_DisableLocal(void); extern void REF_DisableLocal(void);
extern int REF_IsLocalActive(void); extern int REF_IsLocalActive(void);

View File

@@ -86,6 +86,16 @@ typedef struct {
double rtc_gain_rate_ppm; double rtc_gain_rate_ppm;
} RPT_RTC_Report; } 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 { typedef struct {
IPAddr ip_addr; IPAddr ip_addr;
unsigned long client_hits; unsigned long client_hits;

View File

@@ -86,8 +86,8 @@ static int skip_interrupts;
measured, together with a 'trim' that compensates these values for measured, together with a 'trim' that compensates these values for
any steps made to the RTC to bring it back into line any steps made to the RTC to bring it back into line
occasionally. The trim is in seconds. */ occasionally. The trim is in seconds. */
static time_t *rtc_sec = NULL; static time_t rtc_sec[MAX_SAMPLES];
static double *rtc_trim = NULL; static double rtc_trim[MAX_SAMPLES];
/* Reference time, against which delta times on the RTC scale are measured */ /* Reference time, against which delta times on the RTC scale are measured */
static time_t rtc_ref; static time_t rtc_ref;
@@ -95,7 +95,7 @@ static time_t rtc_ref;
/* System clock (gettimeofday) samples associated with the above /* System clock (gettimeofday) samples associated with the above
samples. */ samples. */
static struct timeval *system_times = NULL; static struct timeval system_times[MAX_SAMPLES];
/* Number of samples currently stored. */ /* Number of samples currently stored. */
static int n_samples; static int n_samples;
@@ -530,10 +530,6 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
int int
RTC_Linux_Initialise(void) 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 details depending on configuration options */
setup_config(); setup_config();
@@ -592,9 +588,6 @@ RTC_Linux_Finalise(void)
(void) RTC_Linux_WriteParameters(); (void) RTC_Linux_WriteParameters();
} }
Free(rtc_sec);
Free(rtc_trim);
Free(system_times);
} }
/* ================================================== */ /* ================================================== */

20
sched.c
View File

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

598
sources.c
View File

@@ -36,7 +36,6 @@
#include "sourcestats.h" #include "sourcestats.h"
#include "memory.h" #include "memory.h"
#include "ntp.h" /* For NTP_Leap */ #include "ntp.h" /* For NTP_Leap */
#include "ntp_sources.h"
#include "local.h" #include "local.h"
#include "reference.h" #include "reference.h"
#include "util.h" #include "util.h"
@@ -61,27 +60,20 @@ struct SelectInfo {
double root_distance; double root_distance;
double lo_limit; double lo_limit;
double hi_limit; double hi_limit;
double last_sample_ago;
}; };
/* ================================================== */ /* ================================================== */
/* This enum contains the flag values that are used to label /* This enum contains the flag values that are used to label
each source */ each source */
typedef enum { typedef enum {
SRC_OK, /* OK so far, not a final status! */ SRC_OK, /* OK so far */
SRC_UNSELECTABLE, /* Has noselect option set */ SRC_UNREACHABLE, /* Source is not reachable */
SRC_BAD_STATS, /* Doesn't have valid stats data */ SRC_BAD_STATS, /* Stats driver could not supply valid
SRC_WAITS_STATS, /* Others have bad stats, selection postponed */ data */
SRC_STALE, /* Has older samples than others */ SRC_FALSETICKER, /* Source is found to be a falseticker */
SRC_FALSETICKER, /* Doesn't agree with others */ SRC_JITTERY, /* Source scatter worse than other's dispersion */
SRC_JITTERY, /* Scatter worse than other's dispersion (not used) */ SRC_SELECTABLE, /* Source is acceptable candidate */
SRC_WAITS_SOURCES, /* Not enough sources, selection postponed */ SRC_SYNC /* Current synchronisation source */
SRC_NONPREFERRED, /* Others have prefer option */
SRC_WAITS_UPDATE, /* No updates, selection postponed */
SRC_DISTANT, /* Others have shorter root distance */
SRC_OUTLIER, /* Outlier in clustering (not used yet) */
SRC_UNSELECTED, /* Used for synchronisation, not system peer */
SRC_SELECTED, /* Used for synchronisation, selected as system peer */
} SRC_Status; } SRC_Status;
/* ================================================== */ /* ================================================== */
@@ -96,6 +88,9 @@ struct SRC_Instance_Record {
reference _it_ is sync'd to) */ reference _it_ is sync'd to) */
IPAddr *ip_addr; /* Its IP address if NTP source */ IPAddr *ip_addr; /* Its IP address if NTP source */
/* Flag indicating that we can use this source as a reference */
int selectable;
/* Flag indicating that the source is updating reachability */ /* Flag indicating that the source is updating reachability */
int active; int active;
@@ -105,11 +100,8 @@ struct SRC_Instance_Record {
/* Number of set bits in the reachability register */ /* Number of set bits in the reachability register */
int reachability_size; int reachability_size;
/* Updates since last reference update */
int updates;
/* Updates left before allowing combining */ /* Updates left before allowing combining */
int distant; int outlier;
/* Flag indicating the status of the source */ /* Flag indicating the status of the source */
SRC_Status status; SRC_Status status;
@@ -131,10 +123,7 @@ struct SRC_Instance_Record {
struct Sort_Element { struct Sort_Element {
int index; int index;
double offset; double offset;
enum { enum {LOW=-1, CENTRE=0, HIGH=1} tag;
LOW = -1,
HIGH = 1
} tag;
}; };
/* ================================================== */ /* ================================================== */
@@ -153,8 +142,8 @@ static int selected_source_index; /* Which source index is currently
/* Score needed to replace the currently selected source */ /* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0 #define SCORE_LIMIT 10.0
/* Number of updates needed to reset the distant status */ /* Number of updates needed to reset the outlier status */
#define DISTANT_PENALTY 32 #define OUTLIER_PENALTY 32
static double reselect_distance; static double reselect_distance;
static double stratum_weight; static double stratum_weight;
@@ -176,7 +165,6 @@ source_to_string(SRC_Instance inst);
void SRC_Initialise(void) { void SRC_Initialise(void) {
sources = NULL; sources = NULL;
sort_list = NULL; sort_list = NULL;
sel_sources = NULL;
n_sources = 0; n_sources = 0;
max_n_sources = 0; max_n_sources = 0;
selected_source_index = INVALID_SOURCE; selected_source_index = INVALID_SOURCE;
@@ -195,11 +183,6 @@ void SRC_Finalise(void)
{ {
LCL_RemoveParameterChangeHandler(slew_sources, NULL); LCL_RemoveParameterChangeHandler(slew_sources, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL); LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
Free(sources);
Free(sort_list);
Free(sel_sources);
initialised = 0; initialised = 0;
} }
@@ -207,23 +190,18 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ the individual source-type instance creation routines. */
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples) SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
{ {
SRC_Instance result; SRC_Instance result;
assert(initialised); assert(initialised);
if (min_samples == SRC_DEFAULT_MINSAMPLES)
min_samples = CNF_GetMinSamples();
if (max_samples == SRC_DEFAULT_MAXSAMPLES)
max_samples = CNF_GetMaxSamples();
result = MallocNew(struct SRC_Instance_Record); result = MallocNew(struct SRC_Instance_Record);
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples); result->stats = SST_CreateInstance(ref_id, addr);
if (n_sources == max_n_sources) { if (n_sources == max_n_sources) {
/* Reallocate memory */ /* Reallocate memory */
max_n_sources = max_n_sources > 0 ? 2 * max_n_sources : 4; max_n_sources += 32;
if (sources) { if (sources) {
sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources); sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list); sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
@@ -236,14 +214,20 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOpt
} }
sources[n_sources] = result; sources[n_sources] = result;
result->index = n_sources; result->index = n_sources;
result->leap_status = LEAP_Normal;
result->ref_id = ref_id;
result->ip_addr = addr;
result->active = 0;
result->selectable = 0;
result->reachability = 0;
result->reachability_size = 0;
result->outlier = 0;
result->status = SRC_BAD_STATS;
result->type = type; result->type = type;
result->sel_score = 1.0;
result->sel_option = sel_option; result->sel_option = sel_option;
SRC_SetRefid(result, ref_id, addr);
SRC_ResetInstance(result);
n_sources++; n_sources++;
return result; return result;
@@ -261,6 +245,8 @@ void SRC_DestroyInstance(SRC_Instance instance)
assert(initialised); assert(initialised);
SRC_UnsetSelectable(instance);
SST_DeleteInstance(instance->stats); SST_DeleteInstance(instance->stats);
dead_index = instance->index; dead_index = instance->index;
for (i=dead_index; i<n_sources-1; i++) { for (i=dead_index; i<n_sources-1; i++) {
@@ -270,38 +256,9 @@ void SRC_DestroyInstance(SRC_Instance instance)
--n_sources; --n_sources;
Free(instance); Free(instance);
/* If this was the previous reference source, we have to reselect! */ if (selected_source_index > dead_index) {
if (selected_source_index == dead_index)
SRC_ReselectSource();
else if (selected_source_index > dead_index)
--selected_source_index; --selected_source_index;
} }
/* ================================================== */
void
SRC_ResetInstance(SRC_Instance instance)
{
instance->leap_status = LEAP_Normal;
instance->active = 0;
instance->updates = 0;
instance->reachability = 0;
instance->reachability_size = 0;
instance->distant = 0;
instance->status = SRC_BAD_STATS;
instance->sel_score = 1.0;
SST_ResetInstance(instance->stats);
}
/* ================================================== */
void
SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr)
{
instance->ref_id = ref_id;
instance->ip_addr = addr;
SST_SetRefid(instance->stats, ref_id, addr);
} }
/* ================================================== */ /* ================================================== */
@@ -384,6 +341,37 @@ SRC_UnsetActive(SRC_Instance inst)
/* ================================================== */ /* ================================================== */
void
SRC_SetSelectable(SRC_Instance inst)
{
inst->selectable = 1;
DEBUG_LOG(LOGF_Sources, "%s", source_to_string(inst));
/* Don't do selection at this point, though - that will come about
in due course when we get some useful data from the source */
}
/* ================================================== */
void
SRC_UnsetSelectable(SRC_Instance inst)
{
inst->selectable = 0;
DEBUG_LOG(LOGF_Sources, "%s%s", source_to_string(inst),
(inst->index == selected_source_index) ? "(REF)":"");
/* If this was the previous reference source, we have to reselect! */
if (inst->index == selected_source_index) {
SRC_SelectSource(NULL);
}
}
/* ================================================== */
static int static int
special_mode_end(void) special_mode_end(void)
{ {
@@ -426,12 +414,6 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
if (REF_GetMode() != REF_ModeNormal && special_mode_end()) { if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
REF_SetUnsynchronised(); REF_SetUnsynchronised();
} }
/* Try to replace NTP sources that are unreachable or falsetickers */
if (inst->type == SRC_NTP && (inst->status == SRC_FALSETICKER ||
(!inst->reachability && inst->reachability_size == SOURCE_REACH_BITS))) {
NSR_HandleBadSource(inst->ip_addr);
}
} }
/* ================================================== */ /* ================================================== */
@@ -439,9 +421,13 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
void void
SRC_ResetReachability(SRC_Instance inst) SRC_ResetReachability(SRC_Instance inst)
{ {
/* This should be disabled until source selection is modified to keep
a peer selected even when not reachable */
#if 0
inst->reachability = 0; inst->reachability = 0;
inst->reachability_size = 0; inst->reachability_size = 0;
SRC_UpdateReachability(inst, 0); SRC_UpdateReachability(inst, 0);
#endif
} }
/* ================================================== */ /* ================================================== */
@@ -493,20 +479,6 @@ source_to_string(SRC_Instance inst)
/* ================================================== */ /* ================================================== */
static void
mark_ok_sources(SRC_Status status)
{
int i;
for (i = 0; i < n_sources; i++) {
if (sources[i]->status != SRC_OK)
continue;
sources[i]->status = status;
}
}
/* ================================================== */
static int static int
combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset, combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
double *offset_sd, double *frequency, double *skew) double *offset_sd, double *frequency, double *skew)
@@ -533,7 +505,7 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
/* Don't include this source if its distance is longer than the distance of /* Don't include this source if its distance is longer than the distance of
the selected source multiplied by the limit, their estimated frequencies the selected source multiplied by the limit, their estimated frequencies
are not close, or it was recently marked as distant */ are not close, or it was recently marked as outlier */
if (index != selected_source_index && if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit * (sources[index]->sel_info.root_distance > combine_limit *
@@ -541,19 +513,14 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
fabs(*frequency - src_frequency) > fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) { combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
/* Use a smaller penalty in first few updates */ /* Use a smaller penalty in first few updates */
sources[index]->distant = sources[index]->reachability_size >= SOURCE_REACH_BITS ? sources[index]->outlier = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
DISTANT_PENALTY : 1; OUTLIER_PENALTY : 1;
} else if (sources[index]->distant) { } else if (sources[index]->outlier) {
sources[index]->distant--; sources[index]->outlier--;
} }
if (sources[index]->distant) { if (sources[index]->outlier)
sources[index]->status = SRC_DISTANT;
continue; continue;
}
if (sources[index]->status == SRC_OK)
sources[index]->status = SRC_UNSELECTED;
UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time); UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency; src_offset += elapsed * src_frequency;
@@ -589,30 +556,39 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
/* ================================================== */ /* ================================================== */
/* This function selects the current reference from amongst the pool /* This function selects the current reference from amongst the pool
of sources we are holding and updates the local reference */ of sources we are holding.
Updates are only made to the local reference if a new source is selected
or match_refid is equal to the selected reference source refid */
void void
SRC_SelectSource(SRC_Instance updated_inst) SRC_SelectSource(SRC_Instance updated_inst)
{ {
struct SelectInfo *si; int i, j, index, old_selected_index, sel_prefer;
struct timeval now, ref_time; struct timeval now, ref_time;
int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources;
int n_badstats_sources, max_sel_reach, max_badstat_reach;
int depth, best_depth, combined, stratum, min_stratum, max_score_index;
double src_offset, src_offset_sd, src_frequency, src_skew; double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion; double src_root_delay, src_root_dispersion;
double best_lo, best_hi, distance, sel_src_distance, max_score; int n_endpoints, j1, j2;
double first_sample_ago, max_reach_sample_ago; double best_lo, best_hi;
NTP_Leap leap_status; int depth, best_depth;
int n_sel_sources, combined;
double distance, sel_src_distance;
int stratum, min_stratum;
struct SelectInfo *si;
int n_badstats_sources;
int max_sel_reach, max_badstat_reach;
int max_score_index;
double max_score;
if (updated_inst) NTP_Leap leap_status = LEAP_Normal;
updated_inst->updates++; old_selected_index = selected_source_index;
if (n_sources == 0) { if (n_sources == 0) {
/* In this case, we clearly cannot synchronise to anything */ /* In this case, we clearly cannot synchronise to anything */
if (selected_source_index != INVALID_SOURCE) { if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no sources", NULL); log_selection_message("Can't synchronise: no sources", NULL);
selected_source_index = INVALID_SOURCE; selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
} }
return; return;
} }
@@ -621,61 +597,31 @@ SRC_SelectSource(SRC_Instance updated_inst)
SCH_GetLastEventTime(&now, NULL, NULL); SCH_GetLastEventTime(&now, NULL, NULL);
/* Step 1 - build intervals about each source */ /* Step 1 - build intervals about each source */
n_endpoints = 0; n_endpoints = 0;
n_sel_sources = 0; n_sel_sources = 0;
n_badstats_sources = 0; n_badstats_sources = 0;
max_sel_reach = max_badstat_reach = 0; max_sel_reach = max_badstat_reach = 0;
max_reach_sample_ago = 0.0; for (i=0; i<n_sources; i++) {
for (i = 0; i < n_sources; i++) { if (sources[i]->selectable && sources[i]->reachability &&
assert(sources[i]->status != SRC_OK); sources[i]->sel_option != SRC_SelectNoselect) {
/* Ignore sources which were added with the noselect option */ si = &(sources[i]->sel_info);
if (sources[i]->sel_option == SRC_SelectNoselect) { SST_GetSelectionData(sources[i]->stats, &now,
sources[i]->status = SRC_UNSELECTABLE; &(si->stratum),
continue; &(si->lo_limit),
} &(si->hi_limit),
&(si->root_distance),
&(si->variance),
&(si->select_ok));
si = &sources[i]->sel_info; if (si->select_ok) {
SST_GetSelectionData(sources[i]->stats, &now, &si->stratum, ++n_sel_sources;
&si->lo_limit, &si->hi_limit, &si->root_distance,
&si->variance, &first_sample_ago,
&si->last_sample_ago, &si->select_ok);
if (!si->select_ok) {
++n_badstats_sources;
sources[i]->status = SRC_BAD_STATS;
if (max_badstat_reach < sources[i]->reachability)
max_badstat_reach = sources[i]->reachability;
continue;
}
sources[i]->status = SRC_OK; /* For now */ sources[i]->status = SRC_OK; /* For now */
if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago) /* Otherwise it will be hard to pick this one later! However,
max_reach_sample_ago = first_sample_ago; this test might be too strict, we might want to dump it */
if (max_sel_reach < sources[i]->reachability)
max_sel_reach = sources[i]->reachability;
}
for (i = 0; i < n_sources; i++) {
if (sources[i]->status != SRC_OK)
continue;
si = &sources[i]->sel_info;
/* Reachability is not a requirement for selection. An unreachable source
can still be selected if its newest sample is not older than the oldest
sample from reachable sources. */
if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
sources[i]->status = SRC_STALE;
continue;
}
++n_sel_sources;
j1 = n_endpoints; j1 = n_endpoints;
j2 = j1 + 1; j2 = j1 + 1;
@@ -688,34 +634,44 @@ SRC_SelectSource(SRC_Instance updated_inst)
sort_list[j2].tag = HIGH; sort_list[j2].tag = HIGH;
n_endpoints += 2; n_endpoints += 2;
if (max_sel_reach < sources[i]->reachability) {
max_sel_reach = sources[i]->reachability;
}
} else {
++n_badstats_sources;
sources[i]->status = SRC_BAD_STATS;
if (max_badstat_reach < sources[i]->reachability) {
max_badstat_reach = sources[i]->reachability;
}
}
} else {
/* If the source is not reachable, there is no way we will pick
it. */
sources[i]->status = SRC_UNREACHABLE;
}
} }
DEBUG_LOG(LOGF_Sources, "badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f", DEBUG_LOG(LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
n_badstats_sources, n_sel_sources, max_badstat_reach, n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
max_sel_reach, max_reach_sample_ago);
/* Wait for the next call if we have no source selected and there is /* Wait for the next call if we have no source selected and there is
a source with bad stats (has less than 3 samples) with reachability a source with bad stats (has less than 3 samples) with reachability
equal to shifted maximum reachability of sources with valid stats. equal to shifted maximum reachability of sources with valid stats.
This delays selecting source on start with servers using the same This delays selecting source on start with servers using the same
polling interval until they all have valid stats. */ polling interval until they all have valid stats. */
if (n_badstats_sources && n_sel_sources && if (n_badstats_sources && n_sel_sources &&
selected_source_index == INVALID_SOURCE && selected_source_index == INVALID_SOURCE &&
max_sel_reach >> 1 == max_badstat_reach) { max_sel_reach >> 1 == max_badstat_reach) {
mark_ok_sources(SRC_WAITS_STATS);
return;
}
if (n_endpoints == 0) {
/* No sources provided valid endpoints */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no selectable sources", NULL);
selected_source_index = INVALID_SOURCE;
}
return; return;
} }
/* Now sort the endpoint list */ /* Now sort the endpoint list */
if (n_endpoints > 0) {
/* Sort the list into order */
qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements); qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
/* Now search for the interval which is contained in the most /* Now search for the interval which is contained in the most
@@ -744,8 +700,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
depth = best_depth = 0; depth = best_depth = 0;
best_lo = best_hi = 0.0; best_lo = best_hi = 0.0;
for (i = 0; i < n_endpoints; i++) { for (i=0; i<n_endpoints; i++) {
switch (sort_list[i].tag) { switch(sort_list[i].tag) {
case LOW: case LOW:
depth++; depth++;
if (depth > best_depth) { if (depth > best_depth) {
@@ -753,56 +709,68 @@ SRC_SelectSource(SRC_Instance updated_inst)
best_lo = sort_list[i].offset; best_lo = sort_list[i].offset;
} }
break; break;
case CENTRE:
assert(0);
break;
case HIGH: case HIGH:
if (depth == best_depth) if (depth == best_depth) {
best_hi = sort_list[i].offset; best_hi = sort_list[i].offset;
}
depth--; depth--;
break; break;
default:
assert(0);
} }
} }
if (best_depth <= n_sel_sources / 2) { if (best_depth <= n_sel_sources/2) {
/* Could not even get half the reachable sources to agree - /* Could not even get half the reachable sources to agree -
clearly we can't synchronise. */ clearly we can't synchronise.
srcs #to agree
1 1
2 2
3 2
4 3 etc
*/
if (selected_source_index != INVALID_SOURCE) { if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no majority", NULL); log_selection_message("Can't synchronise: no majority", NULL);
REF_SetUnsynchronised();
selected_source_index = INVALID_SOURCE;
} }
selected_source_index = INVALID_SOURCE;
/* .. and mark all sources as falsetickers (so they appear thus /* .. and mark all sources as falsetickers (so they appear thus
on the outputs from the command client) */ on the outputs from the command client) */
mark_ok_sources(SRC_FALSETICKER);
return; for (i=0; i<n_sources; i++) {
sources[i]->status = SRC_FALSETICKER;
} }
} else {
/* We have our interval, now work out which source are in it, /* We have our interval, now work out which source are in it,
i.e. build list of admissible sources. */ i.e. build list of admissible sources. */
n_sel_sources = 0; n_sel_sources = 0;
for (i=0; i<n_sources; i++) {
for (i = 0; i < n_sources; i++) { if (sources[i]->status == SRC_OK) {
if (sources[i]->status != SRC_OK)
continue;
/* This should be the same condition to get into the endpoint /* This should be the same condition to get into the endpoint
list */ list */
/* Check if source's interval contains the best interval, or /* Check if source's interval contains the best interval, or
is wholly contained within it */ is wholly contained within it */
if ((sources[i]->sel_info.lo_limit <= best_lo && if (((sources[i]->sel_info.lo_limit <= best_lo) &&
sources[i]->sel_info.hi_limit >= best_hi) || (sources[i]->sel_info.hi_limit >= best_hi)) ||
(sources[i]->sel_info.lo_limit >= best_lo && ((sources[i]->sel_info.lo_limit >= best_lo) &&
sources[i]->sel_info.hi_limit <= best_hi)) { (sources[i]->sel_info.hi_limit <= best_hi))) {
sel_sources[n_sel_sources++] = i; sel_sources[n_sel_sources++] = i;
} else { } else {
sources[i]->status = SRC_FALSETICKER; sources[i]->status = SRC_FALSETICKER;
} }
} }
}
#if 0 #if 0
/* We now have a list of indices for the sources which pass the /* We now have a list of indices for the sources which pass the
@@ -812,7 +780,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Find minimum distance */ /* Find minimum distance */
index = sel_sources[0]; index = sel_sources[0];
min_distance = sources[index]->sel_info.root_distance; min_distance = sources[index]->sel_info.root_distance;
for (i = 1; i < n_sel_sources; i++) { for (i=1; i<n_sel_sources; i++) {
index = sel_sources[i]; index = sel_sources[i];
distance = sources[index]->sel_info.root_distance; distance = sources[index]->sel_info.root_distance;
if (distance < min_distance) { if (distance < min_distance) {
@@ -822,7 +790,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Now go through and prune any NTP sources that have excessive /* Now go through and prune any NTP sources that have excessive
variance */ variance */
for (i = 0; i < n_sel_sources; i++) { for (i=0; i<n_sel_sources; i++) {
index = sel_sources[i]; index = sel_sources[i];
if (sources[index]->type == SRC_NTP && if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) { sqrt(sources[index]->sel_info.variance) > min_distance) {
@@ -830,88 +798,80 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[index]->status = SRC_JITTERY; sources[index]->status = SRC_JITTERY;
} }
} }
/* Now crunch the list and mark all sources as selectable */
for (i = j = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (index == INVALID_SOURCE)
continue;
sel_sources[j++] = index;
}
n_sel_sources = j;
#endif #endif
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) { /* Now crunch the list and mark all sources as selectable */
if (selected_source_index != INVALID_SOURCE) { for (i=j=0; i<n_sel_sources; i++) {
log_selection_message("Can't synchronise: %s selectable sources",
n_sel_sources ? "not enough" : "no");
selected_source_index = INVALID_SOURCE;
}
mark_ok_sources(SRC_WAITS_SOURCES);
return;
}
/* Accept leap second status if more than half of selectable sources agree */
for (i = j1 = j2 = 0; i < n_sel_sources; i++) {
index = sel_sources[i]; index = sel_sources[i];
if (sources[index]->leap_status == LEAP_InsertSecond) if (index != INVALID_SOURCE) {
j1++; sources[index]->status = SRC_SELECTABLE;
else if (sources[index]->leap_status == LEAP_DeleteSecond)
j2++;
}
if (j1 > n_sel_sources / 2)
leap_status = LEAP_InsertSecond;
else if (j2 > n_sel_sources / 2)
leap_status = LEAP_DeleteSecond;
else
leap_status = LEAP_Normal;
/* If there are any sources with prefer option, reduce the list again
only to the preferred sources */
for (i = j = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
sel_sources[j++] = sel_sources[i]; sel_sources[j++] = sel_sources[i];
} }
if (j > 0) {
for (i = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option != SRC_SelectPrefer)
sources[sel_sources[i]]->status = SRC_NONPREFERRED;
} }
n_sel_sources = j; n_sel_sources = j;
if (n_sel_sources > 0) {
/* Accept leap second status if more than half of selectable sources agree */
for (i=j1=j2=0; i<n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->leap_status == LEAP_InsertSecond) {
j1++;
} else if (sources[index]->leap_status == LEAP_DeleteSecond) {
j2++;
}
}
if (j1 > n_sel_sources / 2) {
leap_status = LEAP_InsertSecond;
} else if (j2 > n_sel_sources / 2) {
leap_status = LEAP_DeleteSecond;
}
/* If there are any sources with prefer option, reduce the list again
only to the prefer sources */
for (i=j=0; i<n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer) {
sel_sources[j++] = sel_sources[i];
}
}
if (j > 0) {
n_sel_sources = j;
sel_prefer = 1; sel_prefer = 1;
} else { } else {
sel_prefer = 0; sel_prefer = 0;
} }
/* Find minimum stratum */ /* Now find minimum stratum. If none are left now,
tough. RFC1305 is not so harsh on pruning sources due to
excess variance, which prevents this from happening */
index = sel_sources[0]; index = sel_sources[0];
min_stratum = sources[index]->sel_info.stratum; min_stratum = sources[index]->sel_info.stratum;
for (i = 1; i < n_sel_sources; i++) { for (i=1; i<n_sel_sources; i++) {
index = sel_sources[i]; index = sel_sources[i];
stratum = sources[index]->sel_info.stratum; stratum = sources[index]->sel_info.stratum;
if (stratum < min_stratum) if (stratum < min_stratum) min_stratum = stratum;
min_stratum = stratum;
} }
/* Update scores and find the source with maximum score */ /* Update scores and find source with maximum score */
max_score_index = INVALID_SOURCE; max_score_index = INVALID_SOURCE;
max_score = 0.0; max_score = 0.0;
sel_src_distance = 0.0; sel_src_distance = 0.0;
if (selected_source_index != INVALID_SOURCE) if (selected_source_index != INVALID_SOURCE) {
sel_src_distance = sources[selected_source_index]->sel_info.root_distance + sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
(sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight; (sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
}
for (i = 0; i < n_sources; i++) { for (i = 0; i < n_sources; i++) {
/* Reset score for non-selectable sources */ /* Reset score for non-selectable sources */
if (sources[i]->status != SRC_OK || if (sources[i]->status != SRC_SELECTABLE ||
(sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) { (sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) {
sources[i]->sel_score = 1.0; sources[i]->sel_score = 1.0;
sources[i]->distant = DISTANT_PENALTY; sources[i]->outlier = OUTLIER_PENALTY;
continue; continue;
} }
@@ -921,6 +881,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
distance += reselect_distance; distance += reselect_distance;
if (selected_source_index != INVALID_SOURCE) { if (selected_source_index != INVALID_SOURCE) {
/* Update score, but only for source pairs where one source /* Update score, but only for source pairs where one source
has a new sample */ has a new sample */
if (sources[i] == updated_inst || if (sources[i] == updated_inst ||
@@ -931,16 +892,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (sources[i]->sel_score < 1.0) if (sources[i]->sel_score < 1.0)
sources[i]->sel_score = 1.0; sources[i]->sel_score = 1.0;
} }
} else { } else {
/* When there is no selected source yet, assign scores so that the
/* When there is no selected source yet, assign scores so the
source with minimum distance will have maximum score. The scores source with minimum distance will have maximum score. The scores
will be reset when the source is selected later in this function. */ will be immediately reset. */
sources[i]->sel_score = 1.0 / distance; sources[i]->sel_score = 1.0 / distance;
} }
DEBUG_LOG(LOGF_Sources, "select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f", DEBUG_LOG(LOGF_Sources, "select score=%f refid=%x match_refid=%x status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, sources[i]->sel_score, sources[i]->ref_id, updated_inst ? updated_inst->ref_id : 0,
updated_inst ? updated_inst->ref_id : 0,
sources[i]->status, distance); sources[i]->status, distance);
if (max_score < sources[i]->sel_score) { if (max_score < sources[i]->sel_score) {
@@ -951,50 +914,32 @@ SRC_SelectSource(SRC_Instance updated_inst)
assert(max_score_index != INVALID_SOURCE); assert(max_score_index != INVALID_SOURCE);
/* Is the current source still a survivor and no other source has reached /* Is the current source still a survivor
the score limit? */ and no other source has reached the score limit? */
if (selected_source_index == INVALID_SOURCE ||
sources[selected_source_index]->status != SRC_OK || if ((selected_source_index == INVALID_SOURCE) ||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
(max_score_index != selected_source_index && max_score > SCORE_LIMIT)) { (max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
/* Before selecting the new synchronisation source wait until the reference /* We have to elect a new synchronisation source */
can be updated */
if (sources[max_score_index]->updates == 0) {
selected_source_index = INVALID_SOURCE;
mark_ok_sources(SRC_WAITS_UPDATE);
DEBUG_LOG(LOGF_Sources, "best source has no updates");
return;
}
selected_source_index = max_score_index; selected_source_index = max_score_index;
log_selection_message("Selected source %s", log_selection_message("Selected source %s",
source_to_string(sources[selected_source_index])); source_to_string(sources[selected_source_index]));
/* New source has been selected, reset all scores */ /* New source has been selected, reset all scores */
for (i = 0; i < n_sources; i++) { for (i=0; i < n_sources; i++) {
sources[i]->sel_score = 1.0; sources[i]->sel_score = 1.0;
sources[i]->distant = 0; sources[i]->outlier = 0;
} }
} }
sources[selected_source_index]->status = SRC_SELECTED; sources[selected_source_index]->status = SRC_SYNC;
/* Don't update reference when the selected source has no new samples */ /* Update local reference only when a new source was selected
or the selected source has a new sample */
if (sources[selected_source_index]->updates == 0) { if (selected_source_index != old_selected_index ||
/* Mark the remaining sources as last combine_sources() call */ updated_inst == sources[selected_source_index]) {
for (i = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->status == SRC_OK)
sources[index]->status = sources[index]->distant ?
SRC_DISTANT : SRC_UNSELECTED;
}
return;
}
for (i = 0; i < n_sources; i++)
sources[i]->updates = 0;
/* Now just use the statistics of the selected source combined with /* Now just use the statistics of the selected source combined with
the other selectable sources for trimming the local clock */ the other selectable sources for trimming the local clock */
@@ -1008,12 +953,39 @@ SRC_SelectSource(SRC_Instance updated_inst)
&src_offset_sd, &src_frequency, &src_skew); &src_offset_sd, &src_frequency, &src_skew);
REF_SetReference(sources[selected_source_index]->sel_info.stratum, REF_SetReference(sources[selected_source_index]->sel_info.stratum,
leap_status, combined, leap_status,
combined,
sources[selected_source_index]->ref_id, sources[selected_source_index]->ref_id,
sources[selected_source_index]->ip_addr, sources[selected_source_index]->ip_addr,
&ref_time, src_offset, src_offset_sd, &ref_time,
src_frequency, src_skew, src_offset,
src_root_delay, src_root_dispersion); src_offset_sd,
src_frequency,
src_skew,
src_root_delay,
src_root_dispersion);
}
} else {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no selectable sources", NULL);
}
selected_source_index = INVALID_SOURCE;
}
}
} else {
/* No sources provided valid endpoints */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no reachable sources", NULL);
}
selected_source_index = INVALID_SOURCE;
}
if (selected_source_index == INVALID_SOURCE &&
selected_source_index != old_selected_index) {
REF_SetUnsynchronised();
}
} }
/* ================================================== */ /* ================================================== */
@@ -1249,32 +1221,23 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
} }
switch (src->status) { switch (src->status) {
case SRC_UNSELECTABLE: case SRC_SYNC:
report->state = RPT_SYNC;
break;
case SRC_JITTERY:
report->state = RPT_JITTERY;
break;
case SRC_OK:
case SRC_BAD_STATS: case SRC_BAD_STATS:
case SRC_STALE: case SRC_UNREACHABLE:
case SRC_WAITS_STATS:
report->state = RPT_UNREACH; report->state = RPT_UNREACH;
break; break;
case SRC_FALSETICKER: case SRC_FALSETICKER:
report->state = RPT_FALSETICKER; report->state = RPT_FALSETICKER;
break; break;
case SRC_JITTERY: case SRC_SELECTABLE:
report->state = RPT_JITTERY; report->state = src->outlier ? RPT_OUTLIER : RPT_CANDIDATE;
break; break;
case SRC_WAITS_SOURCES:
case SRC_NONPREFERRED:
case SRC_WAITS_UPDATE:
case SRC_DISTANT:
case SRC_OUTLIER:
report->state = RPT_OUTLIER;
break;
case SRC_UNSELECTED:
report->state = RPT_CANDIDATE;
break;
case SRC_SELECTED:
report->state = RPT_SYNC;
break;
case SRC_OK:
default: default:
assert(0); assert(0);
break; break;
@@ -1282,7 +1245,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
switch (src->sel_option) { switch (src->sel_option) {
case SRC_SelectNormal: case SRC_SelectNormal:
report->sel_option = RPT_NORMAL; report->sel_option = RPT_NOSELECT;
break; break;
case SRC_SelectPrefer: case SRC_SelectPrefer:
report->sel_option = RPT_PREFER; report->sel_option = RPT_PREFER;
@@ -1337,6 +1300,27 @@ SRC_GetType(int index)
/* ================================================== */ /* ================================================== */
SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst)
{
SRC_Skew_Direction result = SRC_Skew_Nochange;
switch (SST_LastSkewChange(inst->stats)) {
case SST_Skew_Decrease:
result = SRC_Skew_Decrease;
break;
case SST_Skew_Nochange:
result = SRC_Skew_Nochange;
break;
case SST_Skew_Increase:
result = SRC_Skew_Increase;
break;
}
return result;
}
/* ================================================== */
int int
SRC_Samples(SRC_Instance inst) SRC_Samples(SRC_Instance inst)
{ {

View File

@@ -65,7 +65,7 @@ typedef enum {
/* Function to create a new instance. This would be called by one of /* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */ 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. /* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this 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); 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 /* Function to get the range of frequencies, relative to the given
source, that we believe the local clock lies within. The return 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. indicates that the local clock is FAST relative to it.
root_delay and root_dispersion are in seconds, and are as per 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 + local sampling precision + skew dispersion accrued during the
measurement. It is the job of the source statistics algorithms + measurement. It is the job of the source statistics algorithms +
track.c to add on the extra dispersion due to the residual standard 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 */ /* This routine sets the source as not receiving reachability updates */
extern void SRC_UnsetActive(SRC_Instance inst); 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 */ /* This routine updates the reachability register */
extern void SRC_UpdateReachability(SRC_Instance inst, int reachable); 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 /* 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 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 for the local time. Updates are only made to the local reference
when the selected source was updated (set as updated_inst) since if a new source is selected or updated_inst is the selected
the last reference update. This avoids updating the frequency reference source. (This avoids updating the frequency
tracking for every sample from other sources - only the ones from 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); extern void SRC_SelectSource(SRC_Instance updated_inst);
/* Force reselecting the best source */ /* 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); 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); extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */ #endif /* GOT_SOURCES_H */

View File

@@ -43,6 +43,10 @@
to store per source */ to store per source */
#define MAX_SAMPLES 64 #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, /* This is the assumed worst case bound on an unknown frequency,
2000ppm, which would be pretty bad */ 2000ppm, which would be pretty bad */
#define WORST_CASE_FREQ_BOUND (2000.0/1.0e6) #define WORST_CASE_FREQ_BOUND (2000.0/1.0e6)
@@ -64,10 +68,6 @@ struct SST_Stats_Record {
uint32_t refid; uint32_t refid;
IPAddr *ip_addr; 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 /* Number of samples currently stored. The samples are stored in circular
buffer. */ buffer. */
int n_samples; int n_samples;
@@ -108,6 +108,9 @@ struct SST_Stats_Record {
about estimated_frequency */ about estimated_frequency */
double skew; 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 */ /* This is the estimated residual variance of the data points */
double variance; double variance;
@@ -119,7 +122,8 @@ struct SST_Stats_Record {
sample times. In this module, we use the convention that sample times. In this module, we use the convention that
positive means the local clock is FAST of the source and negative 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 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]; double offsets[MAX_SAMPLES * REGRESS_RUNS_RATIO];
/* This is an array of the offsets as originally measured. Local /* This is an array of the offsets as originally measured. Local
@@ -163,6 +167,8 @@ SST_Initialise(void)
logfileid = CNF_GetLogStatistics() ? LOG_FileOpen("statistics", 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") " Date (UTC) Time IP Address Std dev'n Est offset Offset sd Diff freq Est skew Stress Ns Bs Nr")
: -1; : -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 */ /* This function creates a new instance of the statistics handler */
SST_Stats 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; SST_Stats inst;
inst = MallocNew(struct SST_Stats_Record); 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); SST_ResetInstance(inst);
return inst; return inst;
@@ -212,6 +216,7 @@ SST_ResetInstance(SST_Stats inst)
inst->min_delay_sample = 0; inst->min_delay_sample = 0;
inst->estimated_frequency = 0; inst->estimated_frequency = 0;
inst->skew = 2000.0e-6; inst->skew = 2000.0e-6;
inst->skew_dirn = SST_Skew_Nochange;
inst->estimated_offset = 0.0; inst->estimated_offset = 0.0;
inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */ inst->estimated_offset_sd = 86400.0; /* Assume it's at least within a day! */
inst->offset_time.tv_sec = 0; inst->offset_time.tv_sec = 0;
@@ -220,15 +225,6 @@ SST_ResetInstance(SST_Stats inst)
inst->nruns = 0; 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. /* This function is called to prune the register down when it is full.
For now, just discard the oldest sample. */ 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 */ /* Make room for the new sample */
if (inst->n_samples > 0 && 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); prune_register(inst, 1);
} }
@@ -448,7 +444,7 @@ SST_DoNewRegression(SST_Stats inst)
inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples, inst->regression_ok = RGR_FindBestRegression(times_back + inst->runs_samples,
offsets + inst->runs_samples, weights, offsets + inst->runs_samples, weights,
inst->n_samples, inst->runs_samples, inst->n_samples, inst->runs_samples,
inst->min_samples, min_samples,
&est_intercept, &est_slope, &est_var, &est_intercept, &est_slope, &est_var,
&est_intercept_sd, &est_slope_sd, &est_intercept_sd, &est_slope_sd,
&best_start, &nruns, &degrees_of_freedom); &best_start, &nruns, &degrees_of_freedom);
@@ -471,6 +467,18 @@ SST_DoNewRegression(SST_Stats inst)
stress = fabs(old_freq - inst->estimated_frequency) / old_skew; 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) { if (logfileid != -1) {
LOG_FileWrite(logfileid, "%s %-15s %10.3e %10.3e %10.3e %10.3e %10.3e %7.1e %3d %3d %3d", 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), 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_lo_limit,
double *offset_hi_limit, double *offset_hi_limit,
double *root_distance, double *root_distance,
double *variance, double *variance, int *select_ok)
double *first_sample_ago,
double *last_sample_ago,
int *select_ok)
{ {
double offset, sample_elapsed; double offset, sample_elapsed;
int i, j; int i, j;
if (!inst->n_samples) {
*select_ok = 0;
return;
}
i = get_runsbuf_index(inst, inst->best_single_sample); i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_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 #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; *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", DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f selok=%d",
inst->n_samples, offset, *root_distance, *variance, inst->n_samples, offset, *root_distance, *variance, *select_ok);
*first_sample_ago, *last_sample_ago, *select_ok);
} }
/* ================================================== */ /* ================================================== */
@@ -631,7 +625,12 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
sample = &(inst->sample_times[i]); sample = &(inst->sample_times[i]);
prev = *sample; prev = *sample;
UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset); UTI_AdjustTimeval(sample, when, sample, &delta_time, dfreq, doffset);
prev_offset = inst->offsets[i];
inst->offsets[i] += delta_time; 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]);
} }
/* Do a half-baked update to the regression estimates */ /* Do a half-baked update to the regression estimates */
@@ -643,11 +642,10 @@ SST_SlewSamples(SST_Stats inst, struct timeval *when, double dfreq, double doffs
inst->estimated_offset += delta_time; inst->estimated_offset += delta_time;
inst->estimated_frequency -= 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", DEBUG_LOG(LOGF_SourceStats, "old_off_time=[%s] new=[%s] old_off=%f new_off=%f old_freq=%.3fppm new_freq=%.3fppm",
inst->n_samples, inst->runs_samples,
UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)), UTI_TimevalToString(&prev), UTI_TimevalToString(&(inst->offset_time)),
prev_offset, inst->estimated_offset, 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 int

View File

@@ -38,7 +38,7 @@ extern void SST_Initialise(void);
extern void SST_Finalise(void); extern void SST_Finalise(void);
/* This function creates a new instance of the statistics handler */ /* 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. */ /* This function deletes an instance of the statistics handler. */
extern void SST_DeleteInstance(SST_Stats inst); extern void SST_DeleteInstance(SST_Stats inst);
@@ -46,9 +46,6 @@ extern void SST_DeleteInstance(SST_Stats inst);
/* This function resets an instance */ /* This function resets an instance */
extern void SST_ResetInstance(SST_Stats inst); 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 /* This function accumulates a single sample into the statistics handler
sample_time is the epoch at which the sample is to be considered to 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 seconds. Positive indicates that the local clock if FAST (contrary
to the NTP parts of the software) 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. 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_lo_limit,
double *offset_hi_limit, double *offset_hi_limit,
double *root_distance, double *root_distance,
double *variance, double *variance, int *select_ok);
double *first_sample_ago,
double *last_sample_ago,
int *select_ok);
/* Get data needed when setting up tracking on this source */ /* Get data needed when setting up tracking on this source */
extern void 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); 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); extern int SST_Samples(SST_Stats inst);
#endif /* GOT_SOURCESTATS_H */ #endif /* GOT_SOURCESTATS_H */

View File

@@ -38,11 +38,7 @@ typedef struct {
int iburst; int iburst;
int min_stratum; int min_stratum;
int poll_target; int poll_target;
int version; unsigned long authkey;
int max_sources;
int min_samples;
int max_samples;
uint32_t authkey;
double max_delay; double max_delay;
double max_delay_ratio; double max_delay_ratio;
double max_delay_dev_ratio; double max_delay_dev_ratio;
@@ -58,9 +54,6 @@ typedef struct {
#define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0 #define SRC_DEFAULT_MAXDELAYDEVRATIO 10.0
#define SRC_DEFAULT_MINSTRATUM 0 #define SRC_DEFAULT_MINSTRATUM 0
#define SRC_DEFAULT_POLLTARGET 6 #define SRC_DEFAULT_POLLTARGET 6
#define SRC_DEFAULT_MAXSOURCES 4 #define INACTIVE_AUTHKEY 0UL
#define SRC_DEFAULT_MINSAMPLES (-1)
#define SRC_DEFAULT_MAXSAMPLES (-1)
#define INACTIVE_AUTHKEY 0
#endif /* GOT_SRCPARAMS_H */ #endif /* GOT_SRCPARAMS_H */

329
stubs.c
View File

@@ -1,329 +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.
*
**********************************************************************
=======================================================================
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 "nameserv.h"
#include "nameserv_async.h"
#include "ntp_core.h"
#include "ntp_io.h"
#include "ntp_sources.h"
#include "refclock.h"
#ifndef FEAT_ASYNCDNS
#define MAX_ADDRESSES 16
/* This is a blocking implementation used when asynchronous resolving is not available */
void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{
IPAddr addrs[MAX_ADDRESSES];
DNS_Status status;
int i;
status = DNS_Name2IPAddress(name, addrs, MAX_ADDRESSES);
for (i = 0; status == DNS_Success && i < MAX_ADDRESSES &&
addrs[i].family != IPADDR_UNSPEC; i++)
;
(handler)(status, i, addrs, anything);
}
#endif /* !FEAT_ASYNCDNS */
#ifndef FEAT_CMDMON
void
CAM_Initialise(int family)
{
}
void
CAM_Finalise(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_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 */

2
sys.c
View File

@@ -97,7 +97,7 @@ SYS_Finalise(void)
void SYS_DropRoot(char *user) void SYS_DropRoot(char *user)
{ {
#if defined(LINUX) && defined (FEAT_PRIVDROP) #if defined(LINUX) && defined (FEAT_LINUXCAPS)
SYS_Linux_DropRoot(user); SYS_Linux_DropRoot(user);
#else #else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported"); LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");

View File

@@ -39,10 +39,9 @@
/* ================================================== */ /* ================================================== */
/* System clock drivers */ /* System clock frequency drivers */
static lcl_ReadFrequencyDriver drv_read_freq; static lcl_ReadFrequencyDriver drv_read_freq;
static lcl_SetFrequencyDriver drv_set_freq; static lcl_SetFrequencyDriver drv_set_freq;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* Current frequency as requested by the local module (in ppm) */ /* Current frequency as requested by the local module (in ppm) */
static double base_freq; static double base_freq;
@@ -271,35 +270,17 @@ apply_step_offset(double offset)
/* ================================================== */ /* ================================================== */
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);
}
/* ================================================== */
void void
SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay, SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
lcl_ReadFrequencyDriver sys_read_freq, lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq, lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset, lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap, lcl_SetLeapDriver sys_set_leap)
lcl_SetSyncStatusDriver sys_set_sync_status)
{ {
max_freq = max_set_freq_ppm; max_freq = max_set_freq_ppm;
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6); max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
drv_read_freq = sys_read_freq; drv_read_freq = sys_read_freq;
drv_set_freq = sys_set_freq; drv_set_freq = sys_set_freq;
drv_set_sync_status = sys_set_sync_status;
base_freq = (*drv_read_freq)(); base_freq = (*drv_read_freq)();
slew_freq = 0.0; slew_freq = 0.0;
@@ -310,7 +291,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, sys_apply_step_offset ? accrue_offset, sys_apply_step_offset ?
sys_apply_step_offset : 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); LCL_AddParameterChangeHandler(handle_step, NULL);
} }

View File

@@ -35,8 +35,7 @@ extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_s
lcl_ReadFrequencyDriver sys_read_freq, lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq, lcl_SetFrequencyDriver sys_set_freq,
lcl_ApplyStepOffsetDriver sys_apply_step_offset, lcl_ApplyStepOffsetDriver sys_apply_step_offset,
lcl_SetLeapDriver sys_set_leap, lcl_SetLeapDriver sys_set_leap);
lcl_SetSyncStatusDriver sys_set_sync_status);
extern void SYS_Generic_Finalise(void); extern void SYS_Generic_Finalise(void);

View File

@@ -44,7 +44,7 @@ int SchedPriority = 0;
int LockAll = 0; int LockAll = 0;
#endif #endif
#ifdef FEAT_PRIVDROP #ifdef FEAT_LINUXCAPS
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#include <sys/prctl.h> #include <sys/prctl.h>
@@ -58,9 +58,6 @@ int LockAll = 0;
#include "logging.h" #include "logging.h"
#include "wrap_adjtimex.h" #include "wrap_adjtimex.h"
/* The threshold for adjtimex maxerror when the kernel sets the UNSYNC flag */
#define UNSYNC_MAXERROR 16.0
/* This is the uncompensated system tick value */ /* This is the uncompensated system tick value */
static int nominal_tick; static int nominal_tick;
@@ -85,15 +82,13 @@ static int tick_update_hz;
/* ================================================== */ /* ================================================== */
inline static long inline static long
our_round(double x) our_round(double x) {
{
long y; long y;
if (x > 0.0) if (x > 0.0)
y = x + 0.5; y = x + 0.5;
else else
y = x - 0.5; y = x - 0.5;
return y; return y;
} }
@@ -184,42 +179,21 @@ set_leap(int leap)
/* ================================================== */ /* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
if (synchronised) {
if (est_error > UNSYNC_MAXERROR)
est_error = UNSYNC_MAXERROR;
if (max_error >= UNSYNC_MAXERROR) {
max_error = UNSYNC_MAXERROR;
synchronised = 0;
}
} else {
est_error = max_error = UNSYNC_MAXERROR;
}
/* Clear the UNSYNC flag only if rtcsync is enabled */
if (!CNF_GetRtcSync())
synchronised = 0;
TMX_SetSync(synchronised, est_error, max_error);
}
/* ================================================== */
/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when /* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
* it starts. The only credible values are 100 (Linux/x86) or powers of 2. * it starts. The only credible values are 100 (Linux/x86) or powers of 2.
* Also, the bounds checking inside the kernel's adjtimex system call enforces * Also, the bounds checking inside the kernel's adjtimex system call enforces
* a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */ * a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
static int static void
guess_hz(int tick) guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
{ {
int i, tick_lo, tick_hi, ihz; int i, tick_lo, tick_hi, ihz;
double tick_nominal; double tick_nominal;
/* Pick off the hz=100 case first */ /* Pick off the hz=100 case first */
if (tick >= 9000 && tick <= 11000) { if (tick >= 9000 && tick <= 11000) {
return 100; *hz = 100;
*shift_hz = 7;
return;
} }
for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */ for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */
@@ -229,26 +203,36 @@ guess_hz(int tick)
tick_hi = (int)(0.5 + tick_nominal*4.0/3.0); tick_hi = (int)(0.5 + tick_nominal*4.0/3.0);
if (tick_lo < tick && tick <= tick_hi) { if (tick_lo < tick && tick <= tick_hi) {
return ihz; *hz = ihz;
*shift_hz = i;
return;
} }
} }
/* oh dear. doomed. */ /* oh dear. doomed. */
return 0; *hz = 0;
*shift_hz = 0;
} }
/* ================================================== */ /* ================================================== */
static int static int
get_hz(void) get_hz_and_shift_hz(int *hz, int *shift_hz)
{ {
#ifdef _SC_CLK_TCK #ifdef _SC_CLK_TCK
int hz; if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
if ((hz = sysconf(_SC_CLK_TCK)) < 1)
return 0; return 0;
}
return hz; if (*hz == 100) {
*shift_hz = 7;
return 1;
}
for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
;
return 1;
#else #else
return 0; return 0;
#endif #endif
@@ -275,20 +259,19 @@ static void
get_version_specific_details(void) get_version_specific_details(void)
{ {
int major, minor, patch; int major, minor, patch;
long tick; int shift_hz;
double freq; struct tmx_params tmx_params;
struct utsname uts; struct utsname uts;
hz = get_hz(); if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
if (!hz) { guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (TMX_GetFrequency(&freq, &tick) < 0)
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
hz = guess_hz(tick); if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
if (!hz) tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %ld", tick); }
} }
dhz = (double) hz; dhz = (double) hz;
@@ -349,11 +332,13 @@ SYS_Linux_Initialise(void)
have_setoffset = 0; have_setoffset = 0;
} }
TMX_SetSync(CNF_GetRtcSync());
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick, SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
1.0 / tick_update_hz, 1.0 / tick_update_hz,
read_frequency, set_frequency, read_frequency, set_frequency,
have_setoffset ? apply_step_offset : NULL, have_setoffset ? apply_step_offset : NULL,
set_leap, set_sync_status); set_leap);
} }
/* ================================================== */ /* ================================================== */
@@ -367,7 +352,7 @@ SYS_Linux_Finalise(void)
/* ================================================== */ /* ================================================== */
#ifdef FEAT_PRIVDROP #ifdef FEAT_LINUXCAPS
void void
SYS_Linux_DropRoot(char *user) SYS_Linux_DropRoot(char *user)
{ {
@@ -397,7 +382,7 @@ SYS_Linux_DropRoot(char *user)
LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid); LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid);
} }
if ((cap = cap_from_text("cap_net_bind_service,cap_sys_time=ep")) == NULL) { if ((cap = cap_from_text("cap_sys_time=ep")) == NULL) {
LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed"); LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed");
} }

View File

@@ -307,8 +307,7 @@ SYS_NetBSD_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, get_offset_correction,
NULL /* set_leap */, NULL /* set_leap */);
NULL /* set_sync_status */);
} }

View File

@@ -426,8 +426,7 @@ SYS_Solaris_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, get_offset_correction,
NULL /* set_leap */, NULL /* set_leap */);
NULL /* set_sync_status */);
/* Turn off the kernel switch that keeps the system clock in step /* Turn off the kernel switch that keeps the system clock in step
with the non-volatile clock */ with the non-volatile clock */

View File

@@ -379,8 +379,7 @@ SYS_SunOS_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency, lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset, accrue_offset, apply_step_offset,
get_offset_correction, get_offset_correction,
NULL /* set_leap */, NULL /* set_leap */);
NULL /* set_sync_status */);
/* Turn off the kernel switch that keeps the system clock in step /* Turn off the kernel switch that keeps the system clock in step
with the non-volatile clock */ with the non-volatile clock */

View File

@@ -62,9 +62,9 @@
#include <syslog.h> #include <syslog.h>
#include <time.h> #include <time.h>
#ifdef HAVE_INTTYPES_H #ifdef HAS_INTTYPES_H
#include <inttypes.h> #include <inttypes.h>
#elif HAVE_STDINT_H #elif HAS_STDINT_H
#include <stdint.h> #include <stdint.h>
#else #else
/* Tough */ /* Tough */
@@ -78,7 +78,7 @@
#endif #endif
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
/* For inet_ntop() */ /* For inet_ntop() */
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif

View File

@@ -27,7 +27,6 @@
#include "config.h" #include "config.h"
#include "array.h"
#include "conf.h" #include "conf.h"
#include "local.h" #include "local.h"
#include "memory.h" #include "memory.h"
@@ -47,37 +46,6 @@ static char *filename;
static double update_interval; static double update_interval;
static double T0, k0, k1, k2; static double T0, k0, k1, k2;
struct Point {
double temp;
double comp;
};
static ARR_Instance points;
static double
get_tempcomp(double temp)
{
unsigned int i;
struct Point *p1 = NULL, *p2 = NULL;
/* If not configured with points, calculate the compensation from the
specified quadratic function */
if (!points)
return k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
/* Otherwise interpolate/extrapolate between two nearest points */
for (i = 1; i < ARR_GetSize(points); i++) {
p2 = (struct Point *)ARR_GetElement(points, i);
if (p2->temp >= temp)
break;
}
p1 = p2 - 1;
return (temp - p1->temp) / (p2->temp - p1->temp) *
(p2->comp - p1->comp) + p1->comp;
}
static void static void
read_timeout(void *arg) read_timeout(void *arg)
{ {
@@ -87,13 +55,11 @@ read_timeout(void *arg)
f = fopen(filename, "r"); f = fopen(filename, "r");
if (f && fscanf(f, "%lf", &temp) == 1) { if (f && fscanf(f, "%lf", &temp) == 1) {
comp = get_tempcomp(temp); comp = k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
if (fabs(comp) <= MAX_COMP) { if (fabs(comp) <= MAX_COMP) {
comp = LCL_SetTempComp(comp); comp = LCL_SetTempComp(comp);
DEBUG_LOG(LOGF_TempComp, "tempcomp updated to %f for %f", comp, temp);
if (logfileid != -1) { if (logfileid != -1) {
struct timeval now; struct timeval now;
@@ -117,41 +83,10 @@ read_timeout(void *arg)
timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL); timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
} }
static void
read_points(const char *filename)
{
FILE *f;
char line[256];
struct Point *p;
f = fopen(filename, "r");
if (!f) {
LOG_FATAL(LOGF_TempComp, "Could not open tempcomp point file %s", filename);
return;
}
points = ARR_CreateInstance(sizeof (struct Point));
while (fgets(line, sizeof (line), f)) {
p = (struct Point *)ARR_GetNewElement(points);
if (sscanf(line, "%lf %lf", &p->temp, &p->comp) != 2) {
LOG_FATAL(LOGF_Configure, "Could not read tempcomp point from %s", filename);
break;
}
}
fclose(f);
if (ARR_GetSize(points) < 2)
LOG_FATAL(LOGF_Configure, "Not enough points in %s", filename);
}
void void
TMC_Initialise(void) TMC_Initialise(void)
{ {
char *point_file; CNF_GetTempComp(&filename, &update_interval, &T0, &k0, &k1, &k2);
CNF_GetTempComp(&filename, &update_interval, &point_file, &T0, &k0, &k1, &k2);
if (filename == NULL) if (filename == NULL)
return; return;
@@ -159,9 +94,6 @@ TMC_Initialise(void)
if (update_interval <= 0.0) if (update_interval <= 0.0)
update_interval = 1.0; update_interval = 1.0;
if (point_file)
read_points(point_file);
logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp", logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
" Date (UTC) Time Temp. Comp.") " Date (UTC) Time Temp. Comp.")
: -1; : -1;
@@ -175,8 +107,6 @@ TMC_Finalise(void)
if (filename == NULL) if (filename == NULL)
return; return;
if (points)
ARR_DestroyInstance(points);
SCH_RemoveTimeout(timeout_id); SCH_RemoveTimeout(timeout_id);
Free(filename);
} }

View File

@@ -1,19 +0,0 @@
#!/bin/sh
# Try to compile chrony in various combinations of disabled features
cd ../..
for opts in \
"--disable-asyncdns" \
"--disable-rtc" \
"--disable-cmdmon" \
"--disable-ntp" \
"--disable-refclock" \
"--disable-cmdmon --disable-ntp" \
"--disable-cmdmon --disable-refclock" \
"--disable-cmdmon --disable-ntp --disable-refclock"
do
./configure $opts
make || exit 1
done

View File

@@ -1,40 +0,0 @@
#!/bin/bash
. test.common
test_start "source selection"
# Falsetickers should be detected if their number is less than half of all
servers=5
for falsetickers in 1 2; do
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
done
for falsetickers in 3 4; do
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
# These check are expected to fail
check_source_selection && test_fail
check_sync && test_fail
done
# Sources with large asymmetric delay should be excluded
servers=3
falsetickers=0
base_delay="(+ $default_base_delay (equal 0.1 to 2) (equal 0.1 to 3))"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
test_pass

View File

@@ -4,7 +4,7 @@
test_start "reply to client configured as server" test_start "reply to client configured as server"
server_conf="server 192.168.123.2 noselect server_conf="server 192.168.123.2
acquisitionport 123" acquisitionport 123"
client_conf="acquisitionport 123" client_conf="acquisitionport 123"

View File

@@ -3,8 +3,6 @@
. test.common . test.common
test_start "presend option" test_start "presend option"
min_sync_time=140
max_sync_time=260
client_server_options="presend 6" client_server_options="presend 6"
run_test || test_fail run_test || test_fail

View File

@@ -1,24 +0,0 @@
#!/bin/bash
. test.common
test_start "minsources directive"
client_conf="minsources 3"
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
# These check are expected to fail
check_source_selection && test_fail
check_sync && test_fail
servers=3
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
check_source_selection || test_fail
check_sync || test_fail
test_pass

View File

@@ -18,7 +18,7 @@ export PATH=../../:$PATH
export CLKNETSIM_PATH=clknetsim export CLKNETSIM_PATH=clknetsim
# Known working clknetsim revision # Known working clknetsim revision
clknetsim_revision=565e593b4403d035b459b4f8516dacaeaeeb7739 clknetsim_revision=7ea71b32e0caec4d8da4cecc3499b5c87098e137
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
# Only Linux is supported # Only Linux is supported
@@ -57,7 +57,6 @@ default_server_strata=1
default_servers=1 default_servers=1
default_clients=1 default_clients=1
default_peers=0 default_peers=0
default_falsetickers=0
default_server_start=0.0 default_server_start=0.0
default_client_start=0.0 default_client_start=0.0
default_chronyc_start=1000.0 default_chronyc_start=1000.0
@@ -398,7 +397,7 @@ run_test() {
step=$server_step step=$server_step
start=$server_start start=$server_start
freq="" freq=""
[ $i -le $falsetickers ] && offset=$i.0 || offset=0.0 offset=0.0
elif [ $stratum -le $server_strata ]; then elif [ $stratum -le $server_strata ]; then
step=$server_step step=$server_step
start=$server_start start=$server_start

77
util.c
View File

@@ -238,18 +238,18 @@ char *
UTI_RefidToString(uint32_t ref_id) UTI_RefidToString(uint32_t ref_id)
{ {
unsigned int i, j, c; unsigned int i, j, c;
char *result; char buf[5], *result;
result = NEXT_BUFFER; for (i = j = 0; i < 4; i++) {
for (i = j = 0; i < 4 && i < BUFFER_LENGTH - 1; i++) {
c = (ref_id >> (24 - i * 8)) & 0xff; c = (ref_id >> (24 - i * 8)) & 0xff;
if (isprint(c)) if (isprint(c))
result[j++] = c; buf[j++] = c;
} }
result[j] = '\0'; buf[j] = '\0';
result = NEXT_BUFFER;
snprintf(result, BUFFER_LENGTH, "%s", buf);
return result; return result;
} }
@@ -277,7 +277,7 @@ UTI_IPToString(IPAddr *addr)
break; break;
case IPADDR_INET6: case IPADDR_INET6:
ip6 = addr->addr.in6; ip6 = addr->addr.in6;
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH); inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH);
#else #else
snprintf(result, BUFFER_LENGTH, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", snprintf(result, BUFFER_LENGTH, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
@@ -296,7 +296,7 @@ UTI_IPToString(IPAddr *addr)
int int
UTI_StringToIP(const char *addr, IPAddr *ip) UTI_StringToIP(const char *addr, IPAddr *ip)
{ {
#ifdef FEAT_IPV6 #ifdef HAVE_IPV6
struct in_addr in4; struct in_addr in4;
struct in6_addr in6; struct in6_addr in6;
@@ -426,65 +426,6 @@ UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask)
/* ================================================== */ /* ================================================== */
void
UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port)
{
switch (sa->sa_family) {
case AF_INET:
ip->family = IPADDR_INET4;
ip->addr.in4 = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
*port = ntohs(((struct sockaddr_in *)sa)->sin_port);
break;
#ifdef FEAT_IPV6
case AF_INET6:
ip->family = IPADDR_INET6;
memcpy(ip->addr.in6, ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr,
sizeof (ip->addr.in6));
*port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
break;
#endif
default:
ip->family = IPADDR_UNSPEC;
*port = 0;
}
}
/* ================================================== */
int
UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa)
{
switch (ip->family) {
case IPADDR_INET4:
memset(sa, 0, sizeof (struct sockaddr_in));
sa->sa_family = AF_INET;
((struct sockaddr_in *)sa)->sin_addr.s_addr = htonl(ip->addr.in4);
((struct sockaddr_in *)sa)->sin_port = htons(port);
#ifdef SIN6_LEN
((struct sockaddr_in *)sa)->sin_len = sizeof (struct sockaddr_in);
#endif
return sizeof (struct sockaddr_in);
#ifdef FEAT_IPV6
case IPADDR_INET6:
memset(sa, 0, sizeof (struct sockaddr_in6));
sa->sa_family = AF_INET6;
memcpy(((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr, ip->addr.in6,
sizeof (ip->addr.in6));
((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
#ifdef SIN6_LEN
((struct sockaddr_in6 *)sa)->sin6_len = sizeof (struct sockaddr_in6);
#endif
return sizeof (struct sockaddr_in6);
#endif
default:
memset(sa, 0, sizeof (struct sockaddr));
sa->sa_family = AF_UNSPEC;
return 0;
}
}
/* ================================================== */
char * char *
UTI_TimeToLogForm(time_t t) UTI_TimeToLogForm(time_t t)
{ {
@@ -549,7 +490,7 @@ UTI_DoubleToInt32(double x)
/* ================================================== */ /* ================================================== */
/* Seconds part of NTP timestamp correponding to the origin of the /* Seconds part of RFC1305 timestamp correponding to the origin of the
struct timeval format. */ struct timeval format. */
#define JAN_1970 0x83aa7e80UL #define JAN_1970 0x83aa7e80UL

3
util.h
View File

@@ -86,9 +86,6 @@ extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest); extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask); extern int UTI_CompareIPs(IPAddr *a, IPAddr *b, IPAddr *mask);
extern void UTI_SockaddrToIPAndPort(struct sockaddr *sa, IPAddr *ip, unsigned short *port);
extern int UTI_IPAndPortToSockaddr(IPAddr *ip, unsigned short port, struct sockaddr *sa);
extern char *UTI_TimeToLogForm(time_t t); extern char *UTI_TimeToLogForm(time_t t);
/* Adjust time following a frequency/offset change */ /* Adjust time following a frequency/offset change */

View File

@@ -22,33 +22,18 @@
======================================================================= =======================================================================
This is a wrapper around the Linux adjtimex system call. This is a wrapper around the Linux adjtimex system call. It isolates the
inclusion of <linux/adjtimex.h> from the need to include other header files,
many of which conflict with those in <linux/...> on some recent distributions
(as of Jul 2000) using kernels around 2.2.16 onwards.
*/ */
#include "config.h" #include "config.h"
#include "chrony_timex.h"
#include "wrap_adjtimex.h" #include "wrap_adjtimex.h"
#include <sys/timex.h>
/* Definitions used if missing in the system headers */
#ifndef ADJ_TAI
#define ADJ_TAI 0x0080 /* set TAI offset */
#endif
#ifndef ADJ_SETOFFSET
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
#endif
#ifndef ADJ_NANO
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#endif
#ifndef ADJ_OFFSET_SS_READ
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
#endif
/* Frequency offset scale (shift) */
#define SHIFT_USEC 16
static int status = 0; static int status = 0;
int int
@@ -83,11 +68,19 @@ TMX_SetFrequency(double *freq, long tick)
{ {
struct timex txc; struct timex txc;
txc.modes = ADJ_TICK | ADJ_FREQUENCY; txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS;
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC)); txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC); *freq = txc.freq / (double)(1 << SHIFT_USEC);
txc.tick = tick; txc.tick = tick;
txc.status = status;
if (!(status & STA_UNSYNC)) {
/* maxerror has to be reset periodically to prevent kernel
from enabling UNSYNC flag */
txc.modes |= ADJ_MAXERROR;
txc.maxerror = 0;
}
return adjtimex(&txc); return adjtimex(&txc);
} }
@@ -104,6 +97,51 @@ TMX_GetFrequency(double *freq, long *tick)
return result; return result;
} }
int
TMX_ReadCurrentParams(struct tmx_params *params)
{
struct timex txc;
int result;
txc.modes = 0; /* pure read */
result = adjtimex(&txc);
params->tick = txc.tick;
params->offset = txc.offset;
params->freq = txc.freq;
params->dfreq = txc.freq / (double)(1 << SHIFT_USEC);
params->maxerror = txc.maxerror;
params->esterror = txc.esterror;
params->sta_pll = !!(txc.status & STA_PLL);
params->sta_ppsfreq = !!(txc.status & STA_PPSFREQ);
params->sta_ppstime = !!(txc.status & STA_PPSTIME);
params->sta_fll = !!(txc.status & STA_FLL);
params->sta_ins = !!(txc.status & STA_INS);
params->sta_del = !!(txc.status & STA_DEL);
params->sta_unsync = !!(txc.status & STA_UNSYNC);
params->sta_freqhold = !!(txc.status & STA_FREQHOLD);
params->sta_ppssignal = !!(txc.status & STA_PPSSIGNAL);
params->sta_ppsjitter = !!(txc.status & STA_PPSJITTER);
params->sta_ppswander = !!(txc.status & STA_PPSWANDER);
params->sta_ppserror = !!(txc.status & STA_PPSERROR);
params->sta_clockerr = !!(txc.status & STA_CLOCKERR);
params->constant = txc.constant;
params->precision = txc.precision;
params->tolerance = txc.tolerance;
params->ppsfreq = txc.ppsfreq;
params->jitter = txc.jitter;
params->shift = txc.shift;
params->stabil = txc.stabil;
params->jitcnt = txc.jitcnt;
params->calcnt = txc.calcnt;
params->errcnt = txc.errcnt;
params->stbcnt = txc.stbcnt;
return result;
}
int int
TMX_SetLeap(int leap) TMX_SetLeap(int leap)
{ {
@@ -123,7 +161,7 @@ TMX_SetLeap(int leap)
return adjtimex(&txc); return adjtimex(&txc);
} }
int TMX_SetSync(int sync, double est_error, double max_error) int TMX_SetSync(int sync)
{ {
struct timex txc; struct timex txc;
@@ -133,10 +171,8 @@ int TMX_SetSync(int sync, double est_error, double max_error)
status |= STA_UNSYNC; status |= STA_UNSYNC;
} }
txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR; txc.modes = ADJ_STATUS;
txc.status = status; txc.status = status;
txc.esterror = est_error * 1.0e6;
txc.maxerror = max_error * 1.0e6;
return adjtimex(&txc); return adjtimex(&txc);
} }

View File

@@ -27,11 +27,49 @@
#ifndef GOT_WRAP_ADJTIMEX_H #ifndef GOT_WRAP_ADJTIMEX_H
#define GOT_WRAP_ADJTIMEX_H #define GOT_WRAP_ADJTIMEX_H
/* Cut-down version of struct timex */
struct tmx_params {
long tick;
long offset;
long freq;
double dfreq;
long maxerror;
long esterror;
unsigned sta_pll:1;
unsigned sta_ppsfreq:1;
unsigned sta_ppstime:1;
unsigned sta_fll:1;
unsigned sta_ins:1;
unsigned sta_del:1;
unsigned sta_unsync:1;
unsigned sta_freqhold:1;
unsigned sta_ppssignal:1;
unsigned sta_ppsjitter:1;
unsigned sta_ppswander:1;
unsigned sta_ppserror:1;
unsigned sta_clockerr:1;
int status;
long constant;
long precision;
long tolerance;
long ppsfreq;
long jitter;
int shift;
long stabil;
long jitcnt;
long calcnt;
long errcnt;
long stbcnt;
};
int TMX_ResetOffset(void); int TMX_ResetOffset(void);
int TMX_SetFrequency(double *freq, long tick); int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq, long *tick); int TMX_GetFrequency(double *freq, long *tick);
int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap); int TMX_SetLeap(int leap);
int TMX_SetSync(int sync, double est_error, double max_error); int TMX_SetSync(int sync);
int TMX_TestStepOffset(void); int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset); int TMX_ApplyStepOffset(double offset);