Compare commits

...

114 Commits

Author SHA1 Message Date
Miroslav Lichvar
7446da8c9b doc: update NEWS 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
00eecd3a1d examples: add chrony.conf.example1
This is a minimal example.
2015-01-27 15:03:57 +01:00
Miroslav Lichvar
46a178cf48 examples: update configuration examples 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
ddcc28f726 examples: rename chrony.conf.example to chrony.conf.example3
Order the examples by complexity.
2015-01-27 15:03:57 +01:00
Miroslav Lichvar
04f86aa2ff doc: update chrony.conf man page 2015-01-27 15:03:57 +01:00
Miroslav Lichvar
72f0f99ac3 doc: update chrony.texi 2015-01-27 14:52:32 +01:00
Miroslav Lichvar
c8fe0fe992 test: add compilation test
Check if chrony can be compiled in various combination of disabled
features. This should fail if there are missing functions in stubs.c.
2015-01-26 12:16:17 +01:00
Miroslav Lichvar
be5c3b0b90 clientlog: remove unused code 2015-01-26 11:38:02 +01:00
Miroslav Lichvar
5194101c8b cmdmon: bind to loopback interface by default 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
0ee27c6ef6 cmdmon: use system values for loopback addresses 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
46a0aab6b9 test: require latest clknetsim 2015-01-26 10:40:15 +01:00
Miroslav Lichvar
55fb7abc39 contrib: remove DNSchrony from distribution
With the new pool directive chronyd is now able to replace unreachable
NTP servers with newly resolved addresses automatically. Starting
without DNS wasn't a problem since 1.25.
2015-01-26 10:39:58 +01:00
Miroslav Lichvar
407e47b306 ntp: remove unnecessary check in read_from_socket() 2015-01-22 15:38:41 +01:00
Miroslav Lichvar
4e54770f18 create NTP and cmdmon sockets after root drop
This is now possible as we keep the cap_net_bind_service capability.
2015-01-22 15:38:39 +01:00
Miroslav Lichvar
f9a31f36a0 ntp: keep all length constants signed
This should make it harder to accidentally create an unsafe comparison
between signed and unsigned values.
2015-01-22 14:37:35 +01:00
Miroslav Lichvar
547272e66c ntp: use different value for invalid socket in ntp_core
This should make it easier to see invalid sockets leaking from ntp_core
to ntp_io.
2015-01-07 16:14:29 +01:00
Miroslav Lichvar
35e11ffe60 ntp: fix length check of NTPv4 extension fields
Don't allow extension fields shorter than 16 bytes.
2015-01-07 14:12:29 +01:00
Miroslav Lichvar
52e12e42e5 ntp: open server socket only when access is allowed
When changing access configuration, check if any address is allowed and
open/close the server socket as needed.
2015-01-06 16:35:12 +01:00
Miroslav Lichvar
5214d42c07 ntp: count references to NTP server sockets
Server sockets are now explicitly opened and closed for normal NTP
server, NTP broadcast and NTP peering. This will allow closing the
NTP port when not needed.
2015-01-06 16:33:49 +01:00
Miroslav Lichvar
40bbe2539b sys: keep cap_net_bind_service capability
This will be needed to allow opening of NTP server socket after root
privileges are dropped.
2015-01-06 15:28:22 +01:00
Miroslav Lichvar
6d1dda0fad ntp: rename NIO_Get*Socket functions 2015-01-05 14:17:21 +01:00
Miroslav Lichvar
7a90dab8ff doc: improve FAQ section on improving accuracy 2014-12-17 19:58:23 +01:00
Miroslav Lichvar
395c89cff2 doc: use example.net domain in examples 2014-12-17 16:51:48 +01:00
Miroslav Lichvar
aad242d54b doc: update description of tracking command
Negative root delay is never reported with the current code.
2014-12-17 16:21:19 +01:00
Miroslav Lichvar
220ef264fb doc: list server/peer options that can be set in chronyc 2014-12-15 18:21:56 +01:00
Miroslav Lichvar
f64dcc0ac2 doc: fix examples of add server and add peer commands 2014-12-15 18:21:56 +01:00
Miroslav Lichvar
e57abae138 cmdparse: add function to convert error status to string
This is used to avoid duplication of error printing in chronyd and
chronyc.
2014-12-15 18:21:51 +01:00
Miroslav Lichvar
fc73accfe5 sys: use system headers for adjtimex 2014-12-15 17:25:37 +01:00
Miroslav Lichvar
c4d57f0e3d sys: remove shift_hz
It's not used for anything since commit e147f2f1.
2014-12-10 15:58:27 +01:00
Miroslav Lichvar
eadabfe890 sys: remove TMX_ReadCurrentParams 2014-12-10 15:58:27 +01:00
Miroslav Lichvar
02cbe5e1ad sys: add sync status setting to generic and Linux driver
Set the adjtimex status, esterror and maxerror fields to the values
provided by the reference module.
2014-12-10 15:58:13 +01:00
Miroslav Lichvar
2645e632a8 sys: fix formatting in sys_linux.c 2014-12-10 15:35:56 +01:00
Miroslav Lichvar
e14a03a172 local: add new driver call to set synchronization status
This will be used to set the kernel adjtimex() variables to allow other
applications running on the system to know if the system clock is
synchronized and the estimated error and the maximum error.
2014-12-10 15:35:56 +01:00
Miroslav Lichvar
513e65900c client: add second form of makestep command
The second form configures the automatic stepping, similarly to the
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 burst command to quickly
make a new measurement and correct the clock by stepping if needed,
without waiting for chronyd to complete the measurement and update the
clock.
2014-12-09 12:31:56 +01:00
Miroslav Lichvar
4b81cda521 cmdmon: initialize new source params when adding source 2014-12-09 11:40:19 +01:00
Miroslav Lichvar
6688f40325 sources: allow setting minsamples and maxsamples for each source
The minsamples and maxsamples directives now set the default value,
which can be overriden for individual sources in the server/peer/pool
and refclock directives.
2014-12-03 16:27:51 +01:00
Miroslav Lichvar
42dd5caa1b ntp: don't replace source instance when changing address
Add new functions to change source's reference ID/address and reset the
instance. Use that instead of destroying and creating a new instance
when the NTP address is changed.
2014-12-01 18:40:47 +01:00
Miroslav Lichvar
308bcae257 ntp: limit number of pool sources
A new option can be now used in the pool directive: 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, 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 maxsources, the
other sources will be removed.
2014-11-26 17:56:36 +01:00
Miroslav Lichvar
f2c80cae44 ntp: update number of sources when removing all sources
Also, rehash the records after removal and split cleaning of the source
record to a separate function.
2014-11-26 17:56:29 +01:00
Miroslav Lichvar
aaf744dfab ntp: return status from NCR_ProcessKnown() 2014-11-24 16:14:04 +01:00
Miroslav Lichvar
7534ffee64 doc: update tempcomp description 2014-11-21 13:13:15 +01:00
Miroslav Lichvar
ed862c8d08 tempcomp: allow configuration with list of points
In addition to the quadratic function, allow configuration of the
compensation with a file containing list of (temperature, compensation)
points used for linear interpolation and extrapolation.
2014-11-21 13:11:16 +01:00
Miroslav Lichvar
1d977e021d test: fix 111-knownclient
The new NTPv4 loop synchronization check fails as clknetsim doesn't
support IP_PKTINFO yet. Use the noselect option to prevent the server to
synchronize to the client.
2014-11-21 11:44:15 +01:00
Miroslav Lichvar
dccd61966a ntp: fix accepting requests from configured sources
When using server socket to send client requests (acquisitionport 123)
and currently not waiting for a reply, the socket check will fail for
client requests from the source.

The check needs to be moved to correctly handle the requests as from an
unknown source.
2014-11-21 11:43:47 +01:00
Miroslav Lichvar
93aeecefeb tempcomp: fix double free on sensor filename
This is related to commit f6ed7844e1.
2014-11-04 11:28:29 +01:00
Miroslav Lichvar
df63790bb3 conf: change default stratumweight to 0.001 2014-11-03 15:13:52 +01:00
Miroslav Lichvar
c743ecbf50 ntp: support pools
The pool directive can be used to configure chronyd for a pool of NTP
servers (e.g. pool.ntp.org). The name is expected to resolve to multiple
addresses which change over time.

On start, a source will be added for each resolved address. When a
source from the pool is unreachable or marked as falseticker, chronyd
will try to replace the source with a newly resolved address of the
pool.

The minimum interval between replacements is currently set to 244
seconds to avoid frequent DNS requests.
2014-11-03 11:18:04 +01:00
Miroslav Lichvar
29c1df4610 ntp: allow changing address of core instance 2014-11-03 11:15:20 +01:00
Miroslav Lichvar
40f8591257 ntp: try adding other server addresses
When adding a server from configuration file, don't give up when the
first returned address was already added for another server directive,
but try adding other addresses until one succeeds.
2014-10-31 17:01:03 +01:00
Miroslav Lichvar
4d1a754ec6 nameserv: add support for returning multiple addresses 2014-10-23 16:48:13 +02:00
Miroslav Lichvar
699680807d nameserv: check that address returned from gethostbyname() is IPv4
Also, always return failure with -6.
2014-10-23 15:06:00 +02:00
Miroslav Lichvar
ccaf0874e1 ntp: take auto_offline sources offline before sending new request 2014-10-23 15:06:00 +02:00
Miroslav Lichvar
1afcb4f29a test: add 116-minsources 2014-10-20 18:05:20 +02:00
Miroslav Lichvar
1bb2732056 sources: add minsources option
This sets the minimum number of selectable sources needed to update the
local clock.
2014-10-20 18:04:37 +02:00
Miroslav Lichvar
6744ad392d docs: fix formatting of examples in server options 2014-10-20 16:17:38 +02:00
Miroslav Lichvar
1aecc51c70 ntp: add version option to server/peer directive 2014-10-20 16:14:17 +02:00
Miroslav Lichvar
c9571e55f5 conf: use array for broadcast destinations 2014-10-20 13:05:55 +02:00
Miroslav Lichvar
aba4596ba9 conf: use arrays for NTP and cmdmon restrictions 2014-10-20 12:54:16 +02:00
Miroslav Lichvar
bd3cfeae92 test: add 009-sourceselection 2014-10-20 12:26:49 +02:00
Miroslav Lichvar
9ef723eb97 test: add option to create falsetickers 2014-10-20 12:26:29 +02:00
Miroslav Lichvar
7958b1764e ntp: remove debug messages in slew handler 2014-10-20 12:22:17 +02:00
Miroslav Lichvar
44f612acbc sourcestats: reduce debug messages in slew handler 2014-10-20 12:22:16 +02:00
Miroslav Lichvar
5d7df69116 sources: reset reachability for offline sources
With the recent change allowing unreachable sources to remain selected,
offline sources will now be selectable only for some time, similarly to
online unreachable sources.
2014-10-20 12:19:36 +02:00
Miroslav Lichvar
8f06245428 sources: allow selection of unreachable sources
Reachability is no longer a requirement for selection. An unreachable
source can remain selected if its newest sample is not older than the
oldest sample from all reachable sources.

This is useful to prevent reselection when an accurate source uses a
very short polling interval (e.g. refclock) and is occasionally
unreachable for short periods of time.
2014-10-20 12:19:36 +02:00
Miroslav Lichvar
0f8368bcf1 sources: extend source status tracking
Add new source states and rename some states so there is one state for
each reason a source can be rejected in the source selection.

This fixes reported status when sources are selectable, but the actual
selection was postponed until next update. It will also allow more
detailed reports when the cmdmon protocol is updated.
2014-10-20 11:23:48 +02:00
Miroslav Lichvar
5d0356a75e sources: fix reported normal select option 2014-10-20 11:19:45 +02:00
Miroslav Lichvar
5f68941241 sources: select only when reference can be updated
Before selecting the new synchronization source wait until the reference
can be updated, i.e. the source has new samples.
2014-10-20 11:19:28 +02:00
Miroslav Lichvar
63af4889f6 sources: drop selectable flag
This is no longer needed with new NTP packet processing as the sources
are always selectable after first sample is accumulated.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
6f84d2fac1 sources: reorder SRC_SelectSource()
Reorder the code to improve readability and also update coding style.
No functional changes.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
049eae661a sources: keep synchronized status with unreachable/unselectable sources
Following RFC 5905, don't call REF_SetUnsynchronised() when there are no
reachable or selectable sources. It's up to the client to consider the
source unsynchronized when the root distance exceeds a threshold.

The unsynchronized status is still set when no majority is reached.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
e930d94728 sources: update reference only with new sample
This follows the section 11.2.3. from RFC 5905.
2014-10-20 11:02:07 +02:00
Miroslav Lichvar
819b8eb73d ntp: fix Clang warning 2014-10-15 12:40:12 +02:00
Miroslav Lichvar
a78bf0c34e ntp: merge broadcast code with ntp_core 2014-10-15 12:27:46 +02:00
Miroslav Lichvar
e0059bcc6b ntp: define NTP_MAX_STRATUM for other modules 2014-10-14 17:25:55 +02:00
Miroslav Lichvar
af0b83a2c3 doc: update for NTPv4 support 2014-10-14 16:57:01 +02:00
Miroslav Lichvar
2c033989b6 Update comments referencing RFC 1305 2014-10-14 16:52:22 +02:00
Miroslav Lichvar
8fbfe55e92 ntp: update packet processing to NTPv4 (RFC 5905) 2014-10-14 16:52:22 +02:00
Miroslav Lichvar
740e8130dd ntp: clamp value set by minstratum option 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
5bddaf6820 sources: use correct specifier for refid in debug message 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
c36230e21b ntp: print number of bytes sent in debug message 2014-10-13 15:10:15 +02:00
Miroslav Lichvar
15d8c08eaa ntp: enable PKTINFO on client sockets
This will be useful to detect synchronization loops.
2014-10-08 15:13:02 +02:00
Miroslav Lichvar
2f738d5805 util: fix sockaddr function naming 2014-10-03 10:15:18 +02:00
Miroslav Lichvar
e05b687009 client: improve sources caption 2014-09-29 11:29:51 +02:00
Miroslav Lichvar
55a22656b8 util: use common functions to convert to/from sockaddr 2014-09-26 17:54:45 +02:00
Miroslav Lichvar
2db20adc3e client: print full date in manual list 2014-09-26 15:47:57 +02:00
Miroslav Lichvar
c7eeb57a32 ntp: fix NSR_TakeSourcesOffline()
This was broken when switching to dynamic allocation in commit 9e7193.
2014-09-26 15:27:08 +02:00
Miroslav Lichvar
361726b3ae keys: store IDs in uint32_t 2014-09-26 14:14:54 +02:00
Miroslav Lichvar
c404786b92 logging: remove warning on missing debug messages
The state of the DEBUG feature is now printed with chronyd version.
2014-09-25 11:12:23 +02:00
Miroslav Lichvar
2ff4eca7bf cmdmon: fix initialization of allocated reply slots
The next pointer in the last allocated reply slot was not set. This
could cause a crash when more slots were needed. (the slots are used to
save unacknowledged replies to authenticated commands)
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
1eca83ff22 cmdmon: allocate reply slots in smaller quantums 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
2575fa8f83 cmdmon: use char for permissions table 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
b7e86192ee refclock: include refid in some debug messages 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
078f0f511e util: optimize UTI_RefidToString() 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
4963b931d0 rtc: allocate samples dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
75fd327222 conf: allocate sources dynamically
This removes the limits on maximum number of sources specified by the
initstepslew, server and refclock directives in the config file.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
9e71932c2e ntp: allocate source records dynamically
This removes the limit on maximum number of added NTP sources.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
d92583ed33 refclocks: allocate refclock instances dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
cd27860e55 keys: allocate keys dynamically
This removes the limit on maximum number of keys in the key file.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
ba875fc04a sched: allocate file handlers dynamically 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
b5a85bd2fe sources: reallocate arrays in exponentially increasing sizes 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
4e0df8c2a6 ntp: improve hashing of sources
Use 32-bit hash and switch to quadratic probing. This will be useful to
allow resizing of the hash table and not limit the number of sources.
2014-09-25 10:58:57 +02:00
Miroslav Lichvar
37bc30c8d9 Add array utility functions 2014-09-25 10:58:57 +02:00
Miroslav Lichvar
f6ed7844e1 Free allocated memory on exit
This should reduce the number of possible memory leaks reported by
valgrind. The remaining reported leaks are sched tqe allocation, async
DNS instance allocation, cmdmon response/timestamp cell allocation, and
clientlog subnet allocation.
2014-09-25 10:57:55 +02:00
Miroslav Lichvar
d466390233 cmdparse: don't duplicate hostname in CPS_ParseNTPSourceAdd()
Let the caller duplicate the string if needed.
2014-09-24 12:43:11 +02:00
Miroslav Lichvar
336473398a Check for memory allocation errors 2014-09-23 15:47:02 +02:00
Miroslav Lichvar
bb16c81e7b test: make 114-presend more tolerant 2014-09-23 15:46:27 +02:00
Miroslav Lichvar
f955b46c13 nameserv: move fallback DNS_Name2IPAddressAsync() to stubs.c 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
b54711252b configure: add --disable-sechash option 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
f2710d5b55 Print enabled/disabled features with version 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
285fae856d configure: unify macro naming for optional features 2014-09-22 13:14:16 +02:00
Miroslav Lichvar
111b63bb16 configure: allow building without cmdmon, NTP, refclock support 2014-09-22 13:14:11 +02:00
Miroslav Lichvar
767a8b19a9 configure: unify macro naming for available headers 2014-09-19 11:06:37 +02:00
Miroslav Lichvar
cb28d6cdb7 configure: don't remove config files with --help 2014-09-19 10:13:42 +02:00
Miroslav Lichvar
a0d5abef88 sourcestats: remove tracking of skew change
This is not used since commit 7a6ee1d.
2014-09-19 10:07:03 +02:00
92 changed files with 4017 additions and 3891 deletions

View File

@@ -38,14 +38,9 @@ DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o nameserv_async.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_phc.o refclock_pps.o \
refclock_shm.o refclock_sock.o tempcomp.o $(HASH_OBJ)
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o mkdirpp.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
sys.o tempcomp.o util.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@

31
NEWS
View File

@@ -1,3 +1,34 @@
New in version 2.0
==================
Enhancements
------------
* Update to NTP version 4 (RFC 5905)
* 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
---------
* Fix accepting requests from configured sources when acquisitionport
is equal to server port
* Fix allocation of slots saving replies to authenticated commands
New in version 1.31
===================

3
README
View File

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

View File

@@ -363,6 +363,44 @@ ADF_IsAllowed(ADF_AuthTable table,
/* ================================================== */
static int
is_any_allowed(TableNode *node, State parent)
{
State state;
int i;
state = node->state != AS_PARENT ? node->state : parent;
assert(state != AS_PARENT);
if (node->extended) {
for (i = 0; i < TABLE_SIZE; i++) {
if (is_any_allowed(&node->extended[i], state))
return 1;
}
} else if (state == ALLOW) {
return 1;
}
return 0;
}
/* ================================================== */
int
ADF_IsAnyAllowed(ADF_AuthTable table, int family)
{
switch (family) {
case IPADDR_INET4:
return is_any_allowed(&table->base4, AS_PARENT);
case IPADDR_INET6:
return is_any_allowed(&table->base6, AS_PARENT);
default:
return 0;
}
}
/* ================================================== */
#if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)

View File

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

121
array.c Normal file
View File

@@ -0,0 +1,121 @@
/*
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 Normal file
View File

@@ -0,0 +1,56 @@
/*
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

View File

@@ -1,159 +0,0 @@
/*
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;
}

13
candm.h
View File

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

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.
\fIchronyd\fR is a background (daemon) program and \fIchronyc\fR is a
command-line interface to it. Time reference sources for chronyd can be
RFC1305 NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
NTP servers, human (via keyboard and \fIchronyc\fR), or the computer's
real-time clock at boot time (Linux only). chronyd can determine the rate at
which the computer gains or loses time and compensate for it while no external
reference is present. Its use of NTP servers can be switched on and off
(through \fIchronyc\fR) to support computers with dial-up/intermittent access
to the Internet, and it can also act as an RFC1305-compatible NTP server.
to the Internet, and it can also act as an NTP server.
.SH USAGE
\fIchronyc\fR is a command-line interface program which can be used to
@@ -51,7 +51,8 @@ session to the next)
With a good reference clock the accuracy can reach one microsecond.
\fIchronyd\fR can also operate as an RFC1305-compatible NTP server and peer.
\fIchronyd\fR can also operate as an NTPv4 (RFC 5905) server, peer and
broadcast server.
.SH "SEE ALSO"
.BR chronyc(1),

View File

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

View File

@@ -94,10 +94,9 @@ Data Security, Inc. MD5 Message-Digest Algorithm} for authenticating
messages between different machines on the network.
In writing the @code{chronyd} program, extensive use has been made of
RFC1305, written by David Mills. The @code{ntp} suite's source code has
been occasionally used to check details of the protocol that the RFC did
not make absolutely clear. The core algorithms in @code{chronyd} are
all completely distinct from @code{ntp}, however.
RFC 1305 and RFC 5905, written by David Mills. The source code of
the NTP reference implementation has been used to check details of the
protocol.
@c }}}
@c {{{ S:Availability
@node Availability
@@ -211,11 +210,10 @@ Things @code{ntpd} can do that @code{chronyd} can't:
@itemize @bullet
@item
@code{ntpd} fully supports NTP version 4 (RFC5905), including broadcast,
multicast, manycast clients / servers and the orphan mode. It also
supports extra authentication schemes based on public-key cryptography
(RFC5906). @code{chronyd} uses NTP version 3 (RFC1305), which is
compatible with version 4.
@code{ntpd} supports all operating modes from RFC 5905, including
broadcast, multicast and manycast client / server. It supports the
orphan mode and it also supports authentication based on public-key
cryptography described in RFC 5906.
@item
@code{ntpd} has been ported to more types of computer / operating
@@ -432,15 +430,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
set up a configuration file. The default location of the file
is @file{@SYSCONFDIR@/chrony.conf}. Suppose you want to use public NTP
servers from the pool.ntp.org project as your time reference. A
is @file{@SYSCONFDIR@/chrony.conf}. Several examples of configuration with
comments are included in the examples directory. Suppose you want to use
public NTP servers from the pool.ntp.org project as your time reference. A
minimal useful configuration file could be
@example
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
pool pool.ntp.org iburst
makestep 10 3
rtcsync
@end example
Then, @code{chronyd} can be run.
@@ -575,28 +573,42 @@ use their facilities.
Assuming that you have found some servers, you need to set up a
configuration file to run chrony. The (compiled-in) default location
for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your ntp
servers are called @code{a.b.c} and @code{d.e.f}, your
@file{chrony.conf} file could contain as a minimum
for this file is @file{@SYSCONFDIR@/chrony.conf}. Assuming that your NTP
servers are called @code{foo.example.net}, @code{bar.example.net} and
@code{baz.example.net}, your @file{chrony.conf} file could contain as a minimum
@example
server a.b.c
server d.e.f
server g.h.i
server foo.example.net
server bar.example.net
server baz.example.net
@end example
However, you will probably want to include some of the other directives
described later. The @code{driftfile} and @code{makestep} directives may be
particularly useful. Also, the @code{iburst} server option is useful to speed
up the initial synchronization. The smallest useful configuration file would
look something like
described later. The following directives may be particularly useful :
@code{driftfile}, @code{makestep}, @code{rtcsync}. Also, the @code{iburst}
server option is useful to speed up the initial synchronization. The smallest
useful configuration file would look something like
@example
server a.b.c iburst
server d.e.f iburst
server g.h.i iburst
server foo.example.net iburst
server bar.example.net iburst
server baz.example.net iburst
driftfile @CHRONYVARDIR@/drift
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
@c }}}
@c {{{ S:Infrequent connection
@@ -620,14 +632,14 @@ In this case, you will need some additional configuration to tell
This saves the program from continuously trying to poll the servers when
they are inaccessible.
Again, assuming that your ntp servers are called @code{a.b.c} and
@code{d.e.f}, your @file{chrony.conf} file would need to contain
something like
Again, assuming that your NTP servers are called @code{foo.example.net},
@code{bar.example.net} and @code{baz.example.net}, your @file{chrony.conf} file
would need to contain something like
@example
server a.b.c
server d.e.f
server g.h.i
server foo.example.net
server bar.example.net
server baz.example.net
@end example
However, your computer will keep trying to contact the servers to obtain
@@ -639,9 +651,9 @@ For this reason, it would be better to specify this part of your
configuration file in the following way:
@example
server a.b.c offline
server d.e.f offline
server g.h.i offline
server foo.example.net offline
server bar.example.net offline
server baz.example.net offline
@end example
The @code{offline} keyword indicates that the servers start
@@ -658,9 +670,9 @@ automatically on the first @code{chronyd} start.
The smallest useful configuration file would look something like
@example
server a.b.c offline
server d.e.f offline
server g.h.i offline
server foo.example.net offline
server bar.example.net offline
server baz.example.net offline
keyfile @SYSCONFDIR@/chrony.keys
generatecommandkey
driftfile @CHRONYVARDIR@/drift
@@ -873,9 +885,9 @@ For the @file{@SYSCONFDIR@/chrony.conf} file, the following can be used as an
example.
@example
server 0.pool.ntp.org maxdelay 0.4 offline
server 1.pool.ntp.org maxdelay 0.4 offline
server 2.pool.ntp.org maxdelay 0.4 offline
server foo.example.net maxdelay 0.4 offline
server bar.example.net maxdelay 0.4 offline
server baz.example.net maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
@@ -1162,9 +1174,11 @@ the configuration file is ignored.
* maxslewrate directive:: Set maximum slew rate
* maxupdateskew directive:: Stop bad estimates upsetting machine clock
* 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
* peer directive:: Specify an NTP peer
* pidfile directive:: Specify the file where chronyd's pid is written
* pool directive:: Specify an NTP pool
* port directive:: Set NTP server port
* refclock directive:: Specify a reference clock
* reselectdist directive:: Set improvement in distance needed to reselect a source
@@ -1231,7 +1245,7 @@ to other clients.
Examples of use of the command are as follows:
@example
allow foo.bar.com
allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -1316,47 +1330,32 @@ bindaddress 192.168.1.1
to the configuration file.
This directive affects NTP (UDP port 123 by default) packets. If no
@code{bindcmdaddress} directive is present, the address supplied by
@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.
For each of IPv4 and IPv6 protocols, only one @code{bindaddress} directive can
be specified. Therefore, it's not useful on computers which should serve NTP
on multiple network interfaces.
@c }}}
@c {{{ bindcmdaddress
@node bindcmdaddress directive
@subsection bindcmdaddress
The @code{bindcmdaddress} directive allows you to restrict the network
The @code{bindcmdaddress} directive allows you to specify the network
interface to which @code{chronyd} will listen for command packets (issued by
@code{chronyc}). This provides an additional level of access restriction above
that available through @code{cmddeny} mechanism.
Suppose you want to block all access except from localhost. You
could add the lines
By default, @code{chronyd} binds to the loopback interface (with addresses
@code{127.0.0.1} and @code{::1}). This blocks all access except from
localhost. To listen for command packets on all interfaces, you can add the
lines
@example
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
bindcmdaddress 0.0.0.0
bindcmdaddress ::
@end example
to the configuration file.
For each of IPv4 and IPv6 protocols, only one @code{bindcmdaddress}
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 {{{ broadcast directive
@node broadcast directive
@@ -1424,6 +1423,10 @@ The syntax is identical to the @code{allow} directive.
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
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 {{{ cmddeny
@node cmddeny directive
@@ -1722,7 +1725,7 @@ used instead. This makes it easier to restart @code{chronyd} whilst the
system is in normal operation.
The @code{initstepslew} directive takes a threshold and a list of NTP
servers as arguments. A maximum of 8 will be used. Each of the servers
servers as arguments. Each of the servers
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
step (or slew) is applied to the system clock to correct this error.
@@ -1731,7 +1734,7 @@ step (or slew) is applied to the system clock to correct this error.
An example of use of the command is
@example
initstepslew 30 foo.bar.com baz.quz.com
initstepslew 30 foo.example.net bar.example.net
@end example
where 2 NTP servers are used to make the measurement. The @code{30}
@@ -1935,7 +1938,7 @@ An example line (which actually appears as a single line in the file)
from the measurements log file is shown below.
@example
2010-12-22 05:40:50 158.152.1.76 N 8 1111 111 1111 10 10 1.0 \
2014-10-13 05:40:50 158.152.1.76 N 2 111 111 1111 10 10 1.0 \
-4.966e-03 2.296e-01 1.577e-05 1.615e-01 7.446e-03
@end example
@@ -1944,7 +1947,7 @@ values from the example line above) :
@enumerate 1
@item
Date [2010-12-22]
Date [2014-10-13]
@item
Hour:Minute:Second [05:40:50]. Note that the date/time pair is
expressed in UTC, not the local time zone.
@@ -1958,12 +1961,13 @@ currently synchronised.) [N]
@item
Stratum of remote computer. [2]
@item
RFC1305 tests 1 through 4 (1=pass, 0=fail) [1111]
RFC 5905 tests 1 through 3 (1=pass, 0=fail) [111]
@item
RFC 5905 tests 5 through 7 (1=pass, 0=fail) [111]
@item
Tests for maximum delay, maximum delay ratio and maximum delay dev ratio,
against defined parameters (1=pass, 0=fail) [111]
@item
RFC1305 tests 5 through 8 (1=pass, 0=fail) [1111]
against defined parameters, and a test for synchronisation loop
(1=pass, 0=fail) [1111]
@item
Local poll [10]
@item
@@ -1973,15 +1977,16 @@ Remote poll [10]
to increase or decrease the polling level. This is adjusted based on number
of measurements currently being used for the regression algorithm). [1.0]
@item
The estimated local clock error (`theta' in RFC1305). Positive indicates that the local clock is slow. [-4.966e-03].
The estimated local clock error (`theta' in RFC 5905). Positive
indicates that the local clock is slow of the remote source. [-4.966e-03].
@item
The peer delay (`delta' in RFC1305). [2.296e-01]
The peer delay (`delta' in RFC 5905). [2.296e-01]
@item
The peer dispersion (`epsilon' in RFC1305). [1.577e-05]
The peer dispersion (`epsilon' in RFC 5905). [1.577e-05]
@item
The root delay (`Delta' in RFC1305). [1.615e-01]
The root delay (`DELTA' in RFC 5905). [1.615e-01]
@item
The root dispersion (`E' in RFC1305). [7.446e-03]
The root dispersion (`EPSILON' in RFC 5905). [7.446e-03]
@end enumerate
A banner is periodically written to the log file to indicate the
@@ -2373,9 +2378,11 @@ crystal oscillator.
@c {{{ maxsamples
@node maxsamples directive
@subsection maxsamples
The @code{maxsamples} directive sets the maximum number of samples
@code{chronyd} should keep for each source. The default is 0, which
disables the configurable limit, and the useful range is 4 to 64.
The @code{maxsamples} directive sets the default maximum number of samples
@code{chronyd} should keep for each source. This setting can be overriden for
individual sources in the @code{server} and @code{refclock} directives
(@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
@@ -2437,9 +2444,11 @@ the new master estimate.
@c {{{ minsamples
@node minsamples directive
@subsection minsamples
The @code{minsamples} directive sets the minimum number of samples
@code{chronyd} should try to keep for each source. The default is 0 and the
useful range is 4 to 64.
The @code{minsamples} directive sets the default minimum number of samples
@code{chronyd} should keep for each source. This setting can be overriden for
individual sources in the @code{server} and @code{refclock} directives
(@pxref{server directive}, @pxref{refclock directive}). The default value is
0. The useful range is 4 to 64.
The syntax is
@@ -2447,6 +2456,23 @@ The syntax is
minsamples <samples>
@end example
@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
@node noclientlog directive
@subsection noclientlog
@@ -2470,14 +2496,42 @@ chronyd always writes its process ID (pid) to a file, and checks this file on st
pidfile /var/tmp/chronyd.pid
@end example
@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
@node port directive
@subsection port
This option allows you to configure the port on which @code{chronyd}
will listen for NTP requests.
will listen for NTP requests. The port will be open only when an address is
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,
@code{chronyd} will not open the server socket and will operate strictly in a
@code{chronyd} will never open the server port and will operate strictly in a
client-only mode. The source port used in NTP client requests can be set by
the @code{acquisitionport} directive.
@@ -2624,6 +2678,12 @@ Prefer this source over sources without prefer option.
@item noselect
Never select this source. This is useful for monitoring or with sources
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
@c }}}
@@ -2787,11 +2847,11 @@ required (the default is 123, the standard NTP port).
Although @code{chronyd} will trim the rate at which it samples 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
<tt/minpoll 5/ would mean that the polling interval cannot drop below 32
@code{minpoll 5} would mean that the polling interval cannot drop below 32
seconds. The default is 6 (64 seconds).
@item maxpoll
In a similar way, the user may wish to constrain the maximum polling
interval. Again this is specified as a power of 2, so <tt/maxpoll 9/
interval. Again this is specified as a power of 2, @code{maxpoll 9}
indicates that the polling interval must stay at or below 512 seconds.
The default is 10 (1024 seconds).
@item maxdelay
@@ -2811,7 +2871,7 @@ some sort).
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
maxdelay command. For example, <tt/maxdelay 0.3/ would indicate that
maxdelay command. For example, @code{maxdelay 0.3} would indicate that
measurements with a round-trip delay of 0.3 seconds or more should be
ignored.
@@ -2900,12 +2960,25 @@ Target number of measurements to use for the regression algorithm which
@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.
@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
Prefer this source over sources without prefer option.
@item noselect
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
@c }}}
@c {{{ stratumweight
@@ -2922,30 +2995,31 @@ The syntax is
stratumweight <dist-in-seconds>
@end example
By default, it is 1 second. This usually means that sources with lower stratum
will be preferred to sources with higher stratum even when their distance is
significantly worse. Setting @code{stratumweight} to 0 makes @code{chronyd}
ignore stratum when selecting the source.
By default, the weight is 0.001 seconds. This means that stratum of the
sources in the selection process matters only when the differences between the
distances are in milliseconds.
@c }}}
@c {{{ tempcomp
@node tempcomp directive
@subsection tempcomp
Normally, changes in rate of drift of the system clock are caused mainly by
changes in temperature of the crystal oscillator on the mainboard.
Normally, changes in the rate of drift of the system clock are caused mainly by
changes in the temperature of the crystal oscillator on the mainboard.
If there are available temperature measurements from a sensor close to the
oscillator, @code{tempcomp} directive can be used to compensate for the changes
in rate and possibly improve clock accuracy.
If there are temperature measurements available from a sensor close to the
oscillator, the @code{tempcomp} directive can be used to compensate for the
changes in the temperature and improve the stability and accuracy of the clock.
Whether it will really help depends on many factors, including resolution of
the sensor, noise in measurements, time source polling interval, compensation
update interval, how good are the temperature coefficients, and how close is
the sensor to the oscillator. The frequency reported in tracking.log should
be more stable and the offsets should be smaller.
The result depends on many factors, including the resolution of the sensor,
the amount of noise in the measurements, the polling interval of the time
source, the compensation update interval, how well is the compensation
specified, and how close is the sensor to the oscillator. When it's working
well, the frequency reported in the @file{tracking.log} file is more stable and
the maximum reached offset is smaller.
The directive has six parameters: path to the file which contains current
temperature in text format, update interval (in seconds), and temperature
There are two forms of the directive. The first one has six parameters: a
path to the file containing the current temperature from the sensor (in
text format), the compensation update interval (in seconds), and temperature
coefficients T0, k0, k1, k2.
The frequency compensation is calculated (in ppm) as
@@ -2953,23 +3027,48 @@ The frequency compensation is calculated (in ppm) as
@code{k0 + (T - T0) * k1 + (T - T0)^2 * k2}
The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
considered to be faulty and will be ignored. The k0 coefficient can be used to
get the results in that range.
Valid measurements and calculated corrections are logged to tempcomp.log file if
enabled with @code{log tempcomp} directive.
considered invalid and will be ignored. The k0 coefficient can be used to get
the results in that range.
An example of use is
@example
tempcomp /sys/class/hwmon/hwmon1/device/temp2_input 30 26000 0.0 0.000183 0.0
tempcomp /sys/class/hwmon/hwmon0/temp2_input 30 26000 0.0 0.000183 0.0
@end example
The measured temperature will be read from the file in Linux sysfs filesystem
every 30 seconds. When the temperature is 26 degress (26000), the system clock
frequency will not be adjusted. When it is 27 degrees (27000), the clock will
be set to run 0.183ppm faster than it would be without the compensation, etc.
The measured temperature will be read from the file in the Linux sysfs
filesystem every 30 seconds. When the temperature is 26000 (26 degrees
Celsius), the frequency correction will be zero. When it is 27000 (27 degrees
Celsius), the clock will be set to run 0.183ppm faster, 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 {{{ user
@node user directive
@@ -3137,7 +3236,7 @@ interface.
* exit command:: Exit from chronyc
* help command:: Generate help summary
* local command:: Let computer be a server when it is unsynchronised
* makestep command:: Immediately correct the system clock instead of slewing
* makestep command:: Correct the system clock by stepping instead of slewing
* manual command:: Enable/disable/configure options for settime
* maxdelay command:: Set max measurement delay for a source
* maxdelaydevratio command:: Set max measurement delay for a source as ratio to deviation
@@ -3175,7 +3274,7 @@ Examples of use, showing a named host and a numeric IP address, are as
follows:
@example
accheck a.b.c
accheck foo.example.net
accheck 1.2.3.4
accheck 2001:db8::1
@end example
@@ -3216,13 +3315,16 @@ The @code{add peer} command allows a new NTP peer to be added whilst
@code{chronyd} is running.
Following the words @code{add peer}, the syntax of the following
parameters and options is identical to that for the @code{peer}
parameters and options is similar to that for the @code{peer}
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.
@example
add peer foo.bar.com minpoll 6 maxpoll 10 authkey 25
add peer foo.example.net minpoll 6 maxpoll 10 key 25
@end example
@c }}}
@c {{{ add server
@@ -3232,13 +3334,16 @@ The @code{add server} command allows a new NTP server to be added whilst
@code{chronyd} is running.
Following the words @code{add server}, the syntax of the following
parameters and options is identical to that for the @code{server}
parameters and options is similar to that for the @code{server}
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.
@example
add server foo.bar.com minpoll 6 maxpoll 10 authkey 25
add server foo.example.net minpoll 6 maxpoll 10 key 25
@end example
@c }}}
@c {{{ allow all
@@ -3256,7 +3361,7 @@ the configuration file (@pxref{allow directive}).
The syntax is illustrated in the following examples:
@example
allow foo.bar.com
allow foo.example.net
allow 1.2
allow 3.4.5
allow 6.7.8/22
@@ -3371,7 +3476,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
burst 2/10 foo.bar.com
burst 2/10 foo.example.net
@end example
@c }}}
@c {{{ clients
@@ -3435,7 +3540,7 @@ used to check whether command access is permitted from a named host.
Examples of use are as follows:
@example
cmdaccheck a.b.c
cmdaccheck foo.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
@end example
@@ -3493,7 +3598,7 @@ from the current set of sources.
The syntax is illustrated in the examples below.
@example
delete foo.bar.com
delete foo.example.net
delete 1.2.3.4
delete 2001:db8::1
@end example
@@ -3516,7 +3621,7 @@ directive in the configuration file (@pxref{deny directive}).
The syntax is illustrated in the following examples:
@example
deny foo.bar.com
deny foo.example.net
deny 1.2
deny 3.4.5
deny 6.7.8/22
@@ -3608,17 +3713,27 @@ offset, by slowing down or speeding up the clock as required. In
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.
The @code{makestep} command can be used in this situation. It cancels
any remaining correction that was being slewed, and jumps the system
clock by the equivalent amount, making it correct immediately.
The @code{makestep} command can be used in this situation. There are two forms
of the command. The first form has no parameters. It tells @code{chronyd} to
cancel any remaining correction that was being slewed and jump the system clock
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
the system time. (That is the reason why chronyd uses slewing
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 {{{ manual
@node manual command
@@ -3695,13 +3810,13 @@ directive}).
The following examples illustrate the syntax
@example
maxdelay foo.bar.com 0.3
maxdelay foo.example.net 0.3
maxdelay 1.2.3.4 0.0015
maxdelay 2001:db8::1 0.0015
@end example
The first example sets the maximum network delay allowed for a
measurement to the host @code{foo.bar.com} to 0.3 seconds. The second
measurement to the host @code{foo.example.net} to 0.3 seconds. The second
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
@code{2001:db8::1} to 1.5 milliseconds.
@@ -3720,7 +3835,7 @@ directive}).
The following examples illustrate the syntax
@example
maxdelaydevratio foo.bar.com 0.1
maxdelaydevratio foo.example.net 0.1
maxdelaydevratio 1.2.3.4 1.0
maxdelaydevratio 2001:db8::1 100.0
@end example
@@ -3736,13 +3851,13 @@ directive}).
The following examples illustrate the syntax
@example
maxdelayratio foo.bar.com 1.5
maxdelayratio foo.example.net 1.5
maxdelayratio 1.2.3.4 2.0
maxdelayratio 2001:db8::1 2.0
@end example
The first example sets the maximum network delay for a measurement to
the host @code{foo.bar.com} to be 1.5 times the minimum delay found
the host @code{foo.example.net} to be 1.5 times the minimum delay found
amongst the previous measurements that have been retained. The second
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
@@ -3773,10 +3888,10 @@ sampling).
An example is
@example
maxpoll foo.bar.com 10
maxpoll foo.example.net 10
@end example
which sets the maximum polling interval for the host @code{foo.bar.com}
which sets the maximum polling interval for the host @code{foo.example.net}
to 1024 seconds.
Note that the new maximum polling interval only takes effect after the
@@ -3810,10 +3925,10 @@ sampling).
An example is
@example
minpoll foo.bar.com 5
minpoll foo.example.net 5
@end example
which sets the minimum polling interval for the host @code{foo.bar.com}
which sets the minimum polling interval for the host @code{foo.example.net}
to 32 seconds.
Note that the new minimum polling interval only takes effect after the
@@ -3839,10 +3954,10 @@ IP address.
An example is
@example
minpoll foo.bar.com 5
minpoll foo.example.net 5
@end example
which sets the minimum stratum for the host @code{foo.bar.com}
which sets the minimum stratum for the host @code{foo.example.net}
to 5.
Note that the new minimum stratum only takes effect after the
@@ -3908,7 +4023,7 @@ illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
offline foo.bar.com
offline foo.example.net
@end example
The second form means that the @code{offline} command is to be applied
@@ -3989,10 +4104,10 @@ IP address.
An example is
@example
polltarget foo.bar.com 12
polltarget foo.example.net 12
@end example
which sets the poll target for the host @code{foo.bar.com}
which sets the poll target for the host @code{foo.example.net}
to 12.
@c }}}
@c {{{ quit
@@ -4135,8 +4250,8 @@ columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^? a.b.c 2 6 377 23 -923us[ -924us] +/- 43ms
^+ d.e.f 1 6 377 21 -2629us[-2619us] +/- 86ms
^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
@end group
@end example
@@ -4292,7 +4407,7 @@ The @code{tracking} command displays parameters about the system's clock
performance. An example of the output is shown below.
@example
Reference ID : 1.2.3.4 (a.b.c)
Reference ID : 1.2.3.4 (foo.example.net)
Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
@@ -4323,7 +4438,7 @@ in the @file{@SYSCONFDIR@/chrony.conf} file (@pxref{local directive})).
The stratum indicates how many hops away from a computer with an
attached reference clock we are. Such a computer is a stratum-1
computer, so the computer in the example is two hops away
(i.e. @code{a.b.c} is a stratum-2 and is synchronised from a stratum-1).
(i.e. @code{foo.example.net} is a stratum-2 and is synchronised from a stratum-1).
@item Ref time
This is the time (UTC) at which the last measurement from the reference
@@ -4387,11 +4502,6 @@ This is the estimated error bound on the the frequency.
This is the total of the network path delays to the stratum-1 computer
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
This is the total dispersion accumulated through all the computers back
to the stratum-1 computer from which the computer is ultimately
@@ -4521,9 +4631,9 @@ For the current development from the developers' version control system see the
@code{Git} link on the web site.
@subsection Are there any packaged versions of chrony?
We are aware of packages for Arch, Debian, Fedora, Gentoo, Mandriva, Slackware,
Ubuntu, FreeBSD and NetBSD. We are not involved with how these are built or
distributed.
We are aware of packages for Arch, CentOS, Debian, Fedora, Gentoo, Mageia,
OpenSuse, Slackware, Ubuntu, FreeBSD and NetBSD. We are not involved with how
these are built or distributed.
@subsection Where is the home page?
It is currently at
@@ -4608,13 +4718,16 @@ increasing intervals until it succeeds. The @code{online} command can be
issued from @code{chronyc} to try to resolve them immediately.
@subsection How can I make chronyd more secure?
If you don't need to serve time to NTP clients, you can add @code{port 0} to
the @file{chrony.conf} file to disable the NTP server/peer sockets and prevent
NTP requests from reaching @code{chronyd}.
If you don't need to serve time to NTP clients or peers, you can add
@code{port 0} to the @file{chrony.conf} file to completely disable the NTP
server functionality and prevent 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
directives to the configuration file to bind the command sockets to the
loopback interface
loopback interface. This is done by default since version 2.0.
@example
bindcmdaddress 127.0.0.1
@@ -4642,16 +4755,27 @@ they are @code{minpoll}, @code{maxpoll}, @code{polltarget}, @code{maxdelay},
The first three options set the minimum and maximum allowed polling interval,
and how should be the actual interval adjusted in the specified range. Their
default values are suitable for public NTP servers, which normally don't allow
too frequent polling, but if you run your own NTP servers or have permission to
poll the servers frequently, setting the options for shorter polling intervals
may significantly improve the accuracy of the system clock.
default values are 6 (64 seconds) for @code{minpoll}, 10 (1024 seconds) for
@code{maxpoll} and 6 (samples) for @code{polltarget}. The default values
should be used for general servers on the internet. With your own NTP servers
or if have permission to poll some servers more frequently, setting these
options for shorter polling intervals may significantly improve the accuracy of
the system clock.
The optimal polling interval depends on many factors, this includes the ratio
The optimal polling interval depends on many factors, including the ratio
between the wander of the clock and the network jitter (sometimes expressed in
NTP documents as the Allan intercept), the temperature sensitivity of the
crystal oscillator and the maximum rate of change of the temperature. An
example of the directive for a server located in the same LAN could be
crystal oscillator and the maximum rate of change of the temperature.
An example of the directive for an NTP server on the internet that you are
allowed to poll frequently could be
@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
server ntp.local minpoll 2 maxpoll 4 polltarget 30
@@ -4660,7 +4784,7 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30
The maxdelay options are useful to ignore measurements with larger delay (e.g.
due to congestion in the network) and improve the stability of the
synchronisation. The @code{maxdelaydevratio} option could be added to the
previous example
example with local NTP server
@example
server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
@@ -4698,9 +4822,10 @@ will arise. You should always make X quite high (e.g. 10) in this directive.
@section Issues with chronyc
@subsection I keep getting the error @code{506 Cannot talk to daemon}
Make sure that the @file{chrony.conf} file (on the computer where
@code{chronyd} is running) has a @code{cmdallow} entry for the computer you are
running @code{chronyc} on. This isn't necessary for localhost.
When accessing @code{chronyd} remotely, make sure that the @file{chrony.conf}
file (on the computer where @code{chronyd} is running) has a @code{cmdallow}
entry for the computer you are running @code{chronyc} on and an appropriate
@code{bindcmdaddress} directive. This isn't necessary for localhost.
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

View File

@@ -1,73 +0,0 @@
/* 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,7 +36,6 @@
#include "getdate.h"
#include "cmdparse.h"
#include "pktlength.h"
#include "memory.h"
#include "util.h"
#ifdef FEAT_READLINE
@@ -52,7 +51,7 @@
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
@@ -68,30 +67,6 @@ static int no_dns = 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
might want to use the GNU readline library. */
@@ -144,37 +119,26 @@ open_io(const char *hostname, int port)
int on_off = 1;
/* Note, this call could block for a while */
if (DNS_Name2IPAddress(hostname, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not get IP address for %s\n", hostname);
exit(1);
}
memset(&his_addr, 0, sizeof (his_addr));
switch (ip.family) {
case IPADDR_INET4:
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;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
case IPADDR_INET6:
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;
#endif
default:
assert(0);
}
his_addr_len = UTI_IPAndPortToSockaddr(&ip, port, &his_addr.u);
if (sock_fd < 0) {
perror("Can't create socket");
exit(1);
@@ -187,7 +151,7 @@ open_io(const char *hostname, int port)
recv_errqueue = 1;
}
#endif
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
#ifdef IPV6_RECVERR
if (ip.family == IPADDR_INET6 &&
!setsockopt(sock_fd, IPPROTO_IPV6, IPV6_RECVERR, &on_off, sizeof(on_off))) {
@@ -269,7 +233,7 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address)
}
}
} else {
if (DNS_Name2IPAddress(p, address) == DNS_Success) {
if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) {
bits_to_mask(-1, address->family, mask);
return 1;
} else {
@@ -341,7 +305,7 @@ read_address_integer(char *line, IPAddr *address, int *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -369,7 +333,7 @@ read_address_double(char *line, IPAddr *address, double *value)
fprintf(stderr, "Invalid syntax for address value\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -696,7 +660,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
/* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not read address\n");
return 0;
} else {
@@ -864,7 +828,7 @@ accheck_getaddr(char *line, IPAddr *addr)
addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
return 1;
} else {
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) {
if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
return 0;
} else {
*addr = ip;
@@ -966,17 +930,16 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
CPS_NTP_Source data;
CPS_Status status;
IPAddr ip_addr;
char str[64];
int result = 0;
status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) {
case CPS_Success:
if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) {
Free(data.name);
if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
fprintf(stderr, "Invalid host/IP address\n");
break;
}
Free(data.name);
if (data.params.min_stratum != SRC_DEFAULT_MINSTRATUM) {
fprintf(stderr, "Option minstratum not supported\n");
@@ -993,6 +956,26 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
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);
UTI_IPHostToNetwork(&ip_addr, &msg->data.ntp_source.ip_addr);
msg->data.ntp_source.minpoll = htonl(data.params.minpoll);
@@ -1010,41 +993,9 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
result = 1;
break;
case CPS_BadOption:
fprintf(stderr, "Unrecognized subcommand\n");
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");
default:
CPS_StatusToString(status, str, sizeof (str));
fprintf(stderr, "%s\n", str);
break;
}
@@ -1086,7 +1037,7 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Invalid syntax for address\n");
ok = 0;
} else {
if (DNS_Name2IPAddress(hostname, &address) != DNS_Success) {
if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n");
ok = 0;
} else {
@@ -1216,7 +1167,7 @@ give_help(void)
printf("dump : Dump all measurements to save files\n");
printf("local off : Disable server capability for unsynchronised clock\n");
printf("local stratum <stratum> : Enable server capability for unsynchronised clock\n");
printf("makestep : Jump the time to remove any correction being slewed\n");
printf("makestep [<threshold> <updates>] : Correct clock by stepping\n");
printf("manual off|on|reset : Disable/enable/reset settime command and statistics\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");
@@ -1412,7 +1363,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
(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_port != his_addr.in4.sin_port)) ||
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
(where_from.u.sa_family == AF_INET6 &&
(memcmp(where_from.in6.sin6_addr.s6_addr, his_addr.in6.sin6_addr.s6_addr,
sizeof (where_from.in6.sin6_addr.s6_addr)) != 0 ||
@@ -1750,10 +1701,10 @@ process_cmd_sources(char *line)
printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| / xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) -. | yyyy = measured offset,\n");
printf("|| \\ | zzzz = estimated error.\n");
printf("|| | | \n");
printf("|| Reachability register (octal) -. | xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) --. | | yyyy = measured offset,\n");
printf("|| \\ | | zzzz = estimated error.\n");
printf("|| | | \\\n");
}
printf("MS Name/IP address Stratum Poll Reach LastRx Last sample\n");
@@ -2158,14 +2109,14 @@ process_cmd_manual_list(const char *line)
n_samples = ntohl(reply.data.manual_list.n_samples);
printf("210 n_samples = %d\n", n_samples);
printf("# Date Time(UTC) Slewed Original Residual\n"
"====================================================\n");
"=======================================================\n");
for (i=0; i<n_samples; i++) {
sample = &reply.data.manual_list.samples[i];
UTI_TimevalNetworkToHost(&sample->when, &when);
slewed_offset = UTI_FloatNetworkToHost(sample->slewed_offset);
orig_offset = UTI_FloatNetworkToHost(sample->orig_offset);
residual = UTI_FloatNetworkToHost(sample->residual);
printf("%2d %s %10.2f %10.2f %10.2f\n", i, time_to_log_form(when.tv_sec), slewed_offset, orig_offset, residual);
printf("%2d %s %10.2f %10.2f %10.2f\n", i, UTI_TimeToLogForm(when.tv_sec), slewed_offset, orig_offset, residual);
}
return 1;
}
@@ -2236,10 +2187,25 @@ process_cmd_rekey(CMD_Request *msg, char *line)
/* ================================================== */
static void
static int
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);
}
return 1;
}
/* ================================================== */
@@ -2518,7 +2484,7 @@ process_line(char *line, int *quit)
} else if (!strcmp(command, "local")) {
do_normal_submit = process_cmd_local(&tx_message, line);
} else if (!strcmp(command, "makestep")) {
process_cmd_makestep(&tx_message, line);
do_normal_submit = process_cmd_makestep(&tx_message, line);
} else if (!strcmp(command, "manual")) {
if (!strncmp(line, "list", 4)) {
do_normal_submit = 0;
@@ -2610,8 +2576,8 @@ authenticate_from_config(const char *filename)
CMD_Reply rx_message;
char line[2048], keyfile[2048], *command, *arg, *password;
const char *hashname;
unsigned long key_id = 0, key_id2 = -1;
int ret;
uint32_t key_id = 0, key_id2;
int key_id_valid = 1, ret;
FILE *in;
in = fopen(filename, "r");
@@ -2628,13 +2594,12 @@ authenticate_from_config(const char *filename)
if (!strcasecmp(command, "keyfile")) {
snprintf(keyfile, sizeof (keyfile), "%s", arg);
} else if (!strcasecmp(command, "commandkey")) {
if (sscanf(arg, "%lu", &key_id) != 1)
key_id = -1;
key_id_valid = sscanf(arg, "%"SCNu32, &key_id) == 1;
}
}
fclose(in);
if (!*keyfile || key_id == -1) {
if (!*keyfile || !key_id_valid) {
fprintf(stderr, "Could not read keyfile or commandkey in file %s\n", filename);
return 0;
}
@@ -2645,6 +2610,7 @@ authenticate_from_config(const char *filename)
return 0;
}
key_id2 = key_id + 1;
while (fgets(line, sizeof (line), in)) {
CPS_NormalizeLine(line);
if (!*line || !CPS_ParseKey(line, &key_id2, &hashname, &password))
@@ -2662,7 +2628,7 @@ authenticate_from_config(const char *filename)
ret = 0;
}
} else {
fprintf(stderr, "Could not find key %lu in keyfile %s\n", key_id, keyfile);
fprintf(stderr, "Could not find key %"PRIu32" in keyfile %s\n", key_id, keyfile);
ret = 0;
}
@@ -2762,7 +2728,7 @@ main(int argc, char **argv)
} else if (!strcmp(*argv, "-6")) {
family = IPADDR_INET6;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
printf("chronyc (chrony) version %s\n", CHRONY_VERSION);
printf("chronyc (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYC_FEATURES);
exit(0);
} else if (!strncmp(*argv, "-", 1)) {
fprintf(stderr, "Usage : %s [-h <hostname>] [-p <port-number>] [-n] [-4|-6] [-m] [-a] [-f <file>]] [command]\n", progname);

View File

@@ -174,6 +174,11 @@ CLG_Initialise(void)
void
CLG_Finalise(void)
{
int i;
for (i = 0; i < n_nodes; i++)
Free(nodes[i]);
Free(nodes);
}
/* ================================================== */
@@ -256,31 +261,6 @@ 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
@@ -386,95 +366,6 @@ CLG_LogCommandAccess(IPAddr *client, CLG_Command_Type type, time_t now)
/* ================================================== */
CLG_Status
CLG_GetSubnetBitmap(IPAddr *subnet, int bits, CLG_Bitmap result)
{
Subnet *s;
uint32_t ip6[4];
unsigned long i;
unsigned long word, bit, mask;
if (bits >= 0 && bits % 8 == 0) {
memset (result, 0, TABLE_SIZE/8);
if (active) {
switch (subnet->family) {
case IPADDR_INET4:
if (bits >= 32)
return CLG_BADSUBNET;
s = find_subnet_dont_open(&top_subnet4, &subnet->addr.in4, 1, 32 - bits);
break;
case IPADDR_INET6:
if (bits >= 128)
return CLG_BADSUBNET;
split_ip6(subnet, ip6);
s = find_subnet_dont_open(&top_subnet6, ip6, 4, 128 - bits);
break;
default:
return CLG_BADSUBNET;
}
if (s) {
for (i=0; i<256; i++) {
if (s->entry[i]) {
word = i / 32;
bit = i % 32;
mask = 1UL << bit;
result[word] |= mask;
}
}
return CLG_SUCCESS;
} else {
return CLG_EMPTYSUBNET;
}
} else {
return CLG_INACTIVE;
}
} else {
return CLG_BADSUBNET;
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIP(IPAddr *ip, RPT_ClientAccess_Report *report, time_t now)
{
uint32_t ip6[4];
Node *node;
if (!active) {
return CLG_INACTIVE;
} else {
switch (ip->family) {
case IPADDR_INET4:
node = (Node *) find_subnet_dont_open(&top_subnet4, &ip->addr.in4, 1, 0);
break;
case IPADDR_INET6:
split_ip6(ip, ip6);
node = (Node *) find_subnet_dont_open(&top_subnet6, ip6, 4, 0);
break;
default:
return CLG_EMPTYSUBNET;
}
if (!node) {
return CLG_EMPTYSUBNET;
} else {
report->client_hits = node->client_hits;
report->peer_hits = node->peer_hits;
report->cmd_hits_auth = node->cmd_hits_auth;
report->cmd_hits_normal = node->cmd_hits_normal;
report->cmd_hits_bad = node->cmd_hits_bad;
report->last_ntp_hit_ago = now - node->last_ntp_hit;
report->last_cmd_hit_ago = now - node->last_cmd_hit;
return CLG_SUCCESS;
}
}
}
/* ================================================== */
CLG_Status
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report,
time_t now, unsigned long *n_indices)

View File

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

View File

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

View File

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

View File

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

424
conf.c
View File

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

9
conf.h
View File

@@ -30,7 +30,8 @@
#include "addressing.h"
extern void CNF_SetRestarted(int);
extern void CNF_Initialise(int restarted);
extern void CNF_Finalise(void);
extern char *CNF_GetRtcDevice(void);
@@ -56,7 +57,7 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern unsigned long CNF_GetCommandKey(void);
extern uint32_t CNF_GetCommandKey(void);
extern int CNF_GetGenerateCommandKey(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
@@ -93,13 +94,15 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
extern char *CNF_GetUser(void);
extern int CNF_GetMaxSamples(void);
extern int CNF_GetMinSamples(void);
extern int CNF_GetMinSources(void);
extern double CNF_GetRtcAutotrim(void);
extern char *CNF_GetHwclockFile(void);

121
configure vendored
View File

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

View File

@@ -1,339 +0,0 @@
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.

View File

@@ -1,583 +0,0 @@
#!/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);
}

View File

@@ -1,21 +0,0 @@
#!/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

@@ -1,7 +0,0 @@
#!/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

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

View File

@@ -1,166 +0,0 @@
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

@@ -1,22 +0,0 @@
#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

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

View File

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

2
hash.h
View File

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

View File

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

View File

@@ -87,3 +87,17 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
return ret;
}
void
HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (hashes[i].context)
NSSLOWHASH_Destroy(hashes[i].context);
}
if (ictx)
NSSLOW_Shutdown(ictx);
}

View File

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

164
keys.c
View File

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

14
keys.h
View File

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

26
local.c
View File

@@ -56,6 +56,7 @@ static lcl_AccrueOffsetDriver drv_accrue_offset;
static lcl_ApplyStepOffsetDriver drv_apply_step_offset;
static lcl_OffsetCorrectionDriver drv_offset_convert;
static lcl_SetLeapDriver drv_set_leap;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* ================================================== */
@@ -168,6 +169,13 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
while (change_list.next != &change_list)
LCL_RemoveParameterChangeHandler(change_list.next->handler,
change_list.next->anything);
while (dispersion_notify_list.next != &dispersion_notify_list)
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
dispersion_notify_list.next->anything);
}
/* ================================================== */
@@ -247,7 +255,7 @@ void LCL_RemoveParameterChangeHandler(LCL_ParameterChangeHandler handler, void *
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
free(ptr);
Free(ptr);
}
/* ================================================== */
@@ -324,7 +332,7 @@ void LCL_RemoveDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void
ptr->next->prev = ptr->prev;
ptr->prev->next = ptr->next;
free(ptr);
Free(ptr);
}
/* ================================================== */
@@ -550,7 +558,8 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap)
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status)
{
drv_read_freq = read_freq;
drv_set_freq = set_freq;
@@ -558,6 +567,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
drv_apply_step_offset = apply_step_offset;
drv_offset_convert = offset_convert;
drv_set_leap = set_leap;
drv_set_sync_status = set_sync_status;
current_freq_ppm = (*drv_read_freq)();
@@ -625,3 +635,13 @@ 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,4 +206,8 @@ extern void LCL_SetLeap(int leap);
due to clamping or rounding). */
extern double LCL_SetTempComp(double comp);
/* Routine to update the synchronisation status in the kernel to allow other
applications to know if the system clock is synchronised and error bounds */
extern void LCL_SetSyncStatus(int synchronised, double est_error, double max_error);
#endif /* GOT_LOCAL_H */

View File

@@ -57,6 +57,9 @@ typedef void (*lcl_OffsetCorrectionDriver)(struct timeval *raw, double *corr, do
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);
/* System driver to set the synchronisation status */
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);
extern void lcl_InvokeDispersionNotifyHandlers(double dispersion);
extern void
@@ -65,6 +68,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
lcl_AccrueOffsetDriver accrue_offset,
lcl_ApplyStepOffsetDriver apply_step_offset,
lcl_OffsetCorrectionDriver offset_convert,
lcl_SetLeapDriver set_leap);
lcl_SetLeapDriver set_leap,
lcl_SetSyncStatusDriver set_sync_status);
#endif /* GOT_LOCALP_H */

View File

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

View File

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

26
main.c
View File

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

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2002
* 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
@@ -21,17 +21,47 @@
=======================================================================
Deal with broadcast server functions.
Utility functions for memory allocation.
*/
#ifndef GOT_BROADCAST_H
#define GOT_BROADCAST_H
#include "config.h"
#include "addressing.h"
#include "logging.h"
#include "memory.h"
extern void BRD_Initialise(void);
extern void BRD_Finalise(void);
extern void BRD_AddDestination(IPAddr *addr, unsigned short port, int interval);
void *
Malloc(size_t size)
{
void *r;
#endif /* GOT_BROADCAST_H */
r = malloc(size);
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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

48
ntp.h
View File

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

1083
ntp_core.c

File diff suppressed because it is too large Load Diff

View File

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

198
ntp_io.c
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -928,6 +928,8 @@ REF_SetReference(int stratum,
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped by %.6f seconds", -step_offset);
}
LCL_SetSyncStatus(are_we_synchronised, offset_sd, offset_sd + root_delay / 2.0 + root_dispersion);
abs_freq_ppm = LCL_ReadAbsoluteFrequency();
write_log(&now,
@@ -1016,6 +1018,8 @@ REF_SetUnsynchronised(void)
update_leap_status(LEAP_Unsynchronised, 0);
are_we_synchronised = 0;
LCL_SetSyncStatus(0, 0.0, 0.0);
write_log(&now,
"0.0.0.0",
0,
@@ -1071,7 +1075,7 @@ REF_GetReferenceParams
*ref_id = LOCAL_REFERENCE_ID;
/* Make the reference time be now less a second - this will
scarcely affect the client, but will ensure that the transmit
timestamp cannot come before this (which would cause test 6 to
timestamp cannot come before this (which would cause test 7 to
fail in the client's read routine) if the local system clock's
read routine is broken in any way. */
*ref_time = *local_time;
@@ -1089,7 +1093,7 @@ REF_GetReferenceParams
*is_synchronised = 0;
*leap_status = LEAP_Unsynchronised;
*stratum = 0;
*stratum = NTP_MAX_STRATUM;
*ref_id = 0;
ref_time->tv_sec = ref_time->tv_usec = 0;
/* These values seem to be standard for a client, and
@@ -1111,7 +1115,7 @@ REF_GetOurStratum(void)
} else if (enable_local_stratum) {
return local_stratum;
} else {
return 16;
return NTP_MAX_STRATUM;
}
}
@@ -1125,6 +1129,15 @@ REF_ModifyMaxupdateskew(double new_max_update_skew)
/* ================================================== */
void
REF_ModifyMakestep(int limit, double threshold)
{
make_step_limit = limit;
make_step_threshold = threshold;
}
/* ================================================== */
void
REF_EnableLocal(int stratum)
{

View File

@@ -157,6 +157,9 @@ extern int REF_GetOurStratum(void);
/* Modify the setting for the maximum skew we are prepared to allow updates on (in ppm). */
extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
/* Modify makestep settings */
extern void REF_ModifyMakestep(int limit, double threshold);
extern void REF_EnableLocal(int stratum);
extern void REF_DisableLocal(void);
extern int REF_IsLocalActive(void);

View File

@@ -86,16 +86,6 @@ typedef struct {
double rtc_gain_rate_ppm;
} RPT_RTC_Report;
typedef struct {
unsigned long client_hits;
unsigned long peer_hits;
unsigned long cmd_hits_auth;
unsigned long cmd_hits_normal;
unsigned long cmd_hits_bad;
unsigned long last_ntp_hit_ago;
unsigned long last_cmd_hit_ago;
} RPT_ClientAccess_Report;
typedef struct {
IPAddr ip_addr;
unsigned long client_hits;

View File

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

20
sched.c
View File

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

572
sources.c
View File

@@ -36,6 +36,7 @@
#include "sourcestats.h"
#include "memory.h"
#include "ntp.h" /* For NTP_Leap */
#include "ntp_sources.h"
#include "local.h"
#include "reference.h"
#include "util.h"
@@ -60,20 +61,27 @@ struct SelectInfo {
double root_distance;
double lo_limit;
double hi_limit;
double last_sample_ago;
};
/* ================================================== */
/* This enum contains the flag values that are used to label
each source */
typedef enum {
SRC_OK, /* OK so far */
SRC_UNREACHABLE, /* Source is not reachable */
SRC_BAD_STATS, /* Stats driver could not supply valid
data */
SRC_FALSETICKER, /* Source is found to be a falseticker */
SRC_JITTERY, /* Source scatter worse than other's dispersion */
SRC_SELECTABLE, /* Source is acceptable candidate */
SRC_SYNC /* Current synchronisation source */
SRC_OK, /* OK so far, not a final status! */
SRC_UNSELECTABLE, /* Has noselect option set */
SRC_BAD_STATS, /* Doesn't have valid stats data */
SRC_WAITS_STATS, /* Others have bad stats, selection postponed */
SRC_STALE, /* Has older samples than others */
SRC_FALSETICKER, /* Doesn't agree with others */
SRC_JITTERY, /* Scatter worse than other's dispersion (not used) */
SRC_WAITS_SOURCES, /* Not enough sources, selection postponed */
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;
/* ================================================== */
@@ -88,9 +96,6 @@ struct SRC_Instance_Record {
reference _it_ is sync'd to) */
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 */
int active;
@@ -100,8 +105,11 @@ struct SRC_Instance_Record {
/* Number of set bits in the reachability register */
int reachability_size;
/* Updates since last reference update */
int updates;
/* Updates left before allowing combining */
int outlier;
int distant;
/* Flag indicating the status of the source */
SRC_Status status;
@@ -123,7 +131,10 @@ struct SRC_Instance_Record {
struct Sort_Element {
int index;
double offset;
enum {LOW=-1, CENTRE=0, HIGH=1} tag;
enum {
LOW = -1,
HIGH = 1
} tag;
};
/* ================================================== */
@@ -142,8 +153,8 @@ static int selected_source_index; /* Which source index is currently
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
/* Number of updates needed to reset the outlier status */
#define OUTLIER_PENALTY 32
/* Number of updates needed to reset the distant status */
#define DISTANT_PENALTY 32
static double reselect_distance;
static double stratum_weight;
@@ -165,6 +176,7 @@ source_to_string(SRC_Instance inst);
void SRC_Initialise(void) {
sources = NULL;
sort_list = NULL;
sel_sources = NULL;
n_sources = 0;
max_n_sources = 0;
selected_source_index = INVALID_SOURCE;
@@ -183,6 +195,11 @@ void SRC_Finalise(void)
{
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
LCL_RemoveDispersionNotifyHandler(add_dispersion, NULL);
Free(sources);
Free(sort_list);
Free(sel_sources);
initialised = 0;
}
@@ -190,18 +207,23 @@ void SRC_Finalise(void)
/* Function to create a new instance. This would be called by one of
the individual source-type instance creation routines. */
SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr)
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 result;
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->stats = SST_CreateInstance(ref_id, addr);
result->stats = SST_CreateInstance(ref_id, addr, min_samples, max_samples);
if (n_sources == max_n_sources) {
/* Reallocate memory */
max_n_sources += 32;
max_n_sources = max_n_sources > 0 ? 2 * max_n_sources : 4;
if (sources) {
sources = ReallocArray(struct SRC_Instance_Record *, max_n_sources, sources);
sort_list = ReallocArray(struct Sort_Element, 3*max_n_sources, sort_list);
@@ -214,20 +236,14 @@ SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOpt
}
sources[n_sources] = result;
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->sel_score = 1.0;
result->sel_option = sel_option;
SRC_SetRefid(result, ref_id, addr);
SRC_ResetInstance(result);
n_sources++;
return result;
@@ -245,8 +261,6 @@ void SRC_DestroyInstance(SRC_Instance instance)
assert(initialised);
SRC_UnsetSelectable(instance);
SST_DeleteInstance(instance->stats);
dead_index = instance->index;
for (i=dead_index; i<n_sources-1; i++) {
@@ -256,9 +270,38 @@ void SRC_DestroyInstance(SRC_Instance instance)
--n_sources;
Free(instance);
if (selected_source_index > dead_index) {
/* If this was the previous reference source, we have to reselect! */
if (selected_source_index == dead_index)
SRC_ReselectSource();
else if (selected_source_index > dead_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);
}
/* ================================================== */
@@ -341,37 +384,6 @@ 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
special_mode_end(void)
{
@@ -414,6 +426,12 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
if (REF_GetMode() != REF_ModeNormal && special_mode_end()) {
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);
}
}
/* ================================================== */
@@ -421,13 +439,9 @@ SRC_UpdateReachability(SRC_Instance inst, int reachable)
void
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_size = 0;
SRC_UpdateReachability(inst, 0);
#endif
}
/* ================================================== */
@@ -479,6 +493,20 @@ 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
combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
double *offset_sd, double *frequency, double *skew)
@@ -505,7 +533,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
the selected source multiplied by the limit, their estimated frequencies
are not close, or it was recently marked as outlier */
are not close, or it was recently marked as distant */
if (index != selected_source_index &&
(sources[index]->sel_info.root_distance > combine_limit *
@@ -513,14 +541,19 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
fabs(*frequency - src_frequency) >
combine_limit * (*skew + src_skew + LCL_GetMaxClockError()))) {
/* Use a smaller penalty in first few updates */
sources[index]->outlier = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
OUTLIER_PENALTY : 1;
} else if (sources[index]->outlier) {
sources[index]->outlier--;
sources[index]->distant = sources[index]->reachability_size >= SOURCE_REACH_BITS ?
DISTANT_PENALTY : 1;
} else if (sources[index]->distant) {
sources[index]->distant--;
}
if (sources[index]->outlier)
if (sources[index]->distant) {
sources[index]->status = SRC_DISTANT;
continue;
}
if (sources[index]->status == SRC_OK)
sources[index]->status = SRC_UNSELECTED;
UTI_DiffTimevalsToDouble(&elapsed, ref_time, &src_ref_time);
src_offset += elapsed * src_frequency;
@@ -556,39 +589,30 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
/* ================================================== */
/* This function selects the current reference from amongst the pool
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 */
of sources we are holding and updates the local reference */
void
SRC_SelectSource(SRC_Instance updated_inst)
{
int i, j, index, old_selected_index, sel_prefer;
struct SelectInfo *si;
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_root_delay, src_root_dispersion;
int n_endpoints, j1, j2;
double best_lo, best_hi;
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;
double best_lo, best_hi, distance, sel_src_distance, max_score;
double first_sample_ago, max_reach_sample_ago;
NTP_Leap leap_status;
NTP_Leap leap_status = LEAP_Normal;
old_selected_index = selected_source_index;
if (updated_inst)
updated_inst->updates++;
if (n_sources == 0) {
/* In this case, we clearly cannot synchronise to anything */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no sources", NULL);
selected_source_index = INVALID_SOURCE;
REF_SetUnsynchronised();
}
return;
}
@@ -597,31 +621,61 @@ SRC_SelectSource(SRC_Instance updated_inst)
SCH_GetLastEventTime(&now, NULL, NULL);
/* Step 1 - build intervals about each source */
n_endpoints = 0;
n_sel_sources = 0;
n_badstats_sources = 0;
max_sel_reach = max_badstat_reach = 0;
for (i=0; i<n_sources; i++) {
max_reach_sample_ago = 0.0;
if (sources[i]->selectable && sources[i]->reachability &&
sources[i]->sel_option != SRC_SelectNoselect) {
for (i = 0; i < n_sources; i++) {
assert(sources[i]->status != SRC_OK);
si = &(sources[i]->sel_info);
SST_GetSelectionData(sources[i]->stats, &now,
&(si->stratum),
&(si->lo_limit),
&(si->hi_limit),
&(si->root_distance),
&(si->variance),
&(si->select_ok));
/* Ignore sources which were added with the noselect option */
if (sources[i]->sel_option == SRC_SelectNoselect) {
sources[i]->status = SRC_UNSELECTABLE;
continue;
}
if (si->select_ok) {
++n_sel_sources;
si = &sources[i]->sel_info;
SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
&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 */
/* Otherwise it will be hard to pick this one later! However,
this test might be too strict, we might want to dump it */
if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
max_reach_sample_ago = first_sample_ago;
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;
j2 = j1 + 1;
@@ -634,44 +688,34 @@ SRC_SelectSource(SRC_Instance updated_inst)
sort_list[j2].tag = HIGH;
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_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
DEBUG_LOG(LOGF_Sources, "badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
n_badstats_sources, n_sel_sources, max_badstat_reach,
max_sel_reach, max_reach_sample_ago);
/* 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
equal to shifted maximum reachability of sources with valid stats.
This delays selecting source on start with servers using the same
polling interval until they all have valid stats. */
if (n_badstats_sources && n_sel_sources &&
selected_source_index == INVALID_SOURCE &&
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;
}
/* 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);
/* Now search for the interval which is contained in the most
@@ -700,8 +744,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
depth = best_depth = 0;
best_lo = best_hi = 0.0;
for (i=0; i<n_endpoints; i++) {
switch(sort_list[i].tag) {
for (i = 0; i < n_endpoints; i++) {
switch (sort_list[i].tag) {
case LOW:
depth++;
if (depth > best_depth) {
@@ -709,68 +753,56 @@ SRC_SelectSource(SRC_Instance updated_inst)
best_lo = sort_list[i].offset;
}
break;
case CENTRE:
assert(0);
break;
case HIGH:
if (depth == best_depth) {
if (depth == best_depth)
best_hi = sort_list[i].offset;
}
depth--;
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 -
clearly we can't synchronise.
srcs #to agree
1 1
2 2
3 2
4 3 etc
*/
clearly we can't synchronise. */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no majority", NULL);
}
REF_SetUnsynchronised();
selected_source_index = INVALID_SOURCE;
}
/* .. and mark all sources as falsetickers (so they appear thus
on the outputs from the command client) */
mark_ok_sources(SRC_FALSETICKER);
for (i=0; i<n_sources; i++) {
sources[i]->status = SRC_FALSETICKER;
return;
}
} else {
/* We have our interval, now work out which source are in it,
i.e. build list of admissible sources. */
n_sel_sources = 0;
for (i=0; i<n_sources; i++) {
if (sources[i]->status == SRC_OK) {
for (i = 0; i < n_sources; i++) {
if (sources[i]->status != SRC_OK)
continue;
/* This should be the same condition to get into the endpoint
list */
/* Check if source's interval contains the best interval, or
is wholly contained within it */
if (((sources[i]->sel_info.lo_limit <= best_lo) &&
(sources[i]->sel_info.hi_limit >= best_hi)) ||
((sources[i]->sel_info.lo_limit >= best_lo) &&
(sources[i]->sel_info.hi_limit <= best_hi))) {
if ((sources[i]->sel_info.lo_limit <= best_lo &&
sources[i]->sel_info.hi_limit >= best_hi) ||
(sources[i]->sel_info.lo_limit >= best_lo &&
sources[i]->sel_info.hi_limit <= best_hi)) {
sel_sources[n_sel_sources++] = i;
} else {
sources[i]->status = SRC_FALSETICKER;
}
}
}
#if 0
/* We now have a list of indices for the sources which pass the
@@ -780,7 +812,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Find minimum distance */
index = sel_sources[0];
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];
distance = sources[index]->sel_info.root_distance;
if (distance < min_distance) {
@@ -790,7 +822,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Now go through and prune any NTP sources that have excessive
variance */
for (i=0; i<n_sel_sources; i++) {
for (i = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) {
@@ -798,80 +830,88 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[index]->status = SRC_JITTERY;
}
}
#endif
/* Now crunch the list and mark all sources as selectable */
for (i=j=0; i<n_sel_sources; i++) {
for (i = j = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (index != INVALID_SOURCE) {
sources[index]->status = SRC_SELECTABLE;
sel_sources[j++] = sel_sources[i];
}
if (index == INVALID_SOURCE)
continue;
sel_sources[j++] = index;
}
n_sel_sources = j;
#endif
if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: %s selectable sources",
n_sel_sources ? "not enough" : "no");
selected_source_index = INVALID_SOURCE;
}
mark_ok_sources(SRC_WAITS_SOURCES);
return;
}
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++) {
for (i = j1 = j2 = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->leap_status == LEAP_InsertSecond) {
if (sources[index]->leap_status == LEAP_InsertSecond)
j1++;
} else if (sources[index]->leap_status == LEAP_DeleteSecond) {
else if (sources[index]->leap_status == LEAP_DeleteSecond)
j2++;
}
}
if (j1 > n_sel_sources / 2) {
if (j1 > n_sel_sources / 2)
leap_status = LEAP_InsertSecond;
} else if (j2 > n_sel_sources / 2) {
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 prefer sources */
for (i=j=0; i<n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer) {
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];
}
}
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;
sel_prefer = 1;
} else {
sel_prefer = 0;
}
/* 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 */
/* Find minimum stratum */
index = sel_sources[0];
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];
stratum = sources[index]->sel_info.stratum;
if (stratum < min_stratum) min_stratum = stratum;
if (stratum < min_stratum)
min_stratum = stratum;
}
/* Update scores and find source with maximum score */
/* Update scores and find the source with maximum score */
max_score_index = INVALID_SOURCE;
max_score = 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 +
(sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
}
for (i = 0; i < n_sources; i++) {
/* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE ||
if (sources[i]->status != SRC_OK ||
(sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) {
sources[i]->sel_score = 1.0;
sources[i]->outlier = OUTLIER_PENALTY;
sources[i]->distant = DISTANT_PENALTY;
continue;
}
@@ -881,7 +921,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
distance += reselect_distance;
if (selected_source_index != INVALID_SOURCE) {
/* Update score, but only for source pairs where one source
has a new sample */
if (sources[i] == updated_inst ||
@@ -892,18 +931,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (sources[i]->sel_score < 1.0)
sources[i]->sel_score = 1.0;
}
} else {
/* When there is no selected source yet, assign scores so the
/* When there is no selected source yet, assign scores so that the
source with minimum distance will have maximum score. The scores
will be immediately reset. */
will be reset when the source is selected later in this function. */
sources[i]->sel_score = 1.0 / distance;
}
DEBUG_LOG(LOGF_Sources, "select score=%f refid=%x match_refid=%x status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, updated_inst ? updated_inst->ref_id : 0,
DEBUG_LOG(LOGF_Sources, "select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id,
updated_inst ? updated_inst->ref_id : 0,
sources[i]->status, distance);
if (max_score < sources[i]->sel_score) {
@@ -914,32 +951,50 @@ SRC_SelectSource(SRC_Instance updated_inst)
assert(max_score_index != INVALID_SOURCE);
/* Is the current source still a survivor
and no other source has reached the score limit? */
if ((selected_source_index == INVALID_SOURCE) ||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
/* Is the current source still a survivor and no other source has reached
the score limit? */
if (selected_source_index == INVALID_SOURCE ||
sources[selected_source_index]->status != SRC_OK ||
(max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
/* We have to elect a new synchronisation source */
/* Before selecting the new synchronisation source wait until the reference
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;
log_selection_message("Selected source %s",
source_to_string(sources[selected_source_index]));
/* 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]->outlier = 0;
sources[i]->distant = 0;
}
}
sources[selected_source_index]->status = SRC_SYNC;
sources[selected_source_index]->status = SRC_SELECTED;
/* Update local reference only when a new source was selected
or the selected source has a new sample */
if (selected_source_index != old_selected_index ||
updated_inst == sources[selected_source_index]) {
/* Don't update reference when the selected source has no new samples */
if (sources[selected_source_index]->updates == 0) {
/* Mark the remaining sources as last combine_sources() call */
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
the other selectable sources for trimming the local clock */
@@ -953,39 +1008,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
&src_offset_sd, &src_frequency, &src_skew);
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]->ip_addr,
&ref_time,
src_offset,
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();
}
&ref_time, src_offset, src_offset_sd,
src_frequency, src_skew,
src_root_delay, src_root_dispersion);
}
/* ================================================== */
@@ -1221,23 +1249,32 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
}
switch (src->status) {
case SRC_SYNC:
report->state = RPT_SYNC;
break;
case SRC_JITTERY:
report->state = RPT_JITTERY;
break;
case SRC_OK:
case SRC_UNSELECTABLE:
case SRC_BAD_STATS:
case SRC_UNREACHABLE:
case SRC_STALE:
case SRC_WAITS_STATS:
report->state = RPT_UNREACH;
break;
case SRC_FALSETICKER:
report->state = RPT_FALSETICKER;
break;
case SRC_SELECTABLE:
report->state = src->outlier ? RPT_OUTLIER : RPT_CANDIDATE;
case SRC_JITTERY:
report->state = RPT_JITTERY;
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:
assert(0);
break;
@@ -1245,7 +1282,7 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
switch (src->sel_option) {
case SRC_SelectNormal:
report->sel_option = RPT_NOSELECT;
report->sel_option = RPT_NORMAL;
break;
case SRC_SelectPrefer:
report->sel_option = RPT_PREFER;
@@ -1300,27 +1337,6 @@ 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
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
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);
extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_SelectOption sel_option, IPAddr *addr, int min_samples, int max_samples);
/* Function to get rid of a source when it is being unconfigured.
This may cause the current reference source to be reselected, if this
@@ -74,6 +74,11 @@ extern SRC_Instance SRC_CreateNewInstance(uint32_t ref_id, SRC_Type type, SRC_Se
extern void SRC_DestroyInstance(SRC_Instance instance);
/* Function to reset a source */
extern void SRC_ResetInstance(SRC_Instance instance);
/* Function to change the sources's reference ID and IP address */
extern void SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr);
/* Function to get the range of frequencies, relative to the given
source, that we believe the local clock lies within. The return
@@ -104,7 +109,7 @@ extern void SRC_GetFrequencyRange(SRC_Instance instance, double *lo, double *hi)
indicates that the local clock is FAST relative to it.
root_delay and root_dispersion are in seconds, and are as per
RFC1305. root_dispersion only includes the peer's root dispersion
RFC 5905. root_dispersion only includes the peer's root dispersion
+ local sampling precision + skew dispersion accrued during the
measurement. It is the job of the source statistics algorithms +
track.c to add on the extra dispersion due to the residual standard
@@ -124,14 +129,6 @@ extern void SRC_SetActive(SRC_Instance inst);
/* This routine sets the source as not receiving reachability updates */
extern void SRC_UnsetActive(SRC_Instance inst);
/* This routine indicates that packets with valid headers are being
received from the designated source */
extern void SRC_SetSelectable(SRC_Instance instance);
/* This routine indicates that we are no longer receiving packets with
valid headers from the designated source */
extern void SRC_UnsetSelectable(SRC_Instance instance);
/* This routine updates the reachability register */
extern void SRC_UpdateReachability(SRC_Instance inst, int reachable);
@@ -140,11 +137,11 @@ extern void SRC_ResetReachability(SRC_Instance inst);
/* This routine is used to select the best source from amongst those
we currently have valid data on, and use it as the tracking base
for the local time. Updates are only made to the local reference
if a new source is selected or updated_inst is the selected
reference source. (This avoids updating the frequency
for the local time. Updates are made to the local reference only
when the selected source was updated (set as updated_inst) since
the last reference update. This avoids updating the frequency
tracking for every sample from other sources - only the ones from
the selected reference make a difference) */
the selected reference make a difference. */
extern void SRC_SelectSource(SRC_Instance updated_inst);
/* Force reselecting the best source */
@@ -180,14 +177,6 @@ extern int SRC_ReportSourcestats(int index, RPT_SourcestatsReport *report, struc
extern SRC_Type SRC_GetType(int index);
typedef enum {
SRC_Skew_Decrease,
SRC_Skew_Nochange,
SRC_Skew_Increase
} SRC_Skew_Direction;
extern SRC_Skew_Direction SRC_LastSkewChange(SRC_Instance inst);
extern int SRC_Samples(SRC_Instance inst);
#endif /* GOT_SOURCES_H */

View File

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

View File

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

View File

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

329
stubs.c Normal file
View File

@@ -0,0 +1,329 @@
/*
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)
{
#if defined(LINUX) && defined (FEAT_LINUXCAPS)
#if defined(LINUX) && defined (FEAT_PRIVDROP)
SYS_Linux_DropRoot(user);
#else
LOG_FATAL(LOGF_Sys, "dropping root privileges not supported");

View File

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

View File

@@ -35,7 +35,8 @@ extern void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_s
lcl_ReadFrequencyDriver sys_read_freq,
lcl_SetFrequencyDriver sys_set_freq,
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);

View File

@@ -44,7 +44,7 @@ int SchedPriority = 0;
int LockAll = 0;
#endif
#ifdef FEAT_LINUXCAPS
#ifdef FEAT_PRIVDROP
#include <sys/types.h>
#include <pwd.h>
#include <sys/prctl.h>
@@ -58,6 +58,9 @@ int LockAll = 0;
#include "logging.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 */
static int nominal_tick;
@@ -82,13 +85,15 @@ static int tick_update_hz;
/* ================================================== */
inline static long
our_round(double x) {
our_round(double x)
{
long y;
if (x > 0.0)
y = x + 0.5;
else
y = x - 0.5;
return y;
}
@@ -179,21 +184,42 @@ 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
* 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
* a +/- 10% movement of tick away from the nominal value 1e6/USER_HZ. */
static void
guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
static int
guess_hz(int tick)
{
int i, tick_lo, tick_hi, ihz;
double tick_nominal;
/* Pick off the hz=100 case first */
if (tick >= 9000 && tick <= 11000) {
*hz = 100;
*shift_hz = 7;
return;
return 100;
}
for (i=4; i<16; i++) { /* surely 16 .. 32768 is a wide enough range? */
@@ -203,36 +229,26 @@ guess_hz_and_shift_hz(int tick, int *hz, int *shift_hz)
tick_hi = (int)(0.5 + tick_nominal*4.0/3.0);
if (tick_lo < tick && tick <= tick_hi) {
*hz = ihz;
*shift_hz = i;
return;
return ihz;
}
}
/* oh dear. doomed. */
*hz = 0;
*shift_hz = 0;
return 0;
}
/* ================================================== */
static int
get_hz_and_shift_hz(int *hz, int *shift_hz)
get_hz(void)
{
#ifdef _SC_CLK_TCK
if ((*hz = sysconf(_SC_CLK_TCK)) < 1) {
int hz;
if ((hz = sysconf(_SC_CLK_TCK)) < 1)
return 0;
}
if (*hz == 100) {
*shift_hz = 7;
return 1;
}
for (*shift_hz = 1; (*hz >> *shift_hz) > 1; (*shift_hz)++)
;
return 1;
return hz;
#else
return 0;
#endif
@@ -259,19 +275,20 @@ static void
get_version_specific_details(void)
{
int major, minor, patch;
int shift_hz;
struct tmx_params tmx_params;
long tick;
double freq;
struct utsname uts;
if (!get_hz_and_shift_hz(&hz, &shift_hz)) {
TMX_ReadCurrentParams(&tmx_params);
hz = get_hz();
guess_hz_and_shift_hz(tmx_params.tick, &hz, &shift_hz);
if (!hz) {
if (TMX_GetFrequency(&freq, &tick) < 0)
LOG_FATAL(LOGF_SysLinux, "adjtimex() failed");
if (!shift_hz) {
LOG_FATAL(LOGF_SysLinux, "Can't determine hz (txc.tick=%ld txc.freq=%ld (%.8f) txc.offset=%ld)",
tmx_params.tick, tmx_params.freq, tmx_params.dfreq, tmx_params.offset);
}
hz = guess_hz(tick);
if (!hz)
LOG_FATAL(LOGF_SysLinux, "Can't determine hz from tick %ld", tick);
}
dhz = (double) hz;
@@ -332,13 +349,11 @@ SYS_Linux_Initialise(void)
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRtcSync());
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
1.0 / tick_update_hz,
read_frequency, set_frequency,
have_setoffset ? apply_step_offset : NULL,
set_leap);
set_leap, set_sync_status);
}
/* ================================================== */
@@ -352,7 +367,7 @@ SYS_Linux_Finalise(void)
/* ================================================== */
#ifdef FEAT_LINUXCAPS
#ifdef FEAT_PRIVDROP
void
SYS_Linux_DropRoot(char *user)
{
@@ -382,7 +397,7 @@ SYS_Linux_DropRoot(char *user)
LOG_FATAL(LOGF_SysLinux, "setuid(%d) failed", pw->pw_uid);
}
if ((cap = cap_from_text("cap_sys_time=ep")) == NULL) {
if ((cap = cap_from_text("cap_net_bind_service,cap_sys_time=ep")) == NULL) {
LOG_FATAL(LOGF_SysLinux, "cap_from_text() failed");
}

View File

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

View File

@@ -426,7 +426,8 @@ SYS_Solaris_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
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
with the non-volatile clock */

View File

@@ -379,7 +379,8 @@ SYS_SunOS_Initialise(void)
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, apply_step_offset,
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
with the non-volatile clock */

View File

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

View File

@@ -27,6 +27,7 @@
#include "config.h"
#include "array.h"
#include "conf.h"
#include "local.h"
#include "memory.h"
@@ -46,6 +47,37 @@ static char *filename;
static double update_interval;
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
read_timeout(void *arg)
{
@@ -55,11 +87,13 @@ read_timeout(void *arg)
f = fopen(filename, "r");
if (f && fscanf(f, "%lf", &temp) == 1) {
comp = k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
comp = get_tempcomp(temp);
if (fabs(comp) <= MAX_COMP) {
comp = LCL_SetTempComp(comp);
DEBUG_LOG(LOGF_TempComp, "tempcomp updated to %f for %f", comp, temp);
if (logfileid != -1) {
struct timeval now;
@@ -83,10 +117,41 @@ read_timeout(void *arg)
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
TMC_Initialise(void)
{
CNF_GetTempComp(&filename, &update_interval, &T0, &k0, &k1, &k2);
char *point_file;
CNF_GetTempComp(&filename, &update_interval, &point_file, &T0, &k0, &k1, &k2);
if (filename == NULL)
return;
@@ -94,6 +159,9 @@ TMC_Initialise(void)
if (update_interval <= 0.0)
update_interval = 1.0;
if (point_file)
read_points(point_file);
logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
" Date (UTC) Time Temp. Comp.")
: -1;
@@ -107,6 +175,8 @@ TMC_Finalise(void)
if (filename == NULL)
return;
if (points)
ARR_DestroyInstance(points);
SCH_RemoveTimeout(timeout_id);
Free(filename);
}

19
test/compilation/001-features Executable file
View File

@@ -0,0 +1,19 @@
#!/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

@@ -0,0 +1,40 @@
#!/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"
server_conf="server 192.168.123.2
server_conf="server 192.168.123.2 noselect
acquisitionport 123"
client_conf="acquisitionport 123"

View File

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

24
test/simulation/116-minsources Executable file
View File

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

85
util.c
View File

@@ -238,18 +238,18 @@ char *
UTI_RefidToString(uint32_t ref_id)
{
unsigned int i, j, c;
char buf[5], *result;
for (i = j = 0; i < 4; i++) {
c = (ref_id >> (24 - i * 8)) & 0xff;
if (isprint(c))
buf[j++] = c;
}
buf[j] = '\0';
char *result;
result = NEXT_BUFFER;
snprintf(result, BUFFER_LENGTH, "%s", buf);
for (i = j = 0; i < 4 && i < BUFFER_LENGTH - 1; i++) {
c = (ref_id >> (24 - i * 8)) & 0xff;
if (isprint(c))
result[j++] = c;
}
result[j] = '\0';
return result;
}
@@ -277,7 +277,7 @@ UTI_IPToString(IPAddr *addr)
break;
case IPADDR_INET6:
ip6 = addr->addr.in6;
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
inet_ntop(AF_INET6, ip6, result, BUFFER_LENGTH);
#else
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
UTI_StringToIP(const char *addr, IPAddr *ip)
{
#ifdef HAVE_IPV6
#ifdef FEAT_IPV6
struct in_addr in4;
struct in6_addr in6;
@@ -426,6 +426,65 @@ 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 *
UTI_TimeToLogForm(time_t t)
{
@@ -490,7 +549,7 @@ UTI_DoubleToInt32(double x)
/* ================================================== */
/* Seconds part of RFC1305 timestamp correponding to the origin of the
/* Seconds part of NTP timestamp correponding to the origin of the
struct timeval format. */
#define JAN_1970 0x83aa7e80UL

3
util.h
View File

@@ -86,6 +86,9 @@ extern void UTI_IPHostToNetwork(IPAddr *src, IPAddr *dest);
extern void UTI_IPNetworkToHost(IPAddr *src, IPAddr *dest);
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);
/* Adjust time following a frequency/offset change */

View File

@@ -22,18 +22,33 @@
=======================================================================
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.
This is a wrapper around the Linux adjtimex system call.
*/
#include "config.h"
#include "chrony_timex.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;
int
@@ -68,19 +83,11 @@ TMX_SetFrequency(double *freq, long tick)
{
struct timex txc;
txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS;
txc.modes = ADJ_TICK | ADJ_FREQUENCY;
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC);
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);
}
@@ -97,51 +104,6 @@ TMX_GetFrequency(double *freq, long *tick)
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
TMX_SetLeap(int leap)
{
@@ -161,7 +123,7 @@ TMX_SetLeap(int leap)
return adjtimex(&txc);
}
int TMX_SetSync(int sync)
int TMX_SetSync(int sync, double est_error, double max_error)
{
struct timex txc;
@@ -171,8 +133,10 @@ int TMX_SetSync(int sync)
status |= STA_UNSYNC;
}
txc.modes = ADJ_STATUS;
txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR;
txc.status = status;
txc.esterror = est_error * 1.0e6;
txc.maxerror = max_error * 1.0e6;
return adjtimex(&txc);
}

View File

@@ -27,49 +27,11 @@
#ifndef 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_SetFrequency(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_SetSync(int sync);
int TMX_SetSync(int sync, double est_error, double max_error);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);