mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 21:05:06 -05:00
Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
366345790d | ||
|
|
f881c153bf | ||
|
|
19f3ab2225 | ||
|
|
fd1e80802f | ||
|
|
4b7cb161a8 | ||
|
|
7848794222 | ||
|
|
94822d5156 | ||
|
|
e3f840aae9 | ||
|
|
5aae563277 | ||
|
|
02de782fa3 | ||
|
|
3f6df33feb | ||
|
|
a94f5fe007 | ||
|
|
63f0234748 | ||
|
|
47921c7c0c | ||
|
|
42a85f685e | ||
|
|
feca2399e4 | ||
|
|
d34e611ec8 | ||
|
|
02098ed830 | ||
|
|
aa4228bf1b | ||
|
|
b296441708 | ||
|
|
b827475378 | ||
|
|
78a6698ae1 | ||
|
|
e7b6feb34b | ||
|
|
84be834385 | ||
|
|
e83d808dfd | ||
|
|
35a68d5b59 | ||
|
|
3c593137b0 | ||
|
|
deaf0ffed3 | ||
|
|
af145e871e | ||
|
|
fbca570d0b | ||
|
|
448ef779c2 | ||
|
|
499a69e611 | ||
|
|
58c2915878 | ||
|
|
eda4b111d3 | ||
|
|
c6dd749687 | ||
|
|
d2a96f5fbc | ||
|
|
499f513d40 | ||
|
|
8b1f68b1b4 | ||
|
|
8e4c776900 | ||
|
|
d0eb9427c2 | ||
|
|
7d100b89fc | ||
|
|
a4bd7f1800 | ||
|
|
5308e0a25f | ||
|
|
da862158bf | ||
|
|
7b98443a13 | ||
|
|
4da9f74d24 | ||
|
|
e41042e258 | ||
|
|
5581466c63 | ||
|
|
e79a6c2116 | ||
|
|
666ece122e | ||
|
|
2c7ab98370 | ||
|
|
f0f18a02a7 | ||
|
|
c5d8af0285 | ||
|
|
0ce15a8472 | ||
|
|
da60629201 | ||
|
|
2343e7a89c | ||
|
|
45f27f4f5e | ||
|
|
0bc112f8b4 | ||
|
|
bfc2fa645c | ||
|
|
11111804fd | ||
|
|
87ec67247e | ||
|
|
0df8328ceb | ||
|
|
b563048ee2 | ||
|
|
e8096330be | ||
|
|
b1647dbcb7 | ||
|
|
4ddadd5622 | ||
|
|
3e854006c7 | ||
|
|
2c4c235147 | ||
|
|
6863e43269 | ||
|
|
de8708f331 | ||
|
|
d0b2486036 | ||
|
|
5384a93645 | ||
|
|
4bbc768652 | ||
|
|
fead915b45 | ||
|
|
5422e49026 | ||
|
|
77a1f27a1d | ||
|
|
b45d864f73 | ||
|
|
f35c81c871 | ||
|
|
a349b2803c | ||
|
|
f5d1b8fb74 | ||
|
|
a0fe71eef1 | ||
|
|
154b39cf7a | ||
|
|
6f54210db2 | ||
|
|
f6539449c5 | ||
|
|
b8d546a0d1 | ||
|
|
04e6474b75 | ||
|
|
eb51c500e8 | ||
|
|
6f8fba9a3f | ||
|
|
750afc30f2 |
25
NEWS
25
NEWS
@@ -1,3 +1,28 @@
|
||||
New in version 3.3
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add burst option to server/pool directive
|
||||
* Add stratum and tai options to refclock directive
|
||||
* Add support for Nettle crypto library
|
||||
* Add workaround for missing kernel receive timestamps on Linux
|
||||
* Wait for late hardware transmit timestamps
|
||||
* Improve source selection with unreachable sources
|
||||
* Improve protection against replay attacks on symmetric mode
|
||||
* Allow PHC refclock to use socket in /var/run/chrony
|
||||
* Add shutdown command to stop chronyd
|
||||
* Simplify format of response to manual list command
|
||||
* Improve handling of unknown responses in chronyc
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Respond to NTPv1 client requests with zero mode
|
||||
* Fix -x option to not require CAP_SYS_TIME under non-root user
|
||||
* Fix acquisitionport directive to work with privilege separation
|
||||
* Fix handling of socket errors on Linux to avoid high CPU usage
|
||||
* Fix chronyc to not get stuck in infinite loop after clock step
|
||||
|
||||
New in version 3.2
|
||||
==================
|
||||
|
||||
|
||||
45
README
45
README
@@ -37,20 +37,16 @@ How do I set it up?
|
||||
===================
|
||||
|
||||
The file INSTALL gives instructions. On supported systems the
|
||||
compilation process should be automatic.
|
||||
|
||||
You will need an ANSI C compiler -- gcc is recommended.
|
||||
|
||||
The manual (in texinfo and text formats) describes how to set the
|
||||
software up for the less straightforward cases.
|
||||
compilation process should be automatic. You will need a C compiler,
|
||||
e.g. gcc or clang.
|
||||
|
||||
What documentation is there?
|
||||
============================
|
||||
|
||||
A manual is supplied in Texinfo format (chrony.texi) and
|
||||
ready-formatted plain text (chrony.txt) in the distribution.
|
||||
The distribution includes manual pages and a document containing
|
||||
Frequently Asked Questions (FAQ).
|
||||
|
||||
There is also information available on the chrony web pages, accessible
|
||||
The documentation is also available on the chrony web pages, accessible
|
||||
through the URL
|
||||
|
||||
https://chrony.tuxfamily.org/
|
||||
@@ -126,7 +122,7 @@ Andrew Bishop <amb@gedanken.demon.co.uk>
|
||||
Improvements to 'sources' and 'sourcestats' output from chronyc
|
||||
Improvements to documentation
|
||||
Investigation of required dosynctodr behaviour for various Solaris
|
||||
versions.
|
||||
versions
|
||||
|
||||
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
|
||||
Entries in contrib directory
|
||||
@@ -140,27 +136,27 @@ Bryan Christianson <bryan@whatroute.net>
|
||||
Entries in contrib directory
|
||||
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Fix install rule in Makefile if chronyd file is in use.
|
||||
Patch to fix install rule in Makefile if chronyd file is in use
|
||||
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Patch to generate a warning message when CAP_SYS_TIME is missing
|
||||
|
||||
Paul Elliott <pelliott@io.com>
|
||||
DNSchrony (in contrib directory), a tool for handling NTP servers
|
||||
with variable IP addresses.
|
||||
Entries in contrib directory
|
||||
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
Fixes for compiler warnings
|
||||
|
||||
Alexander Gretencord <arutha@gmx.de>
|
||||
Changes to installation directory system to make it easier for
|
||||
package builders.
|
||||
package builders
|
||||
|
||||
Andrew Griffiths <agriffit@redhat.com>
|
||||
Patch to add support for seccomp filter
|
||||
|
||||
Walter Haidinger <walter.haidinger@gmx.at>
|
||||
Providing me with login access to a Linux installation where v1.12
|
||||
wouldn't compile, so I could develop the fixes for v1.13. Also, for
|
||||
providing the disc space so I can keep an independent backup of the
|
||||
sources.
|
||||
Access to a Linux installation where v1.12 wouldn't compile
|
||||
Disc space for an independent backup of the sources
|
||||
|
||||
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
|
||||
Port to NetBSD
|
||||
@@ -170,7 +166,7 @@ John Hasler <john@dhh.gt.org>
|
||||
Changes to support 64 bit machines (i.e. those where
|
||||
sizeof(unsigned long) > 4)
|
||||
Bug fix to initstepslew directive
|
||||
Fix to remove potential buffer overrun errors.
|
||||
Fix to remove potential buffer overrun errors
|
||||
Memory locking and real-time scheduler support
|
||||
Fix fault where chronyd enters an endless loop
|
||||
|
||||
@@ -198,7 +194,7 @@ Victor Moroz <vim@prv.adlum.ru>
|
||||
Patch to support Linux with HZ!=100
|
||||
|
||||
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
|
||||
acquisitionport support
|
||||
Patch to add acquisitionport directive
|
||||
|
||||
Frank Otto <sandwichmacher@web.de>
|
||||
Handling arbitrary HZ values
|
||||
@@ -206,12 +202,18 @@ Frank Otto <sandwichmacher@web.de>
|
||||
Denny Page <dennypage@me.com>
|
||||
Advice on support for hardware timestamping
|
||||
|
||||
Chris Perl <cperl@janestreet.com>
|
||||
Patches to improve support for refclocks keeping time in TAI
|
||||
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Patch to add refresh command to chronyc
|
||||
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Patch to make chronyc use the readline library if available
|
||||
|
||||
Andreas Steinmetz <ast@domdv.de>
|
||||
Patch to make stratum of refclocks configurable
|
||||
|
||||
Timo Teras <timo.teras@iki.fi>
|
||||
Patch to reply correctly on multihomed hosts
|
||||
|
||||
@@ -228,8 +230,7 @@ Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Many robustness and security improvements
|
||||
|
||||
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
|
||||
Providing me with information about the Linux 2.2 kernel
|
||||
functionality compared to 2.0.
|
||||
Information about the Linux 2.2 kernel functionality compared to 2.0
|
||||
|
||||
Doug Woodward <dougw@whistler.com>
|
||||
Advice on configuring for Solaris 2.8 on x86
|
||||
|
||||
13
candm.h
13
candm.h
@@ -99,7 +99,8 @@
|
||||
#define REQ_ADD_PEER2 59
|
||||
#define REQ_ADD_SERVER3 60
|
||||
#define REQ_ADD_PEER3 61
|
||||
#define N_REQUEST_TYPES 62
|
||||
#define REQ_SHUTDOWN 62
|
||||
#define N_REQUEST_TYPES 63
|
||||
|
||||
/* Structure used to exchange timespecs independent of time_t size */
|
||||
typedef struct {
|
||||
@@ -252,6 +253,7 @@ typedef struct {
|
||||
#define REQ_ADDSRC_TRUST 0x20
|
||||
#define REQ_ADDSRC_REQUIRE 0x40
|
||||
#define REQ_ADDSRC_INTERLEAVED 0x80
|
||||
#define REQ_ADDSRC_BURST 0x100
|
||||
|
||||
typedef struct {
|
||||
IPAddr ip_addr;
|
||||
@@ -367,9 +369,9 @@ typedef struct {
|
||||
domain socket.
|
||||
|
||||
Version 6 (no authentication) : changed format of client accesses by index
|
||||
(using new request/reply types) and manual timestamp, new fields and flags
|
||||
in NTP source request and report, new commands: ntpdata, refresh,
|
||||
serverstats
|
||||
(using new request/reply types) and manual timestamp, added new fields and
|
||||
flags to NTP source request and report, made length of manual list constant,
|
||||
added new commands: ntpdata, refresh, serverstats, shutdown
|
||||
*/
|
||||
|
||||
#define PROTO_VERSION_NUMBER 6
|
||||
@@ -468,7 +470,8 @@ typedef struct {
|
||||
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
|
||||
#define RPY_NTP_DATA 16
|
||||
#define RPY_MANUAL_TIMESTAMP2 17
|
||||
#define N_REPLY_TYPES 18
|
||||
#define RPY_MANUAL_LIST2 18
|
||||
#define N_REPLY_TYPES 19
|
||||
|
||||
/* Status codes */
|
||||
#define STT_SUCCESS 0
|
||||
|
||||
104
client.c
104
client.c
@@ -4,7 +4,7 @@
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Lonnie Abelbeck 2016
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
* Copyright (C) Miroslav Lichvar 2009-2018
|
||||
*
|
||||
* 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
|
||||
@@ -1109,6 +1109,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
|
||||
(data.params.auto_offline ? REQ_ADDSRC_AUTOOFFLINE : 0) |
|
||||
(data.params.iburst ? REQ_ADDSRC_IBURST : 0) |
|
||||
(data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
|
||||
(data.params.burst ? REQ_ADDSRC_BURST : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
|
||||
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
|
||||
@@ -1245,6 +1246,7 @@ give_help(void)
|
||||
"cyclelogs\0Close and re-open log files\0"
|
||||
"dump\0Dump all measurements to save files\0"
|
||||
"rekey\0Re-read keys from key file\0"
|
||||
"shutdown\0Stop daemon\0"
|
||||
"\0\0"
|
||||
"Client commands:\0\0"
|
||||
"dns -n|+n\0Disable/enable resolving IP addresses to hostnames\0"
|
||||
@@ -1279,9 +1281,9 @@ command_name_generator(const char *text, int state)
|
||||
"maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll",
|
||||
"maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online",
|
||||
"polltarget", "quit", "refresh", "rekey", "reselect", "reselectdist",
|
||||
"retries", "rtcdata", "serverstats", "settime", "smoothing", "smoothtime",
|
||||
"sources", "sources -v", "sourcestats", "sourcestats -v", "timeout",
|
||||
"tracking", "trimrtc", "waitsync", "writertc",
|
||||
"retries", "rtcdata", "serverstats", "settime", "shutdown", "smoothing",
|
||||
"smoothtime", "sources", "sources -v", "sourcestats", "sourcestats -v",
|
||||
"timeout", "tracking", "trimrtc", "waitsync", "writertc",
|
||||
NULL
|
||||
};
|
||||
static int list_index, len;
|
||||
@@ -1324,18 +1326,16 @@ static int proto_version = PROTO_VERSION_NUMBER;
|
||||
static int
|
||||
submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
{
|
||||
int bad_length, bad_sequence, bad_header;
|
||||
int select_status;
|
||||
int recv_status;
|
||||
int read_length;
|
||||
int expected_length;
|
||||
int command_length;
|
||||
int padding_length;
|
||||
struct timespec ts_now, ts_start;
|
||||
struct timeval tv;
|
||||
int n_attempts, new_attempt;
|
||||
double timeout;
|
||||
fd_set rdfd, wrfd, exfd;
|
||||
fd_set rdfd;
|
||||
|
||||
request->pkt_type = PKT_TYPE_CMD_REQUEST;
|
||||
request->res1 = 0;
|
||||
@@ -1347,15 +1347,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
new_attempt = 1;
|
||||
|
||||
do {
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return 0;
|
||||
|
||||
if (new_attempt) {
|
||||
new_attempt = 0;
|
||||
|
||||
if (n_attempts > max_retries)
|
||||
return 0;
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return 0;
|
||||
|
||||
UTI_TimevalToTimespec(&tv, &ts_start);
|
||||
|
||||
UTI_GetRandomBytes(&request->sequence, sizeof (request->sequence));
|
||||
@@ -1383,9 +1383,6 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
DEBUG_LOG("Sent %d bytes", command_length);
|
||||
}
|
||||
|
||||
if (gettimeofday(&tv, NULL))
|
||||
return 0;
|
||||
|
||||
UTI_TimevalToTimespec(&tv, &ts_now);
|
||||
|
||||
/* Check if the clock wasn't stepped back */
|
||||
@@ -1394,22 +1391,27 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
|
||||
timeout = initial_timeout / 1000.0 * (1U << (n_attempts - 1)) -
|
||||
UTI_DiffTimespecsToDouble(&ts_now, &ts_start);
|
||||
UTI_DoubleToTimeval(timeout, &tv);
|
||||
DEBUG_LOG("Timeout %f seconds", timeout);
|
||||
|
||||
FD_ZERO(&rdfd);
|
||||
FD_ZERO(&wrfd);
|
||||
FD_ZERO(&exfd);
|
||||
/* Avoid calling select() with an invalid timeout */
|
||||
if (timeout <= 0.0) {
|
||||
new_attempt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
UTI_DoubleToTimeval(timeout, &tv);
|
||||
|
||||
FD_ZERO(&rdfd);
|
||||
FD_SET(sock_fd, &rdfd);
|
||||
|
||||
if (quit)
|
||||
return 0;
|
||||
|
||||
select_status = select(sock_fd + 1, &rdfd, &wrfd, &exfd, &tv);
|
||||
select_status = select(sock_fd + 1, &rdfd, NULL, NULL, &tv);
|
||||
|
||||
if (select_status < 0) {
|
||||
DEBUG_LOG("select failed : %s", strerror(errno));
|
||||
return 0;
|
||||
} else if (select_status == 0) {
|
||||
/* Timeout must have elapsed, try a resend? */
|
||||
new_attempt = 1;
|
||||
@@ -1425,34 +1427,18 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
DEBUG_LOG("Received %d bytes", recv_status);
|
||||
|
||||
read_length = recv_status;
|
||||
if (read_length >= offsetof(CMD_Reply, data)) {
|
||||
expected_length = PKL_ReplyLength(reply);
|
||||
} else {
|
||||
expected_length = 0;
|
||||
}
|
||||
|
||||
bad_length = (read_length < expected_length ||
|
||||
expected_length < offsetof(CMD_Reply, data));
|
||||
|
||||
if (!bad_length) {
|
||||
bad_sequence = reply->sequence != request->sequence;
|
||||
} else {
|
||||
bad_sequence = 0;
|
||||
}
|
||||
|
||||
if (bad_length || bad_sequence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bad_header = ((reply->version != proto_version &&
|
||||
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
||||
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
||||
(reply->pkt_type != PKT_TYPE_CMD_REPLY) ||
|
||||
(reply->res1 != 0) ||
|
||||
(reply->res2 != 0) ||
|
||||
(reply->command != request->command));
|
||||
|
||||
if (bad_header) {
|
||||
/* Check if the header is valid */
|
||||
if (read_length < offsetof(CMD_Reply, data) ||
|
||||
(reply->version != proto_version &&
|
||||
!(reply->version >= PROTO_VERSION_MISMATCH_COMPAT_CLIENT &&
|
||||
ntohs(reply->status) == STT_BADPKTVERSION)) ||
|
||||
reply->pkt_type != PKT_TYPE_CMD_REPLY ||
|
||||
reply->res1 != 0 ||
|
||||
reply->res2 != 0 ||
|
||||
reply->command != request->command ||
|
||||
reply->sequence != request->sequence) {
|
||||
DEBUG_LOG("Invalid reply");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1471,6 +1457,15 @@ submit_request(CMD_Request *request, CMD_Reply *reply)
|
||||
#error unknown compatibility with PROTO_VERSION - 1
|
||||
#endif
|
||||
|
||||
/* Check that the packet contains all data it is supposed to have.
|
||||
Unknown responses will always pass this test as their expected
|
||||
length is zero. */
|
||||
if (read_length < PKL_ReplyLength(reply)) {
|
||||
DEBUG_LOG("Reply too short");
|
||||
new_attempt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Good packet received, print out results */
|
||||
DEBUG_LOG("Reply cmd=%d reply=%d stat=%d",
|
||||
ntohs(reply->command), ntohs(reply->reply), ntohs(reply->status));
|
||||
@@ -1577,6 +1572,9 @@ request_reply(CMD_Request *request, CMD_Reply *reply, int requested_reply, int v
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure an unknown response was not requested */
|
||||
assert(PKL_ReplyLength(reply));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2540,7 +2538,7 @@ process_cmd_manual_list(const char *line)
|
||||
struct timespec when;
|
||||
|
||||
request.command = htons(REQ_MANUAL_LIST);
|
||||
if (!request_reply(&request, &reply, RPY_MANUAL_LIST, 0))
|
||||
if (!request_reply(&request, &reply, RPY_MANUAL_LIST2, 0))
|
||||
return 0;
|
||||
|
||||
n_samples = ntohl(reply.data.manual_list.n_samples);
|
||||
@@ -2548,7 +2546,7 @@ process_cmd_manual_list(const char *line)
|
||||
|
||||
print_header("# Date Time(UTC) Slewed Original Residual");
|
||||
|
||||
for (i = 0; i < n_samples; i++) {
|
||||
for (i = 0; i < n_samples && i < MAX_MANUAL_LIST_SAMPLES; i++) {
|
||||
sample = &reply.data.manual_list.samples[i];
|
||||
UTI_TimespecNetworkToHost(&sample->when, &when);
|
||||
|
||||
@@ -2709,6 +2707,14 @@ process_cmd_refresh(CMD_Request *msg, char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
process_cmd_shutdown(CMD_Request *msg, char *line)
|
||||
{
|
||||
msg->command = htons(REQ_SHUTDOWN);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_waitsync(char *line)
|
||||
{
|
||||
@@ -3004,6 +3010,8 @@ process_line(char *line)
|
||||
} else if (!strcmp(command, "settime")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_settime(line);
|
||||
} else if (!strcmp(command, "shutdown")) {
|
||||
process_cmd_shutdown(&tx_message, line);
|
||||
} else if (!strcmp(command, "smoothing")) {
|
||||
do_normal_submit = 0;
|
||||
ret = process_cmd_smoothing(line);
|
||||
@@ -3098,7 +3106,7 @@ static void
|
||||
display_gpl(void)
|
||||
{
|
||||
printf("chrony version %s\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2017 Richard P. Curnow and others\n"
|
||||
"Copyright (C) 1997-2003, 2007, 2009-2018 Richard P. Curnow and others\n"
|
||||
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
|
||||
"you are welcome to redistribute it under certain conditions. See the\n"
|
||||
"GNU General Public License version 2 for details.\n\n",
|
||||
|
||||
31
cmdmon.c
31
cmdmon.c
@@ -138,6 +138,7 @@ static const char permissions[] = {
|
||||
PERMIT_AUTH, /* ADD_PEER2 */
|
||||
PERMIT_AUTH, /* ADD_SERVER3 */
|
||||
PERMIT_AUTH, /* ADD_PEER3 */
|
||||
PERMIT_AUTH, /* SHUTDOWN */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -278,7 +279,6 @@ do_size_checks(void)
|
||||
for (i = 1; i < N_REPLY_TYPES; i++) {
|
||||
reply.reply = htons(i);
|
||||
reply.status = STT_SUCCESS;
|
||||
reply.data.manual_list.n_samples = htonl(MAX_MANUAL_LIST_SAMPLES);
|
||||
reply_length = PKL_ReplyLength(&reply);
|
||||
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
||||
reply_length > sizeof (CMD_Reply))
|
||||
@@ -801,6 +801,7 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m
|
||||
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
|
||||
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
|
||||
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
|
||||
params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
|
||||
params.sel_options =
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
|
||||
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
|
||||
@@ -1068,9 +1069,6 @@ handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX2);
|
||||
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
||||
|
||||
memset(tx_message->data.client_accesses_by_index.clients, 0,
|
||||
sizeof (tx_message->data.client_accesses_by_index.clients));
|
||||
|
||||
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
||||
if (!CLG_GetClientAccessReportByIndex(i, &report, &now))
|
||||
continue;
|
||||
@@ -1103,10 +1101,11 @@ handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
RPY_ManualListSample *sample;
|
||||
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
||||
|
||||
tx_message->reply = htons(RPY_MANUAL_LIST);
|
||||
tx_message->reply = htons(RPY_MANUAL_LIST2);
|
||||
|
||||
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
||||
tx_message->data.manual_list.n_samples = htonl(n_samples);
|
||||
|
||||
for (i=0; i<n_samples; i++) {
|
||||
sample = &tx_message->data.manual_list.samples[i];
|
||||
UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
|
||||
@@ -1238,6 +1237,15 @@ handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
handle_shutdown(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
{
|
||||
LOG(LOGS_INFO, "Received shutdown command");
|
||||
SCH_QuitProgram();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read a packet and process it */
|
||||
|
||||
@@ -1329,19 +1337,14 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
expected_length = PKL_CommandLength(&rx_message);
|
||||
rx_command = ntohs(rx_message.command);
|
||||
|
||||
memset(&tx_message, 0, sizeof (tx_message));
|
||||
|
||||
tx_message.version = PROTO_VERSION_NUMBER;
|
||||
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
||||
tx_message.res1 = 0;
|
||||
tx_message.res2 = 0;
|
||||
tx_message.command = rx_message.command;
|
||||
tx_message.reply = htons(RPY_NULL);
|
||||
tx_message.status = htons(STT_SUCCESS);
|
||||
tx_message.pad1 = 0;
|
||||
tx_message.pad2 = 0;
|
||||
tx_message.pad3 = 0;
|
||||
tx_message.sequence = rx_message.sequence;
|
||||
tx_message.pad4 = 0;
|
||||
tx_message.pad5 = 0;
|
||||
|
||||
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
||||
DEBUG_LOG("Command packet has invalid version (%d != %d)",
|
||||
@@ -1629,6 +1632,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
handle_ntp_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SHUTDOWN:
|
||||
handle_shutdown(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG("Unhandled command %d", rx_command);
|
||||
tx_message.status = htons(STT_FAILED);
|
||||
|
||||
@@ -51,6 +51,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.online = 1;
|
||||
src->params.auto_offline = 0;
|
||||
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
|
||||
src->params.burst = 0;
|
||||
src->params.iburst = 0;
|
||||
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
|
||||
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
|
||||
@@ -84,6 +85,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
|
||||
if (!strcasecmp(cmd, "auto_offline")) {
|
||||
src->params.auto_offline = 1;
|
||||
} else if (!strcasecmp(cmd, "burst")) {
|
||||
src->params.burst = 1;
|
||||
} else if (!strcasecmp(cmd, "iburst")) {
|
||||
src->params.iburst = 1;
|
||||
} else if (!strcasecmp(cmd, "offline")) {
|
||||
|
||||
19
conf.c
19
conf.c
@@ -681,7 +681,7 @@ static void
|
||||
parse_refclock(char *line)
|
||||
{
|
||||
int n, poll, dpoll, filter_length, pps_rate, min_samples, max_samples, sel_options;
|
||||
int max_lock_age, pps_forced;
|
||||
int max_lock_age, pps_forced, stratum, tai;
|
||||
uint32_t ref_id, lock_ref_id;
|
||||
double offset, delay, precision, max_dispersion, pulse_width;
|
||||
char *p, *cmd, *name, *param;
|
||||
@@ -704,6 +704,8 @@ parse_refclock(char *line)
|
||||
ref_id = 0;
|
||||
max_lock_age = 2;
|
||||
lock_ref_id = 0;
|
||||
stratum = 0;
|
||||
tai = 0;
|
||||
|
||||
if (!*line) {
|
||||
command_parse_error();
|
||||
@@ -774,6 +776,13 @@ parse_refclock(char *line)
|
||||
} else if (!strcasecmp(cmd, "maxdispersion")) {
|
||||
if (sscanf(line, "%lf%n", &max_dispersion, &n) != 1)
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "stratum")) {
|
||||
if (sscanf(line, "%d%n", &stratum, &n) != 1 ||
|
||||
stratum >= NTP_MAX_STRATUM || stratum < 0)
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "tai")) {
|
||||
n = 0;
|
||||
tai = 1;
|
||||
} else if (!strcasecmp(cmd, "width")) {
|
||||
if (sscanf(line, "%lf%n", &pulse_width, &n) != 1)
|
||||
break;
|
||||
@@ -811,6 +820,8 @@ parse_refclock(char *line)
|
||||
refclock->min_samples = min_samples;
|
||||
refclock->max_samples = max_samples;
|
||||
refclock->sel_options = sel_options;
|
||||
refclock->stratum = stratum;
|
||||
refclock->tai = tai;
|
||||
refclock->offset = offset;
|
||||
refclock->delay = delay;
|
||||
refclock->precision = precision;
|
||||
@@ -1335,7 +1346,11 @@ parse_include(char *line)
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
|
||||
if ((r = glob(line, GLOB_ERR | GLOB_NOMAGIC, NULL, &gl)) != 0) {
|
||||
if ((r = glob(line,
|
||||
#ifdef GLOB_NOMAGIC
|
||||
GLOB_NOMAGIC |
|
||||
#endif
|
||||
GLOB_ERR, NULL, &gl)) != 0) {
|
||||
if (r != GLOB_NOMATCH)
|
||||
LOG_FATAL("Could not search for files matching %s", line);
|
||||
|
||||
|
||||
35
configure
vendored
35
configure
vendored
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Copyright (C) Richard P. Curnow 1997-2003
|
||||
# Copyright (C) Bryan Christianson 2016
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2016
|
||||
# Copyright (C) Miroslav Lichvar 2009, 2012-2018
|
||||
#
|
||||
# =======================================================================
|
||||
|
||||
@@ -85,6 +85,7 @@ For better control, use the options below.
|
||||
--with-readline-library=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-nettle Don't use nettle even if it is available
|
||||
--without-nss Don't use NSS even if it is available
|
||||
--without-tomcrypt Don't use libtomcrypt even if it is available
|
||||
--disable-cmdmon Disable command and monitoring support
|
||||
@@ -198,6 +199,7 @@ feat_readline=1
|
||||
try_readline=1
|
||||
try_editline=1
|
||||
feat_sechash=1
|
||||
try_nettle=1
|
||||
try_nss=1
|
||||
try_tomcrypt=1
|
||||
feat_rtc=1
|
||||
@@ -360,6 +362,9 @@ do
|
||||
--disable-sechash )
|
||||
feat_sechash=0
|
||||
;;
|
||||
--without-nettle )
|
||||
try_nettle=0
|
||||
;;
|
||||
--without-nss )
|
||||
try_nss=0
|
||||
;;
|
||||
@@ -550,7 +555,11 @@ then
|
||||
split_seconds=$ntp_era_split
|
||||
split_days=0
|
||||
else
|
||||
split_seconds=`date '+%s'`
|
||||
if [ "x$SOURCE_DATE_EPOCH" != "x" ]; then
|
||||
split_seconds=$SOURCE_DATE_EPOCH
|
||||
else
|
||||
split_seconds=`date '+%s'`
|
||||
fi
|
||||
if [ "x$split_seconds" = "x" ]; then
|
||||
echo "error: could not get current time, --with-ntp-era option is needed"
|
||||
exit 1
|
||||
@@ -696,6 +705,7 @@ then
|
||||
struct scm_ts_pktinfo pktinfo;
|
||||
pktinfo.if_index = pktinfo.pkt_length = 0;
|
||||
return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
|
||||
SCM_TIMESTAMPING_PKTINFO +
|
||||
SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
|
||||
add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
|
||||
add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
|
||||
@@ -852,7 +862,22 @@ fi
|
||||
HASH_OBJ="hash_intmd5.o"
|
||||
HASH_LINK=""
|
||||
|
||||
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
|
||||
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ]; then
|
||||
test_cflags="`pkg_config --cflags nettle`"
|
||||
test_link="`pkg_config --libs nettle`"
|
||||
if test_code 'nettle' 'nettle/nettle-meta.h nettle/sha2.h' \
|
||||
"$test_cflags" "$test_link" \
|
||||
'return nettle_hashes[0]->context_size;'
|
||||
then
|
||||
HASH_OBJ="hash_nettle.o"
|
||||
HASH_LINK="$test_link"
|
||||
LIBS="$LIBS $HASH_LINK"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def FEAT_SECHASH
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $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' \
|
||||
@@ -942,9 +967,9 @@ add_def DEFAULT_USER "\"$default_user\""
|
||||
add_def DEFAULT_COMMAND_SOCKET "\"$CHRONYRUNDIR/chronyd.sock\""
|
||||
add_def MAIL_PROGRAM "\"$mail_program\""
|
||||
|
||||
common_features="`get_features IPV6 DEBUG`"
|
||||
common_features="`get_features SECHASH IPV6 DEBUG`"
|
||||
chronyc_features="`get_features READLINE`"
|
||||
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH SIGND ASYNCDNS`"
|
||||
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SIGND ASYNCDNS`"
|
||||
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
|
||||
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
|
||||
echo "Features : $chronyd_features $chronyc_features $common_features"
|
||||
|
||||
@@ -66,34 +66,44 @@ server, or its IP address. The *server* directive supports the following
|
||||
options:
|
||||
+
|
||||
*minpoll* _poll_:::
|
||||
Although *chronyd* will trim the rate at which it samples the server during
|
||||
normal operation, the user might want to constrain the minimum polling interval.
|
||||
This is always defined as a power of 2, so *minpoll 5* would mean that the
|
||||
polling interval cannot drop below 32 seconds. The default is 6 (64 seconds),
|
||||
the minimum is -4 (1/16th of a second), and the maximum is 24 (6 months). Note
|
||||
that intervals shorter than 6 (64 seconds) should generally not be used with
|
||||
public servers on the Internet, because it might be considered abuse.
|
||||
This option specifies the minimum interval between requests sent to the server
|
||||
as a power of 2 in seconds. For example, *minpoll 5* would mean that the
|
||||
polling interval should not drop below 32 seconds. The default is 6 (64
|
||||
seconds), the minimum is -4 (1/16th of a second), and the maximum is 24 (6
|
||||
months). Note that intervals shorter than 6 (64 seconds) should generally not
|
||||
be used with public servers on the Internet, because it might be considered
|
||||
abuse.
|
||||
*maxpoll* _poll_:::
|
||||
In a similar way, the user might want to constrain the maximum polling interval.
|
||||
Again this is specified as a power of 2, *maxpoll 9* indicates that the polling
|
||||
interval must stay at or below 512 seconds. The default is 10 (1024 seconds),
|
||||
the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||
This option specifies the maximum interval between requests sent to the server
|
||||
as a power of 2 in seconds. For example, *maxpoll 9* indicates that the polling
|
||||
interval should stay at or below 9 (512 seconds). The default is 10 (1024
|
||||
seconds), the minimum is 0 (1 second), and the maximum is 24 (6 months).
|
||||
*iburst*:::
|
||||
If this option is set, the interval between the first four polls will be 2
|
||||
seconds instead of _minpoll_. This is useful to quickly get the first update of
|
||||
the clock after *chronyd* is started.
|
||||
*key* _id_:::
|
||||
The NTP protocol supports the inclusion of checksums in the packets, to prevent
|
||||
With this option, the interval between the first four requests sent to the
|
||||
server will be 2 seconds instead of the interval specified by the *minpoll*
|
||||
option, which allows *chronyd* to make the first update of the clock shortly
|
||||
after start.
|
||||
*burst*:::
|
||||
With this option, *chronyd* will shorten the interval between up to four
|
||||
requests to 2 seconds when it cannot get a good measurement from the server.
|
||||
The number of requests in the burst is limited by the current polling interval
|
||||
to keep the average interval at or above the minimum interval, i.e. the current
|
||||
interval needs to be at least two times longer than the minimum interval in
|
||||
order to allow a burst with two requests.
|
||||
*key* _ID_:::
|
||||
The NTP protocol supports a message authentication code (MAC) to prevent
|
||||
computers having their system time upset by rogue packets being sent to them.
|
||||
The checksums are generated as a function of a password, using the
|
||||
cryptographic hash function set in the key file, which is specified by the
|
||||
<<keyfile,*keyfile*>> directive.
|
||||
The MAC is generated as a function of a password specified in the key file,
|
||||
which is specified by the <<keyfile,*keyfile*>> directive.
|
||||
+
|
||||
If the key option is present, *chronyd* will attempt to use authenticated
|
||||
packets when communicating with this server. The key number used will be the
|
||||
single argument to the key option (an unsigned integer in the range 1 through
|
||||
2^32-1). The server must have the same password for this key number configured,
|
||||
The *key* option specifies which key (with an ID in the range 1 through 2^32-1)
|
||||
should *chronyd* use to authenticate requests sent to the server and verify its
|
||||
responses. The server must have the same key for this number configured,
|
||||
otherwise no relationship between the computers will be possible.
|
||||
+
|
||||
If the server is running *ntpd* and the output size of the hash function used
|
||||
by the key is longer than 160 bits (e.g. SHA256), the *version* option needs to
|
||||
be set to 4 for compatibility.
|
||||
*maxdelay* _delay_:::
|
||||
*chronyd* uses the network round-trip delay to the server to determine how
|
||||
accurate a particular measurement is likely to be. Long round-trip delays
|
||||
@@ -113,7 +123,7 @@ option. For example, *maxdelay 0.3* would indicate that measurements with a
|
||||
round-trip delay of 0.3 seconds or more should be ignored. The default value is
|
||||
3 seconds and the maximum value is 1000 seconds.
|
||||
*maxdelayratio* _ratio_:::
|
||||
This option is similar to the maxdelay option above. *chronyd* keeps a record
|
||||
This option is similar to the *maxdelay* option above. *chronyd* keeps a record
|
||||
of the minimum round-trip delay amongst the previous measurements that it has
|
||||
buffered. If a measurement has a round trip delay that is greater than the
|
||||
maxdelayratio times the minimum delay, it will be rejected.
|
||||
@@ -123,14 +133,14 @@ minimum delay amongst the previous measurements to the standard deviation of
|
||||
the previous measurements that is greater than the specified ratio, it will be
|
||||
rejected. The default is 10.0.
|
||||
*mindelay* _delay_:::
|
||||
This options specifies a fixed minimum round-trip delay to be used instead of
|
||||
This option specifies a fixed minimum round-trip delay to be used instead of
|
||||
the minimum amongst the previous measurements. This can be useful in networks
|
||||
with static configuration to improve the stability of corrections for
|
||||
asymmetric jitter, weighting of the measurements, and the *maxdelayratio* and
|
||||
*maxdelaydevratio* tests. The value should be set accurately in order to have a
|
||||
positive effect on the synchronisation.
|
||||
*asymmetry* _ratio_:::
|
||||
This options specifies the asymmetry of the network jitter on the path to the
|
||||
This option specifies the asymmetry of the network jitter on the path to the
|
||||
source, which is used to correct the measured offset according to the delay.
|
||||
The asymmetry can be between -0.5 and +0.5. A negative value means the delay of
|
||||
packets sent to the source is more variable than the delay of packets sent from
|
||||
@@ -154,14 +164,15 @@ option can be specified. *chronyd* will not try to poll the server until it is
|
||||
enabled to do so (by using the <<chronyc.adoc#online,*online*>> command in
|
||||
*chronyc*).
|
||||
*auto_offline*:::
|
||||
If this option is set, the server will be assumed to have gone offline when 2
|
||||
With this option, the server will be assumed to have gone offline when two
|
||||
requests have been sent to it without receiving a response. This option avoids
|
||||
the need to run the <<chronyc.adoc#offline,*offline*>> command from *chronyc*
|
||||
when disconnecting the network link. (It will still be necessary to use the
|
||||
<<chronyc.adoc#online,*online*>> command when the link has been established, to
|
||||
enable measurements to start.)
|
||||
when disconnecting the network link, if it is safe to assume that the requests
|
||||
and responses will not be dropped in the network, e.g. in a trusted local
|
||||
network. (It will still be necessary to use the <<chronyc.adoc#online,*online*>>
|
||||
command when the link has been established, to enable measurements to start.)
|
||||
*prefer*:::
|
||||
Prefer this source over sources without prefer option.
|
||||
Prefer this source over sources without the *prefer* option.
|
||||
*noselect*:::
|
||||
Never select this source. This is particularly useful for monitoring.
|
||||
*trust*:::
|
||||
@@ -500,7 +511,7 @@ This option specifies the width of the pulses (in seconds). It is used to
|
||||
filter PPS samples when the driver provides samples for both rising and falling
|
||||
edges. Note that it reduces the maximum allowed error of the time source which
|
||||
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
||||
prefered in order to maximise the allowed error.
|
||||
preferred in order to maximise the allowed error.
|
||||
*pps*:::
|
||||
This options forces *chronyd* to treat any refclock (e.g. SHM or PHC) as a PPS
|
||||
refclock. This can be useful when the refclock provides time with a variable
|
||||
@@ -516,6 +527,9 @@ is included in the maximum assumed error which is used in the source selection
|
||||
algorithm. Increasing the delay is useful to avoid having no majority in the
|
||||
source selection or to make it prefer other sources. The default is 1e-9 (1
|
||||
nanosecond).
|
||||
*stratum* _stratum_:::
|
||||
This option sets the NTP stratum of the refclock. This can be useful when the
|
||||
refclock provides time with a stratum other than 0. The default is 0.
|
||||
*precision* _precision_:::
|
||||
This option sets the precision of the reference clock (in seconds). The default
|
||||
value is the estimated precision of the system clock.
|
||||
@@ -546,6 +560,12 @@ but not very precise, reference clock to be safely combined with
|
||||
unauthenticated NTP sources in order to improve the accuracy of the clock. They
|
||||
can be selected and used for synchronisation only if they agree with the
|
||||
trusted and required source.
|
||||
*tai*:::
|
||||
This option indicates that the reference clock keeps time in TAI instead of UTC
|
||||
and that *chronyd* should correct its offset by the current TAI-UTC offset. The
|
||||
<<leapsectz,*leapsectz*>> directive must be used with this option and the
|
||||
database must be kept up to date in order for this correction to work as
|
||||
expected. This option does not make sense with PPS refclocks.
|
||||
*minsamples* _samples_:::
|
||||
Set the minimum number of samples kept for this source. This overrides the
|
||||
<<minsamples,*minsamples*>> directive.
|
||||
@@ -751,9 +771,10 @@ driftfile @CHRONYVARDIR@/drift
|
||||
|
||||
[[fallbackdrift]]*fallbackdrift* _min-interval_ _max-interval_::
|
||||
Fallback drifts are long-term averages of the system clock drift calculated
|
||||
over exponentially increasing intervals. They are used when the clock is no
|
||||
longer synchronised to avoid quickly drifting away from true time if there was
|
||||
a short-term deviation in the drift before the synchronisation was lost.
|
||||
over exponentially increasing intervals. They are used to avoid quickly
|
||||
drifting away from true time when the clock was not updated for a longer period
|
||||
of time and there was a short-term deviation in the drift before the updates
|
||||
stopped.
|
||||
+
|
||||
The directive specifies the minimum and maximum interval since the last clock
|
||||
update to switch between fallback drifts. They are defined as a power of 2 (in
|
||||
@@ -765,8 +786,10 @@ fallbackdrift 16 19
|
||||
+
|
||||
In this example, the minimum interval is 16 (18 hours) and the maximum interval is
|
||||
19 (6 days). The system clock frequency will be set to the first fallback 18
|
||||
hours after last clock update, to the second after 36 hours, etc. This might be
|
||||
a good setting to cover daily and weekly temperature fluctuations.
|
||||
hours after last clock update, to the second after 36 hours, and so on. This
|
||||
might be a good setting to cover frequency changes due to daily and weekly
|
||||
temperature fluctuations. When the frequency is set to a fallback, the state of
|
||||
the clock will change to '`Not synchronised`'.
|
||||
+
|
||||
By default (or if the specified maximum or minimum is 0), no fallbacks are used
|
||||
and the clock frequency changes only with new measurements from NTP sources,
|
||||
@@ -862,6 +885,11 @@ It is also useful when the system clock is required to have correct TAI-UTC
|
||||
offset. Note that the offset is set only when leap seconds are handled by the
|
||||
kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
|
||||
+
|
||||
The specified timezone is not used as an exclusive source of information about
|
||||
leap seconds. If a majority of time sources announce on the last day of June or
|
||||
December that a leap second should be inserted or deleted, it will be accepted
|
||||
even if it is not included in the timezone.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
@@ -1985,12 +2013,18 @@ format of the file is shown below:
|
||||
+
|
||||
Each line consists of an ID, name of an authentication hash function (optional),
|
||||
and a password. The ID can be any unsigned integer in the range 1 through
|
||||
2^32-1. The default hash function is *MD5*. Depending on how *chronyd*
|
||||
was compiled, other supported functions might be *SHA1*, *SHA256*, *SHA384*,
|
||||
*SHA512*, *RMD128*, *RMD160*, *RMD256*, *RMD320*, *TIGER*, and *WHIRLPOOL*. The
|
||||
password can be specified as a string of characters not containing white space
|
||||
with an optional *ASCII:* prefix, or as a hexadecimal number with the *HEX:*
|
||||
prefix. The maximum length of the line is 2047 characters.
|
||||
2^32-1. The default hash function is *MD5*, which is always supported.
|
||||
+
|
||||
If *chronyd* was built with enabled support for hashing using a crypto library
|
||||
(nettle, nss, or libtomcrypt), the following functions are available: *MD5*,
|
||||
*SHA1*, *SHA256*, *SHA384*, *SHA512*. Depending on which library and version is
|
||||
*chronyd* using, some or all of the following functions may also be available:
|
||||
*SHA3-224*, *SHA3-256*, *SHA3-384*, *SHA3-512*, *RMD128*, *RMD160*, *RMD256*,
|
||||
*RMD320*, *TIGER*, *WHIRLPOOL*.
|
||||
+
|
||||
The password can be specified as a string of characters not containing white
|
||||
space with an optional *ASCII:* prefix, or as a hexadecimal number with the
|
||||
*HEX:* prefix. The maximum length of the line is 2047 characters.
|
||||
+
|
||||
The password is used with the hash function to generate and verify a message
|
||||
authentication code (MAC) in NTP packets. It is recommended to use SHA1, or
|
||||
|
||||
@@ -1128,6 +1128,10 @@ running.
|
||||
The *rekey* command causes *chronyd* to re-read the key file specified in the
|
||||
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive.
|
||||
|
||||
[[rekey]]*shutdown*::
|
||||
The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
|
||||
the process the SIGTERM signal.
|
||||
|
||||
=== Client commands
|
||||
|
||||
[[dns]]*dns* _option_::
|
||||
|
||||
@@ -135,7 +135,7 @@ range of privileged system calls on behalf of the parent.
|
||||
*-F* _level_::
|
||||
This option configures a system call filter when *chronyd* is compiled with
|
||||
support for the Linux secure computing (seccomp) facility. In level 1 the
|
||||
process is killed when a forbidden system call is made, in level -1 the SYSSIG
|
||||
process is killed when a forbidden system call is made, in level -1 the SIGSYS
|
||||
signal is thrown instead and in level 0 the filter is disabled (default 0).
|
||||
+
|
||||
It's recommended to enable the filter only when it's known to work on the
|
||||
@@ -157,11 +157,13 @@ This option will lock *chronyd* into RAM so that it will never be paged out.
|
||||
This mode is only supported on Linux.
|
||||
|
||||
*-x*::
|
||||
This option disables the control of the system clock. *chronyd* will not make
|
||||
any adjustments of the clock, but it will still track its offset and frequency
|
||||
relative to the estimated true time, and be able to operate as an NTP server.
|
||||
This allows *chronyd* to run without the capability to adjust or set the system
|
||||
clock (e.g. in some containers).
|
||||
This option disables the control of the system clock. *chronyd* will not try to
|
||||
make any adjustments of the clock. It will assume the clock is free running and
|
||||
still track its offset and frequency relative to the estimated true time. This
|
||||
option allows *chronyd* to run without the capability to adjust or set the
|
||||
system clock (e.g. in some containers) in order to operate as an NTP server. It
|
||||
is not recommended to run *chronyd* (with or without *-x*) when another process
|
||||
is controlling the system clock.
|
||||
|
||||
*-v*::
|
||||
With this option *chronyd* will print version number to the terminal and exit.
|
||||
|
||||
29
doc/faq.adoc
29
doc/faq.adoc
@@ -393,16 +393,31 @@ things
|
||||
|
||||
Some other program running on the system may be using the device.
|
||||
|
||||
=== What if my computer does not have an RTC or backup battery?
|
||||
|
||||
In this case you can still use the `-s` option to set the system clock to the
|
||||
last modification time of the drift file, which should correspond to the system
|
||||
time when `chronyd` was previously stopped. The initial system time will be
|
||||
increasing across reboots and applications started after `chronyd` will not
|
||||
observe backward steps.
|
||||
|
||||
== NTP-specific issues
|
||||
|
||||
=== Can `chronyd` be driven from broadcast NTP servers?
|
||||
=== Can `chronyd` be driven from broadcast/multicast NTP servers?
|
||||
|
||||
No, the broadcast client mode is not supported and there is currently no plan
|
||||
to implement it. The broadcast and multicast modes are inherently less
|
||||
accurate and less secure (even with authentication) than the ordinary
|
||||
server/client mode and they are not as useful as they used to be. Even with
|
||||
very modest hardware a single NTP server can serve time to hundreds of
|
||||
thousands of clients using the ordinary mode.
|
||||
No, the broadcast/multicast client mode is not supported and there is currently
|
||||
no plan to implement it. While the mode may be useful to simplify configuration
|
||||
of clients in large networks, it is inherently less accurate and less secure
|
||||
(even with authentication) than the ordinary client/server mode.
|
||||
|
||||
When configuring a large number of clients in a network, it is recommended to
|
||||
use the `pool` directive with a DNS name which resolves to addresses of
|
||||
multiple NTP servers. The clients will automatically replace the servers when
|
||||
they become unreachable, or otherwise unsuitable for synchronisation, with new
|
||||
servers from the pool.
|
||||
|
||||
Even with very modest hardware, an NTP server can serve time to hundreds of
|
||||
thousands of clients using the ordinary client/server mode.
|
||||
|
||||
=== Can `chronyd` transmit broadcast NTP packets?
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ After unpacking the source code, change directory into it, and type
|
||||
----
|
||||
|
||||
This is a shell script that automatically determines the system type. There is
|
||||
a single optional parameter, `--prefix` which indicates the directory tree
|
||||
where the software should be installed. For example,
|
||||
an optional parameter `--prefix`, which indicates the directory tree where the
|
||||
software should be installed. For example,
|
||||
|
||||
----
|
||||
./configure --prefix=/opt/free
|
||||
@@ -40,11 +40,11 @@ will install the `chronyd` daemon into `/opt/free/sbin` and the `chronyc`
|
||||
control program into `/opt/free/bin`. The default value for the prefix is
|
||||
`/usr/local`.
|
||||
|
||||
The configure script assumes you want to use gcc as your compiler. If you want
|
||||
to use a different compiler, you can configure this way:
|
||||
The `configure` script assumes you want to use `gcc` as your compiler. If you
|
||||
want to use a different compiler, you can configure this way:
|
||||
|
||||
----
|
||||
CC=cc CFLAGS=-O ./configure --prefix=/opt/free
|
||||
CC=cc ./configure --prefix=/opt/free
|
||||
----
|
||||
|
||||
for Bourne-family shells, or
|
||||
@@ -63,11 +63,26 @@ shown. Otherwise, `Makefile` will be generated.
|
||||
On Linux, if development files for the libcap library are available, `chronyd`
|
||||
will be built with support for dropping root privileges. On other systems no
|
||||
extra library is needed. The default user which `chronyd` should run as can be
|
||||
specified with the `--with-user` option of the configure script.
|
||||
specified with the `--with-user` option of the `configure` script.
|
||||
|
||||
If development files for the POSIX threads library are available, `chronyd`
|
||||
will be built with support for asynchronous resolving of hostnames specified in
|
||||
the `server`, `peer`, and `pool` directives. This allows `chronyd` operating as
|
||||
a server to respond to client requests when resolving a hostname. If you don't
|
||||
want to enable the support, specify the `--disable-asyncdns` flag to
|
||||
`configure`.
|
||||
|
||||
If development files for the https://www.lysator.liu.se/~nisse/nettle/[Nettle],
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
|
||||
http://www.libtom.net/LibTomCrypt/[libtomcrypt] library are available,
|
||||
`chronyd` will be built with support for other cryptographic hash functions
|
||||
than MD5, which can be used for NTP authentication with a symmetric key. If you
|
||||
don't want to enable the support, specify the `--disable-sechash` flag to
|
||||
`configure`.
|
||||
|
||||
If development files for the editline or readline library are available,
|
||||
`chronyc` will be built with line editing support. If you don't want this,
|
||||
specify the `--disable-readline` flag to configure.
|
||||
specify the `--disable-readline` flag to `configure`.
|
||||
|
||||
If a `timepps.h` header is available (e.g. from the
|
||||
http://linuxpps.org[LinuxPPS project]), `chronyd` will be built with PPS API
|
||||
@@ -75,6 +90,9 @@ reference clock driver. If the header is installed in a location that isn't
|
||||
normally searched by the compiler, you can add it to the searched locations by
|
||||
setting the `CPPFLAGS` variable to `-I/path/to/timepps`.
|
||||
|
||||
The `--help` option can be specified to `configure` to print all options
|
||||
supported by the script.
|
||||
|
||||
Now type
|
||||
|
||||
----
|
||||
@@ -122,6 +140,16 @@ unprivileged user for `chronyd` and specify it with the `-u` command-line
|
||||
option or the `user` directive in the configuration file, or set the default
|
||||
user with the `--with-user` configure option before building.
|
||||
|
||||
== Support for system call filtering
|
||||
|
||||
`chronyd` can be built with support for the Linux secure computing (seccomp)
|
||||
facility. This requires development files for the
|
||||
https://github.com/seccomp/libseccomp[libseccomp] library and the
|
||||
`--enable-scfilter` option specified to `configure`. The `-F` option of
|
||||
`chronyd` will enable a system call filter, which should significantly reduce
|
||||
the kernel attack surface and possibly prevent kernel exploits from `chronyd`
|
||||
if it is compromised.
|
||||
|
||||
== Support for line editing libraries
|
||||
|
||||
`chronyc` can be built with support for line editing, this allows you to use
|
||||
@@ -132,12 +160,12 @@ Please note that readline since version 6.0 is licensed under GPLv3+ which is
|
||||
incompatible with chrony's license GPLv2. You should use editline instead if
|
||||
you don't want to use older readline versions.
|
||||
|
||||
The configure script will automatically enable the line editing support if one
|
||||
of the supported libraries is available. If they are both available, the
|
||||
The `configure` script will automatically enable the line editing support if
|
||||
one of the supported libraries is available. If they are both available, the
|
||||
editline library will be used.
|
||||
|
||||
If you don't want to use it (in which case chronyc will use a minimal command
|
||||
line interface), invoke configure like this:
|
||||
If you don't want to use it (in which case `chronyc` will use a minimal command
|
||||
line interface), invoke `configure` like this:
|
||||
|
||||
----
|
||||
./configure --disable-readline other-options...
|
||||
@@ -161,12 +189,12 @@ normally searched by the compiler and linker, you need to use extra options:
|
||||
|
||||
== Extra options for package builders
|
||||
|
||||
The configure and make procedures have some extra options that may be useful if
|
||||
you are building a distribution package for chrony.
|
||||
The `configure` and `make` procedures have some extra options that may be
|
||||
useful if you are building a distribution package for `chrony`.
|
||||
|
||||
The `--mandir=DIR` option to configure specifies an install directory for the
|
||||
man pages. This overrides the `man` subdirectory of the argument to the
|
||||
--prefix option.
|
||||
The `--mandir=DIR` option to `configure` specifies an installation directory
|
||||
for the man pages. This overrides the `man` subdirectory of the argument to the
|
||||
`--prefix` option.
|
||||
|
||||
----
|
||||
./configure --prefix=/usr --mandir=/usr/share/man
|
||||
@@ -174,8 +202,8 @@ man pages. This overrides the `man` subdirectory of the argument to the
|
||||
|
||||
to set both options together.
|
||||
|
||||
The final option is the `DESTDIR` option to the make command. For example, you
|
||||
could use the commands
|
||||
The final option is the `DESTDIR` option to the `make` command. For example,
|
||||
you could use the commands
|
||||
|
||||
----
|
||||
./configure --prefix=/usr --mandir=/usr/share/man
|
||||
|
||||
@@ -28,6 +28,9 @@ rtcsync
|
||||
# Specify file containing keys for NTP authentication.
|
||||
#keyfile /etc/chrony.keys
|
||||
|
||||
# Get TAI-UTC offset and leap seconds from the system tz database.
|
||||
#leapsectz right/UTC
|
||||
|
||||
# Specify directory for log files.
|
||||
logdir /var/log/chrony
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ driftfile /var/lib/chrony/drift
|
||||
|
||||
! pidfile /var/run/chronyd.pid
|
||||
|
||||
# If the system timezone database is kept up to date and includes the
|
||||
# right/UTC timezone, chronyd can use it to determine the current
|
||||
# TAI-UTC offset and when will the next leap second occur.
|
||||
|
||||
! leapsectz right/UTC
|
||||
|
||||
#######################################################################
|
||||
### INITIAL CLOCK CORRECTION
|
||||
# This option is useful to quickly correct the clock on start if it's
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
[ "$2" != "up" ] && [ "$2" != "down" ] && exit 0
|
||||
|
||||
# Check if there is a default route
|
||||
|
||||
if /sbin/ip route list 2> /dev/null | grep -q '^default'; then
|
||||
|
||||
120
hash_nettle.c
Normal file
120
hash_nettle.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines implementing crypto hashing using the nettle library.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include <nettle/nettle-meta.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
|
||||
struct hash {
|
||||
const char *name;
|
||||
const char *int_name;
|
||||
const struct nettle_hash *nettle_hash;
|
||||
void *context;
|
||||
};
|
||||
|
||||
static struct hash hashes[] = {
|
||||
{ "MD5", "md5", NULL, NULL },
|
||||
{ "RMD160", "ripemd160", NULL, NULL },
|
||||
{ "SHA1", "sha1", NULL, NULL },
|
||||
{ "SHA256", "sha256", NULL, NULL },
|
||||
{ "SHA384", "sha384", NULL, NULL },
|
||||
{ "SHA512", "sha512", NULL, NULL },
|
||||
{ "SHA3-224", "sha3_224", NULL, NULL },
|
||||
{ "SHA3-256", "sha3_256", NULL, NULL },
|
||||
{ "SHA3-384", "sha3_384", NULL, NULL },
|
||||
{ "SHA3-512", "sha3_512", NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
{
|
||||
int id, nid;
|
||||
|
||||
for (id = 0; hashes[id].name; id++) {
|
||||
if (!strcmp(name, hashes[id].name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hashes[id].name)
|
||||
return -1;
|
||||
|
||||
if (hashes[id].context)
|
||||
return id;
|
||||
|
||||
for (nid = 0; nettle_hashes[nid]; nid++) {
|
||||
if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
|
||||
return -1;
|
||||
|
||||
hashes[id].nettle_hash = nettle_hashes[nid];
|
||||
hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
{
|
||||
const struct nettle_hash *hash;
|
||||
void *context;
|
||||
|
||||
hash = hashes[id].nettle_hash;
|
||||
context = hashes[id].context;
|
||||
|
||||
if (out_len > hash->digest_size)
|
||||
out_len = hash->digest_size;
|
||||
|
||||
hash->init(context);
|
||||
hash->update(context, in1_len, in1);
|
||||
if (in2)
|
||||
hash->update(context, in2_len, in2);
|
||||
hash->digest(context, out_len, out);
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
void
|
||||
HSH_Finalise(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; hashes[i].name; i++) {
|
||||
if (hashes[i].context)
|
||||
Free(hashes[i].context);
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
{
|
||||
unsigned int ret;
|
||||
unsigned int ret = 0;
|
||||
|
||||
NSSLOWHASH_Begin(hashes[id].context);
|
||||
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
|
||||
|
||||
@@ -62,6 +62,12 @@ static const struct hash hashes[] = {
|
||||
#ifdef LTC_SHA512
|
||||
{ "SHA512", "sha512", &sha512_desc },
|
||||
#endif
|
||||
#ifdef LTC_SHA3
|
||||
{ "SHA3-224", "sha3-224", &sha3_224_desc },
|
||||
{ "SHA3-256", "sha3-256", &sha3_256_desc },
|
||||
{ "SHA3-384", "sha3-384", &sha3_384_desc },
|
||||
{ "SHA3-512", "sha3-512", &sha3_512_desc },
|
||||
#endif
|
||||
#ifdef LTC_TIGER
|
||||
{ "TIGER", "tiger", &tiger_desc },
|
||||
#endif
|
||||
|
||||
30
logging.c
30
logging.c
@@ -79,11 +79,11 @@ LOG_Initialise(void)
|
||||
void
|
||||
LOG_Finalise(void)
|
||||
{
|
||||
if (system_log) {
|
||||
if (system_log)
|
||||
closelog();
|
||||
} else {
|
||||
|
||||
if (file_log)
|
||||
fclose(file_log);
|
||||
}
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
@@ -116,7 +116,7 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
|
||||
assert(0);
|
||||
}
|
||||
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
|
||||
} else {
|
||||
} else if (file_log) {
|
||||
fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ void LOG_Message(LOG_Severity severity,
|
||||
time_t t;
|
||||
struct tm stm;
|
||||
|
||||
if (!system_log) {
|
||||
if (!system_log && file_log) {
|
||||
/* Don't clutter up syslog with timestamps and internal debugging info */
|
||||
time(&t);
|
||||
stm = *gmtime(&t);
|
||||
@@ -160,16 +160,14 @@ void LOG_Message(LOG_Severity severity,
|
||||
case LOGS_FATAL:
|
||||
log_message(1, severity, buf);
|
||||
|
||||
/* With syslog, send the message also to the grandparent
|
||||
process or write it to stderr if not detached */
|
||||
if (system_log) {
|
||||
if (parent_fd > 0) {
|
||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
/* Send the message also to the foreground process if it is
|
||||
still running, or stderr if it is still open */
|
||||
if (parent_fd > 0) {
|
||||
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
|
||||
; /* Not much we can do here */
|
||||
} else if (system_log && parent_fd == 0) {
|
||||
system_log = 0;
|
||||
log_message(1, severity, buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -220,6 +218,8 @@ void
|
||||
LOG_SetParentFd(int fd)
|
||||
{
|
||||
parent_fd = fd;
|
||||
if (file_log == stderr)
|
||||
file_log = NULL;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
@@ -105,7 +105,7 @@ extern void LOG_OpenFileLog(const char *log_file);
|
||||
/* Log messages to syslog instead of stderr */
|
||||
extern void LOG_OpenSystemLog(void);
|
||||
|
||||
/* Send fatal message also to the foreground process */
|
||||
/* Stop using stderr and send fatal message to the foreground process */
|
||||
extern void LOG_SetParentFd(int fd);
|
||||
|
||||
/* Close the pipe to the foreground process so it can exit */
|
||||
|
||||
29
main.c
29
main.c
@@ -292,6 +292,8 @@ write_pidfile(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define DEV_NULL "/dev/null"
|
||||
|
||||
static void
|
||||
go_daemon(void)
|
||||
{
|
||||
@@ -352,6 +354,13 @@ go_daemon(void)
|
||||
}
|
||||
|
||||
LOG_SetParentFd(pipefd[1]);
|
||||
|
||||
/* Open /dev/null as new stdin/out/err */
|
||||
errno = 0;
|
||||
if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
|
||||
open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
|
||||
open(DEV_NULL, O_RDWR) != STDERR_FILENO)
|
||||
LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -524,6 +533,16 @@ int main
|
||||
/* Write our pidfile to prevent other chronyds running */
|
||||
write_pidfile();
|
||||
|
||||
if (!user)
|
||||
user = CNF_GetUser();
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (!pw)
|
||||
LOG_FATAL("Could not get user/group ID of %s", user);
|
||||
|
||||
/* Create directories for sockets, log files, and dump files */
|
||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
PRV_Initialise();
|
||||
LCL_Initialise();
|
||||
SCH_Initialise();
|
||||
@@ -551,16 +570,6 @@ int main
|
||||
SYS_LockMemory();
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
user = CNF_GetUser();
|
||||
}
|
||||
|
||||
if ((pw = getpwnam(user)) == NULL)
|
||||
LOG_FATAL("Could not get %s uid/gid", user);
|
||||
|
||||
/* Create all directories before dropping root */
|
||||
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
/* Drop root privileges if the specified user has a non-zero UID */
|
||||
if (!geteuid() && (pw->pw_uid || pw->pw_gid))
|
||||
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
|
||||
|
||||
14
nameserv.c
14
nameserv.c
@@ -53,7 +53,19 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
memset(&hints, 0, sizeof (hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
switch (address_family) {
|
||||
case IPADDR_INET4:
|
||||
hints.ai_family = AF_INET;
|
||||
break;
|
||||
#ifdef FEAT_IPV6
|
||||
case IPADDR_INET6:
|
||||
hints.ai_family = AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
}
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
result = getaddrinfo(name, NULL, &hints, &res);
|
||||
|
||||
165
ntp_core.c
165
ntp_core.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017
|
||||
* Copyright (C) Miroslav Lichvar 2009-2018
|
||||
*
|
||||
* 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
|
||||
@@ -88,6 +88,7 @@ struct NCR_Instance_Record {
|
||||
SCH_TimeoutID tx_timeout_id; /* Timeout ID for next transmission */
|
||||
int tx_suspended; /* Boolean indicating we can't transmit yet */
|
||||
|
||||
int auto_burst; /* If 1, initiate a burst on each poll */
|
||||
int auto_offline; /* If 1, automatically go offline if server/peer
|
||||
isn't responding */
|
||||
|
||||
@@ -149,14 +150,11 @@ struct NCR_Instance_Record {
|
||||
be used for synchronisation */
|
||||
int valid_timestamps;
|
||||
|
||||
/* Flag indicating the timestamps below were updated since last request */
|
||||
int updated_timestamps;
|
||||
|
||||
/* Receive and transmit timestamps from the last received packet */
|
||||
/* Receive and transmit timestamps from the last valid response */
|
||||
NTP_int64 remote_ntp_rx;
|
||||
NTP_int64 remote_ntp_tx;
|
||||
|
||||
/* Local timestamp when the last packet was received from the
|
||||
/* Local timestamp when the last valid response was received from the
|
||||
source. We have to be prepared to tinker with this if the local
|
||||
clock has its frequency adjusted before we repond. The value we
|
||||
store here is what our own local time was when the same arrived.
|
||||
@@ -183,6 +181,15 @@ struct NCR_Instance_Record {
|
||||
int prev_local_poll;
|
||||
unsigned int prev_tx_count;
|
||||
|
||||
/* Flag indicating the two timestamps below were updated since the
|
||||
last transmission */
|
||||
int updated_init_timestamps;
|
||||
|
||||
/* Timestamps used for (re)starting the symmetric protocol, when we
|
||||
need to respond to a packet which is not a valid response */
|
||||
NTP_int64 init_remote_ntp_tx;
|
||||
NTP_Local_Timestamp init_local_rx;
|
||||
|
||||
/* The instance record in the main source management module. This
|
||||
performs the statistical analysis on the samples we generate */
|
||||
|
||||
@@ -230,6 +237,10 @@ static ARR_Instance broadcasts;
|
||||
#define IBURST_GOOD_SAMPLES 4
|
||||
#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
|
||||
|
||||
/* Number of samples in automatic burst */
|
||||
#define BURST_GOOD_SAMPLES 1
|
||||
#define MAX_BURST_TOTAL_SAMPLES 4
|
||||
|
||||
/* Time to wait after sending packet to 'warm up' link */
|
||||
#define WARM_UP_DELAY 2.0
|
||||
|
||||
@@ -551,6 +562,7 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||
result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
|
||||
result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
|
||||
result->offset_correction = params->offset;
|
||||
result->auto_burst = params->burst;
|
||||
result->auto_offline = params->auto_offline;
|
||||
result->poll_target = params->poll_target;
|
||||
|
||||
@@ -652,7 +664,6 @@ NCR_ResetInstance(NCR_Instance instance)
|
||||
|
||||
instance->valid_rx = 0;
|
||||
instance->valid_timestamps = 0;
|
||||
instance->updated_timestamps = 0;
|
||||
UTI_ZeroNtp64(&instance->remote_ntp_rx);
|
||||
UTI_ZeroNtp64(&instance->remote_ntp_tx);
|
||||
UTI_ZeroNtp64(&instance->local_ntp_rx);
|
||||
@@ -662,6 +673,10 @@ NCR_ResetInstance(NCR_Instance instance)
|
||||
zero_local_timestamp(&instance->prev_local_tx);
|
||||
instance->prev_local_poll = 0;
|
||||
instance->prev_tx_count = 0;
|
||||
|
||||
instance->updated_init_timestamps = 0;
|
||||
UTI_ZeroNtp64(&instance->init_remote_ntp_tx);
|
||||
zero_local_timestamp(&instance->init_local_rx);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -890,8 +905,10 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
|
||||
NTP_Local_Timestamp *local_tx, /* The TX time of the previous packet
|
||||
RESULT : TX time of this packet */
|
||||
NTP_int64 *local_ntp_rx, /* RESULT : receive timestamp from this packet */
|
||||
NTP_int64 *local_ntp_tx, /* RESULT : transmit timestamp from this packet */
|
||||
NTP_int64 *local_ntp_rx, /* The receive timestamp from the previous packet
|
||||
RESULT : receive timestamp from this packet */
|
||||
NTP_int64 *local_ntp_tx, /* The transmit timestamp from the previous packet
|
||||
RESULT : transmit timestamp from this packet */
|
||||
NTP_Remote_Address *where_to, /* Where to address the reponse to */
|
||||
NTP_Local_Address *from /* From what address to send it */
|
||||
)
|
||||
@@ -914,8 +931,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
version = NTP_VERSION;
|
||||
}
|
||||
|
||||
/* Allow interleaved mode only if there was a prior transmission */
|
||||
if (interleaved && (!local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
|
||||
/* Check if the packet can be formed in the interleaved mode */
|
||||
if (interleaved && (!remote_ntp_rx || !local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
|
||||
interleaved = 0;
|
||||
|
||||
smooth_time = 0;
|
||||
@@ -989,14 +1006,21 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
/* Originate - this comes from the last packet the source sent us */
|
||||
message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
|
||||
|
||||
/* Prepare random bits which will be added to the receive timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
do {
|
||||
/* Prepare random bits which will be added to the receive timestamp */
|
||||
UTI_GetNtp64Fuzz(&ts_fuzz, precision);
|
||||
|
||||
/* Receive - this is when we received the last packet from the source.
|
||||
This timestamp will have been adjusted so that it will now look to
|
||||
the source like we have been running on our latest estimate of
|
||||
frequency all along */
|
||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||
/* Receive - this is when we received the last packet from the source.
|
||||
This timestamp will have been adjusted so that it will now look to
|
||||
the source like we have been running on our latest estimate of
|
||||
frequency all along */
|
||||
UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
|
||||
|
||||
/* Do not send a packet with a non-zero receive timestamp equal to the
|
||||
originate timestamp or previous receive timestamp */
|
||||
} while (!UTI_IsZeroNtp64(&message.receive_ts) &&
|
||||
UTI_IsEqualAnyNtp64(&message.receive_ts, &message.originate_ts,
|
||||
local_ntp_rx, NULL));
|
||||
} else {
|
||||
UTI_ZeroNtp64(&message.originate_ts);
|
||||
UTI_ZeroNtp64(&message.receive_ts);
|
||||
@@ -1055,10 +1079,16 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||
&message.transmit_ts, &ts_fuzz);
|
||||
}
|
||||
|
||||
/* Avoid sending messages with non-zero transmit timestamp equal to the
|
||||
receive timestamp to allow reliable detection of the interleaved mode */
|
||||
} while (!UTI_CompareNtp64(&message.transmit_ts, &message.receive_ts) &&
|
||||
!UTI_IsZeroNtp64(&message.transmit_ts));
|
||||
/* Do not send a packet with a non-zero transmit timestamp which is
|
||||
equal to any of the following timestamps:
|
||||
- receive (to allow reliable detection of the interleaved mode)
|
||||
- originate (to prevent the packet from being its own valid response
|
||||
in the symmetric mode)
|
||||
- previous transmit (to invalidate responses to the previous packet)
|
||||
(the precision must be at least -30 to prevent an infinite loop!) */
|
||||
} while (!UTI_IsZeroNtp64(&message.transmit_ts) &&
|
||||
UTI_IsEqualAnyNtp64(&message.transmit_ts, &message.receive_ts,
|
||||
&message.originate_ts, local_ntp_tx));
|
||||
|
||||
ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
|
||||
|
||||
@@ -1084,7 +1114,7 @@ transmit_timeout(void *arg)
|
||||
{
|
||||
NCR_Instance inst = (NCR_Instance) arg;
|
||||
NTP_Local_Address local_addr;
|
||||
int interleaved, sent;
|
||||
int interleaved, initial, sent;
|
||||
|
||||
inst->tx_timeout_id = 0;
|
||||
|
||||
@@ -1093,10 +1123,20 @@ transmit_timeout(void *arg)
|
||||
/* With online burst switch to online before last packet */
|
||||
if (inst->burst_total_samples_to_go <= 1)
|
||||
inst->opmode = MD_ONLINE;
|
||||
break;
|
||||
case MD_BURST_WAS_OFFLINE:
|
||||
if (inst->burst_total_samples_to_go <= 0)
|
||||
take_offline(inst);
|
||||
break;
|
||||
case MD_ONLINE:
|
||||
/* Start a new burst if the burst option is enabled and the average
|
||||
polling interval including the burst will not fall below the
|
||||
minimum polling interval */
|
||||
if (inst->auto_burst && inst->local_poll > inst->minpoll && inst->local_poll > 1)
|
||||
NCR_InitiateSampleBurst(inst, BURST_GOOD_SAMPLES,
|
||||
MIN(1 << (inst->local_poll - inst->minpoll),
|
||||
MAX_BURST_TOTAL_SAMPLES));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1137,6 +1177,19 @@ transmit_timeout(void *arg)
|
||||
(inst->mode == MODE_ACTIVE &&
|
||||
inst->prev_tx_count == 1 && inst->tx_count == 0));
|
||||
|
||||
/* In symmetric mode, if no valid response was received since the previous
|
||||
transmission, respond to the last received packet even if it failed some
|
||||
specific NTP tests. This is necessary for starting and restarting the
|
||||
protocol, e.g. when a packet was lost. */
|
||||
initial = inst->mode == MODE_ACTIVE && !inst->valid_rx &&
|
||||
!UTI_IsZeroNtp64(&inst->init_remote_ntp_tx);
|
||||
|
||||
/* Prepare for the response */
|
||||
inst->valid_rx = 0;
|
||||
inst->updated_init_timestamps = 0;
|
||||
if (initial)
|
||||
inst->valid_timestamps = 0;
|
||||
|
||||
/* Check whether we need to 'warm up' the link to the other end by
|
||||
sending an NTP exchange to ensure both ends' ARP caches are
|
||||
primed or whether we need to send two packets first to ensure a
|
||||
@@ -1148,18 +1201,16 @@ transmit_timeout(void *arg)
|
||||
inst->presend_done--;
|
||||
}
|
||||
|
||||
sent = transmit_packet(inst->mode, interleaved, inst->local_poll,
|
||||
inst->version,
|
||||
/* Send the request (which may also be a response in the symmetric mode) */
|
||||
sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
|
||||
inst->auth_mode, inst->auth_key_id,
|
||||
&inst->remote_ntp_rx, &inst->remote_ntp_tx,
|
||||
&inst->local_rx, &inst->local_tx,
|
||||
&inst->local_ntp_rx, &inst->local_ntp_tx,
|
||||
&inst->remote_addr,
|
||||
&local_addr);
|
||||
initial ? NULL : &inst->remote_ntp_rx,
|
||||
initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
|
||||
initial ? &inst->init_local_rx : &inst->local_rx,
|
||||
&inst->local_tx, &inst->local_ntp_rx, &inst->local_ntp_tx,
|
||||
&inst->remote_addr, &local_addr);
|
||||
|
||||
++inst->tx_count;
|
||||
inst->valid_rx = 0;
|
||||
inst->updated_timestamps = 0;
|
||||
if (sent)
|
||||
inst->report.total_tx_count++;
|
||||
|
||||
@@ -1442,6 +1493,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp local_receive, local_transmit;
|
||||
double remote_interval, local_interval, response_time;
|
||||
double delay_time, precision;
|
||||
int updated_timestamps;
|
||||
|
||||
/* ==================== */
|
||||
|
||||
@@ -1459,7 +1511,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
The test values are 1 when passed and 0 when failed. */
|
||||
|
||||
/* Test 1 checks for duplicate packet */
|
||||
test1 = !!UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
|
||||
test1 = UTI_CompareNtp64(&message->receive_ts, &inst->remote_ntp_rx) ||
|
||||
UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
|
||||
|
||||
/* Test 2 checks for bogus packet in the basic and interleaved modes. This
|
||||
ensures the source is responding to the latest packet we sent to it. */
|
||||
@@ -1644,21 +1697,34 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
The authentication test (test5) is required to prevent DoS attacks using
|
||||
unauthenticated packets on authenticated symmetric associations. */
|
||||
if ((inst->mode == MODE_CLIENT && valid_packet && !inst->valid_rx) ||
|
||||
(inst->mode == MODE_ACTIVE && (valid_packet || !inst->valid_rx) &&
|
||||
test5 && !UTI_IsZeroNtp64(&message->transmit_ts) &&
|
||||
(!inst->updated_timestamps || (valid_packet && !inst->valid_rx) ||
|
||||
(inst->mode == MODE_ACTIVE && valid_packet &&
|
||||
(!inst->valid_rx ||
|
||||
UTI_CompareNtp64(&inst->remote_ntp_tx, &message->transmit_ts) < 0))) {
|
||||
inst->remote_ntp_rx = message->receive_ts;
|
||||
inst->remote_ntp_tx = message->transmit_ts;
|
||||
inst->local_rx = *rx_ts;
|
||||
inst->valid_timestamps = synced_packet;
|
||||
inst->updated_timestamps = 1;
|
||||
|
||||
UTI_ZeroNtp64(&inst->init_remote_ntp_tx);
|
||||
zero_local_timestamp(&inst->init_local_rx);
|
||||
inst->updated_init_timestamps = 0;
|
||||
updated_timestamps = 2;
|
||||
|
||||
/* Don't use the same set of timestamps for the next sample */
|
||||
if (interleaved_packet)
|
||||
inst->prev_local_tx = inst->local_tx;
|
||||
else
|
||||
zero_local_timestamp(&inst->prev_local_tx);
|
||||
} else if (inst->mode == MODE_ACTIVE &&
|
||||
test1 && !UTI_IsZeroNtp64(&message->transmit_ts) && test5 &&
|
||||
(!inst->updated_init_timestamps ||
|
||||
UTI_CompareNtp64(&inst->init_remote_ntp_tx, &message->transmit_ts) < 0)) {
|
||||
inst->init_remote_ntp_tx = message->transmit_ts;
|
||||
inst->init_local_rx = *rx_ts;
|
||||
inst->updated_init_timestamps = 1;
|
||||
updated_timestamps = 1;
|
||||
} else {
|
||||
updated_timestamps = 0;
|
||||
}
|
||||
|
||||
/* Accept at most one response per request. The NTP specification recommends
|
||||
@@ -1694,10 +1760,11 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||
DEBUG_LOG("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
|
||||
remote_interval, local_interval, response_time,
|
||||
tss_chars[local_transmit.source], tss_chars[local_receive.source]);
|
||||
DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d presend=%d valid=%d good=%d updated=%d",
|
||||
DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d"
|
||||
" presend=%d valid=%d good=%d updated=%d",
|
||||
test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
|
||||
kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
|
||||
!UTI_CompareTimespecs(&inst->local_rx.ts, &rx_ts->ts));
|
||||
updated_timestamps);
|
||||
|
||||
if (valid_packet) {
|
||||
inst->remote_poll = message->poll;
|
||||
@@ -1988,7 +2055,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
NTP_Mode pkt_mode, my_mode;
|
||||
NTP_int64 *local_ntp_rx, *local_ntp_tx;
|
||||
NTP_Local_Timestamp local_tx, *tx_ts;
|
||||
int valid_auth, log_index, interleaved, poll;
|
||||
int pkt_version, valid_auth, log_index, interleaved, poll;
|
||||
AuthenticationMode auth_mode;
|
||||
uint32_t key_id;
|
||||
|
||||
@@ -2009,6 +2076,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
}
|
||||
|
||||
pkt_mode = NTP_LVM_TO_MODE(message->lvm);
|
||||
pkt_version = NTP_LVM_TO_VERSION(message->lvm);
|
||||
|
||||
switch (pkt_mode) {
|
||||
case MODE_ACTIVE:
|
||||
@@ -2019,6 +2087,15 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
/* Reply with server packet */
|
||||
my_mode = MODE_SERVER;
|
||||
break;
|
||||
case MODE_UNDEFINED:
|
||||
/* Check if it is an NTPv1 client request (NTPv1 packets have a reserved
|
||||
field instead of the mode field and the actual mode is determined from
|
||||
the port numbers). Don't ever respond with a mode 0 packet! */
|
||||
if (pkt_version == 1 && remote_addr->port != NTP_PORT) {
|
||||
my_mode = MODE_SERVER;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
/* Discard */
|
||||
DEBUG_LOG("NTP packet discarded pkt_mode=%d", pkt_mode);
|
||||
@@ -2064,7 +2141,8 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
if (log_index >= 0) {
|
||||
CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
|
||||
interleaved = !UTI_IsZeroNtp64(local_ntp_rx) &&
|
||||
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx);
|
||||
!UTI_CompareNtp64(&message->originate_ts, local_ntp_rx) &&
|
||||
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts);
|
||||
|
||||
if (interleaved) {
|
||||
UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
|
||||
@@ -2081,7 +2159,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||
poll = MAX(poll, message->poll);
|
||||
|
||||
/* Send a reply */
|
||||
transmit_packet(my_mode, interleaved, poll, NTP_LVM_TO_VERSION(message->lvm),
|
||||
transmit_packet(my_mode, interleaved, poll, pkt_version,
|
||||
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
|
||||
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
|
||||
|
||||
@@ -2189,6 +2267,9 @@ NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double dof
|
||||
if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
|
||||
UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
|
||||
doffset);
|
||||
if (!UTI_IsZeroTimespec(&inst->init_local_rx.ts))
|
||||
UTI_AdjustTimespec(&inst->init_local_rx.ts, when, &inst->init_local_rx.ts, &delta, dfreq,
|
||||
doffset);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
22
ntp_io.c
22
ntp_io.c
@@ -318,6 +318,9 @@ close_socket(int sock_fd)
|
||||
if (sock_fd == INVALID_SOCK_FD)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
NIO_Linux_NotifySocketClosing(sock_fd);
|
||||
#endif
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
}
|
||||
@@ -685,6 +688,11 @@ read_from_socket(int sock_fd, int event, void *anything)
|
||||
unsigned int i, n;
|
||||
int status, flags = 0;
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
if (NIO_Linux_ProcessEvent(sock_fd, event))
|
||||
return;
|
||||
#endif
|
||||
|
||||
hdr = ARR_GetElements(recv_headers);
|
||||
n = ARR_GetSize(recv_headers);
|
||||
assert(n >= 1);
|
||||
@@ -709,6 +717,20 @@ read_from_socket(int sock_fd, int event, void *anything)
|
||||
#endif
|
||||
|
||||
if (status < 0) {
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
/* If reading from the error queue failed, the exception should be
|
||||
for a socket error. Clear the error to avoid a busy loop. */
|
||||
if (flags & MSG_ERRQUEUE) {
|
||||
int error = 0;
|
||||
socklen_t len = sizeof (error);
|
||||
|
||||
if (getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, &error, &len))
|
||||
DEBUG_LOG("Could not get SO_ERROR");
|
||||
if (error)
|
||||
errno = error;
|
||||
}
|
||||
#endif
|
||||
|
||||
DEBUG_LOG("Could not receive from fd %d : %s", sock_fd,
|
||||
strerror(errno));
|
||||
return;
|
||||
|
||||
159
ntp_io_linux.c
159
ntp_io_linux.c
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||
* Copyright (C) Miroslav Lichvar 2016-2018
|
||||
*
|
||||
* 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
|
||||
@@ -94,6 +94,27 @@ static int ts_tx_flags;
|
||||
/* Flag indicating the socket options can't be changed in control messages */
|
||||
static int permanent_ts_options;
|
||||
|
||||
/* When sending client requests to a close and fast server, it is possible that
|
||||
a response will be received before the HW transmit timestamp of the request
|
||||
itself. To avoid processing of the response without the HW timestamp, we
|
||||
monitor events returned by select() and suspend reading of packets from the
|
||||
receive queue for up to 200 microseconds. As the requests are normally
|
||||
separated by at least 200 milliseconds, it is sufficient to monitor and
|
||||
suspend one socket at a time. */
|
||||
static int monitored_socket;
|
||||
static int suspended_socket;
|
||||
static SCH_TimeoutID resume_timeout_id;
|
||||
|
||||
#define RESUME_TIMEOUT 200.0e-6
|
||||
|
||||
/* Unbound socket keeping the kernel RX timestamping permanently enabled
|
||||
in order to avoid a race condition between receiving a server response
|
||||
and the kernel actually starting to timestamp received packets after
|
||||
enabling the timestamping and sending a request */
|
||||
static int dummy_rxts_socket;
|
||||
|
||||
#define INVALID_SOCK_FD -3
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
@@ -252,7 +273,7 @@ update_interface_speed(struct Interface *iface)
|
||||
{
|
||||
struct ethtool_cmd cmd;
|
||||
struct ifreq req;
|
||||
int sock_fd;
|
||||
int sock_fd, link_speed;
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock_fd < 0)
|
||||
@@ -273,7 +294,12 @@ update_interface_speed(struct Interface *iface)
|
||||
|
||||
close(sock_fd);
|
||||
|
||||
iface->link_speed = ethtool_cmd_speed(&cmd);
|
||||
link_speed = ethtool_cmd_speed(&cmd);
|
||||
|
||||
if (iface->link_speed != link_speed) {
|
||||
iface->link_speed = link_speed;
|
||||
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -301,6 +327,29 @@ check_timestamping_option(int option)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_dummy_socket(void)
|
||||
{
|
||||
int sock_fd, events = 0;
|
||||
|
||||
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0
|
||||
#ifdef FEAT_IPV6
|
||||
&& (sock_fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0
|
||||
#endif
|
||||
)
|
||||
return INVALID_SOCK_FD;
|
||||
|
||||
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
|
||||
close(sock_fd);
|
||||
return INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(sock_fd);
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_Initialise(void)
|
||||
{
|
||||
@@ -350,6 +399,10 @@ NIO_Linux_Initialise(void)
|
||||
|
||||
/* Kernels before 4.7 ignore timestamping flags set in control messages */
|
||||
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
|
||||
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
dummy_rxts_socket = INVALID_SOCK_FD;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -360,6 +413,9 @@ NIO_Linux_Finalise(void)
|
||||
struct Interface *iface;
|
||||
unsigned int i;
|
||||
|
||||
if (dummy_rxts_socket != INVALID_SOCK_FD)
|
||||
close(dummy_rxts_socket);
|
||||
|
||||
for (i = 0; i < ARR_GetSize(interfaces); i++) {
|
||||
iface = ARR_GetElement(interfaces, i);
|
||||
HCL_DestroyInstance(iface->clock);
|
||||
@@ -406,6 +462,73 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resume_socket(int sock_fd)
|
||||
{
|
||||
if (monitored_socket == sock_fd)
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
if (sock_fd == INVALID_SOCK_FD || sock_fd != suspended_socket)
|
||||
return;
|
||||
|
||||
suspended_socket = INVALID_SOCK_FD;
|
||||
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_INPUT, 1);
|
||||
|
||||
DEBUG_LOG("Resumed RX processing %s timeout fd=%d",
|
||||
resume_timeout_id ? "before" : "on", sock_fd);
|
||||
|
||||
if (resume_timeout_id) {
|
||||
SCH_RemoveTimeout(resume_timeout_id);
|
||||
resume_timeout_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
resume_timeout(void *arg)
|
||||
{
|
||||
resume_timeout_id = 0;
|
||||
resume_socket(suspended_socket);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
suspend_socket(int sock_fd)
|
||||
{
|
||||
resume_socket(suspended_socket);
|
||||
|
||||
suspended_socket = sock_fd;
|
||||
|
||||
SCH_SetFileHandlerEvent(suspended_socket, SCH_FILE_INPUT, 0);
|
||||
resume_timeout_id = SCH_AddTimeoutByDelay(RESUME_TIMEOUT, resume_timeout, NULL);
|
||||
|
||||
DEBUG_LOG("Suspended RX processing fd=%d", sock_fd);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NIO_Linux_ProcessEvent(int sock_fd, int event)
|
||||
{
|
||||
if (sock_fd != monitored_socket)
|
||||
return 0;
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
suspend_socket(monitored_socket);
|
||||
monitored_socket = INVALID_SOCK_FD;
|
||||
|
||||
/* Don't process the message yet */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static struct Interface *
|
||||
get_interface(int if_index)
|
||||
{
|
||||
@@ -614,6 +737,11 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||
} else {
|
||||
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
|
||||
}
|
||||
|
||||
/* If a HW transmit timestamp was received, resume processing
|
||||
of non-error messages on this socket */
|
||||
if (is_tx)
|
||||
resume_socket(local_addr->sock_fd);
|
||||
}
|
||||
|
||||
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&ts3.ts[0]) &&
|
||||
@@ -638,6 +766,14 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
|
||||
}
|
||||
}
|
||||
|
||||
/* If the kernel is slow with enabling RX timestamping, open a dummy
|
||||
socket to keep the kernel RX timestamping permanently enabled */
|
||||
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
|
||||
DEBUG_LOG("Missing kernel RX timestamp");
|
||||
if (dummy_rxts_socket == INVALID_SOCK_FD)
|
||||
dummy_rxts_socket = open_dummy_socket();
|
||||
}
|
||||
|
||||
/* Return the message if it's not received from the error queue */
|
||||
if (!is_tx)
|
||||
return 0;
|
||||
@@ -682,6 +818,15 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
||||
{
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (!ts_flags)
|
||||
return cmsglen;
|
||||
|
||||
/* If a HW transmit timestamp is requested on a client socket, monitor
|
||||
events on the socket in order to avoid processing of a fast response
|
||||
without the HW timestamp of the request */
|
||||
if (ts_tx_flags & SOF_TIMESTAMPING_TX_HARDWARE && !NIO_IsServerSocket(sock_fd))
|
||||
monitored_socket = sock_fd;
|
||||
|
||||
/* Check if TX timestamping is disabled on this socket */
|
||||
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
|
||||
return cmsglen;
|
||||
@@ -701,3 +846,11 @@ NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
|
||||
|
||||
return cmsglen;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
NIO_Linux_NotifySocketClosing(int sock_fd)
|
||||
{
|
||||
resume_socket(sock_fd);
|
||||
}
|
||||
|
||||
@@ -24,13 +24,22 @@
|
||||
This is the header file for the Linux-specific NTP socket I/O bits.
|
||||
*/
|
||||
|
||||
#ifndef GOT_NTP_IO_LINUX_H
|
||||
#define GOT_NTP_IO_LINUX_H
|
||||
|
||||
extern void NIO_Linux_Initialise(void);
|
||||
|
||||
extern void NIO_Linux_Finalise(void);
|
||||
|
||||
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
|
||||
|
||||
extern int NIO_Linux_ProcessEvent(int sock_fd, int event);
|
||||
|
||||
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
|
||||
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length);
|
||||
|
||||
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
|
||||
|
||||
extern void NIO_Linux_NotifySocketClosing(int sock_fd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -235,7 +235,7 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||
return;
|
||||
|
||||
/* Disable output and wait for a response */
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
|
||||
}
|
||||
|
||||
if (event == SCH_FILE_INPUT) {
|
||||
@@ -283,7 +283,7 @@ read_write_socket(int sock_fd, int event, void *anything)
|
||||
/* Move the head and enable output for the next packet */
|
||||
queue_head = NEXT_QUEUE_INDEX(queue_head);
|
||||
if (!IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
|
||||
|
||||
/* Enable output if there was no pending request */
|
||||
if (IS_QUEUE_EMPTY())
|
||||
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
|
||||
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
|
||||
|
||||
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
|
||||
|
||||
|
||||
@@ -206,12 +206,13 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
|
||||
unsigned short port;
|
||||
|
||||
size = ARR_GetSize(records);
|
||||
|
||||
*slot = 0;
|
||||
*found = 0;
|
||||
|
||||
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
|
||||
remote_addr->ip_addr.family != IPADDR_INET6) {
|
||||
*found = *slot = 0;
|
||||
remote_addr->ip_addr.family != IPADDR_INET6)
|
||||
return;
|
||||
}
|
||||
|
||||
hash = UTI_IPToHash(&remote_addr->ip_addr);
|
||||
port = remote_addr->port;
|
||||
@@ -230,8 +231,6 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*found = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
19
pktlength.c
19
pktlength.c
@@ -118,6 +118,7 @@ static const struct request_length request_lengths[] = {
|
||||
{ 0, 0 }, /* ADD_PEER2 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER3 */
|
||||
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER3 */
|
||||
REQ_LENGTH_ENTRY(null, null), /* SHUTDOWN */
|
||||
};
|
||||
|
||||
static const uint16_t reply_lengths[] = {
|
||||
@@ -132,13 +133,14 @@ static const uint16_t reply_lengths[] = {
|
||||
0, /* SUBNETS_ACCESSED - not supported */
|
||||
0, /* CLIENT_ACCESSES - not supported */
|
||||
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
|
||||
0, /* MANUAL_LIST - variable length */
|
||||
0, /* MANUAL_LIST - not supported */
|
||||
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
|
||||
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
|
||||
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
|
||||
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
|
||||
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
|
||||
RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -195,21 +197,6 @@ PKL_ReplyLength(CMD_Reply *r)
|
||||
if (type < 1 || type >= N_REPLY_TYPES)
|
||||
return 0;
|
||||
|
||||
/* Length of MANUAL_LIST depends on number of samples stored in it */
|
||||
if (type == RPY_MANUAL_LIST) {
|
||||
uint32_t ns;
|
||||
|
||||
if (r->status != htons(STT_SUCCESS))
|
||||
return offsetof(CMD_Reply, data);
|
||||
|
||||
ns = ntohl(r->data.manual_list.n_samples);
|
||||
if (ns > MAX_MANUAL_LIST_SAMPLES)
|
||||
return 0;
|
||||
|
||||
return offsetof(CMD_Reply, data.manual_list.samples) +
|
||||
ns * sizeof (RPY_ManualListSample);
|
||||
}
|
||||
|
||||
return reply_lengths[type];
|
||||
}
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ do_bind_socket(ReqBindSocket *req, PrvResponse *res)
|
||||
sock_fd = req->sock;
|
||||
|
||||
UTI_SockaddrToIPAndPort(sa, &ip, &port);
|
||||
if (port && port != CNF_GetNTPPort()) {
|
||||
if (port && port != CNF_GetNTPPort() && port != CNF_GetAcquisitionPort()) {
|
||||
close(sock_fd);
|
||||
res_fatal(res, "Invalid port %d", port);
|
||||
return;
|
||||
@@ -579,7 +579,8 @@ PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len)
|
||||
unsigned short port;
|
||||
|
||||
UTI_SockaddrToIPAndPort(address, &ip, &port);
|
||||
assert(!port || port == CNF_GetNTPPort());
|
||||
if (port && port != CNF_GetNTPPort() && port != CNF_GetAcquisitionPort())
|
||||
assert(0);
|
||||
|
||||
if (!have_helper())
|
||||
return bind(sock, address, address_len);
|
||||
|
||||
48
refclock.c
48
refclock.c
@@ -79,6 +79,8 @@ struct RCL_Instance_Record {
|
||||
int pps_rate;
|
||||
int pps_active;
|
||||
int max_lock_age;
|
||||
int stratum;
|
||||
int tai;
|
||||
struct MedianFilter filter;
|
||||
uint32_t ref_id;
|
||||
uint32_t lock_ref;
|
||||
@@ -181,13 +183,13 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->driver = &RCL_PHC_driver;
|
||||
} else {
|
||||
LOG_FATAL("unknown refclock driver %s", params->driver_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!inst->driver->init && !inst->driver->poll) {
|
||||
if (!inst->driver->init && !inst->driver->poll)
|
||||
LOG_FATAL("refclock driver %s is not compiled in", params->driver_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (params->tai && !CNF_GetLeapSecTimezone())
|
||||
LOG_FATAL("refclock tai option requires leapsectz");
|
||||
|
||||
inst->data = NULL;
|
||||
inst->driver_parameter = params->driver_parameter;
|
||||
@@ -200,6 +202,8 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->pps_rate = params->pps_rate;
|
||||
inst->pps_active = 0;
|
||||
inst->max_lock_age = params->max_lock_age;
|
||||
inst->stratum = params->stratum;
|
||||
inst->tai = params->tai;
|
||||
inst->lock_ref = params->lock_ref_id;
|
||||
inst->offset = params->offset;
|
||||
inst->delay = params->delay;
|
||||
@@ -251,11 +255,8 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->driver->init)
|
||||
if (!inst->driver->init(inst)) {
|
||||
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
||||
return 0;
|
||||
}
|
||||
if (inst->driver->init && !inst->driver->init(inst))
|
||||
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
||||
|
||||
filter_init(&inst->filter, params->filter_length, params->max_dispersion);
|
||||
|
||||
@@ -356,6 +357,28 @@ RCL_GetDriverOption(RCL_Instance instance, char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
convert_tai_offset(struct timespec *sample_time, double *offset)
|
||||
{
|
||||
struct timespec tai_ts, utc_ts;
|
||||
int tai_offset;
|
||||
|
||||
/* Get approximate TAI-UTC offset for the reference time in TAI */
|
||||
UTI_AddDoubleToTimespec(sample_time, *offset, &tai_ts);
|
||||
tai_offset = REF_GetTaiOffset(&tai_ts);
|
||||
|
||||
/* Get TAI-UTC offset for the reference time in UTC +/- 1 second */
|
||||
UTI_AddDoubleToTimespec(&tai_ts, -tai_offset, &utc_ts);
|
||||
tai_offset = REF_GetTaiOffset(&utc_ts);
|
||||
|
||||
if (!tai_offset)
|
||||
return 0;
|
||||
|
||||
*offset -= tai_offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap)
|
||||
{
|
||||
@@ -385,6 +408,11 @@ RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (instance->tai && !convert_tai_offset(sample_time, &offset)) {
|
||||
DEBUG_LOG("refclock sample ignored unknown TAI offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
filter_add_sample(&instance->filter, &cooked_time, offset - correction + instance->offset, dispersion);
|
||||
instance->pps_active = 0;
|
||||
|
||||
@@ -635,7 +663,7 @@ poll_timeout(void *arg)
|
||||
/* Handle special case when PPS is used with local stratum */
|
||||
stratum = pps_stratum(inst, &sample_time);
|
||||
else
|
||||
stratum = 0;
|
||||
stratum = inst->stratum;
|
||||
|
||||
SRC_UpdateReachability(inst->source, 1);
|
||||
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
||||
|
||||
@@ -43,6 +43,8 @@ typedef struct {
|
||||
int max_samples;
|
||||
int sel_options;
|
||||
int max_lock_age;
|
||||
int stratum;
|
||||
int tai;
|
||||
uint32_t ref_id;
|
||||
uint32_t lock_ref_id;
|
||||
double offset;
|
||||
|
||||
31
reference.c
31
reference.c
@@ -609,7 +609,14 @@ is_offset_ok(double offset)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_leap_second_day(struct tm *stm) {
|
||||
is_leap_second_day(time_t when)
|
||||
{
|
||||
struct tm *stm;
|
||||
|
||||
stm = gmtime(&when);
|
||||
if (!stm)
|
||||
return 0;
|
||||
|
||||
/* Allow leap second only on the last day of June and December */
|
||||
return (stm->tm_mon == 5 && stm->tm_mday == 30) ||
|
||||
(stm->tm_mon == 11 && stm->tm_mday == 31);
|
||||
@@ -624,7 +631,7 @@ get_tz_leap(time_t when, int *tai_offset)
|
||||
static NTP_Leap tz_leap;
|
||||
static int tz_tai_offset;
|
||||
|
||||
struct tm stm;
|
||||
struct tm stm, *tm;
|
||||
time_t t;
|
||||
char *tz_env, tz_orig[128];
|
||||
|
||||
@@ -639,7 +646,11 @@ get_tz_leap(time_t when, int *tai_offset)
|
||||
tz_leap = LEAP_Normal;
|
||||
tz_tai_offset = 0;
|
||||
|
||||
stm = *gmtime(&when);
|
||||
tm = gmtime(&when);
|
||||
if (!tm)
|
||||
return tz_leap;
|
||||
|
||||
stm = *tm;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
@@ -784,7 +795,7 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
||||
/* Check that leap second is allowed today */
|
||||
|
||||
if (is_leap_second_day(gmtime(&now))) {
|
||||
if (is_leap_second_day(now)) {
|
||||
if (leap == LEAP_InsertSecond) {
|
||||
leap_sec = 1;
|
||||
} else {
|
||||
@@ -1345,6 +1356,18 @@ int REF_IsLeapSecondClose(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
REF_GetTaiOffset(struct timespec *ts)
|
||||
{
|
||||
int tai_offset;
|
||||
|
||||
get_tz_leap(ts->tv_sec, &tai_offset);
|
||||
|
||||
return tai_offset;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||
{
|
||||
|
||||
@@ -184,6 +184,9 @@ extern void REF_DisableLocal(void);
|
||||
and is better to discard any measurements */
|
||||
extern int REF_IsLeapSecondClose(void);
|
||||
|
||||
/* Return TAI-UTC offset corresponding to a time in UTC if available */
|
||||
extern int REF_GetTaiOffset(struct timespec *ts);
|
||||
|
||||
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
||||
|
||||
#endif /* GOT_REFERENCE_H */
|
||||
|
||||
9
sched.c
9
sched.c
@@ -219,13 +219,16 @@ SCH_RemoveFileHandler(int fd)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
SCH_SetFileHandlerEvents(int fd, int events)
|
||||
SCH_SetFileHandlerEvent(int fd, int event, int enable)
|
||||
{
|
||||
FileHandlerEntry *ptr;
|
||||
|
||||
assert(events);
|
||||
ptr = ARR_GetElement(file_handlers, fd);
|
||||
ptr->events = events;
|
||||
|
||||
if (enable)
|
||||
ptr->events |= event;
|
||||
else
|
||||
ptr->events &= ~event;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
2
sched.h
2
sched.h
@@ -60,7 +60,7 @@ extern void SCH_Finalise(void);
|
||||
/* Register a handler for when select goes true on a file descriptor */
|
||||
extern void SCH_AddFileHandler(int fd, int events, SCH_FileHandler handler, SCH_ArbitraryArgument arg);
|
||||
extern void SCH_RemoveFileHandler(int fd);
|
||||
extern void SCH_SetFileHandlerEvents(int fd, int events);
|
||||
extern void SCH_SetFileHandlerEvent(int fd, int event, int enable);
|
||||
|
||||
/* Get the time stamp taken after a file descriptor became ready or a timeout expired */
|
||||
extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw);
|
||||
|
||||
10
sources.c
10
sources.c
@@ -665,6 +665,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Include extra dispersion in the root distance of sources that don't
|
||||
have new samples (the last sample is older than span of all samples) */
|
||||
if (first_sample_ago < 2.0 * si->last_sample_ago) {
|
||||
double extra_disp = LCL_GetMaxClockError() *
|
||||
(2.0 * si->last_sample_ago - first_sample_ago);
|
||||
si->root_distance += extra_disp;
|
||||
si->lo_limit -= extra_disp;
|
||||
si->hi_limit += extra_disp;
|
||||
}
|
||||
|
||||
/* Require the root distance to be below the allowed maximum */
|
||||
if (si->root_distance > max_distance) {
|
||||
sources[i]->status = SRC_BAD_DISTANCE;
|
||||
|
||||
@@ -51,6 +51,9 @@
|
||||
#define MIN_SKEW 1.0e-12
|
||||
#define MAX_SKEW 1.0e+02
|
||||
|
||||
/* The minimum standard deviation */
|
||||
#define MIN_STDDEV 1.0e-9
|
||||
|
||||
/* The asymmetry of network jitter when all jitter is in one direction */
|
||||
#define MAX_ASYMMETRY 0.5
|
||||
|
||||
@@ -571,7 +574,7 @@ SST_DoNewRegression(SST_Stats inst)
|
||||
inst->estimated_offset = est_intercept;
|
||||
inst->offset_time = inst->sample_times[inst->last_sample];
|
||||
inst->estimated_offset_sd = est_intercept_sd;
|
||||
inst->std_dev = sqrt(est_var);
|
||||
inst->std_dev = MAX(MIN_STDDEV, sqrt(est_var));
|
||||
inst->nruns = nruns;
|
||||
|
||||
inst->skew = CLAMP(MIN_SKEW, inst->skew, MAX_SKEW);
|
||||
@@ -884,7 +887,7 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
char line[1024];
|
||||
double weight;
|
||||
|
||||
assert(!inst->n_samples);
|
||||
SST_ResetInstance(inst);
|
||||
|
||||
if (fgets(line, sizeof(line), in) &&
|
||||
sscanf(line, "%d", &inst->n_samples) == 1 &&
|
||||
@@ -933,7 +936,6 @@ SST_LoadFromFile(SST_Stats inst, FILE *in)
|
||||
return 1;
|
||||
|
||||
inst->last_sample = inst->n_samples - 1;
|
||||
inst->runs_samples = 0;
|
||||
|
||||
find_min_delay_sample(inst);
|
||||
SST_DoNewRegression(inst);
|
||||
|
||||
@@ -35,6 +35,7 @@ typedef struct {
|
||||
int online;
|
||||
int auto_offline;
|
||||
int presend_minpoll;
|
||||
int burst;
|
||||
int iburst;
|
||||
int min_stratum;
|
||||
int poll_target;
|
||||
|
||||
2
sys.c
2
sys.c
@@ -97,7 +97,7 @@ SYS_Finalise(void)
|
||||
void SYS_DropRoot(uid_t uid, gid_t gid)
|
||||
{
|
||||
#if defined(LINUX) && defined (FEAT_PRIVDROP)
|
||||
SYS_Linux_DropRoot(uid, gid);
|
||||
SYS_Linux_DropRoot(uid, gid, !null_driver);
|
||||
#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
|
||||
SYS_Solaris_DropRoot(uid, gid);
|
||||
#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
|
||||
|
||||
29
sys_linux.c
29
sys_linux.c
@@ -380,6 +380,18 @@ test_step_offset(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
report_time_adjust_blockers(void)
|
||||
{
|
||||
#ifdef FEAT_PRIVDROP
|
||||
if (CAP_IS_SUPPORTED(CAP_SYS_TIME) && cap_get_bound(CAP_SYS_TIME))
|
||||
return;
|
||||
LOG(LOGS_WARN, "CAP_SYS_TIME not present");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Initialisation code for this module */
|
||||
|
||||
@@ -388,6 +400,8 @@ SYS_Linux_Initialise(void)
|
||||
{
|
||||
get_version_specific_details();
|
||||
|
||||
report_time_adjust_blockers();
|
||||
|
||||
reset_adjtime_offset();
|
||||
|
||||
if (have_setoffset && !test_step_offset()) {
|
||||
@@ -415,9 +429,9 @@ SYS_Linux_Finalise(void)
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
void
|
||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
||||
SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
|
||||
{
|
||||
const char *cap_text;
|
||||
char cap_text[256];
|
||||
cap_t cap;
|
||||
|
||||
if (prctl(PR_SET_KEEPCAPS, 1)) {
|
||||
@@ -426,9 +440,12 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid)
|
||||
|
||||
UTI_DropRoot(uid, gid);
|
||||
|
||||
/* Keep CAP_NET_BIND_SERVICE only if NTP port can be opened */
|
||||
cap_text = CNF_GetNTPPort() ?
|
||||
"cap_net_bind_service,cap_sys_time=ep" : "cap_sys_time=ep";
|
||||
/* Keep CAP_NET_BIND_SERVICE only if a server NTP port can be opened
|
||||
and keep CAP_SYS_TIME only if the clock control is enabled */
|
||||
if (snprintf(cap_text, sizeof (cap_text), "%s %s",
|
||||
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
|
||||
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
|
||||
assert(0);
|
||||
|
||||
if ((cap = cap_from_text(cap_text)) == NULL) {
|
||||
LOG_FATAL("cap_from_text() failed");
|
||||
@@ -480,7 +497,7 @@ SYS_Linux_EnableSystemCallFilter(int level)
|
||||
SCMP_SYS(lseek), SCMP_SYS(rename), SCMP_SYS(stat), SCMP_SYS(stat64),
|
||||
SCMP_SYS(statfs), SCMP_SYS(statfs64), SCMP_SYS(unlink),
|
||||
/* Socket */
|
||||
SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname),
|
||||
SCMP_SYS(bind), SCMP_SYS(connect), SCMP_SYS(getsockname), SCMP_SYS(getsockopt),
|
||||
SCMP_SYS(recvfrom), SCMP_SYS(recvmmsg), SCMP_SYS(recvmsg),
|
||||
SCMP_SYS(sendmmsg), SCMP_SYS(sendmsg), SCMP_SYS(sendto),
|
||||
/* TODO: check socketcall arguments */
|
||||
|
||||
@@ -31,7 +31,7 @@ extern void SYS_Linux_Initialise(void);
|
||||
|
||||
extern void SYS_Linux_Finalise(void);
|
||||
|
||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid);
|
||||
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control);
|
||||
|
||||
extern void SYS_Linux_EnableSystemCallFilter(int level);
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ for opts in \
|
||||
"--host-system=Linux" \
|
||||
"--host-system=NetBSD" \
|
||||
"--host-system=FreeBSD" \
|
||||
"--without-nss" \
|
||||
"--without-tomcrypt --without-nss"
|
||||
"--without-nettle" \
|
||||
"--without-nettle --without-nss" \
|
||||
"--without-nettle --without-nss --without-tomcrypt"
|
||||
do
|
||||
./configure $opts
|
||||
scan-build make "$@" || exit 1
|
||||
|
||||
@@ -8,11 +8,20 @@ limit=1000
|
||||
refclock_jitter=$jitter
|
||||
min_sync_time=45
|
||||
max_sync_time=70
|
||||
client_conf="refclock SHM 0"
|
||||
chronyc_start=70
|
||||
client_conf="refclock SHM 0 stratum 3 delay 1e-3 refid GPS"
|
||||
chronyc_conf="tracking"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^Reference ID.*47505300 \(GPS\)
|
||||
Stratum.*: 4
|
||||
.*
|
||||
Root delay : 0.001000000 seconds
|
||||
.*
|
||||
Update interval : 16\.. seconds
|
||||
.*$" || test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -4,14 +4,30 @@
|
||||
|
||||
test_start "chronyc"
|
||||
|
||||
chronyc_conf="tracking
|
||||
refclock_jitter=$jitter
|
||||
client_conf="
|
||||
refclock SHM 0 noselect
|
||||
smoothtime 400 0.001 leaponly"
|
||||
|
||||
chronyc_conf="activity
|
||||
tracking
|
||||
sources
|
||||
sourcestats"
|
||||
sourcestats
|
||||
manual list
|
||||
smoothing
|
||||
waitsync
|
||||
rtcdata"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
|
||||
check_chronyc_output "^Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
||||
check_chronyc_output "^200 OK
|
||||
1 sources online
|
||||
0 sources offline
|
||||
0 sources doing burst \(return to online\)
|
||||
0 sources doing burst \(return to offline\)
|
||||
0 sources with unknown address
|
||||
Reference ID : C0A87B01 \(192\.168\.123\.1\)
|
||||
Stratum : 2
|
||||
Ref time \(UTC\) : Fri Jan 01 00:1.:.. 2010
|
||||
System time : 0\.0000..... seconds (slow|fast) of NTP time
|
||||
@@ -24,14 +40,27 @@ Root delay : 0\.000...... seconds
|
||||
Root dispersion : 0\.000...... seconds
|
||||
Update interval : [0-9]+\.. seconds
|
||||
Leap status : Normal
|
||||
210 Number of sources = 1
|
||||
210 Number of sources = 2
|
||||
MS Name/IP address Stratum Poll Reach LastRx Last sample
|
||||
===============================================================================
|
||||
#\? SHM0 0 4 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
\^\* 192\.168\.123\.1 1 [67] 377 [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
|
||||
210 Number of sources = 1
|
||||
210 Number of sources = 2
|
||||
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
|
||||
==============================================================================
|
||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s$" \
|
||||
SHM0 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
192\.168\.123\.1 [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\.... [0-9 +-]+[un]s [0-9 ]+[un]s
|
||||
210 n_samples = 0
|
||||
# Date Time\(UTC\) Slewed Original Residual
|
||||
=======================================================
|
||||
Active : Yes \(leap second only\)
|
||||
Offset : \+0\.000000000 seconds
|
||||
Frequency : \+0\.000000 ppm
|
||||
Wander : \+0\.000000 ppm per second
|
||||
Last update : [0-9]+\.. seconds ago
|
||||
Remaining time : 0\.0 seconds
|
||||
try: 1, refid: C0A87B01, correction: 0\.000......, skew: .\....
|
||||
513 RTC driver not running$" \
|
||||
|| test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -5,8 +5,9 @@ test_start "smoothtime option"
|
||||
|
||||
server_strata=2
|
||||
server_conf="smoothtime 400 0.001"
|
||||
min_sync_time=250
|
||||
max_sync_time=1000
|
||||
server_server_options="minpoll 8"
|
||||
min_sync_time=600
|
||||
max_sync_time=800
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
@@ -22,6 +23,7 @@ server_conf="refclock SHM 0 dpoll 4 poll 6
|
||||
smoothtime 2000 1
|
||||
maxjitter 10.0"
|
||||
time_offset=-10
|
||||
server_server_options=""
|
||||
client_server_options="minpoll 6 maxpoll 6"
|
||||
client_conf="corrtimeratio 100"
|
||||
min_sync_time=8000
|
||||
|
||||
42
test/simulation/124-tai
Executable file
42
test/simulation/124-tai
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
test_start "tai option"
|
||||
|
||||
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 31 2008 23:50:00' +'%s')
|
||||
|
||||
leap=$[10 * 60]
|
||||
limit=$[20 * 60]
|
||||
min_sync_time=2
|
||||
max_sync_time=15
|
||||
refclock_jitter=1e-6
|
||||
servers=0
|
||||
|
||||
refclock_offset="(+ -34 (equal 0.1 (max (sum 1.0) $leap) $leap))"
|
||||
client_conf="
|
||||
refclock SHM 0 dpoll 0 poll 0 tai
|
||||
leapsectz right/UTC
|
||||
leapsecmode ignore
|
||||
maxchange 1e-3 1 0"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Jan 01 2009 00:10:00' +'%s')
|
||||
|
||||
time_offset=-1000
|
||||
refclock_offset="(+ -34)"
|
||||
client_conf="
|
||||
refclock SHM 0 dpoll 0 poll 0 tai
|
||||
leapsectz right/UTC
|
||||
makestep 1 1
|
||||
maxchange 1e-3 1 0"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
29
test/simulation/125-packetloss
Executable file
29
test/simulation/125-packetloss
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "packet loss"
|
||||
|
||||
# Drop 33% of packets by default and 100% on the 3->1 path
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1 (equal 0.33 (uniform) 1.0))
|
||||
(* -1 (equal 0.1 from 3) (equal 0.1 to 1)))
|
||||
EOF
|
||||
)
|
||||
clients=2
|
||||
peers=2
|
||||
jitter=1e-5
|
||||
limit=20000
|
||||
max_sync_time=10000
|
||||
|
||||
for options in "maxpoll 8" "maxpoll 8 xleave"; do
|
||||
client_server_options=$options
|
||||
client_peer_options=$options
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
done
|
||||
|
||||
test_pass
|
||||
45
test/simulation/126-burst
Executable file
45
test/simulation/126-burst
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "burst option"
|
||||
|
||||
# Pass every fourth packet on the 2->1 path
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1
|
||||
(equal 0.1 from 2)
|
||||
(equal 0.1 to 1)
|
||||
(equal 0.1 (min (% (sum 1) 4) 1) 1)))
|
||||
EOF
|
||||
)
|
||||
|
||||
client_server_options="burst polltarget 1"
|
||||
min_sync_time=700
|
||||
max_sync_time=730
|
||||
client_max_min_out_interval=2.2
|
||||
client_min_mean_out_interval=150.0
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
# Add a significant delay to 70% of packets on the 2->1 path after 6th packet
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* 0.15
|
||||
(equal 0.1 from 2)
|
||||
(equal 0.1 to 1)
|
||||
(equal 0.1 (min (sum 1) 7) 7)
|
||||
(equal 0.7 (uniform) 0.0)))
|
||||
EOF
|
||||
)
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -71,6 +71,9 @@ default_freq_rms_limit=1e-5
|
||||
default_min_sync_time=120
|
||||
default_max_sync_time=210
|
||||
|
||||
default_client_min_mean_out_interval=0.0
|
||||
default_client_max_min_out_interval=inf
|
||||
|
||||
# Initialize test settings from their defaults
|
||||
for defopt in $(declare | grep '^default_'); do
|
||||
defoptname=${defopt%%=*}
|
||||
@@ -251,6 +254,7 @@ check_chronyd_exit() {
|
||||
test_message 3 0 "node $i:"
|
||||
|
||||
tail -n 1 tmp/log.$i | grep -q 'chronyd exiting' && \
|
||||
! grep -q 'Adjustment.*exceeds.*exiting' tmp/log.$i && \
|
||||
test_ok || test_bad
|
||||
[ $? -eq 0 ] || ret=1
|
||||
done
|
||||
@@ -302,10 +306,12 @@ check_packet_interval() {
|
||||
([ $i -gt $servers ] || \
|
||||
check_stat $mean_in_interval 0.0 $mean_out_interval 10*$jitter) && \
|
||||
([ $i -le $[$servers * $server_strata] ] || \
|
||||
check_stat $mean_out_interval 0.0 $mean_in_interval 10*$jitter) && \
|
||||
check_stat $mean_out_interval $client_min_mean_out_interval \
|
||||
$mean_in_interval 10*$jitter) && \
|
||||
([ $i -le $[$servers * $server_strata] ] || \
|
||||
check_stat $min_out_interval \
|
||||
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) inf) && \
|
||||
$([ $servers -gt 1 ] && echo 0.18 || echo 1.8) \
|
||||
$client_max_min_out_interval) && \
|
||||
test_ok || test_bad
|
||||
|
||||
[ $? -eq 0 ] || ret=1
|
||||
|
||||
123
test/unit/hash.c
Normal file
123
test/unit/hash.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2018
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <sysincl.h>
|
||||
#include <hash.h>
|
||||
#include <logging.h>
|
||||
#include "test.h"
|
||||
|
||||
struct hash_test {
|
||||
const char *name;
|
||||
const unsigned char out[MAX_HASH_LENGTH];
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
unsigned char data1[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
unsigned char data2[] = "12345678910";
|
||||
unsigned char out[MAX_HASH_LENGTH];
|
||||
struct hash_test tests[] = {
|
||||
{ "MD5", "\xfc\x24\x97\x1b\x52\x66\xdc\x46\xef\xe0\xe8\x08\x46\x89\xb6\x88", 16 },
|
||||
{ "SHA1", "\xd8\x85\xb3\x86\xce\xea\x93\xeb\x92\xcd\x7b\x94\xb9\x8d\xc2\x8e"
|
||||
"\x3e\x31\x13\xdd", 20},
|
||||
{ "SHA256", "\x0e\x35\x14\xe7\x15\x7a\x1d\xdd\xea\x11\x78\xd3\x41\xf6\xb9\x3e"
|
||||
"\xa0\x42\x96\x73\x3c\x54\x74\x0b\xfa\x6b\x9e\x29\x59\xad\x69\xd3", 32 },
|
||||
{ "SHA384", "\x2c\xeb\xbd\x4d\x95\xed\xad\x03\xed\x80\xc4\xf3\xa6\x10\x21\xde"
|
||||
"\x40\x69\x54\xed\x42\x70\xb8\x95\xb0\x6f\x01\x1d\x04\xdf\x57\xbc"
|
||||
"\x1d\xb5\x85\xbf\x4f\x03\x88\xd5\x83\x93\xbc\x81\x90\xb0\xa9\x9b", 48 },
|
||||
{ "SHA512", "\x20\xba\xec\xcb\x68\x98\x33\x5b\x70\x26\x63\x13\xe2\xf7\x0e\x67"
|
||||
"\x08\xf3\x77\x4f\xbd\xeb\xc4\xa8\xc5\x94\xe2\x39\x40\x7e\xed\x0b"
|
||||
"\x69\x0e\x18\xa5\xa2\x03\x73\xe7\x1d\x20\x7d\x3f\xc8\x70\x2d\x64"
|
||||
"\x9e\x89\x6d\x20\x6a\x4a\x5a\x46\xe7\x4f\x2c\xf9\x0f\x0a\x54\xdc", 64 },
|
||||
{ "SHA3-224", "\x3b\xa2\x22\x28\xdd\x26\x18\xec\x3b\xb9\x25\x39\x5e\xbd\x94\x25"
|
||||
"\xd4\x20\x8a\x76\x76\xc0\x3c\x5d\x9e\x0a\x06\x46", 28},
|
||||
{ "SHA3-256", "\x26\xd1\x19\xb2\xc1\x64\xc8\xb8\x10\xd8\xa8\x1c\xb6\xa4\x0d\x29"
|
||||
"\x09\xc9\x8e\x2e\x2d\xde\x7a\x74\x8c\x43\x70\xb8\xaa\x0f\x09\x17", 32 },
|
||||
{ "SHA3-384", "\x6a\x64\xb9\x89\x08\x29\xd0\xa7\x4b\x84\xba\xa6\x65\xf5\xe7\x54"
|
||||
"\xe2\x18\x12\xc3\x63\x34\xc6\xba\x26\xf5\x6e\x99\xe2\x54\xcc\x9d"
|
||||
"\x01\x10\x9d\xee\x35\x38\x04\x83\xe5\x71\x70\xd8\xc8\x99\x96\xd8", 48 },
|
||||
{ "SHA3-512", "\xa8\xe3\x2b\x65\x1f\x87\x90\x73\x19\xc8\xa0\x3f\xe3\x85\x60\x3c"
|
||||
"\x39\xfc\xcb\xc1\x29\xe1\x23\x7d\x8b\x56\x54\xe3\x08\x9d\xf9\x74"
|
||||
"\x78\x69\x2e\x3c\x7e\x51\x1e\x9d\xab\x09\xbe\xe7\x6b\x1a\xa1\x22"
|
||||
"\x93\xb1\x2b\x82\x9d\x1e\xcf\xa8\x99\xc5\xec\x7b\x1d\x89\x07\x2b", 64 },
|
||||
{ "RMD128", "\x6f\xd7\x1f\x37\x47\x0f\xbd\x42\x57\xc8\xbb\xee\xba\x65\xf9\x35", 16 },
|
||||
{ "RMD160", "\x7a\x88\xec\xc7\x09\xc5\x65\x34\x11\x24\xe3\xf9\xf7\xa5\xbf\xc6"
|
||||
"\x01\xe2\xc9\x32", 20},
|
||||
{ "RMD256", "\x59\xdf\xd4\xcb\xc9\xbe\x7c\x27\x08\xa7\x23\xf7\xb3\x0c\xf0\x0d"
|
||||
"\xa0\xcf\x5b\x18\x16\x51\x56\x6d\xda\x7b\x87\x24\x9d\x83\x35\xe1", 32 },
|
||||
{ "RMD320", "\x68\x98\x10\xf4\xb6\x79\xb6\x15\xf1\x48\x2d\x73\xd0\x23\x84\x01"
|
||||
"\xbf\xaa\x67\xcf\x1e\x35\x5c\xbf\xe9\xb8\xaf\xe1\xee\x0d\xf0\x6b"
|
||||
"\xe2\x3a\x9a\x3a\xa7\x56\xad\x70", 40},
|
||||
{ "TIGER", "\x1c\xcd\x68\x74\xca\xd6\xd5\x17\xba\x3e\x82\xaf\xbd\x70\xdc\x66"
|
||||
"\x99\xaa\xae\x16\x72\x59\xd1\x64", 24},
|
||||
{ "WHIRLPOOL", "\xe3\xcd\xe6\xbf\xe1\x8c\xe4\x4d\xc8\xb4\xa5\x7c\x36\x8d\xc8\x8a"
|
||||
"\x8b\xad\x52\x24\xc0\x4e\x99\x5b\x7e\x86\x94\x2d\x10\x56\x12\xa3"
|
||||
"\x29\x2a\x65\x0f\x9e\x07\xbc\x15\x21\x14\xe6\x07\xfc\xe6\xb9\x2f"
|
||||
"\x13\xe2\x57\xe9\x0a\xb0\xd2\xf4\xa3\x20\x36\x9c\x88\x92\x8e\xc9", 64 },
|
||||
{ "", "", 0 }
|
||||
};
|
||||
|
||||
unsigned int length;
|
||||
int i, j, hash_id;
|
||||
|
||||
for (i = 0; tests[i].name[0] != '\0'; i++) {
|
||||
hash_id = HSH_GetHashId(tests[i].name);
|
||||
if (hash_id < 0) {
|
||||
TEST_CHECK(strcmp(tests[i].name, "MD5"));
|
||||
#ifdef FEAT_SECHASH
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA1"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA256"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA384"));
|
||||
TEST_CHECK(strcmp(tests[i].name, "SHA512"));
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUG_LOG("testing %s", tests[i].name);
|
||||
|
||||
for (j = 0; j <= sizeof (out); j++) {
|
||||
TEST_CHECK(HSH_GetHashId(tests[i].name) == hash_id);
|
||||
TEST_CHECK(HSH_GetHashId("nosuchhash") < 0);
|
||||
|
||||
memset(out, 0, sizeof (out));
|
||||
length = HSH_Hash(hash_id, data1, sizeof (data1) - 1, data2, sizeof (data2) - 1,
|
||||
out, j);
|
||||
|
||||
if (j >= tests[i].length)
|
||||
TEST_CHECK(length == tests[i].length);
|
||||
else
|
||||
TEST_CHECK(length == 0 || length == j || length == tests[i].length);
|
||||
|
||||
TEST_CHECK(!memcmp(out, tests[i].out, length));
|
||||
}
|
||||
|
||||
for (j = 0; j < 10000; j++) {
|
||||
length = HSH_Hash(hash_id, data1, random() % sizeof (data1),
|
||||
random() % 2 ? data2 : NULL, random() % sizeof (data2),
|
||||
out, sizeof (out));
|
||||
TEST_CHECK(length == tests[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
HSH_Finalise();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2016
|
||||
* Copyright (C) Miroslav Lichvar 2016-2017
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -134,8 +134,8 @@ test_unit(void)
|
||||
UTI_GetRandomBytes(&key, sizeof (key));
|
||||
if (KEY_KeyKnown(key))
|
||||
continue;
|
||||
TEST_CHECK(!KEY_GenerateAuth(j, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(j, data, data_len, auth, auth_len, auth_len));
|
||||
TEST_CHECK(!KEY_GenerateAuth(key, data, data_len, auth, sizeof (auth)));
|
||||
TEST_CHECK(!KEY_CheckAuth(key, data, data_len, auth, auth_len, auth_len));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2017
|
||||
* Copyright (C) Miroslav Lichvar 2017-2018
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -36,6 +36,7 @@ static int req_length, res_length;
|
||||
#define NIO_CloseServerSocket(fd) assert(fd == 100)
|
||||
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
|
||||
#define NIO_CloseClientSocket(fd) assert(fd == 101)
|
||||
#define NIO_IsServerSocket(fd) (fd == 100)
|
||||
#define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
|
||||
#define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
|
||||
#define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
|
||||
@@ -43,6 +44,7 @@ static int req_length, res_length;
|
||||
#define SCH_RemoveTimeout(id) assert(!id || id == 102)
|
||||
#define LCL_ReadRawTime(ts) (*ts = current_time)
|
||||
#define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
|
||||
#define LCL_GetSysPrecisionAsLog() (random() % 10 - 30)
|
||||
#define SRC_UpdateReachability(inst, reach)
|
||||
#define SRC_ResetReachability(inst)
|
||||
|
||||
@@ -55,8 +57,6 @@ add_timeout_in_class(double min_delay, double separation, double randomness,
|
||||
|
||||
#include <ntp_core.c>
|
||||
|
||||
static NCR_Instance inst;
|
||||
|
||||
static void
|
||||
advance_time(double x)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ advance_time(double x)
|
||||
}
|
||||
|
||||
static void
|
||||
send_request(void)
|
||||
send_request(NCR_Instance inst)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
@@ -74,19 +74,48 @@ send_request(void)
|
||||
|
||||
transmit_timeout(inst);
|
||||
TEST_CHECK(!inst->valid_rx);
|
||||
TEST_CHECK(!inst->updated_timestamps);
|
||||
TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
|
||||
|
||||
advance_time(1e-4);
|
||||
advance_time(1e-5);
|
||||
|
||||
if (random() % 2) {
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_KERNEL;
|
||||
|
||||
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_request(NTP_Remote_Address *remote_addr)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = 101;
|
||||
local_addr.sock_fd = 100;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
local_ts.source = NTP_TS_KERNEL;
|
||||
|
||||
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
|
||||
res_length = 0;
|
||||
NCR_ProcessRxUnknown(remote_addr, &local_addr, &local_ts,
|
||||
&req_buffer.ntp_pkt, req_length);
|
||||
res_length = req_length;
|
||||
res_buffer = req_buffer;
|
||||
|
||||
advance_time(1e-5);
|
||||
|
||||
if (random() % 2) {
|
||||
local_ts.ts = current_time;
|
||||
NCR_ProcessTxUnknown(remote_addr, &local_addr, &local_ts,
|
||||
&res_buffer.ntp_pkt, res_length);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -165,30 +194,36 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
|
||||
}
|
||||
|
||||
static void
|
||||
process_response(int valid, int updated)
|
||||
process_response(NCR_Instance inst, int good, int valid, int updated_sync, int updated_init)
|
||||
{
|
||||
NTP_Local_Address local_addr;
|
||||
NTP_Local_Timestamp local_ts;
|
||||
NTP_Packet *res;
|
||||
uint32_t prev_rx_count, prev_valid_count;
|
||||
struct timespec prev_rx_ts;
|
||||
int prev_open_socket;
|
||||
struct timespec prev_rx_ts, prev_init_rx_ts;
|
||||
int prev_open_socket, ret;
|
||||
|
||||
res = &res_buffer.ntp_pkt;
|
||||
|
||||
local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||
local_addr.if_index = INVALID_IF_INDEX;
|
||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
|
||||
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101;
|
||||
local_ts.ts = current_time;
|
||||
local_ts.err = 0.0;
|
||||
local_ts.source = NTP_TS_DAEMON;
|
||||
local_ts.source = NTP_TS_KERNEL;
|
||||
|
||||
prev_rx_count = inst->report.total_rx_count;
|
||||
prev_valid_count = inst->report.total_valid_count;
|
||||
prev_rx_ts = inst->local_rx.ts;
|
||||
prev_init_rx_ts = inst->init_local_rx.ts;
|
||||
prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
|
||||
|
||||
NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
||||
ret = NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
|
||||
|
||||
if (good > 0)
|
||||
TEST_CHECK(ret);
|
||||
else if (!good)
|
||||
TEST_CHECK(!ret);
|
||||
|
||||
if (prev_open_socket)
|
||||
TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
|
||||
@@ -200,23 +235,51 @@ process_response(int valid, int updated)
|
||||
else
|
||||
TEST_CHECK(prev_valid_count == inst->report.total_valid_count);
|
||||
|
||||
if (updated)
|
||||
if (updated_sync)
|
||||
TEST_CHECK(UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
else
|
||||
TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
|
||||
|
||||
if (updated_init > 0)
|
||||
TEST_CHECK(UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
|
||||
else if (!updated_init)
|
||||
TEST_CHECK(!UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
|
||||
|
||||
if (valid) {
|
||||
TEST_CHECK(UTI_IsZeroTimespec(&inst->init_local_rx.ts));
|
||||
TEST_CHECK(UTI_IsZeroNtp64(&inst->init_remote_ntp_tx));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_replay(NCR_Instance inst, NTP_Receive_Buffer *packet_queue,
|
||||
int queue_length, int updated_init)
|
||||
{
|
||||
do {
|
||||
res_buffer = packet_queue[random() % queue_length];
|
||||
} while (!UTI_CompareNtp64(&res_buffer.ntp_pkt.transmit_ts,
|
||||
&inst->remote_ntp_tx));
|
||||
process_response(inst, 0, 0, 0, updated_init);
|
||||
advance_time(1e-6);
|
||||
}
|
||||
|
||||
#define PACKET_QUEUE_LENGTH 10
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
char source_line[] = "127.0.0.1";
|
||||
char source_line[] = "127.0.0.1 maxdelaydevratio 1e6";
|
||||
char conf[][100] = {
|
||||
"allow",
|
||||
"port 0",
|
||||
"local",
|
||||
"keyfile ntp_core.keys"
|
||||
};
|
||||
int i, j, interleaved, authenticated, valid, updated, has_updated;
|
||||
int i, j, k, interleaved, authenticated, valid, updated, has_updated;
|
||||
CPS_NTP_Source source;
|
||||
NTP_Remote_Address remote_addr;
|
||||
NCR_Instance inst1, inst2;
|
||||
NTP_Receive_Buffer packet_queue[PACKET_QUEUE_LENGTH];
|
||||
|
||||
CNF_Initialise(0, 0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
@@ -231,12 +294,16 @@ test_unit(void)
|
||||
REF_Initialise();
|
||||
KEY_Initialise();
|
||||
|
||||
CNF_SetupAccessRestrictions();
|
||||
|
||||
CPS_ParseNTPSourceAdd(source_line, &source);
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
CPS_ParseNTPSourceAdd(source_line, &source);
|
||||
if (random() % 2)
|
||||
source.params.interleaved = 1;
|
||||
if (random() % 2)
|
||||
source.params.authkey = 1;
|
||||
source.params.version = random() % 4 + 1;
|
||||
|
||||
UTI_ZeroTimespec(¤t_time);
|
||||
advance_time(TST_GetRandomDouble(1.0, 1e9));
|
||||
@@ -244,48 +311,125 @@ test_unit(void)
|
||||
TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
|
||||
remote_addr.port = 123;
|
||||
|
||||
inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst);
|
||||
inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst1);
|
||||
has_updated = 0;
|
||||
|
||||
for (j = 0; j < 50; j++) {
|
||||
DEBUG_LOG("iteration %d, %d", i, j);
|
||||
DEBUG_LOG("client/peer test iteration %d/%d", i, j);
|
||||
|
||||
interleaved = random() % 2 && (inst->mode != MODE_CLIENT ||
|
||||
inst->tx_count < MAX_CLIENT_INTERLEAVED_TX);
|
||||
interleaved = random() % 2 && (inst1->mode != MODE_CLIENT ||
|
||||
inst1->tx_count < MAX_CLIENT_INTERLEAVED_TX);
|
||||
authenticated = random() % 2;
|
||||
valid = (!interleaved || (source.params.interleaved && has_updated)) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
updated = (valid || inst->mode == MODE_ACTIVE) &&
|
||||
updated = (valid || inst1->mode == MODE_ACTIVE) &&
|
||||
(!source.params.authkey || authenticated);
|
||||
has_updated = has_updated || updated;
|
||||
if (inst1->mode == MODE_CLIENT)
|
||||
updated = 0;
|
||||
|
||||
send_request();
|
||||
send_request(inst1);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 0, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
DEBUG_LOG("response 1");
|
||||
process_response(inst1, 0, 0, 0, updated);
|
||||
|
||||
if (source.params.authkey) {
|
||||
send_response(interleaved, authenticated, 1, 1, 0);
|
||||
process_response(0, 0);
|
||||
DEBUG_LOG("response 2");
|
||||
process_response(inst1, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(valid, updated);
|
||||
process_response(0, 0);
|
||||
DEBUG_LOG("response 3");
|
||||
process_response(inst1, -1, valid, valid, updated);
|
||||
DEBUG_LOG("response 4");
|
||||
process_response(inst1, 0, 0, 0, 0);
|
||||
|
||||
advance_time(-1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, 0);
|
||||
DEBUG_LOG("response 5");
|
||||
process_response(inst1, 0, 0, 0, updated && valid);
|
||||
|
||||
advance_time(1.0);
|
||||
|
||||
send_response(interleaved, authenticated, 1, 1, 1);
|
||||
process_response(0, inst->mode == MODE_CLIENT ? 0 : updated);
|
||||
DEBUG_LOG("response 6");
|
||||
process_response(inst1, 0, 0, valid && updated, updated);
|
||||
}
|
||||
|
||||
NCR_DestroyInstance(inst);
|
||||
NCR_DestroyInstance(inst1);
|
||||
|
||||
inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst1);
|
||||
|
||||
for (j = 0; j < 20; j++) {
|
||||
DEBUG_LOG("server test iteration %d/%d", i, j);
|
||||
|
||||
send_request(inst1);
|
||||
process_request(&remote_addr);
|
||||
process_response(inst1, 1, 1, 1, 0);
|
||||
advance_time(1 << inst1->local_poll);
|
||||
}
|
||||
|
||||
NCR_DestroyInstance(inst1);
|
||||
|
||||
inst1 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst1);
|
||||
inst2 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
|
||||
NCR_StartInstance(inst2);
|
||||
|
||||
res_length = req_length = 0;
|
||||
|
||||
for (j = 0; j < 20; j++) {
|
||||
DEBUG_LOG("peer replay test iteration %d/%d", i, j);
|
||||
|
||||
send_request(inst1);
|
||||
res_buffer = req_buffer;
|
||||
assert(!res_length || res_length == req_length);
|
||||
res_length = req_length;
|
||||
|
||||
TEST_CHECK(inst1->valid_timestamps == (j > 0));
|
||||
|
||||
DEBUG_LOG("response 1->2");
|
||||
process_response(inst2, j > source.params.interleaved, j > 0, j > 0, 1);
|
||||
|
||||
packet_queue[(j * 2) % PACKET_QUEUE_LENGTH] = res_buffer;
|
||||
|
||||
for (k = 0; k < j % 4 + 1; k++) {
|
||||
DEBUG_LOG("replay ?->1 %d", k);
|
||||
process_replay(inst1, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), k ? -1 : 1);
|
||||
DEBUG_LOG("replay ?->2 %d", k);
|
||||
process_replay(inst2, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), -1);
|
||||
}
|
||||
|
||||
advance_time(1 << (source.params.minpoll - 1));
|
||||
|
||||
send_request(inst2);
|
||||
res_buffer = req_buffer;
|
||||
assert(res_length == req_length);
|
||||
|
||||
TEST_CHECK(inst2->valid_timestamps == (j > 0));
|
||||
|
||||
DEBUG_LOG("response 2->1");
|
||||
process_response(inst1, 1, 1, 1, 1);
|
||||
|
||||
packet_queue[(j * 2 + 1) % PACKET_QUEUE_LENGTH] = res_buffer;
|
||||
|
||||
for (k = 0; k < j % 4 + 1; k++) {
|
||||
DEBUG_LOG("replay ?->1 %d", k);
|
||||
process_replay(inst1, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), k ? -1 : 1);
|
||||
DEBUG_LOG("replay ?->2 %d", k);
|
||||
process_replay(inst2, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), -1);
|
||||
}
|
||||
|
||||
advance_time(1 << (source.params.minpoll - 1));
|
||||
}
|
||||
|
||||
NCR_DestroyInstance(inst1);
|
||||
NCR_DestroyInstance(inst2);
|
||||
}
|
||||
|
||||
KEY_Finalise();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
void test_unit(void) {
|
||||
NTP_int64 ntp_ts, ntp_fuzz;
|
||||
struct timespec ts, ts2;
|
||||
struct timeval tv;
|
||||
struct sockaddr_un sun;
|
||||
double x, y;
|
||||
Float f;
|
||||
@@ -40,6 +41,32 @@ void test_unit(void) {
|
||||
TEST_CHECK(UTI_DoubleToNtp32(1000000) == htonl(0xffffffff));
|
||||
TEST_CHECK(UTI_DoubleToNtp32(-1.0) == htonl(0));
|
||||
|
||||
UTI_DoubleToTimeval(0.4e-6, &tv);
|
||||
TEST_CHECK(tv.tv_sec == 0);
|
||||
TEST_CHECK(tv.tv_usec == 0);
|
||||
UTI_DoubleToTimeval(-0.4e-6, &tv);
|
||||
TEST_CHECK(tv.tv_sec == 0);
|
||||
TEST_CHECK(tv.tv_usec == 0);
|
||||
UTI_DoubleToTimeval(0.5e-6, &tv);
|
||||
TEST_CHECK(tv.tv_sec == 0);
|
||||
TEST_CHECK(tv.tv_usec == 1);
|
||||
UTI_DoubleToTimeval(-0.5e-6, &tv);
|
||||
TEST_CHECK(tv.tv_sec == -1);
|
||||
TEST_CHECK(tv.tv_usec == 999999);
|
||||
|
||||
UTI_DoubleToTimespec(0.9e-9, &ts);
|
||||
TEST_CHECK(ts.tv_sec == 0);
|
||||
TEST_CHECK(ts.tv_nsec == 0);
|
||||
UTI_DoubleToTimespec(1.0e-9, &ts);
|
||||
TEST_CHECK(ts.tv_sec == 0);
|
||||
TEST_CHECK(ts.tv_nsec == 1);
|
||||
UTI_DoubleToTimespec(-0.9e-9, &ts);
|
||||
TEST_CHECK(ts.tv_sec == 0);
|
||||
TEST_CHECK(ts.tv_nsec == 0);
|
||||
UTI_DoubleToTimespec(-1.0e-9, &ts);
|
||||
TEST_CHECK(ts.tv_sec == -1);
|
||||
TEST_CHECK(ts.tv_nsec == 999999999);
|
||||
|
||||
ntp_ts.hi = htonl(JAN_1970);
|
||||
ntp_ts.lo = 0xffffffff;
|
||||
UTI_Ntp64ToTimespec(&ntp_ts, &ts);
|
||||
@@ -109,6 +136,11 @@ void test_unit(void) {
|
||||
TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_fuzz) < 0);
|
||||
TEST_CHECK(UTI_CompareNtp64(&ntp_fuzz, &ntp_ts) > 0);
|
||||
|
||||
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_ts, NULL, NULL));
|
||||
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, &ntp_ts, NULL));
|
||||
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts));
|
||||
TEST_CHECK(!UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_fuzz, &ntp_fuzz, &ntp_fuzz));
|
||||
|
||||
ts.tv_sec = 1;
|
||||
ts.tv_nsec = 2;
|
||||
ts2.tv_sec = 1;
|
||||
|
||||
41
util.c
41
util.c
@@ -119,13 +119,11 @@ UTI_TimevalToDouble(struct timeval *tv)
|
||||
void
|
||||
UTI_DoubleToTimeval(double a, struct timeval *b)
|
||||
{
|
||||
long int_part;
|
||||
double frac_part;
|
||||
int_part = (long)(a);
|
||||
frac_part = 1.0e6 * (a - (double)(int_part));
|
||||
frac_part = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
|
||||
b->tv_sec = int_part;
|
||||
b->tv_usec = (long)frac_part;
|
||||
|
||||
b->tv_sec = a;
|
||||
frac_part = 1.0e6 * (a - b->tv_sec);
|
||||
b->tv_usec = frac_part > 0 ? frac_part + 0.5 : frac_part - 0.5;
|
||||
UTI_NormaliseTimeval(b);
|
||||
}
|
||||
|
||||
@@ -368,16 +366,14 @@ UTI_IPToRefid(IPAddr *ip)
|
||||
case IPADDR_INET4:
|
||||
return ip->addr.in4;
|
||||
case IPADDR_INET6:
|
||||
if (MD5_hash < 0) {
|
||||
if (MD5_hash < 0)
|
||||
MD5_hash = HSH_GetHashId("MD5");
|
||||
assert(MD5_hash >= 0);
|
||||
}
|
||||
|
||||
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
|
||||
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
|
||||
assert(0);
|
||||
return 0;
|
||||
};
|
||||
if (MD5_hash < 0 ||
|
||||
HSH_Hash(MD5_hash, (const unsigned char *)ip->addr.in6, sizeof (ip->addr.in6),
|
||||
NULL, 0, buf, sizeof (buf)) != sizeof (buf))
|
||||
LOG_FATAL("Could not get MD5");
|
||||
|
||||
return (uint32_t)buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
|
||||
}
|
||||
return 0;
|
||||
@@ -728,6 +724,23 @@ UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3)
|
||||
{
|
||||
if (b1 && a->lo == b1->lo && a->hi == b1->hi)
|
||||
return 1;
|
||||
|
||||
if (b2 && a->lo == b2->lo && a->hi == b2->hi)
|
||||
return 1;
|
||||
|
||||
if (b3 && a->lo == b3->lo && a->hi == b3->hi)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Seconds part of NTP timestamp correponding to the origin of the time_t format */
|
||||
#define JAN_1970 0x83aa7e80UL
|
||||
|
||||
|
||||
4
util.h
4
util.h
@@ -136,6 +136,10 @@ extern int UTI_IsZeroNtp64(NTP_int64 *ts);
|
||||
b, and 1 if a is after b. */
|
||||
extern int UTI_CompareNtp64(NTP_int64 *a, NTP_int64 *b);
|
||||
|
||||
/* Compare an NTP timestamp with up to three other timestamps. Returns 0
|
||||
if a is not equal to any of b1, b2, and b3, 1 otherwise. */
|
||||
extern int UTI_IsEqualAnyNtp64(NTP_int64 *a, NTP_int64 *b1, NTP_int64 *b2, NTP_int64 *b3);
|
||||
|
||||
/* Convert a timespec into an NTP timestamp */
|
||||
extern void UTI_TimespecToNtp64(struct timespec *src, NTP_int64 *dest, NTP_int64 *fuzz);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user