mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 17:35:06 -05:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09cd057c23 | ||
|
|
363aa86861 | ||
|
|
bda2ff77e8 | ||
|
|
545bd59563 | ||
|
|
082af24114 | ||
|
|
577221295f | ||
|
|
eb08c3b013 | ||
|
|
391882dc41 | ||
|
|
b32d85bc54 | ||
|
|
0bf7e49148 | ||
|
|
f5fdfee150 | ||
|
|
c17f481a20 | ||
|
|
8140feb4fd | ||
|
|
6e541afbe9 | ||
|
|
81362fa201 | ||
|
|
ec57de02c7 | ||
|
|
f7da309b83 | ||
|
|
9b28b2f493 | ||
|
|
ebf19ca760 | ||
|
|
2d96077b9f | ||
|
|
2c2dd2d126 | ||
|
|
f7daec0693 | ||
|
|
d115449e85 | ||
|
|
dab98fa8da | ||
|
|
dd8738119b | ||
|
|
75bbccf518 | ||
|
|
1b24a66b3c | ||
|
|
8fd386f287 | ||
|
|
e694ae769a | ||
|
|
2b127b2e93 | ||
|
|
2d3c89e1a3 | ||
|
|
b5d1ae147d | ||
|
|
bf964673cb | ||
|
|
c66c774e26 | ||
|
|
274c1767f2 | ||
|
|
c27a298d9c | ||
|
|
072ec20e2c | ||
|
|
711c7c0c8a | ||
|
|
454ce62672 | ||
|
|
ab850d41f4 | ||
|
|
744768306b | ||
|
|
26d4f0c401 | ||
|
|
717db2cfdd | ||
|
|
55898e9b07 | ||
|
|
f7bb283536 | ||
|
|
1967fbf1f2 | ||
|
|
51da7a0694 | ||
|
|
9ba6e7655c | ||
|
|
3dea7dd723 | ||
|
|
cb1118456b | ||
|
|
8ee725ff18 | ||
|
|
a90a7cf51c | ||
|
|
4f22883f4e | ||
|
|
65be9d9a02 | ||
|
|
a1191f8392 | ||
|
|
924199ef69 | ||
|
|
8028984f34 | ||
|
|
68301238a0 | ||
|
|
13db3d6902 | ||
|
|
8c24086c6d | ||
|
|
e30d5a6e6f | ||
|
|
a0d34eb372 | ||
|
|
7196943f11 | ||
|
|
26fef1751a | ||
|
|
d71e22594e | ||
|
|
d7a578fed2 | ||
|
|
014a67b29e | ||
|
|
d22c8fbcb2 | ||
|
|
2da4e3ce53 | ||
|
|
c92358e041 | ||
|
|
77962bb527 | ||
|
|
65b5f111d2 | ||
|
|
9856bf2d5f | ||
|
|
2205eae2a1 | ||
|
|
6f381fa78b | ||
|
|
bb8050d884 | ||
|
|
c85ec4ff0f | ||
|
|
d9d97f76d7 | ||
|
|
837323d687 | ||
|
|
12237bf283 | ||
|
|
b9b338a8df | ||
|
|
a5d73f692f | ||
|
|
b0ac5992fb | ||
|
|
cd65e32cf0 | ||
|
|
b9f5278846 | ||
|
|
b8b166044f | ||
|
|
42fbf41686 | ||
|
|
79a790e6b5 | ||
|
|
f5cd79d2df | ||
|
|
689605b6a2 | ||
|
|
0707865413 | ||
|
|
2adda9c12c |
@@ -37,7 +37,9 @@ GETDATE_CFLAGS = @GETDATE_CFLAGS@
|
||||
|
||||
EXTRA_OBJS = @EXTRA_OBJS@
|
||||
|
||||
OBJS = array.o cmdparse.o conf.o leapdb.o local.o logging.o main.o memory.o quantiles.o \
|
||||
OBJS = addrfilt.o array.o clientlog.o cmdparse.o conf.o keys.o leapdb.o \
|
||||
local.o logging.o main.o memory.o nameserv.o nameserv_async.o \
|
||||
ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o quantiles.o \
|
||||
reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \
|
||||
stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(EXTRA_OBJS)
|
||||
|
||||
|
||||
42
NEWS
42
NEWS
@@ -1,3 +1,45 @@
|
||||
New in version 4.7
|
||||
==================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add opencommands directive to select remote monitoring commands
|
||||
* Add interval option to driftfile directive
|
||||
* Add waitsynced and waitunsynced options to local directive
|
||||
* Add sanity checks for integer values in configuration
|
||||
* Add support for systemd Type=notify service
|
||||
* Add RTC refclock driver
|
||||
* Allow PHC refclock to be specified with network interface name
|
||||
* Don't require multiple refclock samples per poll to simplify
|
||||
filter configuration
|
||||
* Keep refclock reachable when dropping samples with large delay
|
||||
* Improve quantile-based filtering to adapt faster to larger delay
|
||||
* Improve logging of selection failures
|
||||
* Detect clock interference from other processes
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
* Fix tracking offset after failed clock step
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
* Drop support for NTS with Nettle < 3.6 and GnuTLS < 3.6.14
|
||||
* Drop support for building without POSIX threads
|
||||
|
||||
New in version 4.6.1
|
||||
====================
|
||||
|
||||
Enhancements
|
||||
------------
|
||||
* Add ntsaeads directive to enable only selected AEAD algorithms for NTS
|
||||
|
||||
Workarounds
|
||||
-----------
|
||||
* Negotiate use of compliant NTS keys with AES-128-GCM-SIV AEAD algorithm
|
||||
(by default the keys are generated differently than in RFC 8915 for
|
||||
compatibility with chrony server and client versions 4.4, 4.5, and 4.6)
|
||||
* Switch to compliant NTS keys if first response from server is NTS NAK
|
||||
|
||||
New in version 4.6
|
||||
==================
|
||||
|
||||
|
||||
4
README
4
README
@@ -84,11 +84,14 @@ Erik Bryer <ebryer@spots.ab.ca>
|
||||
Jonathan Cameron <jic23@cam.ac.uk>
|
||||
Bryan Christianson <bryan@whatroute.net>
|
||||
Juliusz Chroboczek <jch@pps.jussieu.fr>
|
||||
Paul Donald <newtwen+gitlab@gmail.com>
|
||||
Dan Drown <dan-ntp@drown.org>
|
||||
Kamil Dudka <kdudka@redhat.com>
|
||||
Christian Ehrhardt <christian.ehrhardt@canonical.com>
|
||||
Paul Elliott <pelliott@io.com>
|
||||
Robert Fairley <rfairley@redhat.com>
|
||||
Ahmad Fatoum <a.fatoum@pengutronix.de>
|
||||
Andreas Fenkart <extern-afe@mission-embedded.com>
|
||||
Stefan R. Filipek <srfilipek@gmail.com>
|
||||
Andy Fiddaman <illumos@fiddaman.net>
|
||||
Mike Fleetwood <mike@rockover.demon.co.uk>
|
||||
@@ -121,6 +124,7 @@ Rupesh Patel <rupatel@redhat.com>
|
||||
Chris Perl <cperl@janestreet.com>
|
||||
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
|
||||
Andreas Piesk <apiesk@virbus.de>
|
||||
Shachar Raindel <shacharr@google.com>
|
||||
Mike Ryan <msr@hsilop.net>
|
||||
Baruch Siach <baruch@tkos.co.il>
|
||||
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
|
||||
|
||||
17
candm.h
17
candm.h
@@ -37,7 +37,6 @@
|
||||
#define DEFAULT_CANDM_PORT 323
|
||||
|
||||
/* Request codes */
|
||||
#define REQ_NULL 0
|
||||
#define REQ_ONLINE 1
|
||||
#define REQ_OFFLINE 2
|
||||
#define REQ_BURST 3
|
||||
@@ -223,11 +222,6 @@ typedef struct {
|
||||
int32_t EOR;
|
||||
} REQ_Modify_Makestep;
|
||||
|
||||
typedef struct {
|
||||
Timespec ts;
|
||||
int32_t EOR;
|
||||
} REQ_Logon;
|
||||
|
||||
typedef struct {
|
||||
Timespec ts;
|
||||
int32_t EOR;
|
||||
@@ -239,7 +233,8 @@ typedef struct {
|
||||
Float distance;
|
||||
int32_t orphan;
|
||||
Float activate;
|
||||
uint32_t reserved[2];
|
||||
Float wait_synced;
|
||||
Float wait_unsynced;
|
||||
int32_t EOR;
|
||||
} REQ_Local;
|
||||
|
||||
@@ -487,7 +482,6 @@ typedef struct {
|
||||
REQ_Modify_Polltarget modify_polltarget;
|
||||
REQ_Modify_Maxupdateskew modify_maxupdateskew;
|
||||
REQ_Modify_Makestep modify_makestep;
|
||||
REQ_Logon logon;
|
||||
REQ_Settime settime;
|
||||
REQ_Local local;
|
||||
REQ_Manual manual;
|
||||
@@ -517,13 +511,6 @@ typedef struct {
|
||||
|
||||
} CMD_Request;
|
||||
|
||||
/* ================================================== */
|
||||
/* Authority codes for command types */
|
||||
|
||||
#define PERMIT_OPEN 0
|
||||
#define PERMIT_LOCAL 1
|
||||
#define PERMIT_AUTH 2
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* Reply codes */
|
||||
|
||||
32
client.c
32
client.c
@@ -125,12 +125,11 @@ read_line(void)
|
||||
strncpy(line, cmd, sizeof(line) - 1);
|
||||
line[sizeof(line) - 1] = '\0';
|
||||
add_history(cmd);
|
||||
/* free the buffer allocated by readline */
|
||||
Free(cmd);
|
||||
} else {
|
||||
/* simulate the user has entered an empty line */
|
||||
*line = '\0';
|
||||
}
|
||||
Free(cmd);
|
||||
return( line );
|
||||
#else
|
||||
printf("%s", prompt);
|
||||
@@ -754,12 +753,13 @@ process_cmd_burst(CMD_Request *msg, char *line)
|
||||
static int
|
||||
process_cmd_local(CMD_Request *msg, char *line)
|
||||
{
|
||||
double distance = 0.0, activate = 0.0, wait_synced = 0.0, wait_unsynced = 0.0;
|
||||
int on_off, stratum = 0, orphan = 0;
|
||||
double distance = 0.0, activate = 0.0;
|
||||
|
||||
if (!strcmp(line, "off")) {
|
||||
on_off = 0;
|
||||
} else if (CPS_ParseLocal(line, &stratum, &orphan, &distance, &activate)) {
|
||||
} else if (CPS_ParseLocal(line, &stratum, &orphan, &distance, &activate,
|
||||
&wait_synced, &wait_unsynced) == CPS_Success) {
|
||||
on_off = 1;
|
||||
} else {
|
||||
LOG(LOGS_ERR, "Invalid syntax for local command");
|
||||
@@ -772,7 +772,8 @@ process_cmd_local(CMD_Request *msg, char *line)
|
||||
msg->data.local.distance = UTI_FloatHostToNetwork(distance);
|
||||
msg->data.local.orphan = htonl(orphan);
|
||||
msg->data.local.activate = UTI_FloatHostToNetwork(activate);
|
||||
memset(msg->data.local.reserved, 0, sizeof (msg->data.local.reserved));
|
||||
msg->data.local.wait_synced = UTI_FloatHostToNetwork(wait_synced);
|
||||
msg->data.local.wait_unsynced = UTI_FloatHostToNetwork(wait_unsynced);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -906,8 +907,9 @@ static int
|
||||
process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
{
|
||||
CPS_NTP_Source data;
|
||||
CPS_Status status;
|
||||
IPAddr ip_addr;
|
||||
int result = 0, status, type;
|
||||
int result = 0, type;
|
||||
const char *opt_name, *word;
|
||||
|
||||
msg->command = htons(REQ_ADD_SOURCE);
|
||||
@@ -928,10 +930,7 @@ process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
|
||||
status = CPS_ParseNTPSourceAdd(line, &data);
|
||||
switch (status) {
|
||||
case 0:
|
||||
LOG(LOGS_ERR, "Invalid syntax for add command");
|
||||
break;
|
||||
default:
|
||||
case CPS_Success:
|
||||
/* Verify that the address is resolvable (chronyc and chronyd are
|
||||
assumed to be running on the same host) */
|
||||
if (strlen(data.name) >= sizeof (msg->data.ntp_source.name) ||
|
||||
@@ -947,8 +946,7 @@ process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
}
|
||||
|
||||
msg->data.ntp_source.type = htonl(type);
|
||||
if (strlen(data.name) >= sizeof (msg->data.ntp_source.name))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(strlen(data.name) < sizeof (msg->data.ntp_source.name));
|
||||
strncpy((char *)msg->data.ntp_source.name, data.name,
|
||||
sizeof (msg->data.ntp_source.name));
|
||||
msg->data.ntp_source.port = htonl(data.port);
|
||||
@@ -993,6 +991,15 @@ process_cmd_add_source(CMD_Request *msg, char *line)
|
||||
|
||||
result = 1;
|
||||
|
||||
break;
|
||||
case CPS_InvalidOption:
|
||||
LOG(LOGS_ERR, "Invalid %s add command", "option in");
|
||||
break;
|
||||
case CPS_InvalidValue:
|
||||
LOG(LOGS_ERR, "Invalid %s add command", "value in");
|
||||
break;
|
||||
default:
|
||||
LOG(LOGS_ERR, "Invalid %s add command", "syntax for");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3588,6 +3595,7 @@ main(int argc, char **argv)
|
||||
close_io();
|
||||
free_addresses(server_addresses);
|
||||
SCK_Finalise();
|
||||
UTI_ResetGetRandomFunctions();
|
||||
|
||||
return !ret;
|
||||
}
|
||||
|
||||
@@ -265,16 +265,13 @@ get_record(IPAddr *ip)
|
||||
}
|
||||
|
||||
record->ip_addr = *ip;
|
||||
for (i = 0; i < MAX_SERVICES; i++)
|
||||
for (i = 0; i < MAX_SERVICES; i++) {
|
||||
record->last_hit[i] = INVALID_TS;
|
||||
for (i = 0; i < MAX_SERVICES; i++)
|
||||
record->hits[i] = 0;
|
||||
for (i = 0; i < MAX_SERVICES; i++)
|
||||
record->drops[i] = 0;
|
||||
for (i = 0; i < MAX_SERVICES; i++)
|
||||
record->tokens[i] = max_tokens[i];
|
||||
for (i = 0; i < MAX_SERVICES; i++)
|
||||
record->rate[i] = INVALID_RATE;
|
||||
}
|
||||
record->ntp_timeout_rate = INVALID_RATE;
|
||||
record->drop_flags = 0;
|
||||
|
||||
|
||||
666
cmdmon.c
666
cmdmon.c
@@ -68,87 +68,6 @@ static int bound_sock_fd4;
|
||||
/* Flag indicating whether this module has been initialised or not */
|
||||
static int initialised = 0;
|
||||
|
||||
/* ================================================== */
|
||||
/* Array of permission levels for command types */
|
||||
|
||||
static const char permissions[] = {
|
||||
PERMIT_OPEN, /* NULL */
|
||||
PERMIT_AUTH, /* ONLINE */
|
||||
PERMIT_AUTH, /* OFFLINE */
|
||||
PERMIT_AUTH, /* BURST */
|
||||
PERMIT_AUTH, /* MODIFY_MINPOLL */
|
||||
PERMIT_AUTH, /* MODIFY_MAXPOLL */
|
||||
PERMIT_AUTH, /* DUMP */
|
||||
PERMIT_AUTH, /* MODIFY_MAXDELAY */
|
||||
PERMIT_AUTH, /* MODIFY_MAXDELAYRATIO */
|
||||
PERMIT_AUTH, /* MODIFY_MAXUPDATESKEW */
|
||||
PERMIT_OPEN, /* LOGON */
|
||||
PERMIT_AUTH, /* SETTIME */
|
||||
PERMIT_AUTH, /* LOCAL */
|
||||
PERMIT_AUTH, /* MANUAL */
|
||||
PERMIT_OPEN, /* N_SOURCES */
|
||||
PERMIT_OPEN, /* SOURCE_DATA */
|
||||
PERMIT_AUTH, /* REKEY */
|
||||
PERMIT_AUTH, /* ALLOW */
|
||||
PERMIT_AUTH, /* ALLOWALL */
|
||||
PERMIT_AUTH, /* DENY */
|
||||
PERMIT_AUTH, /* DENYALL */
|
||||
PERMIT_AUTH, /* CMDALLOW */
|
||||
PERMIT_AUTH, /* CMDALLOWALL */
|
||||
PERMIT_AUTH, /* CMDDENY */
|
||||
PERMIT_AUTH, /* CMDDENYALL */
|
||||
PERMIT_AUTH, /* ACCHECK */
|
||||
PERMIT_AUTH, /* CMDACCHECK */
|
||||
PERMIT_AUTH, /* ADD_SERVER */
|
||||
PERMIT_AUTH, /* ADD_PEER */
|
||||
PERMIT_AUTH, /* DEL_SOURCE */
|
||||
PERMIT_AUTH, /* WRITERTC */
|
||||
PERMIT_AUTH, /* DFREQ */
|
||||
PERMIT_AUTH, /* DOFFSET */
|
||||
PERMIT_OPEN, /* TRACKING */
|
||||
PERMIT_OPEN, /* SOURCESTATS */
|
||||
PERMIT_OPEN, /* RTCREPORT */
|
||||
PERMIT_AUTH, /* TRIMRTC */
|
||||
PERMIT_AUTH, /* CYCLELOGS */
|
||||
PERMIT_AUTH, /* SUBNETS_ACCESSED */
|
||||
PERMIT_AUTH, /* CLIENT_ACCESSES (by subnet) */
|
||||
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX */
|
||||
PERMIT_OPEN, /* MANUAL_LIST */
|
||||
PERMIT_AUTH, /* MANUAL_DELETE */
|
||||
PERMIT_AUTH, /* MAKESTEP */
|
||||
PERMIT_OPEN, /* ACTIVITY */
|
||||
PERMIT_AUTH, /* MODIFY_MINSTRATUM */
|
||||
PERMIT_AUTH, /* MODIFY_POLLTARGET */
|
||||
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
|
||||
PERMIT_AUTH, /* RESELECT */
|
||||
PERMIT_AUTH, /* RESELECTDISTANCE */
|
||||
PERMIT_AUTH, /* MODIFY_MAKESTEP */
|
||||
PERMIT_OPEN, /* SMOOTHING */
|
||||
PERMIT_AUTH, /* SMOOTHTIME */
|
||||
PERMIT_AUTH, /* REFRESH */
|
||||
PERMIT_AUTH, /* SERVER_STATS */
|
||||
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX2 */
|
||||
PERMIT_AUTH, /* LOCAL2 */
|
||||
PERMIT_AUTH, /* NTP_DATA */
|
||||
PERMIT_AUTH, /* ADD_SERVER2 */
|
||||
PERMIT_AUTH, /* ADD_PEER2 */
|
||||
PERMIT_AUTH, /* ADD_SERVER3 */
|
||||
PERMIT_AUTH, /* ADD_PEER3 */
|
||||
PERMIT_AUTH, /* SHUTDOWN */
|
||||
PERMIT_AUTH, /* ONOFFLINE */
|
||||
PERMIT_AUTH, /* ADD_SOURCE */
|
||||
PERMIT_OPEN, /* NTP_SOURCE_NAME */
|
||||
PERMIT_AUTH, /* RESET_SOURCES */
|
||||
PERMIT_AUTH, /* AUTH_DATA */
|
||||
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX3 */
|
||||
PERMIT_AUTH, /* SELECT_DATA */
|
||||
PERMIT_AUTH, /* RELOAD_SOURCES */
|
||||
PERMIT_AUTH, /* DOFFSET2 */
|
||||
PERMIT_AUTH, /* MODIFY_SELECTOPTS */
|
||||
PERMIT_AUTH, /* MODIFY_OFFSET */
|
||||
PERMIT_AUTH, /* LOCAL3 */
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
/* This authorisation table is used for checking whether particular
|
||||
@@ -227,19 +146,17 @@ do_size_checks(void)
|
||||
request.command = htons(i);
|
||||
request_length = PKL_CommandLength(&request);
|
||||
padding_length = PKL_CommandPaddingLength(&request);
|
||||
if (padding_length > MAX_PADDING_LENGTH || padding_length > request_length ||
|
||||
request_length > sizeof (CMD_Request) ||
|
||||
(request_length && request_length < offsetof(CMD_Request, data)))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(padding_length <= MAX_PADDING_LENGTH && padding_length <= request_length &&
|
||||
request_length <= sizeof (CMD_Request) &&
|
||||
(request_length == 0 || request_length >= offsetof(CMD_Request, data)));
|
||||
}
|
||||
|
||||
for (i = 1; i < N_REPLY_TYPES; i++) {
|
||||
reply.reply = htons(i);
|
||||
reply.status = STT_SUCCESS;
|
||||
reply_length = PKL_ReplyLength(&reply);
|
||||
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
||||
reply_length > sizeof (CMD_Reply))
|
||||
assert(0);
|
||||
BRIEF_ASSERT((reply_length == 0 || reply_length >= offsetof(CMD_Reply, data)) &&
|
||||
reply_length <= sizeof (CMD_Reply));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +166,6 @@ void
|
||||
CAM_Initialise(void)
|
||||
{
|
||||
assert(!initialised);
|
||||
assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
|
||||
do_size_checks();
|
||||
|
||||
initialised = 1;
|
||||
@@ -533,7 +449,9 @@ handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
REF_EnableLocal(ntohl(rx_message->data.local.stratum),
|
||||
UTI_FloatNetworkToHost(rx_message->data.local.distance),
|
||||
ntohl(rx_message->data.local.orphan),
|
||||
UTI_FloatNetworkToHost(rx_message->data.local.activate));
|
||||
UTI_FloatNetworkToHost(rx_message->data.local.activate),
|
||||
UTI_FloatNetworkToHost(rx_message->data.local.wait_synced),
|
||||
UTI_FloatNetworkToHost(rx_message->data.local.wait_unsynced));
|
||||
} else {
|
||||
REF_DisableLocal();
|
||||
}
|
||||
@@ -1439,18 +1357,242 @@ handle_modify_offset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
||||
tx_message->status = htons(STT_NOSUCHSOURCE);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
handle_readwrite_commands(int command, CMD_Request *request, CMD_Reply *reply)
|
||||
{
|
||||
switch (command) {
|
||||
case REQ_ADD_SOURCE:
|
||||
handle_add_source(request, reply);
|
||||
break;
|
||||
case REQ_ALLOW:
|
||||
handle_allowdeny(request, reply, 1, 0);
|
||||
break;
|
||||
case REQ_ALLOWALL:
|
||||
handle_allowdeny(request, reply, 1, 1);
|
||||
break;
|
||||
case REQ_BURST:
|
||||
handle_burst(request, reply);
|
||||
break;
|
||||
case REQ_CMDALLOW:
|
||||
handle_cmdallowdeny(request, reply, 1, 0);
|
||||
break;
|
||||
case REQ_CMDALLOWALL:
|
||||
handle_cmdallowdeny(request, reply, 1, 1);
|
||||
break;
|
||||
case REQ_CMDDENY:
|
||||
handle_cmdallowdeny(request, reply, 0, 0);
|
||||
break;
|
||||
case REQ_CMDDENYALL:
|
||||
handle_cmdallowdeny(request, reply, 0, 1);
|
||||
break;
|
||||
case REQ_CYCLELOGS:
|
||||
handle_cyclelogs(request, reply);
|
||||
break;
|
||||
case REQ_DEL_SOURCE:
|
||||
handle_del_source(request, reply);
|
||||
break;
|
||||
case REQ_DENY:
|
||||
handle_allowdeny(request, reply, 0, 0);
|
||||
break;
|
||||
case REQ_DENYALL:
|
||||
handle_allowdeny(request, reply, 0, 1);
|
||||
break;
|
||||
case REQ_DFREQ:
|
||||
handle_dfreq(request, reply);
|
||||
break;
|
||||
case REQ_DOFFSET2:
|
||||
handle_doffset(request, reply);
|
||||
break;
|
||||
case REQ_DUMP:
|
||||
handle_dump(request, reply);
|
||||
break;
|
||||
case REQ_LOCAL3:
|
||||
handle_local(request, reply);
|
||||
break;
|
||||
case REQ_MAKESTEP:
|
||||
handle_make_step(request, reply);
|
||||
break;
|
||||
case REQ_MANUAL:
|
||||
handle_manual(request, reply);
|
||||
break;
|
||||
case REQ_MANUAL_DELETE:
|
||||
handle_manual_delete(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAKESTEP:
|
||||
handle_modify_makestep(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAXDELAY:
|
||||
handle_modify_maxdelay(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAXDELAYDEVRATIO:
|
||||
handle_modify_maxdelaydevratio(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAXDELAYRATIO:
|
||||
handle_modify_maxdelayratio(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAXPOLL:
|
||||
handle_modify_maxpoll(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MAXUPDATESKEW:
|
||||
handle_modify_maxupdateskew(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MINPOLL:
|
||||
handle_modify_minpoll(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_MINSTRATUM:
|
||||
handle_modify_minstratum(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_OFFSET:
|
||||
handle_modify_offset(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_POLLTARGET:
|
||||
handle_modify_polltarget(request, reply);
|
||||
break;
|
||||
case REQ_MODIFY_SELECTOPTS:
|
||||
handle_modify_selectopts(request, reply);
|
||||
break;
|
||||
case REQ_OFFLINE:
|
||||
handle_offline(request, reply);
|
||||
break;
|
||||
case REQ_ONLINE:
|
||||
handle_online(request, reply);
|
||||
break;
|
||||
case REQ_ONOFFLINE:
|
||||
handle_onoffline(request, reply);
|
||||
break;
|
||||
case REQ_REFRESH:
|
||||
handle_refresh(request, reply);
|
||||
break;
|
||||
case REQ_REKEY:
|
||||
handle_rekey(request, reply);
|
||||
break;
|
||||
case REQ_RELOAD_SOURCES:
|
||||
handle_reload_sources(request, reply);
|
||||
break;
|
||||
case REQ_RESELECT:
|
||||
handle_reselect(request, reply);
|
||||
break;
|
||||
case REQ_RESELECTDISTANCE:
|
||||
handle_reselect_distance(request, reply);
|
||||
break;
|
||||
case REQ_RESET_SOURCES:
|
||||
handle_reset_sources(request, reply);
|
||||
break;
|
||||
case REQ_SETTIME:
|
||||
handle_settime(request, reply);
|
||||
break;
|
||||
case REQ_SHUTDOWN:
|
||||
handle_shutdown(request, reply);
|
||||
break;
|
||||
case REQ_SMOOTHTIME:
|
||||
handle_smoothtime(request, reply);
|
||||
break;
|
||||
case REQ_TRIMRTC:
|
||||
handle_trimrtc(request, reply);
|
||||
break;
|
||||
case REQ_WRITERTC:
|
||||
handle_writertc(request, reply);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
handle_readonly_commands(int command, int full_access, CMD_Request *request, CMD_Reply *reply)
|
||||
{
|
||||
ARR_Instance open_commands;
|
||||
int i, allowed = 0;
|
||||
|
||||
if (full_access) {
|
||||
allowed = 1;
|
||||
} else {
|
||||
open_commands = CNF_GetOpenCommands();
|
||||
|
||||
for (i = 0; i < ARR_GetSize(open_commands); i++) {
|
||||
if (*(int *)ARR_GetElement(open_commands, i) == command) {
|
||||
allowed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowed)
|
||||
return 0;
|
||||
|
||||
switch (command) {
|
||||
case REQ_ACCHECK:
|
||||
handle_accheck(request, reply);
|
||||
break;
|
||||
case REQ_ACTIVITY:
|
||||
handle_activity(request, reply);
|
||||
break;
|
||||
case REQ_AUTH_DATA:
|
||||
handle_auth_data(request, reply);
|
||||
break;
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX3:
|
||||
handle_client_accesses_by_index(request, reply);
|
||||
break;
|
||||
case REQ_CMDACCHECK:
|
||||
handle_cmdaccheck(request, reply);
|
||||
break;
|
||||
case REQ_MANUAL_LIST:
|
||||
handle_manual_list(request, reply);
|
||||
break;
|
||||
case REQ_NTP_DATA:
|
||||
handle_ntp_data(request, reply);
|
||||
break;
|
||||
case REQ_NTP_SOURCE_NAME:
|
||||
handle_ntp_source_name(request, reply);
|
||||
break;
|
||||
case REQ_N_SOURCES:
|
||||
handle_n_sources(request, reply);
|
||||
break;
|
||||
case REQ_RTCREPORT:
|
||||
handle_rtcreport(request, reply);
|
||||
break;
|
||||
case REQ_SELECT_DATA:
|
||||
handle_select_data(request, reply);
|
||||
break;
|
||||
case REQ_SERVER_STATS:
|
||||
handle_server_stats(request, reply);
|
||||
break;
|
||||
case REQ_SMOOTHING:
|
||||
handle_smoothing(request, reply);
|
||||
break;
|
||||
case REQ_SOURCESTATS:
|
||||
handle_sourcestats(request, reply);
|
||||
break;
|
||||
case REQ_SOURCE_DATA:
|
||||
handle_source_data(request, reply);
|
||||
break;
|
||||
case REQ_TRACKING:
|
||||
handle_tracking(request, reply);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Read a packet and process it */
|
||||
|
||||
static void
|
||||
read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
{
|
||||
int read_length, expected_length, localhost, log_index, full_access, handled;
|
||||
SCK_Message *sck_message;
|
||||
CMD_Request rx_message;
|
||||
CMD_Reply tx_message;
|
||||
IPAddr loopback_addr, remote_ip;
|
||||
int read_length, expected_length;
|
||||
int localhost, allowed, log_index;
|
||||
uint16_t rx_command;
|
||||
struct timespec now, cooked_now;
|
||||
|
||||
@@ -1463,32 +1605,27 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
/* Get current time cheaply */
|
||||
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
||||
|
||||
/* Check if it's from localhost (127.0.0.1, ::1, or Unix domain),
|
||||
or an authorised address */
|
||||
switch (sck_message->addr_type) {
|
||||
case SCK_ADDR_IP:
|
||||
assert(sock_fd == sock_fd4 || sock_fd == sock_fd6);
|
||||
remote_ip = sck_message->remote_addr.ip.ip_addr;
|
||||
SCK_GetLoopbackIPAddress(remote_ip.family, &loopback_addr);
|
||||
localhost = UTI_CompareIPs(&remote_ip, &loopback_addr, NULL) == 0;
|
||||
/* Check if the request came from the Unix domain socket, or network and
|
||||
whether the address is allowed (127.0.0.1 and ::1 is always allowed) */
|
||||
if ((sock_fd == sock_fd4 || sock_fd == sock_fd6) && sck_message->addr_type == SCK_ADDR_IP) {
|
||||
remote_ip = sck_message->remote_addr.ip.ip_addr;
|
||||
SCK_GetLoopbackIPAddress(remote_ip.family, &loopback_addr);
|
||||
localhost = UTI_CompareIPs(&remote_ip, &loopback_addr, NULL) == 0;
|
||||
|
||||
if (!localhost && !ADF_IsAllowed(access_auth_table, &remote_ip)) {
|
||||
DEBUG_LOG("Unauthorised host %s",
|
||||
UTI_IPSockAddrToString(&sck_message->remote_addr.ip));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(remote_ip.family != IPADDR_UNSPEC);
|
||||
|
||||
break;
|
||||
case SCK_ADDR_UNIX:
|
||||
assert(sock_fd == sock_fdu);
|
||||
remote_ip.family = IPADDR_UNSPEC;
|
||||
localhost = 1;
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG("Unexpected address type");
|
||||
if (!localhost && !ADF_IsAllowed(access_auth_table, &remote_ip)) {
|
||||
DEBUG_LOG("Unauthorised host %s",
|
||||
UTI_IPSockAddrToString(&sck_message->remote_addr.ip));
|
||||
return;
|
||||
}
|
||||
|
||||
full_access = 0;
|
||||
} else if (sock_fd == sock_fdu && sck_message->addr_type == SCK_ADDR_UNIX) {
|
||||
remote_ip.family = IPADDR_UNSPEC;
|
||||
localhost = 1;
|
||||
full_access = 1;
|
||||
} else {
|
||||
DEBUG_LOG("Unexpected socket/address");
|
||||
return;
|
||||
}
|
||||
|
||||
if (read_length < offsetof(CMD_Request, data) ||
|
||||
@@ -1564,297 +1701,20 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
|
||||
|
||||
/* OK, we have a valid message. Now dispatch on message type and process it. */
|
||||
|
||||
if (rx_command >= N_REQUEST_TYPES) {
|
||||
/* This should be already handled */
|
||||
assert(0);
|
||||
} else {
|
||||
/* Check level of authority required to issue the command. All commands
|
||||
from the Unix domain socket (which is accessible only by the root and
|
||||
chrony user/group) are allowed. */
|
||||
if (remote_ip.family == IPADDR_UNSPEC) {
|
||||
assert(sock_fd == sock_fdu);
|
||||
allowed = 1;
|
||||
} else {
|
||||
switch (permissions[rx_command]) {
|
||||
case PERMIT_AUTH:
|
||||
allowed = 0;
|
||||
break;
|
||||
case PERMIT_LOCAL:
|
||||
allowed = localhost;
|
||||
break;
|
||||
case PERMIT_OPEN:
|
||||
allowed = 1;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
allowed = 0;
|
||||
}
|
||||
}
|
||||
LOG_SetContext(LOGC_Command);
|
||||
|
||||
if (allowed) {
|
||||
LOG_SetContext(LOGC_Command);
|
||||
if (full_access)
|
||||
handled = handle_readwrite_commands(rx_command, &rx_message, &tx_message);
|
||||
else
|
||||
handled = 0;
|
||||
|
||||
switch(rx_command) {
|
||||
case REQ_NULL:
|
||||
/* Do nothing */
|
||||
break;
|
||||
if (!handled)
|
||||
handled = handle_readonly_commands(rx_command, full_access, &rx_message, &tx_message);
|
||||
|
||||
case REQ_DUMP:
|
||||
handle_dump(&rx_message, &tx_message);
|
||||
break;
|
||||
if (!handled)
|
||||
tx_message.status = htons(STT_UNAUTH);
|
||||
|
||||
case REQ_ONLINE:
|
||||
handle_online(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_OFFLINE:
|
||||
handle_offline(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_BURST:
|
||||
handle_burst(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MINPOLL:
|
||||
handle_modify_minpoll(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXPOLL:
|
||||
handle_modify_maxpoll(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXDELAY:
|
||||
handle_modify_maxdelay(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXDELAYRATIO:
|
||||
handle_modify_maxdelayratio(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXDELAYDEVRATIO:
|
||||
handle_modify_maxdelaydevratio(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAXUPDATESKEW:
|
||||
handle_modify_maxupdateskew(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MAKESTEP:
|
||||
handle_modify_makestep(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_LOGON:
|
||||
/* Authentication is no longer supported, log-on always fails */
|
||||
tx_message.status = htons(STT_FAILED);
|
||||
break;
|
||||
|
||||
case REQ_SETTIME:
|
||||
handle_settime(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_LOCAL3:
|
||||
handle_local(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MANUAL:
|
||||
handle_manual(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_N_SOURCES:
|
||||
handle_n_sources(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SOURCE_DATA:
|
||||
handle_source_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_REKEY:
|
||||
handle_rekey(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ALLOW:
|
||||
handle_allowdeny(&rx_message, &tx_message, 1, 0);
|
||||
break;
|
||||
|
||||
case REQ_ALLOWALL:
|
||||
handle_allowdeny(&rx_message, &tx_message, 1, 1);
|
||||
break;
|
||||
|
||||
case REQ_DENY:
|
||||
handle_allowdeny(&rx_message, &tx_message, 0, 0);
|
||||
break;
|
||||
|
||||
case REQ_DENYALL:
|
||||
handle_allowdeny(&rx_message, &tx_message, 0, 1);
|
||||
break;
|
||||
|
||||
case REQ_CMDALLOW:
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
|
||||
break;
|
||||
|
||||
case REQ_CMDALLOWALL:
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
|
||||
break;
|
||||
|
||||
case REQ_CMDDENY:
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
|
||||
break;
|
||||
|
||||
case REQ_CMDDENYALL:
|
||||
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
|
||||
break;
|
||||
|
||||
case REQ_ACCHECK:
|
||||
handle_accheck(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_CMDACCHECK:
|
||||
handle_cmdaccheck(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ADD_SOURCE:
|
||||
handle_add_source(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_DEL_SOURCE:
|
||||
handle_del_source(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_WRITERTC:
|
||||
handle_writertc(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_DFREQ:
|
||||
handle_dfreq(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_DOFFSET2:
|
||||
handle_doffset(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_TRACKING:
|
||||
handle_tracking(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SMOOTHING:
|
||||
handle_smoothing(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SMOOTHTIME:
|
||||
handle_smoothtime(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SOURCESTATS:
|
||||
handle_sourcestats(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RTCREPORT:
|
||||
handle_rtcreport(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_TRIMRTC:
|
||||
handle_trimrtc(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_CYCLELOGS:
|
||||
handle_cyclelogs(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_CLIENT_ACCESSES_BY_INDEX3:
|
||||
handle_client_accesses_by_index(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MANUAL_LIST:
|
||||
handle_manual_list(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MANUAL_DELETE:
|
||||
handle_manual_delete(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MAKESTEP:
|
||||
handle_make_step(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ACTIVITY:
|
||||
handle_activity(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RESELECTDISTANCE:
|
||||
handle_reselect_distance(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RESELECT:
|
||||
handle_reselect(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_MINSTRATUM:
|
||||
handle_modify_minstratum(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_POLLTARGET:
|
||||
handle_modify_polltarget(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_REFRESH:
|
||||
handle_refresh(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SERVER_STATS:
|
||||
handle_server_stats(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_NTP_DATA:
|
||||
handle_ntp_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SHUTDOWN:
|
||||
handle_shutdown(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_ONOFFLINE:
|
||||
handle_onoffline(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_NTP_SOURCE_NAME:
|
||||
handle_ntp_source_name(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RESET_SOURCES:
|
||||
handle_reset_sources(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_AUTH_DATA:
|
||||
handle_auth_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_SELECT_DATA:
|
||||
handle_select_data(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_RELOAD_SOURCES:
|
||||
handle_reload_sources(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_SELECTOPTS:
|
||||
handle_modify_selectopts(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
case REQ_MODIFY_OFFSET:
|
||||
handle_modify_offset(&rx_message, &tx_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_LOG("Unhandled command %d", rx_command);
|
||||
tx_message.status = htons(STT_FAILED);
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_UnsetContext(LOGC_Command);
|
||||
} else {
|
||||
tx_message.status = htons(STT_UNAUTH);
|
||||
}
|
||||
}
|
||||
LOG_UnsetContext(LOGC_Command);
|
||||
|
||||
/* Transmit the response */
|
||||
transmit_reply(sock_fd, read_length, sck_message);
|
||||
|
||||
110
cmdparse.c
110
cmdparse.c
@@ -39,7 +39,12 @@
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
#define SSCANF_IN_RANGE(s, f, x, n, min, max) \
|
||||
(sscanf((s), (f), (x), (n)) == 1 && *(x) >= (min) && *(x) <= (max))
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
CPS_Status
|
||||
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
{
|
||||
char *hostname, *cmd;
|
||||
@@ -82,7 +87,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!*hostname)
|
||||
return 0;
|
||||
return CPS_MissingArgument;
|
||||
|
||||
src->name = hostname;
|
||||
|
||||
@@ -104,17 +109,17 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.connectivity = SRC_OFFLINE;
|
||||
} else if (!strcasecmp(cmd, "certset")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.cert_set, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "key")) {
|
||||
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
|
||||
src->params.authkey == INACTIVE_AUTHKEY)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "asymmetry")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "extfield")) {
|
||||
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
switch (ef_type) {
|
||||
case NTP_EF_EXP_MONO_ROOT:
|
||||
src->params.ext_fields |= NTP_EF_FLAG_EXP_MONO_ROOT;
|
||||
@@ -123,78 +128,78 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
|
||||
src->params.ext_fields |= NTP_EF_FLAG_EXP_NET_CORRECTION;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "filter")) {
|
||||
if (sscanf(line, "%d%n", &src->params.filter_length, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.filter_length, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "ipv4")) {
|
||||
src->family = IPADDR_INET4;
|
||||
} else if (!strcasecmp(cmd, "ipv6")) {
|
||||
src->family = IPADDR_INET6;
|
||||
} else if (!strcasecmp(cmd, "maxdelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelayratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_ratio, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxdelayquant")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.max_delay_quant, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.maxpoll, &n, -32, 32))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_samples, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_samples, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "maxsources")) {
|
||||
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.max_sources, &n, 1, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "mindelay")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minsamples")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_samples, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_samples, &n, 0, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "minstratum")) {
|
||||
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.min_stratum, &n, 0, NTP_MAX_STRATUM))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "nts")) {
|
||||
src->params.nts = 1;
|
||||
} else if (!strcasecmp(cmd, "ntsport")) {
|
||||
if (sscanf(line, "%d%n", &src->params.nts_port, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.nts_port, &n, 0, 65535))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "offset")) {
|
||||
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "port")) {
|
||||
if (sscanf(line, "%d%n", &src->port, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->port, &n, 0, 65535))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "polltarget")) {
|
||||
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.poll_target, &n, 1, INT_MAX))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "presend")) {
|
||||
if (sscanf(line, "%d%n", &src->params.presend_minpoll, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.presend_minpoll, &n, -32, 32))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "version")) {
|
||||
if (sscanf(line, "%d%n", &src->params.version, &n) != 1)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &src->params.version, &n, 1, NTP_VERSION))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "xleave")) {
|
||||
src->params.interleaved = 1;
|
||||
} else if ((sel_option = CPS_GetSelectOption(cmd)) != 0) {
|
||||
src->params.sel_options |= sel_option;
|
||||
} else {
|
||||
return 0;
|
||||
return CPS_InvalidOption;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return CPS_Success;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -295,8 +300,9 @@ CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *activate)
|
||||
CPS_Status
|
||||
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *activate,
|
||||
double *wait_synced, double *wait_unsynced)
|
||||
{
|
||||
int n;
|
||||
char *cmd;
|
||||
@@ -305,32 +311,42 @@ CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *
|
||||
*distance = 1.0;
|
||||
*activate = 0.0;
|
||||
*orphan = 0;
|
||||
*wait_synced = 0;
|
||||
*wait_unsynced = -1.0;
|
||||
|
||||
while (*line) {
|
||||
cmd = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(cmd, "stratum")) {
|
||||
if (sscanf(line, "%d%n", stratum, &n) != 1 ||
|
||||
*stratum >= NTP_MAX_STRATUM || *stratum <= 0)
|
||||
return 0;
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", stratum, &n, 1, NTP_MAX_STRATUM - 1))
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "orphan")) {
|
||||
*orphan = 1;
|
||||
n = 0;
|
||||
} else if (!strcasecmp(cmd, "distance")) {
|
||||
if (sscanf(line, "%lf%n", distance, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "activate")) {
|
||||
if (sscanf(line, "%lf%n", activate, &n) != 1)
|
||||
return 0;
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "waitsynced")) {
|
||||
if (sscanf(line, "%lf%n", wait_synced, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else if (!strcasecmp(cmd, "waitunsynced")) {
|
||||
if (sscanf(line, "%lf%n", wait_unsynced, &n) != 1)
|
||||
return CPS_InvalidValue;
|
||||
} else {
|
||||
return 0;
|
||||
return CPS_InvalidOption;
|
||||
}
|
||||
|
||||
line += n;
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (*wait_unsynced < 0.0)
|
||||
*wait_unsynced = *orphan ? 300 : 0.0;
|
||||
|
||||
return CPS_Success;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
12
cmdparse.h
12
cmdparse.h
@@ -30,6 +30,13 @@
|
||||
#include "srcparams.h"
|
||||
#include "addressing.h"
|
||||
|
||||
typedef enum {
|
||||
CPS_Success,
|
||||
CPS_InvalidValue,
|
||||
CPS_InvalidOption,
|
||||
CPS_MissingArgument,
|
||||
} CPS_Status;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int family;
|
||||
@@ -38,7 +45,7 @@ typedef struct {
|
||||
} CPS_NTP_Source;
|
||||
|
||||
/* Parse a command to add an NTP server or peer */
|
||||
extern int CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
|
||||
extern CPS_Status CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
|
||||
|
||||
/* Get an NTP/refclock select option */
|
||||
extern int CPS_GetSelectOption(char *option);
|
||||
@@ -47,7 +54,8 @@ extern int CPS_GetSelectOption(char *option);
|
||||
extern int CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits);
|
||||
|
||||
/* Parse a command to enable local reference */
|
||||
extern int CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance, double *activate);
|
||||
extern CPS_Status CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance,
|
||||
double *activate, double *wait_synced, double *wait_unsynced);
|
||||
|
||||
/* Remove extra white-space and comments */
|
||||
extern void CPS_NormalizeLine(char *line);
|
||||
|
||||
334
conf.c
334
conf.c
@@ -3,7 +3,7 @@
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Richard P. Curnow 1997-2003
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017, 2020
|
||||
* Copyright (C) Miroslav Lichvar 2009-2017, 2020, 2024
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -50,13 +50,17 @@
|
||||
#define MAX_CONF_DIRS 10
|
||||
#define MAX_INCLUDE_LEVEL 10
|
||||
|
||||
#define SSCANF_IN_RANGE(s, f, x, n, min, max) \
|
||||
(sscanf((s), (f), (x), (n)) == 1 && *(x) >= (min) && *(x) <= (max))
|
||||
|
||||
/* ================================================== */
|
||||
/* Forward prototypes */
|
||||
|
||||
static int parse_string(char *line, char **result);
|
||||
static int parse_int(char *line, int *result);
|
||||
static int parse_double(char *line, double *result);
|
||||
static int parse_null(char *line);
|
||||
static void parse_string(char *line, char **result);
|
||||
static void parse_int(char *line, int *result, int min, int max);
|
||||
static void parse_double(char *line, double *result);
|
||||
static void parse_null(char *line, int *result);
|
||||
static void parse_ints(char *line, ARR_Instance array, int min, int max);
|
||||
|
||||
static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow);
|
||||
static void parse_authselectmode(char *);
|
||||
@@ -66,6 +70,7 @@ static void parse_bindcmdaddress(char *);
|
||||
static void parse_broadcast(char *);
|
||||
static void parse_clientloglimit(char *);
|
||||
static void parse_confdir(char *);
|
||||
static void parse_driftfile(char *);
|
||||
static void parse_fallbackdrift(char *);
|
||||
static void parse_hwtimestamp(char *);
|
||||
static void parse_include(char *);
|
||||
@@ -78,6 +83,7 @@ static void parse_makestep(char *);
|
||||
static void parse_maxchange(char *);
|
||||
static void parse_ntsserver(char *, ARR_Instance files);
|
||||
static void parse_ntstrustedcerts(char *);
|
||||
static void parse_open_commands(char *line);
|
||||
static void parse_pidfile(char *line);
|
||||
static void parse_ratelimit(char *line, int *enabled, int *interval,
|
||||
int *burst, int *leak, int *kod);
|
||||
@@ -97,6 +103,7 @@ static int acquisition_port = -1;
|
||||
static int ntp_port = NTP_PORT;
|
||||
static char *keys_file = NULL;
|
||||
static char *drift_file = NULL;
|
||||
static int drift_file_interval = 3600;
|
||||
static char *rtc_file = NULL;
|
||||
static double max_update_skew = 1000.0;
|
||||
static double correction_time_ratio = 3.0;
|
||||
@@ -131,6 +138,8 @@ static int local_stratum;
|
||||
static int local_orphan;
|
||||
static double local_distance;
|
||||
static double local_activate;
|
||||
static double local_wait_synced;
|
||||
static double local_wait_unsynced;
|
||||
|
||||
/* Threshold (in seconds) - if absolute value of initial error is less
|
||||
than this, slew instead of stepping */
|
||||
@@ -261,7 +270,10 @@ static char *user;
|
||||
/* Address refresh interval */
|
||||
static int refresh = 1209600; /* 2 weeks */
|
||||
|
||||
#define DEFAULT_NTS_AEADS "30 15"
|
||||
|
||||
/* NTS server and client configuration */
|
||||
static ARR_Instance nts_aeads; /* array of int */
|
||||
static char *nts_dump_dir = NULL;
|
||||
static char *nts_ntp_server = NULL;
|
||||
static ARR_Instance nts_server_cert_files; /* array of (char *) */
|
||||
@@ -320,6 +332,11 @@ typedef struct _AllowDeny {
|
||||
static ARR_Instance ntp_restrictions;
|
||||
static ARR_Instance cmd_restrictions;
|
||||
|
||||
#define DEFAULT_OPEN_COMMANDS "activity manual rtcdata smoothing sourcename sources sourcestats tracking"
|
||||
|
||||
/* Array of int specifying commands allowed from network */
|
||||
static ARR_Instance open_commands;
|
||||
|
||||
typedef struct {
|
||||
NTP_Remote_Address addr;
|
||||
int interval;
|
||||
@@ -349,12 +366,20 @@ command_parse_error(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
FORMAT_ATTRIBUTE_PRINTF(1, 2)
|
||||
static void
|
||||
other_parse_error(const char *message)
|
||||
other_parse_error(const char *format, ...)
|
||||
{
|
||||
LOG_FATAL("%s at line %d%s%s",
|
||||
message, line_number, processed_file ? " in file " : "",
|
||||
processed_file ? processed_file : "");
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof (buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
LOG_FATAL("%s at line %d%s%s",
|
||||
buf, line_number, processed_file ? " in file " : "",
|
||||
processed_file ? processed_file : "");
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -397,6 +422,8 @@ check_number_of_args(char *line, int num)
|
||||
void
|
||||
CNF_Initialise(int r, int client_only)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
restarted = r;
|
||||
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
||||
@@ -410,6 +437,13 @@ CNF_Initialise(int r, int client_only)
|
||||
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
|
||||
open_commands = ARR_CreateInstance(sizeof (int));
|
||||
snprintf(buf, sizeof (buf), DEFAULT_OPEN_COMMANDS);
|
||||
parse_open_commands(buf);
|
||||
|
||||
nts_aeads = ARR_CreateInstance(sizeof (int));
|
||||
snprintf(buf, sizeof (buf), DEFAULT_NTS_AEADS);
|
||||
parse_ints(buf, nts_aeads, 0, INT_MAX);
|
||||
nts_server_cert_files = ARR_CreateInstance(sizeof (char *));
|
||||
nts_server_key_files = ARR_CreateInstance(sizeof (char *));
|
||||
nts_trusted_certs_paths = ARR_CreateInstance(sizeof (char *));
|
||||
@@ -466,9 +500,12 @@ CNF_Finalise(void)
|
||||
ARR_DestroyInstance(refclock_sources);
|
||||
ARR_DestroyInstance(broadcasts);
|
||||
|
||||
ARR_DestroyInstance(open_commands);
|
||||
|
||||
ARR_DestroyInstance(ntp_restrictions);
|
||||
ARR_DestroyInstance(cmd_restrictions);
|
||||
|
||||
ARR_DestroyInstance(nts_aeads);
|
||||
ARR_DestroyInstance(nts_server_cert_files);
|
||||
ARR_DestroyInstance(nts_server_key_files);
|
||||
ARR_DestroyInstance(nts_trusted_certs_paths);
|
||||
@@ -563,7 +600,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
printf("%s%s%s\n", command, p[0] != '\0' ? " " : "", p);
|
||||
|
||||
if (!strcasecmp(command, "acquisitionport")) {
|
||||
parse_int(p, &acquisition_port);
|
||||
parse_int(p, &acquisition_port, 0, 65535);
|
||||
} else if (!strcasecmp(command, "allow")) {
|
||||
parse_allow_deny(p, ntp_restrictions, 1);
|
||||
} else if (!strcasecmp(command, "authselectmode")) {
|
||||
@@ -591,7 +628,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "cmddeny")) {
|
||||
parse_allow_deny(p, cmd_restrictions, 0);
|
||||
} else if (!strcasecmp(command, "cmdport")) {
|
||||
parse_int(p, &cmd_port);
|
||||
parse_int(p, &cmd_port, 0, 65535);
|
||||
} else if (!strcasecmp(command, "cmdratelimit")) {
|
||||
parse_ratelimit(p, &cmd_ratelimit_enabled, &cmd_ratelimit_interval,
|
||||
&cmd_ratelimit_burst, &cmd_ratelimit_leak, NULL);
|
||||
@@ -604,9 +641,9 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "deny")) {
|
||||
parse_allow_deny(p, ntp_restrictions, 0);
|
||||
} else if (!strcasecmp(command, "driftfile")) {
|
||||
parse_string(p, &drift_file);
|
||||
parse_driftfile(p);
|
||||
} else if (!strcasecmp(command, "dscp")) {
|
||||
parse_int(p, &ntp_dscp);
|
||||
parse_int(p, &ntp_dscp, 0, 63);
|
||||
} else if (!strcasecmp(command, "dumpdir")) {
|
||||
parse_string(p, &dumpdir);
|
||||
} else if (!strcasecmp(command, "dumponexit")) {
|
||||
@@ -634,11 +671,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "local")) {
|
||||
parse_local(p);
|
||||
} else if (!strcasecmp(command, "lock_all")) {
|
||||
lock_memory = parse_null(p);
|
||||
parse_null(p, &lock_memory);
|
||||
} else if (!strcasecmp(command, "log")) {
|
||||
parse_log(p);
|
||||
} else if (!strcasecmp(command, "logbanner")) {
|
||||
parse_int(p, &log_banner);
|
||||
parse_int(p, &log_banner, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "logchange")) {
|
||||
parse_double(p, &log_change_threshold);
|
||||
} else if (!strcasecmp(command, "logdir")) {
|
||||
@@ -648,7 +685,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "makestep")) {
|
||||
parse_makestep(p);
|
||||
} else if (!strcasecmp(command, "manual")) {
|
||||
enable_manual = parse_null(p);
|
||||
parse_null(p, &enable_manual);
|
||||
} else if (!strcasecmp(command, "maxchange")) {
|
||||
parse_maxchange(p);
|
||||
} else if (!strcasecmp(command, "maxclockerror")) {
|
||||
@@ -660,25 +697,27 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "maxjitter")) {
|
||||
parse_double(p, &max_jitter);
|
||||
} else if (!strcasecmp(command, "maxntsconnections")) {
|
||||
parse_int(p, &nts_server_connections);
|
||||
parse_int(p, &nts_server_connections, 1, INT_MAX);
|
||||
} else if (!strcasecmp(command, "maxsamples")) {
|
||||
parse_int(p, &max_samples);
|
||||
parse_int(p, &max_samples, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "maxslewrate")) {
|
||||
parse_double(p, &max_slew_rate);
|
||||
} else if (!strcasecmp(command, "maxupdateskew")) {
|
||||
parse_double(p, &max_update_skew);
|
||||
} else if (!strcasecmp(command, "minsamples")) {
|
||||
parse_int(p, &min_samples);
|
||||
parse_int(p, &min_samples, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "minsources")) {
|
||||
parse_int(p, &min_sources);
|
||||
parse_int(p, &min_sources, 1, INT_MAX);
|
||||
} else if (!strcasecmp(command, "nocerttimecheck")) {
|
||||
parse_int(p, &no_cert_time_check);
|
||||
parse_int(p, &no_cert_time_check, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "noclientlog")) {
|
||||
no_client_log = parse_null(p);
|
||||
parse_null(p, &no_client_log);
|
||||
} else if (!strcasecmp(command, "nosystemcert")) {
|
||||
no_system_cert = parse_null(p);
|
||||
parse_null(p, &no_system_cert);
|
||||
} else if (!strcasecmp(command, "ntpsigndsocket")) {
|
||||
parse_string(p, &ntp_signd_socket);
|
||||
} else if (!strcasecmp(command, "ntsaeads")) {
|
||||
parse_ints(p, nts_aeads, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "ntsratelimit")) {
|
||||
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval,
|
||||
&nts_ratelimit_burst, &nts_ratelimit_leak, NULL);
|
||||
@@ -688,19 +727,21 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "ntsntpserver")) {
|
||||
parse_string(p, &nts_ntp_server);
|
||||
} else if (!strcasecmp(command, "ntsport")) {
|
||||
parse_int(p, &nts_server_port);
|
||||
parse_int(p, &nts_server_port, 0, 65535);
|
||||
} else if (!strcasecmp(command, "ntsprocesses")) {
|
||||
parse_int(p, &nts_server_processes);
|
||||
parse_int(p, &nts_server_processes, 0, 1000);
|
||||
} else if (!strcasecmp(command, "ntsrefresh")) {
|
||||
parse_int(p, &nts_refresh);
|
||||
parse_int(p, &nts_refresh, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "ntsrotate")) {
|
||||
parse_int(p, &nts_rotate);
|
||||
parse_int(p, &nts_rotate, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "ntsservercert")) {
|
||||
parse_ntsserver(p, nts_server_cert_files);
|
||||
} else if (!strcasecmp(command, "ntsserverkey")) {
|
||||
parse_ntsserver(p, nts_server_key_files);
|
||||
} else if (!strcasecmp(command, "ntstrustedcerts")) {
|
||||
parse_ntstrustedcerts(p);
|
||||
} else if (!strcasecmp(command, "opencommands")) {
|
||||
parse_open_commands(p);
|
||||
} else if (!strcasecmp(command, "peer")) {
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "pidfile")) {
|
||||
@@ -708,18 +749,18 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "pool")) {
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "port")) {
|
||||
parse_int(p, &ntp_port);
|
||||
parse_int(p, &ntp_port, 0, 65535);
|
||||
} else if (!strcasecmp(command, "ptpdomain")) {
|
||||
parse_int(p, &ptp_domain);
|
||||
parse_int(p, &ptp_domain, 0, 255);
|
||||
} else if (!strcasecmp(command, "ptpport")) {
|
||||
parse_int(p, &ptp_port);
|
||||
parse_int(p, &ptp_port, 0, 65535);
|
||||
} else if (!strcasecmp(command, "ratelimit")) {
|
||||
parse_ratelimit(p, &ntp_ratelimit_enabled, &ntp_ratelimit_interval,
|
||||
&ntp_ratelimit_burst, &ntp_ratelimit_leak, &ntp_ratelimit_kod);
|
||||
} else if (!strcasecmp(command, "refclock")) {
|
||||
parse_refclock(p);
|
||||
} else if (!strcasecmp(command, "refresh")) {
|
||||
parse_int(p, &refresh);
|
||||
parse_int(p, &refresh, 0, INT_MAX);
|
||||
} else if (!strcasecmp(command, "reselectdist")) {
|
||||
parse_double(p, &reselect_distance);
|
||||
} else if (!strcasecmp(command, "rtcautotrim")) {
|
||||
@@ -729,11 +770,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
} else if (!strcasecmp(command, "rtcfile")) {
|
||||
parse_string(p, &rtc_file);
|
||||
} else if (!strcasecmp(command, "rtconutc")) {
|
||||
rtc_on_utc = parse_null(p);
|
||||
parse_null(p, &rtc_on_utc);
|
||||
} else if (!strcasecmp(command, "rtcsync")) {
|
||||
rtc_sync = parse_null(p);
|
||||
parse_null(p, &rtc_sync);
|
||||
} else if (!strcasecmp(command, "sched_priority")) {
|
||||
parse_int(p, &sched_priority);
|
||||
parse_int(p, &sched_priority, 0, 100);
|
||||
} else if (!strcasecmp(command, "server")) {
|
||||
parse_source(p, command, 1);
|
||||
} else if (!strcasecmp(command, "smoothtime")) {
|
||||
@@ -752,7 +793,7 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
!strcasecmp(command, "linux_hz")) {
|
||||
LOG(LOGS_WARN, "%s directive is no longer supported", command);
|
||||
} else {
|
||||
other_parse_error("Invalid directive");
|
||||
other_parse_error("Invalid directive %s", command);
|
||||
}
|
||||
|
||||
processed_file = processed_command = NULL;
|
||||
@@ -760,48 +801,70 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
static void
|
||||
parse_string(char *line, char **result)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
Free(*result);
|
||||
*result = Strdup(line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_int(char *line, int *result)
|
||||
static void
|
||||
parse_int(char *line, int *result, int min, int max)
|
||||
{
|
||||
char *end;
|
||||
long r;
|
||||
|
||||
check_number_of_args(line, 1);
|
||||
if (sscanf(line, "%d", result) != 1) {
|
||||
|
||||
errno = 0;
|
||||
r = strtol(line, &end, 10);
|
||||
if (errno != 0 || *end != '\0')
|
||||
command_parse_error();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
if (r < min || r > max)
|
||||
other_parse_error("Invalid value %ld in %s directive (min %d, max %d)",
|
||||
r, processed_command, min, max);
|
||||
*result = r;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
static void
|
||||
parse_double(char *line, double *result)
|
||||
{
|
||||
check_number_of_args(line, 1);
|
||||
if (sscanf(line, "%lf", result) != 1) {
|
||||
command_parse_error();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_null(char *line)
|
||||
static void
|
||||
parse_null(char *line, int *result)
|
||||
{
|
||||
check_number_of_args(line, 0);
|
||||
return 1;
|
||||
*result = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_ints(char *line, ARR_Instance array, int min, int max)
|
||||
{
|
||||
char *s;
|
||||
int v;
|
||||
|
||||
ARR_SetSize(array, 0);
|
||||
|
||||
while (*line) {
|
||||
s = line;
|
||||
line = CPS_SplitWord(line);
|
||||
parse_int(s, &v, min, max);
|
||||
ARR_AppendElement(array, &v);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -809,6 +872,7 @@ parse_null(char *line)
|
||||
static void
|
||||
parse_source(char *line, char *type, int fatal)
|
||||
{
|
||||
CPS_Status status;
|
||||
NTP_Source source;
|
||||
|
||||
if (strcasecmp(type, "peer") == 0) {
|
||||
@@ -829,9 +893,13 @@ parse_source(char *line, char *type, int fatal)
|
||||
/* Avoid comparing uninitialized data in compare_sources() */
|
||||
memset(&source.params, 0, sizeof (source.params));
|
||||
|
||||
if (!CPS_ParseNTPSourceAdd(line, &source.params)) {
|
||||
if (fatal)
|
||||
command_parse_error();
|
||||
status = CPS_ParseNTPSourceAdd(line, &source.params);
|
||||
if (status != CPS_Success) {
|
||||
if (fatal) {
|
||||
other_parse_error("Invalid %s %s directive",
|
||||
status == CPS_InvalidOption ? "option in" :
|
||||
status == CPS_InvalidValue ? "value in" : "syntax for", type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -866,7 +934,7 @@ parse_ratelimit(char *line, int *enabled, int *interval, int *burst, int *leak,
|
||||
while (*line) {
|
||||
opt = line;
|
||||
line = CPS_SplitWord(line);
|
||||
if (sscanf(line, "%d%n", &val, &n) != 1) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &val, &n, -32, 32)) {
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
@@ -945,31 +1013,28 @@ parse_refclock(char *line)
|
||||
if ((n = CPS_ParseRefid(line, &lock_ref_id)) == 0)
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "poll")) {
|
||||
if (sscanf(line, "%d%n", &poll, &n) != 1) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &poll, &n, -32, 32))
|
||||
break;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "dpoll")) {
|
||||
if (sscanf(line, "%d%n", &dpoll, &n) != 1) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &dpoll, &n, -32, 32))
|
||||
break;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "filter")) {
|
||||
if (sscanf(line, "%d%n", &filter_length, &n) != 1) {
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &filter_length, &n, 0, INT_MAX))
|
||||
break;
|
||||
}
|
||||
} else if (!strcasecmp(cmd, "local")) {
|
||||
n = 0;
|
||||
local = 1;
|
||||
} else if (!strcasecmp(cmd, "rate")) {
|
||||
if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &pps_rate, &n, 1, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "minsamples")) {
|
||||
if (sscanf(line, "%d%n", &min_samples, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &min_samples, &n, 0, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "maxlockage")) {
|
||||
if (sscanf(line, "%d%n", &max_lock_age, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &max_lock_age, &n, 0, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "maxsamples")) {
|
||||
if (sscanf(line, "%d%n", &max_samples, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &max_samples, &n, 0, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "offset")) {
|
||||
if (sscanf(line, "%lf%n", &offset, &n) != 1)
|
||||
@@ -987,8 +1052,7 @@ parse_refclock(char *line)
|
||||
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)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &stratum, &n, 0, NTP_MAX_STRATUM - 1))
|
||||
break;
|
||||
} else if (!strcasecmp(cmd, "tai")) {
|
||||
n = 0;
|
||||
@@ -1000,13 +1064,13 @@ parse_refclock(char *line)
|
||||
n = 0;
|
||||
sel_options |= sel_option;
|
||||
} else {
|
||||
other_parse_error("Invalid refclock option");
|
||||
other_parse_error("Invalid %s %s directive", "option in", processed_command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (*cmd) {
|
||||
command_parse_error();
|
||||
other_parse_error("Invalid %s %s directive", "value in", processed_command);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1076,8 +1140,16 @@ parse_log(char *line)
|
||||
static void
|
||||
parse_local(char *line)
|
||||
{
|
||||
if (!CPS_ParseLocal(line, &local_stratum, &local_orphan, &local_distance, &local_activate))
|
||||
command_parse_error();
|
||||
CPS_Status status;
|
||||
|
||||
status = CPS_ParseLocal(line, &local_stratum, &local_orphan, &local_distance,
|
||||
&local_activate, &local_wait_synced, &local_wait_unsynced);
|
||||
if (status != CPS_Success) {
|
||||
other_parse_error("Invalid %s %s directive",
|
||||
status == CPS_InvalidOption ? "option in" : "value in",
|
||||
processed_command);
|
||||
}
|
||||
|
||||
enable_local = 1;
|
||||
}
|
||||
|
||||
@@ -1238,6 +1310,72 @@ parse_ntstrustedcerts(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
add_open_command(int command)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Avoid duplicates */
|
||||
for (i = 0; i < ARR_GetSize(open_commands); i++) {
|
||||
if (*(int *)ARR_GetElement(open_commands, i) == command)
|
||||
return;
|
||||
}
|
||||
|
||||
ARR_AppendElement(open_commands, &command);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_open_commands(char *line)
|
||||
{
|
||||
char *s;
|
||||
|
||||
ARR_SetSize(open_commands, 0);
|
||||
|
||||
while (*line) {
|
||||
s = line;
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (strcasecmp(s, "activity") == 0) {
|
||||
add_open_command(REQ_ACTIVITY);
|
||||
} else if (strcasecmp(s, "authdata") == 0) {
|
||||
add_open_command(REQ_N_SOURCES);
|
||||
add_open_command(REQ_AUTH_DATA);
|
||||
} else if (strcasecmp(s, "clients") == 0) {
|
||||
add_open_command(REQ_CLIENT_ACCESSES_BY_INDEX3);
|
||||
} else if (strcasecmp(s, "manual") == 0) {
|
||||
add_open_command(REQ_MANUAL_LIST);
|
||||
} else if (strcasecmp(s, "ntpdata") == 0) {
|
||||
add_open_command(REQ_N_SOURCES);
|
||||
add_open_command(REQ_NTP_DATA);
|
||||
} else if (strcasecmp(s, "rtcdata") == 0) {
|
||||
add_open_command(REQ_RTCREPORT);
|
||||
} else if (strcasecmp(s, "selectdata") == 0) {
|
||||
add_open_command(REQ_N_SOURCES);
|
||||
add_open_command(REQ_SELECT_DATA);
|
||||
} else if (strcasecmp(s, "serverstats") == 0) {
|
||||
add_open_command(REQ_SERVER_STATS);
|
||||
} else if (strcasecmp(s, "smoothing") == 0) {
|
||||
add_open_command(REQ_SMOOTHING);
|
||||
} else if (strcasecmp(s, "sourcename") == 0) {
|
||||
add_open_command(REQ_NTP_SOURCE_NAME);
|
||||
} else if (strcasecmp(s, "sources") == 0) {
|
||||
add_open_command(REQ_N_SOURCES);
|
||||
add_open_command(REQ_SOURCE_DATA);
|
||||
} else if (strcasecmp(s, "sourcestats") == 0) {
|
||||
add_open_command(REQ_N_SOURCES);
|
||||
add_open_command(REQ_SOURCESTATS);
|
||||
} else if (strcasecmp(s, "tracking") == 0) {
|
||||
add_open_command(REQ_TRACKING);
|
||||
} else {
|
||||
command_parse_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
|
||||
{
|
||||
@@ -1479,17 +1617,17 @@ parse_hwtimestamp(char *line)
|
||||
line = CPS_SplitWord(line);
|
||||
|
||||
if (!strcasecmp(p, "maxsamples")) {
|
||||
if (sscanf(line, "%d%n", &iface->max_samples, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &iface->max_samples, &n, 0, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(p, "minpoll")) {
|
||||
if (sscanf(line, "%d%n", &iface->minpoll, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &iface->minpoll, &n, -32, 32))
|
||||
break;
|
||||
} else if (!strcasecmp(p, "maxpoll")) {
|
||||
if (sscanf(line, "%d%n", &iface->maxpoll, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &iface->maxpoll, &n, -32, 32))
|
||||
break;
|
||||
maxpoll_set = 1;
|
||||
} else if (!strcasecmp(p, "minsamples")) {
|
||||
if (sscanf(line, "%d%n", &iface->min_samples, &n) != 1)
|
||||
if (!SSCANF_IN_RANGE(line, "%d%n", &iface->min_samples, &n, 0, INT_MAX))
|
||||
break;
|
||||
} else if (!strcasecmp(p, "precision")) {
|
||||
if (sscanf(line, "%lf%n", &iface->precision, &n) != 1)
|
||||
@@ -1624,6 +1762,29 @@ parse_confdir(char *line)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_driftfile(char *line)
|
||||
{
|
||||
char *path, *opt, *val;
|
||||
|
||||
path = line;
|
||||
opt = CPS_SplitWord(path);
|
||||
val = CPS_SplitWord(opt);
|
||||
|
||||
if (*path == '\0' ||
|
||||
(*opt != '\0' && (strcasecmp(opt, "interval") != 0 ||
|
||||
sscanf(val, "%d", &drift_file_interval) != 1 ||
|
||||
*CPS_SplitWord(val) != '\0'))) {
|
||||
command_parse_error();
|
||||
return;
|
||||
}
|
||||
|
||||
Free(drift_file);
|
||||
drift_file = Strdup(path);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_include(char *line)
|
||||
{
|
||||
@@ -1949,8 +2110,9 @@ CNF_GetAcquisitionPort(void)
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetDriftFile(void)
|
||||
CNF_GetDriftFile(int *interval)
|
||||
{
|
||||
*interval = drift_file_interval;
|
||||
return drift_file;
|
||||
}
|
||||
|
||||
@@ -2173,6 +2335,14 @@ CNF_GetManualEnabled(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetOpenCommands(void)
|
||||
{
|
||||
return open_commands;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_GetCommandPort(void) {
|
||||
return cmd_port;
|
||||
@@ -2181,13 +2351,16 @@ CNF_GetCommandPort(void) {
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
CNF_AllowLocalReference(int *stratum, int *orphan, double *distance, double *activate)
|
||||
CNF_AllowLocalReference(int *stratum, int *orphan, double *distance, double *activate,
|
||||
double *wait_synced, double *wait_unsynced)
|
||||
{
|
||||
if (enable_local) {
|
||||
*stratum = local_stratum;
|
||||
*orphan = local_orphan;
|
||||
*distance = local_distance;
|
||||
*activate = local_activate;
|
||||
*wait_synced = local_wait_synced;
|
||||
*wait_unsynced = local_wait_unsynced;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -2599,6 +2772,14 @@ CNF_GetRefresh(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetNtsAeads(void)
|
||||
{
|
||||
return nts_aeads;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetNtsDumpDir(void)
|
||||
{
|
||||
@@ -2675,8 +2856,7 @@ CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids)
|
||||
*paths = ARR_GetElements(nts_trusted_certs_paths);
|
||||
*ids = ARR_GetElements(nts_trusted_certs_ids);
|
||||
|
||||
if (ARR_GetSize(nts_trusted_certs_paths) != ARR_GetSize(nts_trusted_certs_ids))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(ARR_GetSize(nts_trusted_certs_paths) == ARR_GetSize(nts_trusted_certs_ids));
|
||||
|
||||
return ARR_GetSize(nts_trusted_certs_paths);
|
||||
}
|
||||
|
||||
8
conf.h
8
conf.h
@@ -29,6 +29,7 @@
|
||||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.h"
|
||||
#include "reference.h"
|
||||
#include "sources.h"
|
||||
|
||||
@@ -55,7 +56,7 @@ extern void CNF_ReloadSources(void);
|
||||
|
||||
extern int CNF_GetAcquisitionPort(void);
|
||||
extern int CNF_GetNTPPort(void);
|
||||
extern char *CNF_GetDriftFile(void);
|
||||
extern char *CNF_GetDriftFile(int *interval);
|
||||
extern char *CNF_GetLogDir(void);
|
||||
extern char *CNF_GetDumpDir(void);
|
||||
extern int CNF_GetLogBanner(void);
|
||||
@@ -69,6 +70,7 @@ extern int CNF_GetLogTempComp(void);
|
||||
extern char *CNF_GetKeysFile(void);
|
||||
extern char *CNF_GetRtcFile(void);
|
||||
extern int CNF_GetManualEnabled(void);
|
||||
extern ARR_Instance CNF_GetOpenCommands(void);
|
||||
extern int CNF_GetCommandPort(void);
|
||||
extern int CNF_GetRtcOnUtc(void);
|
||||
extern int CNF_GetRtcSync(void);
|
||||
@@ -108,7 +110,8 @@ extern double CNF_GetReselectDistance(void);
|
||||
extern double CNF_GetStratumWeight(void);
|
||||
extern double CNF_GetCombineLimit(void);
|
||||
|
||||
extern int CNF_AllowLocalReference(int *stratum, int *orphan, double *distance, double *activate);
|
||||
extern int CNF_AllowLocalReference(int *stratum, int *orphan, double *distance, double *activate,
|
||||
double *wait_synced, double *wait_unsynced);
|
||||
|
||||
extern void CNF_SetupAccessRestrictions(void);
|
||||
|
||||
@@ -163,6 +166,7 @@ extern int CNF_GetPtpDomain(void);
|
||||
|
||||
extern int CNF_GetRefresh(void);
|
||||
|
||||
extern ARR_Instance CNF_GetNtsAeads(void);
|
||||
extern char *CNF_GetNtsDumpDir(void);
|
||||
extern char *CNF_GetNtsNtpServer(void);
|
||||
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
|
||||
|
||||
83
configure
vendored
83
configure
vendored
@@ -116,7 +116,6 @@ For better control, use the options below.
|
||||
--without-tomcrypt Don't use libtomcrypt even if it is available
|
||||
--disable-nts Disable NTS support
|
||||
--disable-cmdmon Disable command and monitoring support
|
||||
--disable-ntp Disable NTP support
|
||||
--disable-refclock Disable reference clock support
|
||||
--disable-phc Disable PHC refclock driver
|
||||
--disable-pps Disable PPS refclock driver
|
||||
@@ -126,7 +125,6 @@ For better control, use the options below.
|
||||
--without-libcap Don't use libcap even if it is available
|
||||
--enable-scfilter Enable support for system call filtering
|
||||
--without-seccomp Don't use seccomp even if it is available
|
||||
--disable-asyncdns Disable asynchronous name resolving
|
||||
--disable-forcednsretry Don't retry on permanent DNS error
|
||||
--without-aes-gcm-siv Don't use AES-GCM-SIV for NTS even if it is available
|
||||
--without-clock-gettime Don't use clock_gettime() even if it is available
|
||||
@@ -219,7 +217,6 @@ EXTRA_CLI_OBJECTS=""
|
||||
|
||||
feat_debug=0
|
||||
feat_cmdmon=1
|
||||
feat_ntp=1
|
||||
feat_refclock=1
|
||||
feat_readline=1
|
||||
try_editline=1
|
||||
@@ -243,7 +240,6 @@ try_phc=0
|
||||
feat_pps=1
|
||||
try_setsched=0
|
||||
try_lockmem=0
|
||||
feat_asyncdns=1
|
||||
feat_forcednsretry=1
|
||||
try_aes_gcm_siv=1
|
||||
try_clock_gettime=1
|
||||
@@ -253,7 +249,6 @@ feat_timestamping=1
|
||||
try_timestamping=0
|
||||
feat_ntp_signd=0
|
||||
ntp_era_split=""
|
||||
use_pthread=0
|
||||
default_user="root"
|
||||
default_hwclockfile=""
|
||||
default_pidfile="/var/run/chrony/chronyd.pid"
|
||||
@@ -308,9 +303,6 @@ do
|
||||
--disable-cmdmon)
|
||||
feat_cmdmon=0
|
||||
;;
|
||||
--disable-ntp)
|
||||
feat_ntp=0
|
||||
;;
|
||||
--disable-refclock)
|
||||
feat_refclock=0
|
||||
;;
|
||||
@@ -341,9 +333,6 @@ do
|
||||
--without-seccomp)
|
||||
try_seccomp=0
|
||||
;;
|
||||
--disable-asyncdns)
|
||||
feat_asyncdns=0
|
||||
;;
|
||||
--disable-forcednsretry)
|
||||
feat_forcednsretry=0
|
||||
;;
|
||||
@@ -504,27 +493,15 @@ if [ $feat_cmdmon = "1" ]; then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS cmdmon.o manual.o pktlength.o"
|
||||
fi
|
||||
|
||||
if [ $feat_ntp = "1" ]; then
|
||||
add_def FEAT_NTP
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o"
|
||||
if [ $feat_ntp_signd = "1" ]; then
|
||||
add_def FEAT_SIGND
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
|
||||
fi
|
||||
else
|
||||
feat_asyncdns=0
|
||||
feat_timestamping=0
|
||||
fi
|
||||
|
||||
if [ "$feat_cmdmon" = "1" ] || [ $feat_ntp = "1" ]; then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS addrfilt.o clientlog.o keys.o nameserv.o"
|
||||
else
|
||||
feat_ipv6=0
|
||||
if [ $feat_ntp_signd = "1" ]; then
|
||||
add_def FEAT_SIGND
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
|
||||
fi
|
||||
|
||||
if [ $feat_refclock = "1" ]; then
|
||||
add_def FEAT_REFCLOCK
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS refclock.o refclock_phc.o refclock_pps.o refclock_shm.o refclock_sock.o"
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS refclock.o refclock_phc.o refclock_pps.o \
|
||||
refclock_rtc.o refclock_shm.o refclock_sock.o"
|
||||
fi
|
||||
|
||||
MYCC="$CC"
|
||||
@@ -705,15 +682,15 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $feat_asyncdns = "1" ] && \
|
||||
test_code 'pthread' 'pthread.h' '-pthread' '' '
|
||||
pthread_t thread;
|
||||
return (int)pthread_create(&thread, NULL, (void *)1, NULL);'
|
||||
if test_code 'pthread' 'pthread.h' '-pthread' '' '
|
||||
pthread_t thread;
|
||||
return (int)pthread_create(&thread, NULL, (void *)1, NULL);'
|
||||
then
|
||||
add_def FEAT_ASYNCDNS
|
||||
add_def USE_PTHREAD_ASYNCDNS
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
|
||||
use_pthread=1
|
||||
MYCFLAGS="$MYCFLAGS -pthread"
|
||||
else
|
||||
echo "error: pthread_create() not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $try_arc4random = "1" ] && \
|
||||
@@ -816,12 +793,10 @@ if [ $feat_scfilter = "1" ] && [ $try_seccomp = "1" ] && \
|
||||
'seccomp_init(SCMP_ACT_KILL);'
|
||||
then
|
||||
add_def FEAT_SCFILTER
|
||||
if [ $feat_ntp = "1" ]; then
|
||||
# NAME2IPADDRESS shouldn't be enabled together with a privops operation
|
||||
# used by the main thread as the helper process works on one request at
|
||||
# a time and the async resolver would block the main thread
|
||||
priv_ops="NAME2IPADDRESS RELOADDNS"
|
||||
fi
|
||||
# NAME2IPADDRESS shouldn't be enabled together with a privops operation
|
||||
# used by the main thread as the helper process works on one request at
|
||||
# a time and the async resolver would block the main thread
|
||||
priv_ops="NAME2IPADDRESS RELOADDNS"
|
||||
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
|
||||
fi
|
||||
|
||||
@@ -860,7 +835,6 @@ if [ $try_setsched = "1" ] && \
|
||||
pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched);'
|
||||
then
|
||||
add_def HAVE_PTHREAD_SETSCHEDPARAM
|
||||
use_pthread=1
|
||||
fi
|
||||
|
||||
if [ $try_lockmem = "1" ] && \
|
||||
@@ -914,6 +888,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ];
|
||||
HASH_OBJ="hash_nettle.o"
|
||||
HASH_LINK="$test_link"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def HAVE_NETTLE
|
||||
add_def FEAT_SECHASH
|
||||
|
||||
if test_code 'CMAC in nettle' 'nettle/cmac.h' "$test_cflags" "$test_link" \
|
||||
@@ -923,6 +898,13 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ];
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS cmac_nettle.o"
|
||||
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS cmac_nettle.o"
|
||||
fi
|
||||
|
||||
if test_code 'nettle_memeql_sec()' 'nettle/memops.h' \
|
||||
"$test_cflags" "$test_link" \
|
||||
'return nettle_memeql_sec("", "", 0);'
|
||||
then
|
||||
add_def HAVE_NETTLE_MEMEQL
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -936,6 +918,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ];
|
||||
HASH_OBJ="hash_gnutls.o"
|
||||
HASH_LINK="$test_link"
|
||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||
add_def HAVE_GNUTLS
|
||||
add_def FEAT_SECHASH
|
||||
|
||||
if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
|
||||
@@ -977,7 +960,7 @@ EXTRA_OBJECTS="$EXTRA_OBJECTS $HASH_OBJ"
|
||||
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ"
|
||||
LIBS="$LIBS $HASH_LINK"
|
||||
|
||||
if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
if [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
if [ "$HASH_OBJ" = "hash_gnutls.o" ]; then
|
||||
test_cflags=""
|
||||
test_link=""
|
||||
@@ -997,7 +980,6 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
add_def HAVE_NETTLE_SIV_CMAC
|
||||
if [ $try_aes_gcm_siv = "1" ] && test_code 'AES-GCM-SIV in nettle' \
|
||||
'nettle/siv-gcm.h' "" "$LIBS" \
|
||||
'siv_gcm_aes128_encrypt_message((void *)1, 0, NULL, 0, (void *)2, 16, (void *)3,
|
||||
@@ -1025,13 +1007,6 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
then
|
||||
add_def HAVE_GNUTLS_AEAD_CIPHER_SET_KEY
|
||||
fi
|
||||
else
|
||||
if test_code 'AES128 in nettle' 'nettle/aes.h' '' "$LIBS" \
|
||||
'aes128_set_encrypt_key((void *)1, (void *)2);'
|
||||
then
|
||||
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
|
||||
add_def HAVE_SIV
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1045,10 +1020,6 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $use_pthread = "1" ]; then
|
||||
MYCFLAGS="$MYCFLAGS -pthread"
|
||||
fi
|
||||
|
||||
SYSCONFDIR=/etc
|
||||
if [ "x$SETSYSCONFDIR" != "x" ]; then
|
||||
SYSCONFDIR=$SETSYSCONFDIR
|
||||
@@ -1114,7 +1085,7 @@ add_def MAIL_PROGRAM "\"$mail_program\""
|
||||
|
||||
common_features="`get_features SECHASH IPV6 DEBUG`"
|
||||
chronyc_features="`get_features READLINE`"
|
||||
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SIGND ASYNCDNS NTS`"
|
||||
chronyd_features="`get_features CMDMON REFCLOCK RTC PRIVDROP SCFILTER SIGND NTS`"
|
||||
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
|
||||
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
|
||||
echo "Features : $chronyd_features $chronyc_features $common_features"
|
||||
|
||||
@@ -69,12 +69,19 @@ also when the <<chronyc.adoc#online,*online*>> command is issued in *chronyc*.
|
||||
+
|
||||
The DNS record can change over time. The used address will be replaced with a
|
||||
newly resolved address when the server becomes unreachable (i.e. no valid
|
||||
response to last 8 requests), unsynchronised, a falseticker (i.e. does not
|
||||
response to the last 8 requests), unsynchronised, a falseticker (i.e. does not
|
||||
agree with a majority of other sources), or the root distance is too large (the
|
||||
limit can be configured by the <<maxdistance,*maxdistance*>> directive). The
|
||||
automatic replacement happens at most once per 30 minutes.
|
||||
automatic replacement happens at most once per 30 minutes and only one
|
||||
server can be replaced at a time. The address is also refreshed periodically
|
||||
when the server is working normally (the interval can be configured by the
|
||||
<<refresh,*refresh*>> directive).
|
||||
+
|
||||
This directive can be used multiple times to specify multiple servers.
|
||||
This directive can be used multiple times to specify multiple servers. Each
|
||||
server must have a different IP address to be usable by *chronyd*. If a server
|
||||
is specified by a hostname that resolves only to addresses already used by
|
||||
other servers, the server will be treated as having an unknown address (e.g.
|
||||
reported by the *chronyc* <<chronyc.adoc#activity,*activity*>> command).
|
||||
+
|
||||
The directive supports the following options:
|
||||
+
|
||||
@@ -108,13 +115,13 @@ 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.
|
||||
computers from having their system time upset by rogue packets being sent to them.
|
||||
The MAC is generated as a function of a key specified in the key file,
|
||||
which is specified by the <<keyfile,*keyfile*>> directive.
|
||||
+
|
||||
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,
|
||||
*chronyd* should 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
|
||||
@@ -128,7 +135,7 @@ the Transport Layer Security (TLS) protocol to get the keys and cookies
|
||||
required by NTS for authentication of NTP packets.
|
||||
+
|
||||
With this option, the hostname specified in the server or pool directive is the
|
||||
NTS-KE server or pool of NTS-KE servers respectively. The NTP server usually
|
||||
NTS-KE server or pool of NTS-KE servers, respectively. The NTP server usually
|
||||
runs on the same host, but it can be separated from the NTS-KE server (the
|
||||
hostname or address of the NTP server is provided to the client by the NTS-KE
|
||||
server).
|
||||
@@ -145,10 +152,10 @@ default trusted certificate authorities.
|
||||
*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
|
||||
indicate that the request, or the response, or both were delayed. If only one
|
||||
of the messages was delayed the measurement error is likely to be substantial.
|
||||
of the messages was delayed, the measurement error is likely to be substantial.
|
||||
+
|
||||
For small variations in the round-trip delay, *chronyd* uses a weighting scheme
|
||||
when processing the measurements. However, beyond a certain level of delay the
|
||||
when processing the measurements. Beyond a certain level of delay, however, the
|
||||
measurements are likely to be so corrupted as to be useless. (This is
|
||||
particularly so on wireless networks and other slow links, where a long delay
|
||||
probably indicates a highly asymmetric delay caused by the response waiting
|
||||
@@ -158,7 +165,7 @@ If the user knows that round trip delays above a certain level should cause the
|
||||
measurement to be ignored, this level can be defined with the *maxdelay*
|
||||
option. For example, *maxdelay 0.3* would indicate that measurements with a
|
||||
round-trip delay greater than 0.3 seconds should be ignored. The default value
|
||||
is 3 seconds and the maximum value is 1000 seconds.
|
||||
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
|
||||
of the minimum round-trip delay amongst the previous measurements that it has
|
||||
@@ -198,7 +205,7 @@ 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
|
||||
the source back. By default, *chronyd* estimates the asymmetry automatically.
|
||||
*offset* _offset_:::
|
||||
This option specifies a correction (in seconds) which will be applied to
|
||||
This option specifies a correction (in seconds) that will be applied to
|
||||
offsets measured with this source. It's particularly useful to compensate for a
|
||||
known asymmetry in network delay or timestamping errors. For example, if
|
||||
packets sent to the source were on average delayed by 100 microseconds more
|
||||
@@ -292,7 +299,7 @@ included in a *server* directive:
|
||||
presend 9
|
||||
----
|
||||
+
|
||||
when the polling interval is 512 seconds or more, an extra NTP client packet
|
||||
When the polling interval is 512 seconds or more, an extra NTP client packet
|
||||
will be sent to the server a short time (2 seconds) before making the actual
|
||||
measurement.
|
||||
+
|
||||
@@ -303,7 +310,7 @@ When the synchronisation source is selected from available sources, sources
|
||||
with lower stratum are normally slightly preferred. This option can be used to
|
||||
increase stratum of the source to the specified minimum, so *chronyd* will
|
||||
avoid selecting that source. This is useful with low-stratum sources that are
|
||||
known to be unreliable or inaccurate and which should be used only when other
|
||||
known to be unreliable or inaccurate and that should be used only when other
|
||||
sources are unreachable.
|
||||
*version* _version_:::
|
||||
This option sets the NTP version of packets sent to the server. This can be
|
||||
@@ -311,7 +318,7 @@ useful when the server runs an old NTP implementation that does not respond to
|
||||
requests using a newer version. The default version depends on other options.
|
||||
If the *extfield* or *xleave* option is used, the default version is 4. If
|
||||
those options are not used and the *key* option specifies a key using a hash
|
||||
function with output size longer than 160 bits (e.g. SHA256), the default
|
||||
function with an output size longer than 160 bits (e.g. SHA256), the default
|
||||
version is 3 for compatibility with older *chronyd* servers. In other cases,
|
||||
the default version is 4.
|
||||
*copy*:::
|
||||
@@ -374,7 +381,7 @@ directive too. There is one option specific to the *pool* directive:
|
||||
*maxsources* _sources_:::
|
||||
This option sets the desired number of sources to be used from the pool.
|
||||
*chronyd* will repeatedly try to resolve the name until it gets this number of
|
||||
sources responding to requests. The default value is 4 and the maximum value is
|
||||
sources responding to requests. The default value is 4, and the maximum value is
|
||||
16.
|
||||
+
|
||||
An example of the *pool* directive is
|
||||
@@ -398,7 +405,7 @@ The following options of the *server* directive do not work in the *peer*
|
||||
directive: *iburst*, *burst*, *nts*, *presend*, *copy*.
|
||||
+
|
||||
When using the *xleave* option, both peers must support and have enabled the
|
||||
interleaved mode, otherwise the synchronisation will work in one direction
|
||||
interleaved mode; otherwise the synchronisation will work in one direction
|
||||
only.
|
||||
When a key is specified by the *key* option to enable authentication, both
|
||||
peers must use the same key and the same key number.
|
||||
@@ -426,7 +433,7 @@ recommended to use two separate client/server associations (specified by the
|
||||
directive.)
|
||||
+
|
||||
The purpose of the *initstepslew* directive is to allow *chronyd* to make a
|
||||
rapid measurement of the system clock error at boot time, and to correct the
|
||||
rapid measurement of the system clock error at boot time and to correct the
|
||||
system clock by stepping before normal operation begins. Since this would
|
||||
normally be performed only at an appropriate point in the system boot sequence,
|
||||
no other software should be adversely affected by the step.
|
||||
@@ -455,7 +462,7 @@ The *initstepslew* directive can also be used in an isolated LAN environment,
|
||||
where the clocks are set manually. The most stable computer is chosen as the
|
||||
primary server and the other computers are its clients. If each of the clients
|
||||
is configured with the <<local,*local*>> directive, the server can be set up
|
||||
with an *initstepslew* directive which references some or all of the clients.
|
||||
with an *initstepslew* directive that references some or all of the clients.
|
||||
Then, if the server machine has to be rebooted, the clients can be relied on to
|
||||
act analogously to a flywheel and preserve the time for a short period while
|
||||
the server completes its reboot.
|
||||
@@ -478,7 +485,7 @@ the driver-specific parameter using the *:* character.
|
||||
+
|
||||
This directive can be used multiple times to specify multiple reference clocks.
|
||||
+
|
||||
There are four drivers included in *chronyd*:
|
||||
There are five drivers included in *chronyd*:
|
||||
+
|
||||
*PPS*:::
|
||||
Driver for the kernel PPS (pulse per second) API. The parameter is the path to
|
||||
@@ -508,7 +515,7 @@ samples from another application running on the system. The parameter is the
|
||||
path to the socket, which *chronyd* will create on start. The format of the
|
||||
messages is described in the _refclock_sock.c_ file in the chrony source code.
|
||||
+
|
||||
An application which supports the SOCK protocol is the *gpsd* daemon. It can
|
||||
An application that supports the SOCK protocol is the *gpsd* daemon. It can
|
||||
provide accurate measurements using the receiver's PPS signal, and since
|
||||
version 3.25 also (much less accurate) measurements based on the timing of
|
||||
serial data (e.g. NMEA), which can be useful when the receiver does not provide
|
||||
@@ -557,8 +564,9 @@ refclock SHM 1:perm=0644 refid GPS2
|
||||
----
|
||||
+
|
||||
*PHC*:::
|
||||
PTP hardware clock (PHC) driver. The parameter is the path to the device of
|
||||
the PTP clock which should be used as a time source. If the clock is kept in
|
||||
PTP hardware clock (PHC) driver. The parameter is the absolute path to the
|
||||
device of the PTP clock which should be used as a time source, or the name of
|
||||
the network interface whose PTP clock should be used. If the clock is kept in
|
||||
TAI instead of UTC (e.g. it is synchronised by a PTP daemon), the current
|
||||
UTC-TAI offset needs to be specified by the *offset* option. Alternatively, the
|
||||
*pps* refclock option can be enabled to treat the PHC as a PPS refclock, using
|
||||
@@ -596,6 +604,23 @@ refclock PHC /dev/ptp1:nocrossts poll 3 pps
|
||||
refclock PHC /dev/ptp2:extpps:pin=1 width 0.2 poll 2
|
||||
----
|
||||
+
|
||||
*RTC*:::
|
||||
Driver for using the Real Time Clock (RTC) as a reference clock. The parameter
|
||||
is the path to the RTC character device which should be used as a time source.
|
||||
This driver cannot be used together with the <<rtcfile,*rtcfile*>> or
|
||||
<<rtcsync,*rtcsync*>> directive. The driver supports the following option:
|
||||
+
|
||||
*utc*::::
|
||||
Assume that RTC keeps Universal Coordinated Time (UTC) instead of local
|
||||
time.
|
||||
{blank}:::
|
||||
+
|
||||
Examples:
|
||||
+
|
||||
----
|
||||
refclock RTC /dev/rtc0:utc
|
||||
----
|
||||
+
|
||||
{blank}::
|
||||
The *refclock* directive supports the following options:
|
||||
+
|
||||
@@ -622,18 +647,18 @@ specified by its reference ID. In this mode received PPS samples are paired
|
||||
directly with raw samples from the specified refclock.
|
||||
*rate* _rate_:::
|
||||
This option sets the rate of the pulses in the PPS signal (in Hz). This option
|
||||
controls how the pulses will be completed with real time. To actually receive
|
||||
controls how the pulses will be completed with real time. In order to receive
|
||||
more than one pulse per second, a negative *dpoll* has to be specified (-3 for
|
||||
a 5Hz signal). The default is 1.
|
||||
*maxlockage* _pulses_:::
|
||||
This option specifies in number of pulses how old can be samples from the
|
||||
This option specifies in number of pulses how old samples can be from the
|
||||
refclock specified by the *lock* option to be paired with the pulses.
|
||||
Increasing this value is useful when the samples are produced at a lower rate
|
||||
than the pulses. The default is 2.
|
||||
*width* _width_:::
|
||||
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
|
||||
edges. Note that it reduces the maximum allowed error of the time source that
|
||||
completes the PPS samples. If the duty cycle is configurable, 50% should be
|
||||
preferred in order to maximise the allowed error.
|
||||
*pps*:::
|
||||
@@ -647,7 +672,7 @@ offset (in seconds) is applied to all samples produced by the reference clock.
|
||||
The default is 0.0.
|
||||
*delay* _delay_:::
|
||||
This option sets the NTP delay of the source (in seconds). Half of this value
|
||||
is included in the maximum assumed error which is used in the source selection
|
||||
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).
|
||||
@@ -661,14 +686,13 @@ value is the estimated precision of the system clock.
|
||||
Maximum allowed dispersion for filtered samples (in seconds). Samples with
|
||||
larger estimated dispersion are ignored. By default, this limit is disabled.
|
||||
*filter* _samples_:::
|
||||
This option sets the length of the median filter which is used to reduce the
|
||||
noise in the measurements. With each poll about 40 percent of the stored
|
||||
samples are discarded and one final sample is calculated as an average of the
|
||||
remaining samples. If the length is 4 or more, at least 4 samples have to be
|
||||
collected between polls. For lengths below 4, the filter has to be full. The
|
||||
default is 64. With drivers that perform their own polling (PPS, PHC, SHM), the
|
||||
maximum value is adjusted to the number of driver polls per source poll, i.e.
|
||||
2^(_poll_ - _dpoll_).
|
||||
This option sets the maximum number of samples that can be stored in the median
|
||||
filter between polls of the source. The filter combines about 60 percent of the
|
||||
samples closest to the median offset into one sample. If more samples are
|
||||
received by the driver between polls, the oldest samples will be dropped. One
|
||||
sample per poll is sufficient for the source to be selectable. The default
|
||||
is 64. Note that the PHC driver has additional filtering based on the reading
|
||||
delay.
|
||||
*prefer*:::
|
||||
Prefer this source over other selectable sources without the *prefer* option.
|
||||
*noselect*:::
|
||||
@@ -833,6 +857,34 @@ changes in the frequency and offset of the clock. The offsets in the
|
||||
<<chronyc.adoc#sourcestats,*sourcestats*>> reports (and the _tracking.log_ and
|
||||
_statistics.log_ files) may be smaller than the actual offsets.
|
||||
|
||||
[[ntsaeads1]]*ntsaeads* _ID_...::
|
||||
This directive specifies a list of IDs of Authenticated Encryption with
|
||||
Associated Data (AEAD) algorithms enabled for NTS authentication of NTP
|
||||
messages. The algorithms are specified in decreasing order of priority.
|
||||
Algorithms that are not supported by the installed version of the crypto
|
||||
library (Nettle, GnuTLS) are ignored.
|
||||
+
|
||||
The following IDs are supported:
|
||||
+
|
||||
* 15: AES-SIV-CMAC-256
|
||||
* 30: AES-128-GCM-SIV
|
||||
{blank}::
|
||||
+
|
||||
The default list of IDs is _30 15_. AES-128-GCM-SIV is preferred over
|
||||
AES-SIV-CMAC-256 for shorter keys, which makes NTS cookies shorter and improves
|
||||
reliability of NTS in networks that block or limit rate of longer NTP messages.
|
||||
+
|
||||
The ID of the used algorithm is reported for each server by the
|
||||
<<chronyc.adoc#authdata,*authdata*>> command.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsaeads 15
|
||||
----
|
||||
+
|
||||
This list is used also by the <<ntsaeads2,NTS server>>.
|
||||
|
||||
[[ntsdumpdir1]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory for the client to save NTS cookies it
|
||||
received from the server in order to avoid making an NTS-KE request when
|
||||
@@ -861,7 +913,7 @@ refresh the keys on each poll and no NTP packets will be exchanged.
|
||||
|
||||
[[ntstrustedcerts]]*ntstrustedcerts* [_set-ID_] _file_|_directory_::
|
||||
This directive specifies a file or directory containing trusted certificates
|
||||
(in the PEM format) which are needed to verify certificates of NTS-KE servers,
|
||||
(in the PEM format) that are needed to verify certificates of NTS-KE servers,
|
||||
e.g. certificates of trusted certificate authorities (CA) or self-signed
|
||||
certificates of the servers.
|
||||
+
|
||||
@@ -896,7 +948,7 @@ specified by the *ntstrustedcerts* directive will be trusted.
|
||||
[[nocerttimecheck]]*nocerttimecheck* _limit_::
|
||||
This directive disables the checks of the activation and expiration times of
|
||||
certificates for the specified number of clock updates. It allows the NTS
|
||||
authentication mechanism to be used on computers which start with wrong time
|
||||
authentication mechanism to be used on computers which start with the wrong time
|
||||
(e.g. due to not having an RTC or backup battery). Disabling the time checks
|
||||
has important security implications and should be used only as a last resort,
|
||||
preferably with a minimal number of trusted certificates. The default value is
|
||||
@@ -910,17 +962,18 @@ nocerttimecheck 1
|
||||
+
|
||||
This would disable the time checks until the clock is updated for the first
|
||||
time, assuming the first update corrects the clock and later checks can work
|
||||
with correct time.
|
||||
with the correct time.
|
||||
|
||||
[[refresh]]*refresh* _interval_::
|
||||
This directive specifies the interval (in seconds) between refreshing IP
|
||||
addresses of NTP sources specified by hostname. If the hostname no longer
|
||||
This directive specifies the minimum interval (in seconds) between refreshing
|
||||
IP addresses of NTP sources specified by hostname. If the hostname no longer
|
||||
resolves to the currently used address, it will be replaced with one of the new
|
||||
addresses to avoid using a server which is no longer intended for service, even
|
||||
if it is still responding correctly and would not be replaced as unreachable.
|
||||
Only one source is refreshed at a time. The default value is 1209600 (2 weeks)
|
||||
and the maximum value is 2^31-1 (68 years). A value of 0 disables the periodic
|
||||
refreshment.
|
||||
Only one source is refreshed at a time and only when a valid response is
|
||||
received (unreachable sources are replaced independently). The default value is
|
||||
1209600 (2 weeks) and the maximum value is 2^31-1 (68 years). A value of 0
|
||||
disables the periodic refreshment.
|
||||
+
|
||||
The <<chronyc.adoc#refresh,*refresh*>> command can be used to refresh all
|
||||
sources immediately.
|
||||
@@ -933,11 +986,11 @@ authentication to limit the impact of man-in-the-middle attacks. The
|
||||
attackers can drop or delay NTP packets (up to the *maxdelay* and
|
||||
<<maxdistance,*maxdistance*>> limits), but they cannot modify the timestamps
|
||||
contained in the packets. The attack can cause only a limited slew or step, and
|
||||
also cause the clock to run faster or slower than real time (up to double of
|
||||
also cause the clock to run faster or slower than real time (up to double
|
||||
the <<maxdrift,*maxdrift*>> limit).
|
||||
+
|
||||
When authentication is enabled for an NTP source, it is important to disable
|
||||
unauthenticated NTP sources which could be exploited in the attack, e.g. if
|
||||
unauthenticated NTP sources that could be exploited in the attack, e.g. if
|
||||
they are not reachable only over a trusted network. Alternatively, the source
|
||||
selection can be configured with the *require* and *trust* options to
|
||||
synchronise to the unauthenticated sources only if they agree with the
|
||||
@@ -1013,7 +1066,7 @@ If the selected source was specified with the *prefer* option, it can be
|
||||
combined only with other sources specified with this option.
|
||||
+
|
||||
By default, the limit is 3. Setting the limit to 0 effectively disables the
|
||||
source combining algorithm and only the selected source will be used to control
|
||||
source-combining algorithm and only the selected source will be used to control
|
||||
the system clock.
|
||||
|
||||
[[maxdistance]]*maxdistance* _distance_::
|
||||
@@ -1042,14 +1095,14 @@ considered as selectable in the source selection algorithm before the local
|
||||
clock is updated. The default value is 1.
|
||||
+
|
||||
Setting this option to a larger number can be used to improve the reliability.
|
||||
More sources will have to agree with each other and the clock will not be
|
||||
More sources will have to agree with each other, and the clock will not be
|
||||
updated when only one source (which could be serving incorrect time) is
|
||||
reachable.
|
||||
|
||||
[[reselectdist]]*reselectdist* _distance_::
|
||||
When *chronyd* selects a synchronisation source from available sources, it
|
||||
will prefer the one with the shortest synchronisation distance. However, to
|
||||
avoid frequent reselecting when there are sources with similar distance, a
|
||||
will prefer the one with the shortest synchronisation distance. To avoid
|
||||
frequent reselecting when there are sources with similar distance, however, a
|
||||
fixed distance is added to the distance for sources that are currently not
|
||||
selected. This can be set with the *reselectdist* directive. By default, the
|
||||
distance is 100 microseconds.
|
||||
@@ -1069,11 +1122,11 @@ distances are in milliseconds.
|
||||
The *clockprecision* directive specifies the precision of the system clock (in
|
||||
seconds). It is used by *chronyd* to estimate the minimum noise in NTP
|
||||
measurements and randomise low-order bits of timestamps in NTP responses. By
|
||||
default, the precision is measured on start as the minimum time to read the
|
||||
default, the precision is measured on start-up as the minimum time to read the
|
||||
clock.
|
||||
+
|
||||
The measured value works well in most cases. However, it generally
|
||||
overestimates the precision and it can be sensitive to the CPU speed, which can
|
||||
The measured value works well in most cases. It generally overestimates the
|
||||
precision and it can be sensitive to the CPU speed, however, which can
|
||||
change over time to save power. In some cases with a high-precision clocksource
|
||||
(e.g. the Time Stamp Counter of the CPU) and hardware timestamping, setting the
|
||||
precision on the server to a smaller value can improve stability of clients'
|
||||
@@ -1096,7 +1149,7 @@ The *corrtimeratio* directive sets the ratio between the duration in which the
|
||||
clock is slewed for an average correction according to the source history and
|
||||
the interval in which the corrections are done (usually the NTP polling
|
||||
interval). Corrections larger than the average take less time and smaller
|
||||
corrections take more time, the amount of the correction and the correction
|
||||
corrections take more time; the amount of the correction and the correction
|
||||
time are inversely proportional.
|
||||
+
|
||||
Increasing *corrtimeratio* improves the overall frequency error of the system
|
||||
@@ -1109,7 +1162,7 @@ The maximum allowed slew rate can be set by the <<maxslewrate,*maxslewrate*>>
|
||||
directive. The current remaining correction is shown in the
|
||||
<<chronyc.adoc#tracking,*tracking*>> report as the *System time* value.
|
||||
|
||||
[[driftfile]]*driftfile* _file_::
|
||||
[[driftfile]]*driftfile* _file_ [*interval* _interval_]::
|
||||
One of the main activities of the *chronyd* program is to work out the rate at
|
||||
which the system clock gains or loses time relative to real time.
|
||||
+
|
||||
@@ -1128,6 +1181,10 @@ microseconds in reality (so the true time has only advanced by 999900
|
||||
microseconds). The second is an estimate of the error bound around the first
|
||||
value in which the true rate actually lies.
|
||||
+
|
||||
The *interval* option specifies the minimum interval between updates of the
|
||||
file in seconds. The file is written only on an update of the local clock.
|
||||
The default interval is 3600 seconds.
|
||||
+
|
||||
An example of the driftfile directive is:
|
||||
+
|
||||
----
|
||||
@@ -1151,7 +1208,7 @@ 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, and so on. This
|
||||
hours after the 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`'.
|
||||
@@ -1210,7 +1267,7 @@ When smearing a leap second, the leap status is suppressed on the server and
|
||||
the served time is corrected slowly by slewing instead of stepping. The clients
|
||||
do not need any special configuration as they do not know there is any leap
|
||||
second and they follow the server time which eventually brings them back to
|
||||
UTC. Care must be taken to ensure they use only NTP servers which smear the
|
||||
UTC. Care must be taken to ensure they use only NTP servers that smear the
|
||||
leap second in exactly the same way for synchronisation.
|
||||
+
|
||||
This feature must be used carefully, because the server is intentionally not
|
||||
@@ -1243,15 +1300,15 @@ duration = sqrt(4 / wander)
|
||||
|
||||
[[leapsectz]]*leapsectz* _timezone_::
|
||||
This directive specifies a timezone in the system timezone database which
|
||||
*chronyd* can use to determine when will the next leap second occur and what is
|
||||
the current offset between TAI and UTC. It will periodically check if 23:59:59
|
||||
*chronyd* can use to determine when the next leap second occurs and what
|
||||
the current offset between TAI and UTC is. It will periodically check if 23:59:59
|
||||
and 23:59:60 are valid times in the timezone. This normally works with the
|
||||
_right/UTC_ timezone.
|
||||
+
|
||||
When a leap second is announced, the timezone needs to be updated at least 12
|
||||
hours before the leap second. It is not necessary to restart *chronyd*.
|
||||
+
|
||||
This directive is useful with reference clocks and other time sources which do
|
||||
This directive is useful with reference clocks and other time sources that do
|
||||
not announce leap seconds, or announce them too late for an NTP server to
|
||||
forward them to its own clients. Clients of leap smearing servers must not
|
||||
use this directive.
|
||||
@@ -1293,7 +1350,7 @@ leapseclist /usr/share/zoneinfo/leap-seconds.list
|
||||
----
|
||||
|
||||
[[makestep]]*makestep* _threshold_ _limit_::
|
||||
Normally *chronyd* will cause the system to gradually correct any time offset,
|
||||
Normally *chronyd* will cause the system to gradually correct any time offset
|
||||
by slowing down or speeding up the clock as required. In certain situations,
|
||||
e.g. when *chronyd* is initially started, the system clock might be so far
|
||||
adrift that this slewing process would take a very long time to correct the
|
||||
@@ -1315,6 +1372,9 @@ makestep 0.1 3
|
||||
+
|
||||
This would step the system clock if the adjustment is larger than 0.1 seconds, but
|
||||
only in the first three clock updates.
|
||||
+
|
||||
Note that this directive does not work and should not be used when the system
|
||||
clock control is disabled by the *-x* option of *chronyd*.
|
||||
|
||||
[[maxchange]]*maxchange* _offset_ _start_ _ignore_::
|
||||
This directive sets the maximum offset to be accepted on a clock update. The
|
||||
@@ -1522,13 +1582,13 @@ allow all 1.2.0.0/16
|
||||
+
|
||||
In the first example, the effect is the same regardless of what order the three
|
||||
directives are given in. So the _1.2.0.0/16_ subnet is allowed access, except
|
||||
for the _1.2.3.0/24_ subnet, which is denied access, however the host _1.2.3.4_
|
||||
for the _1.2.3.0/24_ subnet, which is denied access, while the host _1.2.3.4_
|
||||
is allowed access.
|
||||
+
|
||||
In the second example, the *allow all 1.2.0.0/16* directive overrides the
|
||||
effect of _any_ previous directive relating to a subnet within the specified
|
||||
subnet. Within a configuration file this capability is probably rather moot;
|
||||
however, it is of greater use for reconfiguration at run-time via *chronyc*
|
||||
yet, it is of greater use for reconfiguration at run-time via *chronyc*
|
||||
with the <<chronyc.adoc#allow,*allow all*>> command.
|
||||
+
|
||||
The rules are internally represented as a tree of tables with one level per
|
||||
@@ -1555,7 +1615,7 @@ This is similar to the <<allow,*allow*>> directive, except that it denies NTP
|
||||
and NTS-KE client access to a particular subnet or host, rather than allowing
|
||||
it.
|
||||
+
|
||||
The syntax is identical and the directive can be used multiple times too.
|
||||
The syntax is identical, and the directive can be used multiple times too.
|
||||
+
|
||||
There is also a *deny all* directive with similar behaviour to the *allow all*
|
||||
directive.
|
||||
@@ -1573,7 +1633,7 @@ bindaddress 192.168.1.1
|
||||
----
|
||||
+
|
||||
Currently, for each of the IPv4 and IPv6 protocols, only one *bindaddress*
|
||||
directive can be specified. Therefore, it is not useful on computers which
|
||||
directive can be specified. Therefore, it is not useful on computers that
|
||||
should serve NTP on multiple network interfaces.
|
||||
|
||||
[[binddevice]]*binddevice* _interface_::
|
||||
@@ -1667,16 +1727,19 @@ expected stratum in the network when external NTP servers are accessible.
|
||||
+
|
||||
Stratum 1 indicates a computer that has a true real-time reference directly
|
||||
connected to it (e.g. GPS, atomic clock, etc.), such computers are expected to
|
||||
be very close to real time. Stratum 2 computers are those which have a stratum
|
||||
be very close to real time. Stratum 2 computers are those that have a stratum
|
||||
1 server; stratum 3 computers have a stratum 2 server and so on. A value
|
||||
of 10 indicates that the clock is so many hops away from a reference clock that
|
||||
its time is fairly unreliable.
|
||||
*distance* _distance_:::
|
||||
This option sets the threshold for the root distance which will activate the local
|
||||
reference. If *chronyd* was synchronised to some source, the local reference
|
||||
will not be activated until its root distance reaches the specified value (the
|
||||
rate at which the distance is increasing depends on how well the clock was
|
||||
tracking the source). The default value is 1 second.
|
||||
reference. If *chronyd* was synchronised to a configured time source, the local
|
||||
reference will not be activated until its root distance reaches the specified
|
||||
value (the rate at which the distance is increasing depends on how well the
|
||||
clock was tracking the source). When the clock is not synchronised, it is
|
||||
considered to have an infinite root distance, i.e. the local reference
|
||||
activates as soon as allowed by the *waitunsynced* option. The default
|
||||
threshold is 1 second.
|
||||
+
|
||||
The current root distance can be calculated from root delay and root dispersion
|
||||
(reported by the <<chronyc.adoc#tracking,*tracking*>> command in *chronyc*) as:
|
||||
@@ -1699,7 +1762,7 @@ unless no other source is selectable and their reference IDs are smaller than
|
||||
the local reference ID.
|
||||
+
|
||||
This allows multiple servers in the network to use the same *local*
|
||||
configuration and to be synchronised to one another, without confusing clients
|
||||
configuration and to be synchronised to one another without confusing clients
|
||||
that poll more than one server. Each server needs to be configured to poll all
|
||||
other servers with the *local* directive. This ensures only the server with the
|
||||
smallest reference ID has the local reference active and others are
|
||||
@@ -1709,12 +1772,30 @@ smallest reference ID will take over when its local reference mode activates
|
||||
+
|
||||
The *orphan* mode is compatible with the *ntpd*'s orphan mode (enabled by the
|
||||
*tos orphan* command).
|
||||
*waitsynced* _interval_:::
|
||||
This option specifies the minimum interval (in seconds) between the last update
|
||||
of the clock and activation of the local reference as configured by the
|
||||
*distance* and *activate* options. The *distance* option can be set to 0 to
|
||||
ignore the root distance and control the activation only by the interval. In
|
||||
such case it should be at least as long as the maximum expected polling
|
||||
interval to prevent frequent activation in normal polling of the source.
|
||||
The default minimum interval is 0.
|
||||
*waitunsynced* _interval_:::
|
||||
This option specifies how long (in seconds) *chronyd* needs to wait before
|
||||
activating the local reference when the clock is not considered to be
|
||||
synchronised (e.g. after start or the source selection failing due to no
|
||||
majority). This delay prevents *chronyd* from serving incorrect time to clients
|
||||
before the configured time sources are given a chance to synchronise the local
|
||||
clock. The default interval is 300 seconds if the *orphan* option is set,
|
||||
otherwise it is 0 (i.e. local reference activates immediately).
|
||||
{blank}::
|
||||
+
|
||||
An example of the directive is:
|
||||
Examples of the directive are:
|
||||
+
|
||||
----
|
||||
local stratum 5
|
||||
local stratum 10 orphan distance 0.1 activate 0.5
|
||||
local stratum 10 orphan distance 0.0 waitsynced 7200 waitunsynced 300
|
||||
----
|
||||
|
||||
[[ntpsigndsocket]]*ntpsigndsocket* _directory_::
|
||||
@@ -1763,7 +1844,7 @@ the user under which *chronyd* is running after dropping root privileges. For
|
||||
security reasons, it should not be readable by other users.
|
||||
+
|
||||
This directive can be used multiple times to specify multiple keys. The number
|
||||
of keys must be the same as the number of certificates and the corresponding
|
||||
of keys must be the same as the number of certificates, and the corresponding
|
||||
files must be specified in the same order.
|
||||
|
||||
[[ntsprocesses]]*ntsprocesses* _processes_::
|
||||
@@ -1771,7 +1852,7 @@ This directive specifies how many helper processes will *chronyd* operating
|
||||
as an NTS server start for handling client NTS-KE requests in order to improve
|
||||
performance with multi-core CPUs and multithreading. If set to 0, no helper
|
||||
process will be started and all NTS-KE requests will be handled by the main
|
||||
*chronyd* process. The default value is 1.
|
||||
*chronyd* process. The default value is 1, and the maximum value is 1000.
|
||||
|
||||
[[maxntsconnections]]*maxntsconnections* _connections_::
|
||||
This directive specifies the maximum number of concurrent NTS-KE connections
|
||||
@@ -1779,6 +1860,43 @@ per process that the NTS server will accept. The default value is 100. The
|
||||
maximum practical value is half of the system *FD_SETSIZE* constant (usually
|
||||
1024).
|
||||
|
||||
[[ntsaeads2]]*ntsaeads* _ID_...::
|
||||
This directive specifies a list of IDs of Authenticated Encryption with
|
||||
Associated Data (AEAD) algorithms enabled for NTS authentication of NTP
|
||||
messages. *chronyd* as a server uses the first enabled algorithm from the list
|
||||
provided by the client. Algorithms that are not supported by the installed
|
||||
version of the crypto library (Nettle, GnuTLS) are ignored.
|
||||
+
|
||||
The following IDs are supported:
|
||||
+
|
||||
* 15: AES-SIV-CMAC-256
|
||||
* 30: AES-128-GCM-SIV
|
||||
{blank}::
|
||||
+
|
||||
The default list of IDs is _30 15_. AES-128-GCM-SIV is preferred over
|
||||
AES-SIV-CMAC-256 for shorter keys, which makes NTS cookies shorter and improves
|
||||
reliability of NTS in networks that block or limit rate of longer NTP messages.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsaeads 15
|
||||
----
|
||||
+
|
||||
This list is used also by the <<ntsaeads1,NTS client>>.
|
||||
+
|
||||
Note the the NTS specification (RFC 8915) requires servers to support
|
||||
AES-SIV-CMAC-256, i.e. 15 should always be included in the specified list.
|
||||
+
|
||||
The AES-128-GCM-SIV keys used by *chronyd* do not comply to RFC 8915 for
|
||||
compatibility with older *chrony* clients unless the use of compliant keys is
|
||||
negotiated with an
|
||||
https://chrony-project.org/doc/spec/nts-compliant-128gcm.html[NTS-KE record].
|
||||
Support for this record was added in version 4.6.1. As a client, *chronyd* can
|
||||
interoperate with a server that uses compliant keys, but does not support the
|
||||
negotiation if it responds to incorrectly authenticated requests with an NTS
|
||||
NAK.
|
||||
|
||||
[[ntsdumpdir2]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory where *chronyd* operating as an NTS server
|
||||
can save the keys which encrypt NTS cookies provided to clients. The keys are
|
||||
@@ -1796,9 +1914,9 @@ This directory is used also by the <<ntsdumpdir1,NTS client>> to save NTS cookie
|
||||
|
||||
[[ntsntpserver]]*ntsntpserver* _hostname_::
|
||||
This directive specifies the hostname (as a fully qualified domain name) or
|
||||
address of the NTP server(s) which is
|
||||
address of the NTP server(s) that is
|
||||
provided in the NTS-KE response to the clients. It allows the NTS-KE server to
|
||||
be separated from the NTP server. However, the servers need to share the keys,
|
||||
be separated from the NTP server. The servers need to share the keys, however,
|
||||
i.e. external key management needs to be enabled by setting
|
||||
<<ntsrotate,*ntsrotate*>> to 0. By default, no hostname or address is provided
|
||||
to the clients, which means they should use the same server for NTS-KE and NTP.
|
||||
@@ -1850,7 +1968,7 @@ addresses. If multiple clients share one IP address (e.g. multiple hosts behind
|
||||
NAT), the sum of their traffic will be limited. If a client that increases its
|
||||
polling rate when it does not receive a reply is detected, its rate limiting
|
||||
will be temporarily suspended to avoid increasing the overall amount of
|
||||
traffic. The maximum number of IP addresses which can be monitored at the same
|
||||
traffic. The maximum number of IP addresses that can be monitored at the same
|
||||
time depends on the memory limit set by the <<clientloglimit,*clientloglimit*>>
|
||||
directive.
|
||||
+
|
||||
@@ -1868,7 +1986,7 @@ than the specified interval).
|
||||
This option sets the maximum number of responses that can be sent in a burst,
|
||||
temporarily exceeding the limit specified by the *interval* option. This is
|
||||
useful for clients that make rapid measurements on start (e.g. *chronyd* with
|
||||
the *iburst* option). The default value is 8. The minimum value is 1 and the
|
||||
the *iburst* option). The default value is 8. The minimum value is 1, and the
|
||||
maximum value is 255.
|
||||
*leak* _rate_:::
|
||||
This option sets the rate at which responses are randomly allowed even if the
|
||||
@@ -1876,7 +1994,7 @@ limits specified by the *interval* and *burst* options are exceeded. This is
|
||||
necessary to prevent an attacker who is sending requests with a spoofed
|
||||
source address from completely blocking responses to that address. The leak
|
||||
rate is defined as a power of 1/2 and it is 2 by default, i.e. on average at
|
||||
least every fourth request has a response. The minimum value is 1 and the
|
||||
least every fourth request has a response. The minimum value is 1, and the
|
||||
maximum value is 4.
|
||||
*kod* _rate_:::
|
||||
This option sets the rate at which Kiss-o'-Death (KoD) RATE responses are
|
||||
@@ -1884,7 +2002,7 @@ randomly sent when the limits specified by the *interval* and *burst* options
|
||||
are exceeded. It is an additional stream of responses to the *leak* option. A
|
||||
KoD RATE response is a request for the client to reduce its polling rate. Few
|
||||
implementations actually support it. The rate is defined as a power of 1/2. The
|
||||
default value is 0, which means disabled. The minimum value is 0 and the
|
||||
default value is 0, which means disabled. The minimum value is 0, and the
|
||||
maximum value is 4.
|
||||
{blank}::
|
||||
+
|
||||
@@ -1913,13 +2031,13 @@ ntsratelimit interval 3 burst 1
|
||||
The *smoothtime* directive can be used to enable smoothing of the time that
|
||||
*chronyd* serves to its clients to make it easier for them to track it and keep
|
||||
their clocks close together even when large offset or frequency corrections are
|
||||
applied to the server's clock, for example after being offline for a longer
|
||||
applied to the server's clock, for example, after being offline for a longer
|
||||
time.
|
||||
+
|
||||
BE WARNED: The server is intentionally not serving its best estimate of the
|
||||
true time. If a large offset has been accumulated, it can take a very long time
|
||||
to smooth it out. This directive should be used only when the clients are not
|
||||
configured to also poll another NTP server, because they could reject this
|
||||
configured to poll another NTP server also, because they could reject this
|
||||
server as a falseticker or fail to select a source completely.
|
||||
+
|
||||
The smoothing process is implemented with a quadratic spline function with two
|
||||
@@ -1933,7 +2051,7 @@ reset*>> command.
|
||||
The first two arguments of the directive are the maximum frequency offset of
|
||||
the smoothed time to the tracked NTP time (in ppm) and the maximum rate at
|
||||
which the frequency offset is allowed to change (in ppm per second). *leaponly*
|
||||
is an optional third argument which enables a mode where only leap seconds are
|
||||
is an optional third argument that enables a mode where only leap seconds are
|
||||
smoothed out and normal offset and frequency changes are ignored. The *leaponly*
|
||||
option is useful in a combination with the <<leapsecmode,*leapsecmode slew*>>
|
||||
directive to allow the clients to use multiple time smoothing servers safely.
|
||||
@@ -2017,6 +2135,9 @@ The syntax is identical to the *allow* directive.
|
||||
There is also a *cmdallow all* directive with similar behaviour to the *allow
|
||||
all* directive (but applying to monitoring access in this case, of course).
|
||||
+
|
||||
Addresses _127.0.0.1_ and _::1_ (i.e. the loopback interface) are always
|
||||
allowed.
|
||||
+
|
||||
Note that *chronyd* has to be configured with the
|
||||
<<bindcmdaddress,*bindcmdaddress*>> directive to not listen only on the
|
||||
loopback interface to actually allow remote access.
|
||||
@@ -2058,6 +2179,27 @@ An example of the use of the directive is:
|
||||
cmdratelimit interval 2
|
||||
----
|
||||
|
||||
[[opencommands]]*opencommands* [_command_]...::
|
||||
This directive specifies a list of monitoring commands to be enabled for the
|
||||
hosts allowed by the *cmdallow* directive. The following commands can be
|
||||
specified (the naming follows *chronyc*):
|
||||
+
|
||||
*activity*+*+, *authdata*, *clients*, *manual*+*+, *ntpdata*, *rtcdata*+*+,
|
||||
*selectdata*, *serverstats*+*+, *smoothing*+*+, *sourcename*+*+, *sources*+*+,
|
||||
*sourcestats*, *tracking*+*+.
|
||||
+
|
||||
The commands marked with +*+ are enabled by default. The protocol of these
|
||||
commands is considered stable and can be expected to work between different
|
||||
versions of *chronyc* and *chronyd*. The protocol of the other commands is not
|
||||
considered stable and different versions of *chronyc* and *chronyd* may not
|
||||
interoperate. When that happens, *chronyc* will print an '`Invalid command`' or
|
||||
'`Bad reply from daemon`' error.
|
||||
+
|
||||
Note that some of the reported data can be potentially useful to attackers,
|
||||
enabling them to observe and predict better the internal state of *chronyd*.
|
||||
It is recommended to enable only commands that are actually needed for
|
||||
monitoring and limit the access to the hosts that need it.
|
||||
|
||||
=== Real-time clock (RTC)
|
||||
|
||||
[[hwclockfile]]*hwclockfile* _file_::
|
||||
@@ -2123,7 +2265,7 @@ option to *chronyd*) if the following three conditions apply:
|
||||
|
||||
[[rtconutc]]*rtconutc*::
|
||||
*chronyd* assumes by default that the RTC keeps local time (including any
|
||||
daylight saving changes). This is convenient on PCs running Linux which are
|
||||
daylight saving changes). This is convenient on PCs running Linux that are
|
||||
dual-booted with Windows.
|
||||
+
|
||||
If you keep the RTC on local time and your computer is off when daylight saving
|
||||
@@ -2138,7 +2280,8 @@ The directive takes no arguments. It is equivalent to specifying the *-u*
|
||||
switch to the Linux *hwclock* program.
|
||||
+
|
||||
Note that this setting is overridden by the <<hwclockfile,*hwclockfile*>> file
|
||||
and is not relevant for the <<rtcsync,*rtcsync*>> directive.
|
||||
and is not relevant for the <<rtcsync,*rtcsync*>> directive or when the RTC
|
||||
is used as reference clock.
|
||||
|
||||
[[rtcsync]]*rtcsync*::
|
||||
The *rtcsync* directive enables a mode where the system time is periodically
|
||||
@@ -2211,7 +2354,7 @@ from the example line above):
|
||||
+
|
||||
*measurements*:::
|
||||
This option is identical to the *rawmeasurements* option, except it logs only
|
||||
valid measurements from synchronised sources, i.e. measurements which passed
|
||||
valid measurements from synchronised sources, i.e. measurements that passed
|
||||
the RFC 5905 tests 1 through 7. This can be useful for producing graphs of the
|
||||
source's performance.
|
||||
+
|
||||
@@ -2252,7 +2395,7 @@ from the example line above):
|
||||
used to prune old samples when it no longer looks like the measurements fit a
|
||||
linear model). [0, i.e. no samples discarded this time]
|
||||
. The number of runs. The number of runs of regression residuals with the same
|
||||
sign is computed. If this is too small it indicates that the measurements are
|
||||
sign is computed. If this is too small, it indicates that the measurements are
|
||||
no longer represented well by a linear model and that some older samples need
|
||||
to be discarded. The number of runs for the data that is being retained is
|
||||
tabulated. Values of approximately half the number of samples are expected.
|
||||
@@ -2471,9 +2614,9 @@ log measurements statistics tracking
|
||||
A banner is periodically written to the log files enabled by the <<log,*log*>>
|
||||
directive to indicate the meanings of the columns.
|
||||
+
|
||||
The *logbanner* directive specifies after how many entries in the log file
|
||||
should be the banner written. The default is 32, and 0 can be used to disable
|
||||
it entirely.
|
||||
The *logbanner* directive specifies the cadence size of how many entries are
|
||||
written to the log file after which the banner is written anew. The default is
|
||||
32, and 0 can be used to disable it entirely.
|
||||
|
||||
[[logchange]]*logchange* _threshold_::
|
||||
This directive sets the threshold for the adjustment of the system clock that
|
||||
@@ -2563,7 +2706,7 @@ sourcedir /var/run/chrony-dhcp
|
||||
[[include]]*include* _pattern_::
|
||||
The *include* directive includes a configuration file, or multiple configuration
|
||||
files if a wildcard pattern is specified. Unlike with the *confdir* directive,
|
||||
the full name of the files needs to be specified and at least one file is
|
||||
the full name of the files needs to be specified, and at least one file is
|
||||
required to exist.
|
||||
+
|
||||
This directive can be used multiple times.
|
||||
@@ -2649,8 +2792,8 @@ timestamp and the actual reception time at the physical layer. This value will
|
||||
be subtracted from receive timestamps obtained from the NIC. The default value
|
||||
is 0.
|
||||
*nocrossts*:::
|
||||
Some hardware can precisely cross timestamp the NIC clock with the system
|
||||
clock. This option disables the use of the cross timestamping.
|
||||
Some hardware can precisely cross-timestamp the NIC clock with the system
|
||||
clock. This option disables the use of the cross-timestamping.
|
||||
*rxfilter* _filter_:::
|
||||
This option selects the receive timestamping filter. The _filter_ can be one of
|
||||
the following:
|
||||
@@ -2690,7 +2833,7 @@ To avoid calculating the offset with a less accurate transmit timestamp,
|
||||
*chronyd* can save the response for later processing and wait for the hardware
|
||||
transmit timestamp. There is no guarantee that the timestamp will be provided
|
||||
(NICs typically have a limited rate of transmit timestamping). This directive
|
||||
configures how long should *chronyd* wait for the timestamp after receiving a
|
||||
configures how long *chronyd* should wait for the timestamp after receiving a
|
||||
valid response from the server. If a second valid response is received from the
|
||||
server while waiting for the timestamp, they will be both processed
|
||||
immediately.
|
||||
@@ -2705,7 +2848,7 @@ Note that the maximum timeout is limited by the NTP polling interval.
|
||||
|
||||
[[keyfile]]*keyfile* _file_::
|
||||
This directive is used to specify the location of the file containing symmetric
|
||||
keys which are shared between NTP servers and clients, or peers, in order to
|
||||
keys, which are shared between NTP servers and clients, or peers, in order to
|
||||
authenticate NTP packets with a message authentication code (MAC) using a
|
||||
cryptographic hash function or cipher.
|
||||
+
|
||||
@@ -2732,7 +2875,7 @@ Each line consists of an ID, optional type, and key.
|
||||
+
|
||||
The ID can be any positive integer in the range 1 through 2^32-1.
|
||||
+
|
||||
The type is a name of a cryptographic hash function or cipher which is used to
|
||||
The type is a name of a cryptographic hash function or cipher that is used to
|
||||
generate and verify the MAC. The default type is *MD5*, which is always
|
||||
supported.
|
||||
If *chronyd* was built with enabled support for hashing using a crypto library
|
||||
@@ -2756,7 +2899,11 @@ source is specified in the configuration file with a key shorter than 80 bits.
|
||||
+
|
||||
The recommended key types are AES ciphers and SHA3 hash functions. MD5 should
|
||||
be avoided unless no other type is supported on the server and client, or
|
||||
peers.
|
||||
peers. A major weakness of MD5 for the NTP MAC is a length extension attack,
|
||||
where a man-in-the-middle attacker can add arbitrary extension fields to the
|
||||
NTP message and update the MAC to pass the verification of the extended
|
||||
message. The *extfield* option (enabling processing of the specified extension
|
||||
field) should not be used for NTP sources authenticated with an MD5 key.
|
||||
+
|
||||
The <<chronyc.adoc#keygen,*keygen*>> command of *chronyc* can be used to
|
||||
generate random keys for the key file. By default, it generates 160-bit MD5 or
|
||||
@@ -2787,7 +2934,7 @@ Setting this directive to _/_ disables writing and checking of the PID file.
|
||||
[[ptpport]]*ptpport* _port_::
|
||||
The *ptpport* directive enables *chronyd* to send and receive NTP messages
|
||||
contained in PTP event messages (NTP-over-PTP) to enable hardware timestamping
|
||||
on NICs which cannot timestamp NTP packets, but can timestamp unicast PTP
|
||||
on NICs that cannot timestamp NTP packets, but can timestamp unicast PTP
|
||||
packets, and also use corrections provided by PTP one-step end-to-end
|
||||
transparent clocks in network switches and routers. The port recognized by the
|
||||
NICs and PTP transparent clocks is 319 (PTP event port). The default value is 0
|
||||
@@ -2800,7 +2947,7 @@ The PTP port will be open even if *chronyd* is not configured to operate as a
|
||||
server or client. The directive does not change the default protocol of
|
||||
specified NTP sources. Each NTP source that should use NTP-over-PTP needs to
|
||||
be specified with the *port* option set to the PTP port. To actually enable
|
||||
hardware timestamping on NICs which can timestamp PTP packets only, the
|
||||
hardware timestamping on NICs that can timestamp PTP packets only, the
|
||||
*rxfilter* option of the *hwtimestamp* directive needs to be set to _ptp_. The
|
||||
extension field _F324_ needs to be enabled to use the corrections provided by
|
||||
the PTP transparent clocks.
|
||||
@@ -2857,7 +3004,7 @@ The compiled-in default value is _@DEFAULT_USER@_.
|
||||
=== NTP client with permanent connection to NTP servers
|
||||
|
||||
This section shows how to configure *chronyd* for computers that are connected
|
||||
to the Internet (or to any network containing true NTP servers which ultimately
|
||||
to the Internet (or to any network containing true NTP servers that ultimately
|
||||
derive their time from a reference clock) permanently or most of the time.
|
||||
|
||||
To operate in this mode, you will need to know the names of the NTP servers
|
||||
@@ -2883,7 +3030,7 @@ server ntp2.example.net
|
||||
server ntp3.example.net
|
||||
----
|
||||
|
||||
However, you will probably want to include some of the other directives. The
|
||||
You will probably want to include some of the other directives, however. The
|
||||
<<driftfile,*driftfile*>>, <<makestep,*makestep*>> and <<rtcsync,*rtcsync*>>
|
||||
might be particularly useful. Also, the *iburst* option of the
|
||||
<<server,*server*>> directive is useful to speed up the initial
|
||||
@@ -2972,7 +3119,7 @@ actually connected to the Internet.
|
||||
=== Isolated networks
|
||||
|
||||
This section shows how to configure *chronyd* for computers that never have
|
||||
network connectivity to any computer which ultimately derives its time from a
|
||||
network connectivity to any computer that ultimately derives its time from a
|
||||
reference clock.
|
||||
|
||||
In this situation, one computer is selected to be the primary timeserver. The
|
||||
@@ -2987,7 +3134,7 @@ in the form of the <<manual,*manual*>> directive and the
|
||||
<<chronyc.adoc#settime,*settime*>> command in the *chronyc* program.
|
||||
|
||||
If the server is rebooted, *chronyd* can re-read the drift rate from the drift
|
||||
file. However, the server has no accurate estimate of the current time. To get
|
||||
file. The server has no accurate estimate of the current time, however. To get
|
||||
around this, the system can be configured so that the server can initially set
|
||||
itself to a '`majority-vote`' of selected clients' times; this allows the
|
||||
clients to '`flywheel`' the server while it is rebooting.
|
||||
@@ -3055,7 +3202,7 @@ clients might be configured to poll all three servers.
|
||||
|
||||
=== RTC tracking
|
||||
|
||||
This section considers a computer which has occasional connections to the
|
||||
This section considers a computer that has occasional connections to the
|
||||
Internet and is turned off between '`sessions`'. In this case, *chronyd* relies
|
||||
on the computer's RTC to maintain the time between the periods when it is
|
||||
powered up. It assumes that Linux is run exclusively on the computer. Dual-boot
|
||||
@@ -3066,7 +3213,7 @@ enable the *HPET_EMULATE_RTC* option in your kernel configuration. Otherwise,
|
||||
using it.
|
||||
|
||||
When the computer is connected to the Internet, *chronyd* has access to
|
||||
external NTP servers which it makes measurements from. These measurements are
|
||||
external NTP servers that it makes measurements from. These measurements are
|
||||
saved, and straight-line fits are performed on them to provide an estimate of
|
||||
the computer's time error and rate of gaining or losing time.
|
||||
|
||||
@@ -3109,7 +3256,7 @@ take *chronyd* offline; because *chronyd* free-runs between online sessions, no
|
||||
parameters will change significantly between going offline from the Internet
|
||||
and any power failure.
|
||||
|
||||
A final point regards computers which are left running for extended periods and
|
||||
A final point regards computers that are left running for extended periods and
|
||||
where it is desired to spin down the hard disc when it is not in use (e.g. when
|
||||
not accessed for 15 minutes). *chronyd* has been planned so it supports such
|
||||
operation; this is the reason why the RTC tracking parameters are not saved to
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Copyright (C) Richard P. Curnow 1997-2003
|
||||
// Copyright (C) Stephen Wadeley 2016
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017, 2019-2023
|
||||
// Copyright (C) Miroslav Lichvar 2009-2017, 2019-2024
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -50,7 +50,7 @@ running under a non-root user), it will try to connect to 127.0.0.1 and then
|
||||
::1.
|
||||
|
||||
Only the following monitoring commands, which do not affect the behaviour of
|
||||
*chronyd*, are allowed from the network: *activity*, *manual list*,
|
||||
*chronyd*, are allowed from the network by default: *activity*, *manual list*,
|
||||
*rtcdata*, *smoothing*, *sourcename*, *sources*, *sourcestats*, *tracking*,
|
||||
*waitsync*. The
|
||||
set of hosts from which *chronyd* will accept these commands can be configured
|
||||
@@ -58,7 +58,10 @@ with the <<chrony.conf.adoc#cmdallow,*cmdallow*>> directive in the *chronyd*'s
|
||||
configuration file or the <<cmdallow,*cmdallow*>> command in *chronyc*. By
|
||||
default, the commands are accepted only from localhost (127.0.0.1 or ::1).
|
||||
|
||||
All other commands are allowed only through the Unix domain socket. When sent
|
||||
Other monitoring commands can be enabled for network access by the
|
||||
<<chrony.conf.adoc#opencommands,*opencommands*>> directive. Monitoring commands
|
||||
with disabled network access and commands that affect the behaviour of
|
||||
*chronyd* are allowed only through the Unix domain socket. If they are sent
|
||||
over the network, *chronyd* will respond with a '`Not authorised`' error, even
|
||||
if it is from localhost.
|
||||
|
||||
@@ -364,9 +367,12 @@ a measurement is being made every 64 seconds. *chronyd* automatically varies
|
||||
the polling rate in response to prevailing conditions.
|
||||
*Reach*:::
|
||||
This shows the source's reachability register printed as an octal number. The
|
||||
register has 8 bits and is updated on every received or missed packet from
|
||||
the source. A value of 377 indicates that a valid reply was received for all
|
||||
from the last eight transmissions.
|
||||
register has 8 bits. It is shifted to left by one bit with each poll and it is
|
||||
updated by 1 when a valid NTP response, or just a sample in case of a reference
|
||||
clock, is received from the source. A value of 377 indicates that a valid
|
||||
response or sample was received for all of the last 8 polls. Note that samples
|
||||
can be dropped if they are not considered good enough for synchronisation, but
|
||||
the reachability register will still have 1s for their polls.
|
||||
*LastRx*:::
|
||||
This column shows how long ago the last good sample (which is shown in the next
|
||||
column) was received from the source. Measurements that failed some tests are
|
||||
@@ -1461,6 +1467,13 @@ purged. An example of how to do this is shown below.
|
||||
# chronyc cyclelogs
|
||||
# rm /var/log/chrony/measurements1.log
|
||||
----
|
||||
+
|
||||
Note that log files enabled by the *log* directive are opened when the first
|
||||
entry is made. The message log file specified by the *chronyd*'s *-l* option is
|
||||
opened early on start and closed on the *cyclelogs* command only if opening of
|
||||
the new file succeeds to avoid losing messages. If *chronyd* is configured to
|
||||
drop root privileges and the directory containg the log file is not writable
|
||||
for the specified user, *chronyd* will not be able to open the file again.
|
||||
|
||||
[[dump]]*dump*::
|
||||
The *dump* command causes *chronyd* to write its current history of
|
||||
|
||||
@@ -217,6 +217,14 @@ client requests until the service is able to handle them. The service manager
|
||||
sets the LISTEN_FDS environment variable to the number of passed file
|
||||
descriptors.
|
||||
|
||||
*NOTIFY_SOCKET*::
|
||||
The systemd service manager sets this variable for services of the *notify*
|
||||
type. *chronyd* sends a message to this socket when it it is fully initialised
|
||||
and ready to accept commands (e.g. from *chronyc*), with the clock already set
|
||||
if using the *-s* option or *initstepslew* directive. It is an alternative to
|
||||
the *forking* service type, which does not need the PID file. *chronyd* needs
|
||||
to be started with the *-n* or *-d* option to not fork.
|
||||
|
||||
== FILES
|
||||
|
||||
_@SYSCONFDIR@/chrony.conf_
|
||||
|
||||
@@ -85,13 +85,6 @@ 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.
|
||||
|
||||
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
|
||||
https://www.libtom.net/LibTomCrypt/[libtomcrypt] library are available,
|
||||
|
||||
@@ -12,10 +12,11 @@ Conflicts=chronyd.service ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
Type=notify
|
||||
PIDFile=/run/chrony/chronyd.pid
|
||||
Environment="OPTIONS="
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd -U $OPTIONS
|
||||
ExecStart=/usr/sbin/chronyd -n -U $OPTIONS
|
||||
|
||||
User=chrony
|
||||
LogsDirectory=chrony
|
||||
|
||||
@@ -6,10 +6,11 @@ Conflicts=ntpd.service systemd-timesyncd.service
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
Type=notify
|
||||
PIDFile=/run/chrony/chronyd.pid
|
||||
Environment="OPTIONS="
|
||||
EnvironmentFile=-/etc/sysconfig/chronyd
|
||||
ExecStart=/usr/sbin/chronyd $OPTIONS
|
||||
ExecStart=/usr/sbin/chronyd -n $OPTIONS
|
||||
|
||||
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
|
||||
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE
|
||||
|
||||
@@ -907,6 +907,7 @@ get_date (const char *p, const time_t *now)
|
||||
yyHour = tmp->tm_hour;
|
||||
yyMinutes = tmp->tm_min;
|
||||
yySeconds = tmp->tm_sec;
|
||||
memset(&tm, 0, sizeof (tm));
|
||||
tm.tm_isdst = tmp->tm_isdst;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
@@ -943,7 +944,6 @@ get_date (const char *p, const time_t *now)
|
||||
tm.tm_hour += yyRelHour;
|
||||
tm.tm_min += yyRelMinutes;
|
||||
tm.tm_sec += yyRelSeconds;
|
||||
tm.tm_wday = 0;
|
||||
|
||||
/* Let mktime deduce tm_isdst if we have an absolute timestamp,
|
||||
or if the relative timestamp mentions days, months, or years. */
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#define DELAY_QUANT_MAX_K 2
|
||||
#define DELAY_QUANT_Q 10
|
||||
#define DELAY_QUANT_REPEAT 7
|
||||
#define DELAY_QUANT_LARGE_STEP_DELAY 1000
|
||||
#define DELAY_QUANT_MIN_STEP 1.0e-9
|
||||
|
||||
struct HCL_Instance_Record {
|
||||
@@ -127,6 +128,7 @@ HCL_CreateInstance(int min_samples, int max_samples, double min_separation, doub
|
||||
clock->precision = precision;
|
||||
clock->delay_quants = QNT_CreateInstance(DELAY_QUANT_MIN_K, DELAY_QUANT_MAX_K,
|
||||
DELAY_QUANT_Q, DELAY_QUANT_REPEAT,
|
||||
DELAY_QUANT_LARGE_STEP_DELAY,
|
||||
DELAY_QUANT_MIN_STEP);
|
||||
|
||||
LCL_AddParameterChangeHandler(handle_slew, clock);
|
||||
@@ -199,8 +201,10 @@ HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3]
|
||||
|
||||
local_prec = LCL_GetSysPrecisionAsQuantum();
|
||||
|
||||
low_delay = QNT_GetQuantile(clock->delay_quants, DELAY_QUANT_MIN_K);
|
||||
high_delay = QNT_GetQuantile(clock->delay_quants, DELAY_QUANT_MAX_K);
|
||||
low_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMinK(clock->delay_quants)) -
|
||||
QNT_GetMinStep(clock->delay_quants) / 2.0;
|
||||
high_delay = QNT_GetQuantile(clock->delay_quants, QNT_GetMaxK(clock->delay_quants)) +
|
||||
QNT_GetMinStep(clock->delay_quants) / 2.0;
|
||||
low_delay = MIN(low_delay, high_delay);
|
||||
high_delay = MAX(high_delay, low_delay + local_prec);
|
||||
|
||||
|
||||
2
keys.c
2
keys.c
@@ -405,7 +405,7 @@ check_auth(Key *key, const void *data, int data_len,
|
||||
|
||||
hash_len = generate_auth(key, data, data_len, buf, sizeof (buf));
|
||||
|
||||
return MIN(hash_len, trunc_len) == auth_len && !memcmp(buf, auth, auth_len);
|
||||
return MIN(hash_len, trunc_len) == auth_len && UTI_IsMemoryEqual(buf, auth, auth_len);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
19
local.c
19
local.c
@@ -184,10 +184,8 @@ void
|
||||
LCL_Finalise(void)
|
||||
{
|
||||
/* Make sure all handlers have been removed */
|
||||
if (change_list.next != &change_list)
|
||||
assert(0);
|
||||
if (dispersion_notify_list.next != &dispersion_notify_list)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(change_list.next == &change_list);
|
||||
BRIEF_ASSERT(dispersion_notify_list.next == &dispersion_notify_list);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -225,9 +223,7 @@ LCL_AddParameterChangeHandler(LCL_ParameterChangeHandler handler, void *anything
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
assert(0);
|
||||
}
|
||||
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
|
||||
}
|
||||
|
||||
new_entry = MallocNew(ChangeListEntry);
|
||||
@@ -301,9 +297,7 @@ LCL_AddDispersionNotifyHandler(LCL_DispersionNotifyHandler handler, void *anythi
|
||||
|
||||
/* Check that the handler is not already registered */
|
||||
for (ptr = dispersion_notify_list.next; ptr != &dispersion_notify_list; ptr = ptr->next) {
|
||||
if (!(ptr->handler != handler || ptr->anything != anything)) {
|
||||
assert(0);
|
||||
}
|
||||
BRIEF_ASSERT(ptr->handler != handler || ptr->anything != anything);
|
||||
}
|
||||
|
||||
new_entry = MallocNew(DispersionNotifyListEntry);
|
||||
@@ -701,8 +695,11 @@ LCL_MakeStep(void)
|
||||
|
||||
/* Cancel remaining slew and make the step */
|
||||
LCL_AccumulateOffset(correction, 0.0);
|
||||
if (!LCL_ApplyStepOffset(-correction))
|
||||
if (!LCL_ApplyStepOffset(-correction)) {
|
||||
/* Revert the correction */
|
||||
LCL_AccumulateOffset(-correction, 0.0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
|
||||
|
||||
|
||||
46
logging.c
46
logging.c
@@ -46,6 +46,7 @@ static LOG_Context log_contexts;
|
||||
/* Flag indicating we have initialised */
|
||||
static int initialised = 0;
|
||||
|
||||
static char *file_log_path = NULL;
|
||||
static FILE *file_log = NULL;
|
||||
static int system_log = 0;
|
||||
|
||||
@@ -92,6 +93,9 @@ LOG_Finalise(void)
|
||||
|
||||
if (file_log)
|
||||
fclose(file_log);
|
||||
file_log = NULL;
|
||||
Free(file_log_path);
|
||||
file_log_path = NULL;
|
||||
|
||||
LOG_CycleLogFiles();
|
||||
|
||||
@@ -200,27 +204,42 @@ void LOG_Message(LOG_Severity severity,
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenFileLog(const char *log_file)
|
||||
static FILE *
|
||||
open_file_log(const char *log_file, char mode)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (log_file) {
|
||||
f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640);
|
||||
f = UTI_OpenFile(NULL, log_file, NULL, mode, 0640);
|
||||
} else {
|
||||
f = stderr;
|
||||
}
|
||||
|
||||
/* Enable line buffering */
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
if (f)
|
||||
setvbuf(f, NULL, _IOLBF, BUFSIZ);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LOG_OpenFileLog(const char *log_file)
|
||||
{
|
||||
if (file_log_path)
|
||||
Free(file_log_path);
|
||||
if (log_file)
|
||||
file_log_path = Strdup(log_file);
|
||||
else
|
||||
file_log_path = NULL;
|
||||
|
||||
if (file_log && file_log != stderr)
|
||||
fclose(file_log);
|
||||
|
||||
file_log = f;
|
||||
file_log = open_file_log(file_log_path, 'A');
|
||||
}
|
||||
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
@@ -385,14 +404,29 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
|
||||
void
|
||||
LOG_CycleLogFiles(void)
|
||||
{
|
||||
struct stat st;
|
||||
LOG_FileID i;
|
||||
FILE *f;
|
||||
|
||||
/* The log will be opened later when an entry is logged */
|
||||
for (i = 0; i < n_filelogs; i++) {
|
||||
if (logfiles[i].file)
|
||||
fclose(logfiles[i].file);
|
||||
logfiles[i].file = NULL;
|
||||
logfiles[i].writes = 0;
|
||||
}
|
||||
|
||||
/* Try to open the log specified by the -l option, but only if nothing is
|
||||
present at its path to avoid unnecessary error messages. Keep the
|
||||
original file if that fails (the process might no longer have the
|
||||
necessary privileges to write in the directory). */
|
||||
if (file_log && file_log != stderr && stat(file_log_path, &st) < 0 && errno == ENOENT) {
|
||||
f = open_file_log(file_log_path, 'a');
|
||||
if (f) {
|
||||
fclose(file_log);
|
||||
file_log = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
39
main.c
39
main.c
@@ -107,11 +107,40 @@ delete_pidfile(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
notify_system_manager(int start)
|
||||
{
|
||||
#ifdef LINUX
|
||||
/* The systemd protocol is documented in the sd_notify(3) man page */
|
||||
const char *message, *path = getenv("NOTIFY_SOCKET");
|
||||
int sock_fd;
|
||||
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
if (path[0] != '/')
|
||||
LOG_FATAL("Unsupported notification socket");
|
||||
|
||||
message = start ? "READY=1" : "STOPPING=1";
|
||||
|
||||
sock_fd = SCK_OpenUnixDatagramSocket(path, NULL, 0);
|
||||
|
||||
if (sock_fd < 0 || SCK_Send(sock_fd, message, strlen(message), 0) != strlen(message))
|
||||
LOG_FATAL("Could not send notification");
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
MAI_CleanupAndExit(void)
|
||||
{
|
||||
if (!initialised) exit(exit_status);
|
||||
|
||||
notify_system_manager(0);
|
||||
|
||||
LCL_CancelOffsetCorrection();
|
||||
SRC_DumpSources();
|
||||
|
||||
@@ -215,6 +244,8 @@ post_init_ntp_hook(void *anything)
|
||||
REF_SetMode(ref_mode);
|
||||
}
|
||||
|
||||
notify_system_manager(1);
|
||||
|
||||
/* Send an empty message to the foreground process so it can exit.
|
||||
If that fails, indicating the process was killed, exit too. */
|
||||
if (!LOG_NotifyParent(""))
|
||||
@@ -339,8 +370,11 @@ go_daemon(void)
|
||||
/* Don't exit before the 'parent' */
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
close(pipefd[1]);
|
||||
r = read(pipefd[0], message, sizeof (message));
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
if (r != 1 || message[0] != '\0') {
|
||||
if (r > 1) {
|
||||
/* Print the error message from the child */
|
||||
@@ -351,8 +385,6 @@ go_daemon(void)
|
||||
} else
|
||||
exit(0);
|
||||
} else {
|
||||
close(pipefd[0]);
|
||||
|
||||
setsid();
|
||||
|
||||
/* Do 2nd fork, as-per recommended practice for launching daemons. */
|
||||
@@ -362,6 +394,7 @@ go_daemon(void)
|
||||
LOG_FATAL("fork() failed : %s", strerror(errno));
|
||||
} else if (pid > 0) {
|
||||
/* In the 'parent' */
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
exit(0);
|
||||
} else {
|
||||
|
||||
@@ -286,6 +286,7 @@ static ARR_Instance broadcasts;
|
||||
|
||||
/* Parameters for the peer delay quantile */
|
||||
#define DELAY_QUANT_Q 100
|
||||
#define DELAY_QUANT_LARGE_STEP_DELAY 100
|
||||
#define DELAY_QUANT_REPEAT 7
|
||||
|
||||
/* Minimum and maximum allowed poll interval */
|
||||
@@ -690,6 +691,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
if (params->max_delay_quant > 0.0) {
|
||||
int k = round(CLAMP(0.05, params->max_delay_quant, 0.95) * DELAY_QUANT_Q);
|
||||
result->delay_quant = QNT_CreateInstance(k, k, DELAY_QUANT_Q, DELAY_QUANT_REPEAT,
|
||||
DELAY_QUANT_LARGE_STEP_DELAY,
|
||||
LCL_GetSysPrecisionAsQuantum() / 2.0);
|
||||
} else {
|
||||
result->delay_quant = NULL;
|
||||
@@ -1742,7 +1744,7 @@ check_delay_quant(NCR_Instance inst, double delay)
|
||||
|
||||
quant = QNT_GetQuantile(inst->delay_quant, QNT_GetMinK(inst->delay_quant));
|
||||
|
||||
if (delay <= quant)
|
||||
if (delay <= quant + QNT_GetMinStep(inst->delay_quant) / 2.0)
|
||||
return 1;
|
||||
|
||||
DEBUG_LOG("maxdelayquant: delay=%e quant=%e", delay, quant);
|
||||
@@ -2335,9 +2337,8 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
|
||||
inst->valid_rx = 1;
|
||||
}
|
||||
|
||||
if ((unsigned int)local_receive.source >= sizeof (tss_chars) ||
|
||||
(unsigned int)local_transmit.source >= sizeof (tss_chars))
|
||||
assert(0);
|
||||
BRIEF_ASSERT((unsigned int)local_receive.source < sizeof (tss_chars) &&
|
||||
(unsigned int)local_transmit.source < sizeof (tss_chars));
|
||||
|
||||
DEBUG_LOG("NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%.9f root_disp=%.9f refid=%"PRIx32" [%s]",
|
||||
message->lvm, message->stratum, message->poll, message->precision,
|
||||
|
||||
@@ -220,7 +220,7 @@ add_interface(CNF_HwTsInterface *conf_iface)
|
||||
|
||||
SCK_CloseSocket(sock_fd);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
|
||||
phc_fd = SYS_Linux_OpenPHC(req.ifr_name);
|
||||
if (phc_fd < 0)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -457,9 +457,8 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
|
||||
if (replacement)
|
||||
record->resolved_addr = new_addr->ip_addr;
|
||||
|
||||
if (record->remote_addr != NCR_GetRemoteAddress(record->data) ||
|
||||
UTI_CompareIPs(&record->remote_addr->ip_addr, &new_addr->ip_addr, NULL) != 0)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(record->remote_addr == NCR_GetRemoteAddress(record->data) &&
|
||||
UTI_CompareIPs(&record->remote_addr->ip_addr, &new_addr->ip_addr, NULL) == 0);
|
||||
|
||||
if (!UTI_IsIPReal(&old_addr->ip_addr) && UTI_IsIPReal(&new_addr->ip_addr)) {
|
||||
if (auto_start_sources)
|
||||
|
||||
3
nts_ke.h
3
nts_ke.h
@@ -40,6 +40,7 @@
|
||||
#define NKE_RECORD_COOKIE 5
|
||||
#define NKE_RECORD_NTPV4_SERVER_NEGOTIATION 6
|
||||
#define NKE_RECORD_NTPV4_PORT_NEGOTIATION 7
|
||||
#define NKE_RECORD_COMPLIANT_128GCM_EXPORT 1024
|
||||
|
||||
#define NKE_NEXT_PROTOCOL_NTPV4 0
|
||||
|
||||
@@ -49,8 +50,6 @@
|
||||
|
||||
#define NKE_ALPN_NAME "ntske/1"
|
||||
#define NKE_EXPORTER_LABEL "EXPORTER-network-time-security"
|
||||
#define NKE_EXPORTER_CONTEXT_C2S "\x0\x0\x0\xf\x0"
|
||||
#define NKE_EXPORTER_CONTEXT_S2C "\x0\x0\x0\xf\x1"
|
||||
|
||||
#define NKE_MAX_MESSAGE_LENGTH 16384
|
||||
#define NKE_MAX_RECORD_BODY_LENGTH 256
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020-2021
|
||||
* Copyright (C) Miroslav Lichvar 2020-2021, 2024
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
@@ -50,7 +50,9 @@ struct NKC_Instance_Record {
|
||||
int got_response;
|
||||
int resolving_name;
|
||||
|
||||
int compliant_128gcm;
|
||||
NKE_Context context;
|
||||
NKE_Context alt_context;
|
||||
NKE_Cookie cookies[NKE_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 2];
|
||||
@@ -98,12 +100,14 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_AEAD_ALGORITHMS 4
|
||||
|
||||
static int
|
||||
prepare_request(NKC_Instance inst)
|
||||
{
|
||||
NKSN_Instance session = inst->session;
|
||||
uint16_t data[2];
|
||||
int length;
|
||||
uint16_t data[MAX_AEAD_ALGORITHMS];
|
||||
int i, aead_algorithm, length;
|
||||
|
||||
NKSN_BeginMessage(session);
|
||||
|
||||
@@ -111,15 +115,24 @@ prepare_request(NKC_Instance inst)
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
|
||||
return 0;
|
||||
|
||||
length = 0;
|
||||
if (SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0)
|
||||
data[length++] = htons(AEAD_AES_128_GCM_SIV);
|
||||
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) > 0)
|
||||
data[length++] = htons(AEAD_AES_SIV_CMAC_256);
|
||||
for (i = length = 0; i < ARR_GetSize(CNF_GetNtsAeads()) && length < MAX_AEAD_ALGORITHMS;
|
||||
i++) {
|
||||
aead_algorithm = *(int *)ARR_GetElement(CNF_GetNtsAeads(), i);
|
||||
if (SIV_GetKeyLength(aead_algorithm) > 0)
|
||||
data[length++] = htons(aead_algorithm);
|
||||
}
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data,
|
||||
length * sizeof (data[0])))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (data[i] == htons(AEAD_AES_128_GCM_SIV)) {
|
||||
if (!NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NKSN_EndMessage(session))
|
||||
return 0;
|
||||
|
||||
@@ -139,6 +152,8 @@ process_response(NKC_Instance inst)
|
||||
assert(sizeof (data) % sizeof (uint16_t) == 0);
|
||||
assert(sizeof (uint16_t) == 2);
|
||||
|
||||
inst->compliant_128gcm = 0;
|
||||
inst->alt_context.algorithm = AEAD_SIV_INVALID;
|
||||
inst->num_cookies = 0;
|
||||
inst->ntp_address.ip_addr.family = IPADDR_UNSPEC;
|
||||
inst->ntp_address.port = 0;
|
||||
@@ -165,15 +180,31 @@ process_response(NKC_Instance inst)
|
||||
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
||||
break;
|
||||
case NKE_RECORD_AEAD_ALGORITHM:
|
||||
if (length != 2 || (ntohs(data[0]) != AEAD_AES_SIV_CMAC_256 &&
|
||||
ntohs(data[0]) != AEAD_AES_128_GCM_SIV) ||
|
||||
SIV_GetKeyLength(ntohs(data[0])) <= 0) {
|
||||
DEBUG_LOG("Unexpected NTS-KE AEAD algorithm");
|
||||
if (length != 2) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
aead_algorithm = ntohs(data[0]);
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
for (i = 0; i < ARR_GetSize(CNF_GetNtsAeads()); i++) {
|
||||
if (ntohs(data[0]) == *(int *)ARR_GetElement(CNF_GetNtsAeads(), i) &&
|
||||
SIV_GetKeyLength(ntohs(data[0])) > 0) {
|
||||
aead_algorithm = ntohs(data[0]);
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
}
|
||||
}
|
||||
if (aead_algorithm < 0) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
|
||||
if (length != 0) {
|
||||
DEBUG_LOG("Non-empty compliant-128gcm record");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG("Compliant AES-128-GCM-SIV export");
|
||||
inst->compliant_128gcm = 1;
|
||||
break;
|
||||
case NKE_RECORD_ERROR:
|
||||
if (length == 2)
|
||||
@@ -255,6 +286,7 @@ process_response(NKC_Instance inst)
|
||||
static int
|
||||
handle_message(void *arg)
|
||||
{
|
||||
SIV_Algorithm exporter_algorithm;
|
||||
NKC_Instance inst = arg;
|
||||
|
||||
if (!process_response(inst)) {
|
||||
@@ -262,8 +294,25 @@ handle_message(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!NKSN_GetKeys(inst->session, inst->context.algorithm,
|
||||
&inst->context.c2s, &inst->context.s2c))
|
||||
exporter_algorithm = inst->context.algorithm;
|
||||
|
||||
/* With AES-128-GCM-SIV, set the algorithm ID in the RFC5705 key exporter
|
||||
context incorrectly for compatibility with older chrony servers unless
|
||||
the server confirmed support for the compliant context. Generate both
|
||||
sets of keys in case the server uses the compliant context, but does not
|
||||
support the negotiation record, assuming it will respond with an NTS NAK
|
||||
to a request authenticated with the noncompliant key. */
|
||||
if (exporter_algorithm == AEAD_AES_128_GCM_SIV && !inst->compliant_128gcm) {
|
||||
inst->alt_context.algorithm = inst->context.algorithm;
|
||||
if (!NKSN_GetKeys(inst->session, inst->alt_context.algorithm, exporter_algorithm,
|
||||
NKE_NEXT_PROTOCOL_NTPV4, &inst->alt_context.c2s, &inst->alt_context.s2c))
|
||||
return 0;
|
||||
|
||||
exporter_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
}
|
||||
|
||||
if (!NKSN_GetKeys(inst->session, inst->context.algorithm, exporter_algorithm,
|
||||
NKE_NEXT_PROTOCOL_NTPV4, &inst->context.c2s, &inst->context.s2c))
|
||||
return 0;
|
||||
|
||||
if (inst->server_name[0] != '\0') {
|
||||
@@ -428,7 +477,7 @@ NKC_IsActive(NKC_Instance inst)
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
NKC_GetNtsData(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address)
|
||||
{
|
||||
@@ -438,6 +487,7 @@ NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
return 0;
|
||||
|
||||
*context = inst->context;
|
||||
*alt_context = inst->alt_context;
|
||||
|
||||
for (i = 0; i < inst->num_cookies && i < max_cookies; i++)
|
||||
cookies[i] = inst->cookies[i];
|
||||
|
||||
@@ -46,7 +46,7 @@ extern int NKC_Start(NKC_Instance inst);
|
||||
extern int NKC_IsActive(NKC_Instance inst);
|
||||
|
||||
/* Get the NTS data if the session was successful */
|
||||
extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
|
||||
extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020, 2022
|
||||
* Copyright (C) Miroslav Lichvar 2020, 2022, 2024
|
||||
*
|
||||
* 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
|
||||
@@ -337,8 +337,10 @@ helper_signal(int x)
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm)
|
||||
prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm,
|
||||
int compliant_128gcm)
|
||||
{
|
||||
SIV_Algorithm exporter_algorithm;
|
||||
NKE_Context context;
|
||||
NKE_Cookie cookie;
|
||||
char *ntp_server;
|
||||
@@ -371,6 +373,11 @@ prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_a
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, &datum, sizeof (datum)))
|
||||
return 0;
|
||||
|
||||
if (aead_algorithm == AEAD_AES_128_GCM_SIV && compliant_128gcm) {
|
||||
if (!NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (CNF_GetNTPPort() != NTP_PORT) {
|
||||
datum = htons(CNF_GetNTPPort());
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NTPV4_PORT_NEGOTIATION, &datum, sizeof (datum)))
|
||||
@@ -385,8 +392,16 @@ prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_a
|
||||
}
|
||||
|
||||
context.algorithm = aead_algorithm;
|
||||
exporter_algorithm = aead_algorithm;
|
||||
|
||||
if (!NKSN_GetKeys(session, aead_algorithm, &context.c2s, &context.s2c))
|
||||
/* With AES-128-GCM-SIV, set the algorithm ID in the RFC5705 key exporter
|
||||
context incorrectly for compatibility with older chrony clients unless
|
||||
the client requested the compliant context */
|
||||
if (exporter_algorithm == AEAD_AES_128_GCM_SIV && !compliant_128gcm)
|
||||
exporter_algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
|
||||
if (!NKSN_GetKeys(session, aead_algorithm, exporter_algorithm,
|
||||
NKE_NEXT_PROTOCOL_NTPV4, &context.c2s, &context.s2c))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < NKE_MAX_COOKIES; i++) {
|
||||
@@ -411,7 +426,8 @@ process_request(NKSN_Instance session)
|
||||
int next_protocol_records = 0, aead_algorithm_records = 0;
|
||||
int next_protocol_values = 0, aead_algorithm_values = 0;
|
||||
int next_protocol = -1, aead_algorithm = -1, error = -1;
|
||||
int i, critical, type, length;
|
||||
int i, j, critical, type, length;
|
||||
int compliant_128gcm = 0;
|
||||
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
|
||||
|
||||
assert(NKE_MAX_RECORD_BODY_LENGTH % sizeof (uint16_t) == 0);
|
||||
@@ -446,11 +462,21 @@ process_request(NKSN_Instance session)
|
||||
|
||||
for (i = 0; i < MIN(length, sizeof (data)) / 2; i++) {
|
||||
aead_algorithm_values++;
|
||||
/* Use the first supported algorithm */
|
||||
if (aead_algorithm < 0 && SIV_GetKeyLength(ntohs(data[i])) > 0)
|
||||
aead_algorithm = ntohs(data[i]);
|
||||
/* Use the first enabled and supported algorithm */
|
||||
for (j = 0; j < ARR_GetSize(CNF_GetNtsAeads()); j++) {
|
||||
if (ntohs(data[i]) == *(int *)ARR_GetElement(CNF_GetNtsAeads(), j) &&
|
||||
aead_algorithm < 0 && SIV_GetKeyLength(ntohs(data[i])) > 0)
|
||||
aead_algorithm = ntohs(data[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
|
||||
if (length != 0) {
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
break;
|
||||
}
|
||||
compliant_128gcm = 1;
|
||||
break;
|
||||
case NKE_RECORD_ERROR:
|
||||
case NKE_RECORD_WARNING:
|
||||
case NKE_RECORD_COOKIE:
|
||||
@@ -469,7 +495,7 @@ process_request(NKSN_Instance session)
|
||||
error = NKE_ERROR_BAD_REQUEST;
|
||||
}
|
||||
|
||||
if (!prepare_response(session, error, next_protocol, aead_algorithm))
|
||||
if (!prepare_response(session, error, next_protocol, aead_algorithm, compliant_128gcm))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -494,8 +520,7 @@ generate_key(int index)
|
||||
ServerKey *key;
|
||||
int key_length;
|
||||
|
||||
if (index < 0 || index >= MAX_SERVER_KEYS)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(index >= 0 && index < MAX_SERVER_KEYS);
|
||||
|
||||
/* Prefer AES-128-GCM-SIV if available. Note that if older keys loaded
|
||||
from ntsdumpdir use a different algorithm, responding to NTP requests
|
||||
@@ -508,11 +533,11 @@ generate_key(int index)
|
||||
key = &server_keys[index];
|
||||
|
||||
key_length = SIV_GetKeyLength(algorithm);
|
||||
if (key_length > sizeof (key->key))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(key_length <= sizeof (key->key));
|
||||
|
||||
UTI_GetRandomBytesUrandom(key->key, key_length);
|
||||
memset(key->key + key_length, 0, sizeof (key->key) - key_length);
|
||||
if (key_length < sizeof (key->key))
|
||||
memset(key->key + key_length, 0, sizeof (key->key) - key_length);
|
||||
UTI_GetRandomBytes(&key->id, sizeof (key->id));
|
||||
|
||||
/* Encode the index in the lowest bits of the ID */
|
||||
@@ -676,7 +701,7 @@ key_timeout(void *arg)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
run_helper(uid_t uid, gid_t gid, int scfilter_level)
|
||||
run_helper(uid_t uid, gid_t gid, int scfilter_level, int sock_fd)
|
||||
{
|
||||
LOG_Severity log_severity;
|
||||
|
||||
@@ -703,10 +728,15 @@ run_helper(uid_t uid, gid_t gid, int scfilter_level)
|
||||
if (scfilter_level != 0)
|
||||
SYS_EnableSystemCallFilter(scfilter_level, SYS_NTSKE_HELPER);
|
||||
|
||||
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, handle_helper_request, NULL);
|
||||
|
||||
SCH_MainLoop();
|
||||
|
||||
DEBUG_LOG("Helper exiting");
|
||||
|
||||
SCH_RemoveFileHandler(sock_fd);
|
||||
close(sock_fd);
|
||||
|
||||
NKS_Finalise();
|
||||
SCK_Finalise();
|
||||
SYS_Finalise();
|
||||
@@ -766,9 +796,8 @@ NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
|
||||
LOG_CloseParentFd();
|
||||
|
||||
SCK_CloseSocket(sock_fd1);
|
||||
SCH_AddFileHandler(sock_fd2, SCH_FILE_INPUT, handle_helper_request, NULL);
|
||||
|
||||
run_helper(uid, gid, scfilter_level);
|
||||
run_helper(uid, gid, scfilter_level, sock_fd2);
|
||||
}
|
||||
|
||||
SCK_CloseSocket(sock_fd2);
|
||||
@@ -931,8 +960,7 @@ NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie)
|
||||
header->key_id = htonl(key->id);
|
||||
|
||||
nonce = cookie->cookie + sizeof (*header);
|
||||
if (key->nonce_length > sizeof (cookie->cookie) - sizeof (*header))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(key->nonce_length <= sizeof (cookie->cookie) - sizeof (*header));
|
||||
UTI_GetRandomBytes(nonce, key->nonce_length);
|
||||
|
||||
plaintext_length = context->c2s.length + context->s2c.length;
|
||||
|
||||
@@ -663,8 +663,7 @@ create_credentials(const char **certs, const char **keys, int n_certs_keys,
|
||||
goto error;
|
||||
|
||||
if (certs && keys) {
|
||||
if (trusted_certs || trusted_certs_ids)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(!trusted_certs && !trusted_certs_ids);
|
||||
|
||||
for (i = 0; i < n_certs_keys; i++) {
|
||||
if (!UTI_CheckFilePermissions(keys[i], 0771))
|
||||
@@ -675,8 +674,7 @@ create_credentials(const char **certs, const char **keys, int n_certs_keys,
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (certs || keys || n_certs_keys > 0)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(!certs && !keys && n_certs_keys <= 0);
|
||||
|
||||
if (trusted_cert_set == 0 && !CNF_GetNoSystemCert()) {
|
||||
r = gnutls_certificate_set_x509_system_trust(credentials);
|
||||
@@ -877,22 +875,42 @@ NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c)
|
||||
NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm algorithm, SIV_Algorithm exporter_algorithm,
|
||||
int next_protocol, NKE_Key *c2s, NKE_Key *s2c)
|
||||
{
|
||||
int length = SIV_GetKeyLength(siv);
|
||||
int length = SIV_GetKeyLength(algorithm);
|
||||
struct {
|
||||
uint16_t next_protocol;
|
||||
uint16_t algorithm;
|
||||
uint8_t is_s2c;
|
||||
uint8_t _pad;
|
||||
} context;
|
||||
|
||||
if (!inst->tls_session)
|
||||
return 0;
|
||||
|
||||
if (length <= 0 || length > sizeof (c2s->key) || length > sizeof (s2c->key)) {
|
||||
DEBUG_LOG("Invalid algorithm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(sizeof (context) == 6);
|
||||
context.next_protocol = htons(next_protocol);
|
||||
context.algorithm = htons(exporter_algorithm);
|
||||
|
||||
context.is_s2c = 0;
|
||||
if (gnutls_prf_rfc5705(inst->tls_session,
|
||||
sizeof (NKE_EXPORTER_LABEL) - 1, NKE_EXPORTER_LABEL,
|
||||
sizeof (NKE_EXPORTER_CONTEXT_C2S) - 1, NKE_EXPORTER_CONTEXT_C2S,
|
||||
length, (char *)c2s->key) < 0 ||
|
||||
gnutls_prf_rfc5705(inst->tls_session,
|
||||
sizeof (context) - 1, (char *)&context,
|
||||
length, (char *)c2s->key) < 0) {
|
||||
DEBUG_LOG("Could not export key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
context.is_s2c = 1;
|
||||
if (gnutls_prf_rfc5705(inst->tls_session,
|
||||
sizeof (NKE_EXPORTER_LABEL) - 1, NKE_EXPORTER_LABEL,
|
||||
sizeof (NKE_EXPORTER_CONTEXT_S2C) - 1, NKE_EXPORTER_CONTEXT_S2C,
|
||||
sizeof (context) - 1, (char *)&context,
|
||||
length, (char *)s2c->key) < 0) {
|
||||
DEBUG_LOG("Could not export key");
|
||||
return 0;
|
||||
|
||||
@@ -77,8 +77,11 @@ extern int NKSN_EndMessage(NKSN_Instance inst);
|
||||
extern int NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
|
||||
void *body, int buffer_length);
|
||||
|
||||
/* Export NTS keys for a specified algorithm */
|
||||
extern int NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c);
|
||||
/* Export NTS keys for a specified algorithm (for compatibility reasons the
|
||||
RFC5705 exporter context is allowed to have a different algorithm) */
|
||||
extern int NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm algorithm,
|
||||
SIV_Algorithm exporter_algorithm,
|
||||
int next_protocol, NKE_Key *c2s, NKE_Key *s2c);
|
||||
|
||||
/* Check if the session has stopped */
|
||||
extern int NKSN_IsStopped(NKSN_Instance inst);
|
||||
|
||||
@@ -104,9 +104,8 @@ NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
||||
body = (unsigned char *)(header + 1);
|
||||
ciphertext = body + nonce_length + nonce_padding;
|
||||
|
||||
if ((unsigned char *)header + auth_length !=
|
||||
ciphertext + ciphertext_length + ciphertext_padding + additional_padding)
|
||||
assert(0);
|
||||
BRIEF_ASSERT((unsigned char *)header + auth_length ==
|
||||
ciphertext + ciphertext_length + ciphertext_padding + additional_padding);
|
||||
|
||||
memcpy(body, nonce, nonce_length);
|
||||
memset(body + nonce_length, 0, nonce_padding);
|
||||
|
||||
@@ -72,6 +72,7 @@ struct NNC_Instance_Record {
|
||||
double last_nke_success;
|
||||
|
||||
NKE_Context context;
|
||||
NKE_Context alt_context;
|
||||
unsigned int context_id;
|
||||
NKE_Cookie cookies[NTS_MAX_COOKIES];
|
||||
int num_cookies;
|
||||
@@ -105,6 +106,7 @@ reset_instance(NNC_Instance inst)
|
||||
inst->last_nke_success = 0.0;
|
||||
|
||||
memset(&inst->context, 0, sizeof (inst->context));
|
||||
memset(&inst->alt_context, 0, sizeof (inst->alt_context));
|
||||
inst->context_id = 0;
|
||||
memset(inst->cookies, 0, sizeof (inst->cookies));
|
||||
inst->num_cookies = 0;
|
||||
@@ -165,6 +167,21 @@ check_cookies(NNC_Instance inst)
|
||||
if (inst->num_cookies > 0 &&
|
||||
((inst->nak_response && !inst->ok_response) ||
|
||||
SCH_GetLastEventMonoTime() - inst->last_nke_success > CNF_GetNtsRefresh())) {
|
||||
|
||||
/* Before dropping the cookies, check whether there is an alternate set of
|
||||
keys available (exported with the compliant context for AES-128-GCM-SIV)
|
||||
and the NAK was the only valid response after the last NTS-KE session,
|
||||
indicating we use incorrect keys and switching to the other set of keys
|
||||
for the following NTP requests might work */
|
||||
if (inst->alt_context.algorithm != AEAD_SIV_INVALID &&
|
||||
inst->alt_context.algorithm == inst->context.algorithm &&
|
||||
inst->nke_attempts > 0 && inst->nak_response && !inst->ok_response) {
|
||||
inst->context = inst->alt_context;
|
||||
inst->alt_context.algorithm = AEAD_SIV_INVALID;
|
||||
DEBUG_LOG("Switched to compliant keys");
|
||||
return 1;
|
||||
}
|
||||
|
||||
inst->num_cookies = 0;
|
||||
DEBUG_LOG("Dropped cookies");
|
||||
}
|
||||
@@ -261,7 +278,7 @@ get_cookies(NNC_Instance inst)
|
||||
assert(sizeof (inst->cookies) / sizeof (inst->cookies[0]) == NTS_MAX_COOKIES);
|
||||
|
||||
/* Get the new keys, cookies and NTP address if the session was successful */
|
||||
got_data = NKC_GetNtsData(inst->nke, &inst->context,
|
||||
got_data = NKC_GetNtsData(inst->nke, &inst->context, &inst->alt_context,
|
||||
inst->cookies, &inst->num_cookies, NTS_MAX_COOKIES,
|
||||
&ntp_address);
|
||||
|
||||
@@ -520,6 +537,7 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
|
||||
new NTS-KE session to be started as soon as the cookies run out. */
|
||||
inst->nke_attempts = 0;
|
||||
inst->next_nke_attempt = 0.0;
|
||||
inst->alt_context.algorithm = AEAD_SIV_INVALID;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -643,6 +661,7 @@ load_cookies(NNC_Instance inst)
|
||||
sscanf(words[0], "%u", &context_id) != 1 || sscanf(words[1], "%d", &algorithm) != 1)
|
||||
goto error;
|
||||
|
||||
inst->alt_context.algorithm = AEAD_SIV_INVALID;
|
||||
inst->context.algorithm = algorithm;
|
||||
inst->context.s2c.length = UTI_HexToBytes(words[2], inst->context.s2c.key,
|
||||
sizeof (inst->context.s2c.key));
|
||||
@@ -687,6 +706,7 @@ error:
|
||||
fclose(f);
|
||||
|
||||
memset(&inst->context, 0, sizeof (inst->context));
|
||||
memset(&inst->alt_context, 0, sizeof (inst->alt_context));
|
||||
inst->num_cookies = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -259,8 +259,7 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
|
||||
|
||||
/* Make sure this is a response to the request from the last call
|
||||
of NNS_CheckRequestAuth() */
|
||||
if (UTI_CompareNtp64(&server->req_tx, &request->transmit_ts) != 0)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(UTI_CompareNtp64(&server->req_tx, &request->transmit_ts) == 0);
|
||||
|
||||
for (parsed = NTP_HEADER_LENGTH; parsed < req_info->length; parsed += ef_length) {
|
||||
if (!NEF_ParseField(request, req_info->length, parsed,
|
||||
|
||||
@@ -55,7 +55,7 @@ struct request_length {
|
||||
};
|
||||
|
||||
static const struct request_length request_lengths[] = {
|
||||
REQ_LENGTH_ENTRY(null, null), /* NULL */
|
||||
{ 0, 0 }, /* NULL - not supported */
|
||||
REQ_LENGTH_ENTRY(online, null), /* ONLINE */
|
||||
REQ_LENGTH_ENTRY(offline, null), /* OFFLINE */
|
||||
REQ_LENGTH_ENTRY(burst, null), /* BURST */
|
||||
@@ -65,7 +65,7 @@ static const struct request_length request_lengths[] = {
|
||||
REQ_LENGTH_ENTRY(modify_maxdelay, null), /* MODIFY_MAXDELAY */
|
||||
REQ_LENGTH_ENTRY(modify_maxdelayratio, null), /* MODIFY_MAXDELAYRATIO */
|
||||
REQ_LENGTH_ENTRY(modify_maxupdateskew, null), /* MODIFY_MAXUPDATESKEW */
|
||||
REQ_LENGTH_ENTRY(logon, null), /* LOGON */
|
||||
{ 0, 0 }, /* LOGON - not supported */
|
||||
REQ_LENGTH_ENTRY(settime, manual_timestamp), /* SETTIME */
|
||||
{ 0, 0 }, /* LOCAL */
|
||||
REQ_LENGTH_ENTRY(manual, null), /* MANUAL */
|
||||
|
||||
@@ -141,6 +141,7 @@ have_helper(void)
|
||||
/* ======================================================================= */
|
||||
|
||||
/* HELPER - prepare fatal error for daemon */
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
static void
|
||||
res_fatal(PrvResponse *res, const char *fmt, ...)
|
||||
{
|
||||
@@ -546,9 +547,9 @@ PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len)
|
||||
PrvResponse res;
|
||||
|
||||
SCK_SockaddrToIPSockAddr(address, address_len, &ip_saddr);
|
||||
if (ip_saddr.port != 0 && ip_saddr.port != CNF_GetNTPPort() &&
|
||||
ip_saddr.port != CNF_GetAcquisitionPort() && ip_saddr.port != CNF_GetPtpPort())
|
||||
assert(0);
|
||||
BRIEF_ASSERT(ip_saddr.port == 0 || ip_saddr.port == CNF_GetNTPPort() ||
|
||||
ip_saddr.port == CNF_GetAcquisitionPort() ||
|
||||
ip_saddr.port == CNF_GetPtpPort());
|
||||
|
||||
if (!have_helper())
|
||||
return bind(sock, address, address_len);
|
||||
|
||||
55
quantiles.c
55
quantiles.c
@@ -49,20 +49,21 @@ struct QNT_Instance_Record {
|
||||
int q;
|
||||
int min_k;
|
||||
double min_step;
|
||||
double neg_step_limit;
|
||||
int n_set;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
QNT_Instance
|
||||
QNT_CreateInstance(int min_k, int max_k, int q, int repeat, double min_step)
|
||||
QNT_CreateInstance(int min_k, int max_k, int q, int repeat,
|
||||
int large_step_delay, double min_step)
|
||||
{
|
||||
QNT_Instance inst;
|
||||
long seed;
|
||||
|
||||
if (q < 2 || min_k > max_k || min_k < 1 || max_k >= q ||
|
||||
repeat < 1 || repeat > MAX_REPEAT || min_step <= 0.0)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(q >= 2 && min_k <= max_k && min_k >= 1 && max_k < q && repeat >= 1 &&
|
||||
repeat <= MAX_REPEAT && min_step > 0.0 && large_step_delay >= 0);
|
||||
|
||||
inst = MallocNew(struct QNT_Instance_Record);
|
||||
inst->n_quants = (max_k - min_k + 1) * repeat;
|
||||
@@ -71,6 +72,7 @@ QNT_CreateInstance(int min_k, int max_k, int q, int repeat, double min_step)
|
||||
inst->q = q;
|
||||
inst->min_k = min_k;
|
||||
inst->min_step = min_step;
|
||||
inst->neg_step_limit = -large_step_delay * min_step;
|
||||
|
||||
QNT_Reset(inst);
|
||||
|
||||
@@ -114,8 +116,7 @@ insert_initial_value(QNT_Instance inst, double value)
|
||||
{
|
||||
int i, j, r = inst->repeat;
|
||||
|
||||
if (inst->n_set * r >= inst->n_quants)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(inst->n_set * r < inst->n_quants);
|
||||
|
||||
/* Keep the initial estimates repeated and ordered */
|
||||
for (i = inst->n_set; i > 0 && inst->quants[(i - 1) * r].est > value; i--) {
|
||||
@@ -136,29 +137,36 @@ insert_initial_value(QNT_Instance inst, double value)
|
||||
|
||||
static void
|
||||
update_estimate(struct Quantile *quantile, double value, double p, double rand,
|
||||
double min_step)
|
||||
double min_step, double neg_step_limit)
|
||||
{
|
||||
if (value > quantile->est && rand > (1.0 - p)) {
|
||||
if (value >= quantile->est) {
|
||||
if (rand < (1.0 - p))
|
||||
return;
|
||||
quantile->step += quantile->sign > 0 ? min_step : -min_step;
|
||||
quantile->est += quantile->step > 0.0 ? fabs(quantile->step) : min_step;
|
||||
quantile->est += quantile->step > min_step ? quantile->step : min_step;
|
||||
if (quantile->est > value) {
|
||||
quantile->step += value - quantile->est;
|
||||
quantile->est = value;
|
||||
quantile->est = value + min_step / 4.0;
|
||||
}
|
||||
if (quantile->sign < 0 && quantile->step > min_step)
|
||||
quantile->step = min_step;
|
||||
quantile->sign = 1;
|
||||
} else if (value < quantile->est && rand > p) {
|
||||
} else {
|
||||
if (rand < p)
|
||||
return;
|
||||
quantile->step += quantile->sign < 0 ? min_step : -min_step;
|
||||
quantile->est -= quantile->step > 0.0 ? fabs(quantile->step) : min_step;
|
||||
quantile->est -= quantile->step > min_step ? quantile->step : min_step;
|
||||
if (quantile->est < value) {
|
||||
quantile->step += quantile->est - value;
|
||||
quantile->est = value;
|
||||
quantile->est = value - min_step / 4.0;
|
||||
}
|
||||
if (quantile->sign > 0 && quantile->step > min_step)
|
||||
quantile->step = min_step;
|
||||
quantile->sign = -1;
|
||||
}
|
||||
|
||||
if (quantile->step < neg_step_limit)
|
||||
quantile->step = neg_step_limit;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -179,7 +187,7 @@ QNT_Accumulate(QNT_Instance inst, double value)
|
||||
p = (double)(i / inst->repeat + inst->min_k) / inst->q;
|
||||
rand = (double)random() / ((1U << 31) - 1);
|
||||
|
||||
update_estimate(&inst->quants[i], value, p, rand, inst->min_step);
|
||||
update_estimate(&inst->quants[i], value, p, rand, inst->min_step, inst->neg_step_limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,14 +201,29 @@ QNT_GetMinK(QNT_Instance inst)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
QNT_GetMaxK(QNT_Instance inst)
|
||||
{
|
||||
return inst->min_k + (inst->n_quants / inst->repeat) - 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
QNT_GetMinStep(QNT_Instance inst)
|
||||
{
|
||||
return inst->min_step;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
double
|
||||
QNT_GetQuantile(QNT_Instance inst, int k)
|
||||
{
|
||||
double estimates[MAX_REPEAT];
|
||||
int i;
|
||||
|
||||
if (k < inst->min_k || k - inst->min_k >= inst->n_quants)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(k >= inst->min_k && (k - inst->min_k) * inst->repeat < inst->n_quants);
|
||||
|
||||
for (i = 0; i < inst->repeat; i++)
|
||||
estimates[i] = inst->quants[(k - inst->min_k) * inst->repeat + i].est;
|
||||
|
||||
@@ -30,12 +30,15 @@
|
||||
|
||||
typedef struct QNT_Instance_Record *QNT_Instance;
|
||||
|
||||
extern QNT_Instance QNT_CreateInstance(int min_k, int max_k, int q, int repeat, double min_step);
|
||||
extern QNT_Instance QNT_CreateInstance(int min_k, int max_k, int q, int repeat,
|
||||
int large_step_delay, double min_step);
|
||||
extern void QNT_DestroyInstance(QNT_Instance inst);
|
||||
|
||||
extern void QNT_Reset(QNT_Instance inst);
|
||||
extern void QNT_Accumulate(QNT_Instance inst, double value);
|
||||
extern int QNT_GetMinK(QNT_Instance inst);
|
||||
extern int QNT_GetMaxK(QNT_Instance inst);
|
||||
extern double QNT_GetMinStep(QNT_Instance inst);
|
||||
extern double QNT_GetQuantile(QNT_Instance inst, int k);
|
||||
|
||||
#endif
|
||||
|
||||
36
refclock.c
36
refclock.c
@@ -48,6 +48,7 @@ extern RefclockDriver RCL_SHM_driver;
|
||||
extern RefclockDriver RCL_SOCK_driver;
|
||||
extern RefclockDriver RCL_PPS_driver;
|
||||
extern RefclockDriver RCL_PHC_driver;
|
||||
extern RefclockDriver RCL_RTC_driver;
|
||||
|
||||
struct FilterSample {
|
||||
double offset;
|
||||
@@ -63,6 +64,7 @@ struct RCL_Instance_Record {
|
||||
int driver_poll;
|
||||
int driver_polled;
|
||||
int poll;
|
||||
int reached;
|
||||
int leap_status;
|
||||
int local;
|
||||
int pps_forced;
|
||||
@@ -159,6 +161,8 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->driver = &RCL_PPS_driver;
|
||||
} else if (strcmp(params->driver_name, "PHC") == 0) {
|
||||
inst->driver = &RCL_PHC_driver;
|
||||
} else if (strcmp(params->driver_name, "RTC") == 0) {
|
||||
inst->driver = &RCL_RTC_driver;
|
||||
} else {
|
||||
LOG_FATAL("unknown refclock driver %s", params->driver_name);
|
||||
}
|
||||
@@ -175,6 +179,7 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
inst->driver_poll = params->driver_poll;
|
||||
inst->poll = params->poll;
|
||||
inst->driver_polled = 0;
|
||||
inst->reached = 0;
|
||||
inst->leap_status = LEAP_Normal;
|
||||
inst->local = params->local;
|
||||
inst->pps_forced = params->pps_forced;
|
||||
@@ -226,29 +231,16 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||
}
|
||||
|
||||
if (inst->driver->poll) {
|
||||
int max_samples;
|
||||
|
||||
if (inst->driver_poll > inst->poll)
|
||||
inst->driver_poll = inst->poll;
|
||||
|
||||
max_samples = 1 << (inst->poll - inst->driver_poll);
|
||||
if (max_samples < params->filter_length) {
|
||||
if (max_samples < 4) {
|
||||
LOG(LOGS_WARN, "Setting filter length for %s to %d",
|
||||
UTI_RefidToString(inst->ref_id), max_samples);
|
||||
}
|
||||
params->filter_length = max_samples;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->driver->init && !inst->driver->init(inst))
|
||||
LOG_FATAL("refclock %s initialisation failed", params->driver_name);
|
||||
|
||||
/* Require the filter to have at least 4 samples to produce a filtered
|
||||
sample, or be full for shorter lengths, and combine 60% of samples
|
||||
closest to the median */
|
||||
inst->filter = SPF_CreateInstance(MIN(params->filter_length, 4), params->filter_length,
|
||||
params->max_dispersion, 0.6);
|
||||
/* Don't require more than one sample per poll and combine 60% of the
|
||||
samples closest to the median offset */
|
||||
inst->filter = SPF_CreateInstance(1, params->filter_length, params->max_dispersion, 0.6);
|
||||
|
||||
inst->source = SRC_CreateNewInstance(inst->ref_id, SRC_REFCLOCK, 0, params->sel_options,
|
||||
NULL, params->min_samples, params->max_samples,
|
||||
@@ -665,6 +657,12 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
RCL_UpdateReachability(RCL_Instance instance)
|
||||
{
|
||||
instance->reached++;
|
||||
}
|
||||
|
||||
double
|
||||
RCL_GetPrecision(RCL_Instance instance)
|
||||
{
|
||||
@@ -792,6 +790,9 @@ poll_timeout(void *arg)
|
||||
if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) {
|
||||
inst->driver_polled = 0;
|
||||
|
||||
SRC_UpdateReachability(inst->source, inst->reached > 0);
|
||||
inst->reached = 0;
|
||||
|
||||
if (SPF_GetFilteredSample(inst->filter, &sample)) {
|
||||
double local_freq, local_offset;
|
||||
struct timespec local_ref_time;
|
||||
@@ -807,7 +808,6 @@ poll_timeout(void *arg)
|
||||
inst->leap_status = LEAP_Unsynchronised;
|
||||
}
|
||||
|
||||
SRC_UpdateReachability(inst->source, 1);
|
||||
SRC_UpdateStatus(inst->source, stratum, inst->leap_status);
|
||||
SRC_AccumulateSample(inst->source, &sample);
|
||||
SRC_SelectSource(inst->source);
|
||||
@@ -816,8 +816,6 @@ poll_timeout(void *arg)
|
||||
follow_local(inst, &local_ref_time, local_freq, local_offset);
|
||||
|
||||
log_sample(inst, &sample.time, 1, 0, 0.0, sample.offset, sample.peer_dispersion);
|
||||
} else {
|
||||
SRC_UpdateReachability(inst->source, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time,
|
||||
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
|
||||
extern int RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
|
||||
double second, double dispersion, double raw_correction);
|
||||
extern void RCL_UpdateReachability(RCL_Instance instance);
|
||||
extern double RCL_GetPrecision(RCL_Instance instance);
|
||||
extern int RCL_GetDriverPoll(RCL_Instance instance);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ static int phc_initialise(RCL_Instance instance)
|
||||
|
||||
path = RCL_GetDriverParameter(instance);
|
||||
|
||||
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
||||
phc_fd = SYS_Linux_OpenPHC(path);
|
||||
if (phc_fd < 0)
|
||||
LOG_FATAL("Could not open PHC");
|
||||
|
||||
@@ -154,6 +154,8 @@ static void process_ext_pulse(RCL_Instance instance, struct timespec *phc_ts)
|
||||
}
|
||||
phc->last_extts = *phc_ts;
|
||||
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
if (!HCL_CookTime(phc->clock, phc_ts, &local_ts, &local_err))
|
||||
return;
|
||||
|
||||
@@ -204,6 +206,9 @@ static int phc_poll(RCL_Instance instance)
|
||||
if (n_readings < 1)
|
||||
return 0;
|
||||
|
||||
if (!phc->extpps)
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
if (!HCL_ProcessReadings(phc->clock, n_readings, readings, &phc_ts, &sys_ts, &phc_err))
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -143,6 +143,8 @@ static int pps_poll(RCL_Instance instance)
|
||||
|
||||
pps->last_seq = seq;
|
||||
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
return RCL_AddPulse(instance, &ts, 1.0e-9 * ts.tv_nsec);
|
||||
}
|
||||
|
||||
|
||||
179
refclock_rtc.c
Normal file
179
refclock_rtc.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Uwe Kleine-König, Pengutronix 2021
|
||||
* Copyright (C) Ahmad Fatoum, Pengutronix 2024
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
RTC refclock driver.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "refclock.h"
|
||||
|
||||
#ifdef FEAT_RTC
|
||||
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include "conf.h"
|
||||
#include "local.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
#include "rtc_linux.h"
|
||||
|
||||
struct refrtc_instance {
|
||||
int fd;
|
||||
int polling;
|
||||
int utc;
|
||||
};
|
||||
|
||||
static int refrtc_add_sample(RCL_Instance instance, struct timespec *now,
|
||||
time_t rtc_sec, long rtc_nsec)
|
||||
{
|
||||
struct timespec rtc_ts;
|
||||
int status;
|
||||
|
||||
rtc_ts.tv_sec = rtc_sec;
|
||||
rtc_ts.tv_nsec = rtc_nsec;
|
||||
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
status = RCL_AddSample(instance, now, &rtc_ts, LEAP_Normal);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void refrtc_read_after_uie(int rtcfd, int event, void *data)
|
||||
{
|
||||
RCL_Instance instance = (RCL_Instance)data;
|
||||
struct refrtc_instance *rtc = RCL_GetDriverData(instance);
|
||||
struct timespec now;
|
||||
time_t rtc_sec;
|
||||
int status;
|
||||
|
||||
status = RTC_Linux_CheckInterrupt(rtcfd);
|
||||
if (status < 0) {
|
||||
SCH_RemoveFileHandler(rtcfd);
|
||||
RTC_Linux_SwitchInterrupt(rtcfd, 0); /* Likely to raise error too, but just to be sure... */
|
||||
close(rtcfd);
|
||||
rtc->fd = -1;
|
||||
return;
|
||||
} else if (status == 0) {
|
||||
/* Wait for the next interrupt, this one may be bogus */
|
||||
return;
|
||||
}
|
||||
|
||||
rtc_sec = RTC_Linux_ReadTimeAfterInterrupt(rtcfd, rtc->utc, NULL, &now);
|
||||
if (rtc_sec == (time_t)-1)
|
||||
return;
|
||||
|
||||
refrtc_add_sample(instance, &now, rtc_sec, 0);
|
||||
}
|
||||
|
||||
static int refrtc_initialise(RCL_Instance instance)
|
||||
{
|
||||
const char *options[] = {"utc", NULL};
|
||||
struct refrtc_instance *rtc;
|
||||
int rtcfd, status;
|
||||
const char *path;
|
||||
|
||||
RCL_CheckDriverOptions(instance, options);
|
||||
|
||||
if (CNF_GetRtcSync() || CNF_GetRtcFile())
|
||||
LOG_FATAL("RTC refclock cannot be used together with rtcsync or rtcfile");
|
||||
|
||||
path = RCL_GetDriverParameter(instance);
|
||||
|
||||
rtcfd = open(path, O_RDONLY);
|
||||
if (rtcfd < 0)
|
||||
LOG_FATAL("Could not open RTC device %s : %s", path, strerror(errno));
|
||||
|
||||
/* Close on exec */
|
||||
UTI_FdSetCloexec(rtcfd);
|
||||
|
||||
rtc = MallocNew(struct refrtc_instance);
|
||||
rtc->fd = rtcfd;
|
||||
rtc->utc = RCL_GetDriverOption(instance, "utc") ? 1 : 0;
|
||||
|
||||
RCL_SetDriverData(instance, rtc);
|
||||
|
||||
/* Try to enable update interrupts */
|
||||
status = RTC_Linux_SwitchInterrupt(rtcfd, 1);
|
||||
if (status) {
|
||||
SCH_AddFileHandler(rtcfd, SCH_FILE_INPUT, refrtc_read_after_uie, instance);
|
||||
rtc->polling = 0;
|
||||
} else {
|
||||
LOG(LOGS_INFO, "Falling back to polling for %s", path);
|
||||
rtc->polling = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void refrtc_finalise(RCL_Instance instance)
|
||||
{
|
||||
struct refrtc_instance *rtc;
|
||||
|
||||
rtc = RCL_GetDriverData(instance);
|
||||
|
||||
if (!rtc->polling) {
|
||||
SCH_RemoveFileHandler(rtc->fd);
|
||||
RTC_Linux_SwitchInterrupt(rtc->fd, 0);
|
||||
}
|
||||
|
||||
close(rtc->fd);
|
||||
Free(rtc);
|
||||
}
|
||||
|
||||
static int refrtc_poll(RCL_Instance instance)
|
||||
{
|
||||
struct refrtc_instance *rtc;
|
||||
struct timespec now;
|
||||
time_t rtc_sec;
|
||||
|
||||
rtc = RCL_GetDriverData(instance);
|
||||
|
||||
if (!rtc->polling)
|
||||
return 0;
|
||||
|
||||
rtc_sec = RTC_Linux_ReadTimeNow(rtc->fd, rtc->utc, NULL, &now);
|
||||
if (rtc_sec == (time_t)-1)
|
||||
return 0;
|
||||
|
||||
/* As the rtc has a resolution of 1s, only add half a second */
|
||||
return refrtc_add_sample(instance, &now, rtc_sec, 500000000);
|
||||
}
|
||||
|
||||
RefclockDriver RCL_RTC_driver = {
|
||||
refrtc_initialise,
|
||||
refrtc_finalise,
|
||||
refrtc_poll
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
RefclockDriver RCL_RTC_driver = { NULL, NULL, NULL };
|
||||
|
||||
#endif
|
||||
@@ -109,6 +109,8 @@ static int shm_poll(RCL_Instance instance)
|
||||
|
||||
shm->valid = 0;
|
||||
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
receive_ts.tv_sec = t.receiveTimeStampSec;
|
||||
clock_ts.tv_sec = t.clockTimeStampSec;
|
||||
|
||||
|
||||
@@ -129,6 +129,8 @@ static void read_sample(int sockfd, int event, void *anything)
|
||||
UTI_TimevalToTimespec(&sample.tv, &sys_ts);
|
||||
UTI_NormaliseTimespec(&sys_ts);
|
||||
|
||||
RCL_UpdateReachability(instance);
|
||||
|
||||
if (!UTI_IsTimeOffsetSane(&sys_ts, sample.offset))
|
||||
return;
|
||||
|
||||
|
||||
34
reference.c
34
reference.c
@@ -47,9 +47,6 @@
|
||||
/* The update interval of the reference in the local reference mode */
|
||||
#define LOCAL_REF_UPDATE_INTERVAL 64.0
|
||||
|
||||
/* Interval between updates of the drift file */
|
||||
#define MAX_DRIFTFILE_AGE 3600.0
|
||||
|
||||
static int are_we_synchronised;
|
||||
static int enable_local_stratum;
|
||||
static int local_stratum;
|
||||
@@ -57,6 +54,8 @@ static int local_orphan;
|
||||
static double local_distance;
|
||||
static int local_activate_ok;
|
||||
static double local_activate;
|
||||
static double local_wait_synced;
|
||||
static double local_wait_unsynced;
|
||||
static struct timespec local_ref_time;
|
||||
static NTP_Leap our_leap_status;
|
||||
static int our_leap_sec;
|
||||
@@ -65,6 +64,7 @@ static int our_stratum;
|
||||
static uint32_t our_ref_id;
|
||||
static IPAddr our_ref_ip;
|
||||
static struct timespec our_ref_time;
|
||||
static double unsynchronised_since;
|
||||
static double our_skew;
|
||||
static double our_residual_freq;
|
||||
static double our_root_delay;
|
||||
@@ -110,6 +110,7 @@ static REF_ModeEndHandler mode_end_handler = NULL;
|
||||
/* Filename of the drift file. */
|
||||
static char *drift_file=NULL;
|
||||
static double drift_file_age;
|
||||
static int drift_file_interval;
|
||||
|
||||
static void update_drift_file(double, double);
|
||||
|
||||
@@ -213,7 +214,7 @@ REF_Initialise(void)
|
||||
local_activate_ok = 0;
|
||||
|
||||
/* Now see if we can get the drift file opened */
|
||||
drift_file = CNF_GetDriftFile();
|
||||
drift_file = CNF_GetDriftFile(&drift_file_interval);
|
||||
if (drift_file) {
|
||||
in = UTI_OpenFile(NULL, drift_file, NULL, 'r', 0);
|
||||
if (in) {
|
||||
@@ -250,8 +251,11 @@ REF_Initialise(void)
|
||||
correction_time_ratio = CNF_GetCorrectionTimeRatio();
|
||||
|
||||
enable_local_stratum = CNF_AllowLocalReference(&local_stratum, &local_orphan,
|
||||
&local_distance, &local_activate);
|
||||
&local_distance, &local_activate,
|
||||
&local_wait_synced,
|
||||
&local_wait_unsynced);
|
||||
UTI_ZeroTimespec(&local_ref_time);
|
||||
unsynchronised_since = SCH_GetLastEventMonoTime();
|
||||
|
||||
leap_when = 0;
|
||||
leap_timeout_id = 0;
|
||||
@@ -987,6 +991,8 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||
if (step_offset != 0.0) {
|
||||
if (LCL_ApplyStepOffset(step_offset))
|
||||
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", -step_offset);
|
||||
else
|
||||
LCL_AccumulateOffset(step_offset, 0.0);
|
||||
}
|
||||
|
||||
update_leap_status(leap, raw_now.tv_sec, 0);
|
||||
@@ -1005,7 +1011,7 @@ REF_SetReference(int stratum, NTP_Leap leap, int combined_sources,
|
||||
if (drift_file) {
|
||||
/* Update drift file at most once per hour */
|
||||
drift_file_age += update_interval;
|
||||
if (drift_file_age >= MAX_DRIFTFILE_AGE) {
|
||||
if (drift_file_age >= drift_file_interval) {
|
||||
update_drift_file(local_abs_frequency, our_skew);
|
||||
drift_file_age = 0.0;
|
||||
}
|
||||
@@ -1095,6 +1101,9 @@ REF_SetUnsynchronised(void)
|
||||
our_ref_ip.family = IPADDR_INET4;
|
||||
our_ref_ip.addr.in4 = 0;
|
||||
our_stratum = 0;
|
||||
|
||||
if (are_we_synchronised)
|
||||
unsynchronised_since = SCH_GetLastEventMonoTime();
|
||||
are_we_synchronised = 0;
|
||||
|
||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||
@@ -1138,13 +1147,16 @@ REF_GetReferenceParams
|
||||
)
|
||||
{
|
||||
double dispersion, delta, distance;
|
||||
int wait_local_ok;
|
||||
|
||||
assert(initialised);
|
||||
|
||||
if (are_we_synchronised) {
|
||||
dispersion = get_root_dispersion(local_time);
|
||||
wait_local_ok = UTI_DiffTimespecsToDouble(local_time, &our_ref_time) >= local_wait_synced;
|
||||
} else {
|
||||
dispersion = 0.0;
|
||||
wait_local_ok = SCH_GetLastEventMonoTime() - unsynchronised_since >= local_wait_unsynced;
|
||||
}
|
||||
|
||||
distance = our_root_delay / 2 + dispersion;
|
||||
@@ -1156,7 +1168,8 @@ REF_GetReferenceParams
|
||||
or the root distance exceeds the threshold */
|
||||
|
||||
if (are_we_synchronised &&
|
||||
!(enable_local_stratum && local_activate_ok && distance > local_distance)) {
|
||||
!(enable_local_stratum && local_activate_ok && wait_local_ok &&
|
||||
distance > local_distance)) {
|
||||
|
||||
*is_synchronised = 1;
|
||||
|
||||
@@ -1168,7 +1181,7 @@ REF_GetReferenceParams
|
||||
*root_delay = our_root_delay;
|
||||
*root_dispersion = dispersion;
|
||||
|
||||
} else if (enable_local_stratum && local_activate_ok) {
|
||||
} else if (enable_local_stratum && local_activate_ok && wait_local_ok) {
|
||||
|
||||
*is_synchronised = 0;
|
||||
|
||||
@@ -1268,13 +1281,16 @@ REF_ModifyMakestep(int limit, double threshold)
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
REF_EnableLocal(int stratum, double distance, int orphan, double activate)
|
||||
REF_EnableLocal(int stratum, double distance, int orphan, double activate,
|
||||
double wait_synced, double wait_unsynced)
|
||||
{
|
||||
enable_local_stratum = 1;
|
||||
local_stratum = CLAMP(1, stratum, NTP_MAX_STRATUM - 1);
|
||||
local_distance = distance;
|
||||
local_orphan = !!orphan;
|
||||
local_activate = activate;
|
||||
local_wait_synced = wait_synced;
|
||||
local_wait_unsynced = wait_unsynced;
|
||||
LOG(LOGS_INFO, "%s local reference mode", "Enabled");
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,8 @@ extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
|
||||
/* Modify makestep settings */
|
||||
extern void REF_ModifyMakestep(int limit, double threshold);
|
||||
|
||||
extern void REF_EnableLocal(int stratum, double distance, int orphan, double activate);
|
||||
extern void REF_EnableLocal(int stratum, double distance, int orphan, double activate,
|
||||
double wait_synced, double wait_unsynced);
|
||||
extern void REF_DisableLocal(void);
|
||||
|
||||
/* Check if either of the current raw and cooked time, and optionally a
|
||||
|
||||
3
rtc.c
3
rtc.c
@@ -81,8 +81,9 @@ get_driftfile_time(void)
|
||||
{
|
||||
struct stat buf;
|
||||
char *drift_file;
|
||||
int interval;
|
||||
|
||||
drift_file = CNF_GetDriftFile();
|
||||
drift_file = CNF_GetDriftFile(&interval);
|
||||
if (!drift_file)
|
||||
return 0;
|
||||
|
||||
|
||||
308
rtc_linux.c
308
rtc_linux.c
@@ -296,14 +296,25 @@ slew_samples
|
||||
corresponding real time clock 'DMY HMS' form, taking account of
|
||||
whether the user runs his RTC on the local time zone or UTC */
|
||||
|
||||
static struct tm *
|
||||
rtc_from_t(const time_t *t)
|
||||
static void
|
||||
rtc_from_t(const time_t *t, struct rtc_time *rtc_raw, int utc)
|
||||
{
|
||||
if (rtc_on_utc) {
|
||||
return gmtime(t);
|
||||
struct tm *rtc_tm;
|
||||
if (utc) {
|
||||
rtc_tm = gmtime(t);
|
||||
} else {
|
||||
return localtime(t);
|
||||
rtc_tm = localtime(t);
|
||||
}
|
||||
|
||||
rtc_raw->tm_sec = rtc_tm->tm_sec;
|
||||
rtc_raw->tm_min = rtc_tm->tm_min;
|
||||
rtc_raw->tm_hour = rtc_tm->tm_hour;
|
||||
rtc_raw->tm_mday = rtc_tm->tm_mday;
|
||||
rtc_raw->tm_mon = rtc_tm->tm_mon;
|
||||
rtc_raw->tm_year = rtc_tm->tm_year;
|
||||
rtc_raw->tm_wday = rtc_tm->tm_wday;
|
||||
rtc_raw->tm_yday = rtc_tm->tm_yday;
|
||||
rtc_raw->tm_isdst = rtc_tm->tm_isdst;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -341,17 +352,27 @@ rtc_from_t(const time_t *t)
|
||||
*/
|
||||
|
||||
static time_t
|
||||
t_from_rtc(struct tm *stm) {
|
||||
struct tm temp1, temp2, *tm;
|
||||
t_from_rtc(struct rtc_time *rtc_raw, int utc)
|
||||
{
|
||||
struct tm rtc_tm, temp1, temp2, *tm;
|
||||
long diff;
|
||||
time_t t1, t2;
|
||||
|
||||
temp1 = *stm;
|
||||
/* Convert to seconds since 1970 */
|
||||
memset(&rtc_tm, 0, sizeof (rtc_tm));
|
||||
rtc_tm.tm_sec = rtc_raw->tm_sec;
|
||||
rtc_tm.tm_min = rtc_raw->tm_min;
|
||||
rtc_tm.tm_hour = rtc_raw->tm_hour;
|
||||
rtc_tm.tm_mday = rtc_raw->tm_mday;
|
||||
rtc_tm.tm_mon = rtc_raw->tm_mon;
|
||||
rtc_tm.tm_year = rtc_raw->tm_year;
|
||||
|
||||
temp1 = rtc_tm;
|
||||
temp1.tm_isdst = 0;
|
||||
|
||||
|
||||
t1 = mktime(&temp1);
|
||||
|
||||
tm = rtc_on_utc ? gmtime(&t1) : localtime(&t1);
|
||||
tm = utc ? gmtime(&t1) : localtime(&t1);
|
||||
if (!tm) {
|
||||
DEBUG_LOG("gmtime()/localtime() failed");
|
||||
return -1;
|
||||
@@ -476,8 +497,8 @@ write_coefs_to_file(int valid,time_t ref_time,double offset,double rate)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
switch_interrupts(int on_off)
|
||||
int
|
||||
RTC_Linux_SwitchInterrupt(int fd, int on_off)
|
||||
{
|
||||
if (ioctl(fd, on_off ? RTC_UIE_ON : RTC_UIE_OFF, 0) < 0) {
|
||||
LOG(LOGS_ERR, "Could not %s RTC interrupt : %s",
|
||||
@@ -508,7 +529,7 @@ RTC_Linux_Initialise(void)
|
||||
}
|
||||
|
||||
/* Make sure the RTC supports interrupts */
|
||||
if (!switch_interrupts(1) || !switch_interrupts(0)) {
|
||||
if (!RTC_Linux_SwitchInterrupt(fd, 1) || !RTC_Linux_SwitchInterrupt(fd, 0)) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -557,7 +578,7 @@ RTC_Linux_Finalise(void)
|
||||
/* Remove input file handler */
|
||||
if (fd >= 0) {
|
||||
SCH_RemoveFileHandler(fd);
|
||||
switch_interrupts(0);
|
||||
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||
close(fd);
|
||||
|
||||
/* Save the RTC data */
|
||||
@@ -578,7 +599,7 @@ static void
|
||||
measurement_timeout(void *any)
|
||||
{
|
||||
timeout_id = 0;
|
||||
switch_interrupts(1);
|
||||
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -586,21 +607,10 @@ measurement_timeout(void *any)
|
||||
static void
|
||||
set_rtc(time_t new_rtc_time)
|
||||
{
|
||||
struct tm rtc_tm;
|
||||
struct rtc_time rtc_raw;
|
||||
int status;
|
||||
|
||||
rtc_tm = *rtc_from_t(&new_rtc_time);
|
||||
|
||||
rtc_raw.tm_sec = rtc_tm.tm_sec;
|
||||
rtc_raw.tm_min = rtc_tm.tm_min;
|
||||
rtc_raw.tm_hour = rtc_tm.tm_hour;
|
||||
rtc_raw.tm_mday = rtc_tm.tm_mday;
|
||||
rtc_raw.tm_mon = rtc_tm.tm_mon;
|
||||
rtc_raw.tm_year = rtc_tm.tm_year;
|
||||
rtc_raw.tm_wday = rtc_tm.tm_wday;
|
||||
rtc_raw.tm_yday = rtc_tm.tm_yday;
|
||||
rtc_raw.tm_isdst = rtc_tm.tm_isdst;
|
||||
rtc_from_t(&new_rtc_time, &rtc_raw, rtc_on_utc);
|
||||
|
||||
status = ioctl(fd, RTC_SET_TIME, &rtc_raw);
|
||||
if (status < 0) {
|
||||
@@ -750,16 +760,11 @@ process_reading(time_t rtc_time, struct timespec *system_time)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
read_from_device(int fd_, int event, void *any)
|
||||
int
|
||||
RTC_Linux_CheckInterrupt(int fd)
|
||||
{
|
||||
int status;
|
||||
unsigned long data;
|
||||
struct timespec sys_time;
|
||||
struct rtc_time rtc_raw;
|
||||
struct tm rtc_tm;
|
||||
time_t rtc_t;
|
||||
int error = 0;
|
||||
|
||||
status = read(fd, &data, sizeof(data));
|
||||
|
||||
@@ -767,64 +772,79 @@ read_from_device(int fd_, int event, void *any)
|
||||
/* This looks like a bad error : the file descriptor was indicating it was
|
||||
* ready to read but we couldn't read anything. Give up. */
|
||||
LOG(LOGS_ERR, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
||||
SCH_RemoveFileHandler(fd);
|
||||
switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
|
||||
close(fd);
|
||||
fd = -1;
|
||||
return;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (skip_interrupts > 0) {
|
||||
/* Wait for the next interrupt, this one may be bogus */
|
||||
skip_interrupts--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update interrupt detected? */
|
||||
return (data & RTC_UF) == RTC_UF;
|
||||
}
|
||||
|
||||
time_t
|
||||
RTC_Linux_ReadTimeAfterInterrupt(int fd, int utc,
|
||||
struct timespec *sys_time_cooked,
|
||||
struct timespec *sys_time_raw)
|
||||
{
|
||||
int status;
|
||||
struct rtc_time rtc_raw;
|
||||
|
||||
/* Read RTC time, sandwiched between two polls of the system clock
|
||||
so we can bound any error */
|
||||
|
||||
SCH_GetLastEventTime(sys_time_cooked, NULL, sys_time_raw);
|
||||
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
||||
if (status < 0) {
|
||||
LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert RTC time into a struct timespec */
|
||||
return t_from_rtc(&rtc_raw, utc);
|
||||
}
|
||||
|
||||
static void
|
||||
read_from_device(int fd_, int event, void *any)
|
||||
{
|
||||
struct timespec sys_time;
|
||||
int status, error = 0;
|
||||
time_t rtc_t;
|
||||
|
||||
status = RTC_Linux_CheckInterrupt(fd);
|
||||
if (status < 0) {
|
||||
SCH_RemoveFileHandler(fd);
|
||||
RTC_Linux_SwitchInterrupt(fd, 0); /* Likely to raise error too, but just to be sure... */
|
||||
close(fd);
|
||||
fd = -1;
|
||||
return;
|
||||
} else if (status == 0) {
|
||||
/* Wait for the next interrupt, this one may be bogus */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data & RTC_UF) == RTC_UF) {
|
||||
/* Update interrupt detected */
|
||||
|
||||
/* Read RTC time, sandwiched between two polls of the system clock
|
||||
so we can bound any error. */
|
||||
rtc_t = RTC_Linux_ReadTimeAfterInterrupt(fd, rtc_on_utc, &sys_time, NULL);
|
||||
if (rtc_t == (time_t)-1) {
|
||||
error = 1;
|
||||
goto turn_off_interrupt;
|
||||
}
|
||||
|
||||
SCH_GetLastEventTime(&sys_time, NULL, NULL);
|
||||
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
||||
if (status < 0) {
|
||||
LOG(LOGS_ERR, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno));
|
||||
error = 1;
|
||||
goto turn_off_interrupt;
|
||||
}
|
||||
|
||||
/* Convert RTC time into a struct timespec */
|
||||
rtc_tm.tm_sec = rtc_raw.tm_sec;
|
||||
rtc_tm.tm_min = rtc_raw.tm_min;
|
||||
rtc_tm.tm_hour = rtc_raw.tm_hour;
|
||||
rtc_tm.tm_mday = rtc_raw.tm_mday;
|
||||
rtc_tm.tm_mon = rtc_raw.tm_mon;
|
||||
rtc_tm.tm_year = rtc_raw.tm_year;
|
||||
rtc_tm.tm_wday = 0;
|
||||
|
||||
rtc_t = t_from_rtc(&rtc_tm);
|
||||
|
||||
if (rtc_t == (time_t)(-1)) {
|
||||
error = 1;
|
||||
goto turn_off_interrupt;
|
||||
}
|
||||
|
||||
process_reading(rtc_t, &sys_time);
|
||||
|
||||
if (n_samples < 4) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD;
|
||||
} else if (n_samples < 6) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 1;
|
||||
} else if (n_samples < 10) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 2;
|
||||
} else if (n_samples < 14) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 3;
|
||||
} else {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 4;
|
||||
}
|
||||
process_reading(rtc_t, &sys_time);
|
||||
|
||||
if (n_samples < 4) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD;
|
||||
} else if (n_samples < 6) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 1;
|
||||
} else if (n_samples < 10) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 2;
|
||||
} else if (n_samples < 14) {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 3;
|
||||
} else {
|
||||
measurement_period = LOWEST_MEASUREMENT_PERIOD << 4;
|
||||
}
|
||||
|
||||
turn_off_interrupt:
|
||||
@@ -836,7 +856,7 @@ turn_off_interrupt:
|
||||
operating_mode = OM_NORMAL;
|
||||
(after_init_hook)(after_init_hook_arg);
|
||||
|
||||
switch_interrupts(0);
|
||||
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||
|
||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||
}
|
||||
@@ -848,7 +868,7 @@ turn_off_interrupt:
|
||||
DEBUG_LOG("Could not complete after trim relock due to errors");
|
||||
operating_mode = OM_NORMAL;
|
||||
|
||||
switch_interrupts(0);
|
||||
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||
|
||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||
}
|
||||
@@ -856,7 +876,7 @@ turn_off_interrupt:
|
||||
break;
|
||||
|
||||
case OM_NORMAL:
|
||||
switch_interrupts(0);
|
||||
RTC_Linux_SwitchInterrupt(fd, 0);
|
||||
|
||||
timeout_id = SCH_AddTimeoutByDelay((double) measurement_period, measurement_timeout, NULL);
|
||||
|
||||
@@ -878,7 +898,7 @@ RTC_Linux_TimeInit(void (*after_hook)(void *), void *anything)
|
||||
|
||||
operating_mode = OM_INITIAL;
|
||||
timeout_id = 0;
|
||||
switch_interrupts(1);
|
||||
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -911,6 +931,33 @@ RTC_Linux_WriteParameters(void)
|
||||
return(retval);
|
||||
}
|
||||
|
||||
time_t
|
||||
RTC_Linux_ReadTimeNow(int fd, int utc,
|
||||
struct timespec *old_sys_cooked,
|
||||
struct timespec *old_sys_raw)
|
||||
{
|
||||
struct rtc_time rtc_raw, rtc_raw_retry;
|
||||
int status;
|
||||
|
||||
/* Retry reading the RTC until both read attempts give the same sec value.
|
||||
This way the race condition is prevented that the RTC has updated itself
|
||||
during the first read operation. */
|
||||
do {
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
||||
if (status >= 0) {
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
|
||||
}
|
||||
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
|
||||
|
||||
/* Read system clock */
|
||||
if (old_sys_raw)
|
||||
LCL_ReadRawTime(old_sys_raw);
|
||||
if (old_sys_cooked)
|
||||
LCL_ReadCookedTime(old_sys_cooked, NULL);
|
||||
|
||||
return status >= 0 ? t_from_rtc(&rtc_raw, utc) : -1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
/* Try to set the system clock from the RTC, in the same manner as
|
||||
/sbin/hwclock -s would do. We're not as picky about OS version
|
||||
@@ -920,12 +967,10 @@ RTC_Linux_WriteParameters(void)
|
||||
int
|
||||
RTC_Linux_TimePreInit(time_t driftfile_time)
|
||||
{
|
||||
int fd, status;
|
||||
struct rtc_time rtc_raw, rtc_raw_retry;
|
||||
struct tm rtc_tm;
|
||||
time_t rtc_t;
|
||||
double accumulated_error, sys_offset;
|
||||
struct timespec new_sys_time, old_sys_time;
|
||||
int fd;
|
||||
|
||||
coefs_file_name = CNF_GetRtcFile();
|
||||
|
||||
@@ -938,66 +983,41 @@ RTC_Linux_TimePreInit(time_t driftfile_time)
|
||||
return 0; /* Can't open it, and won't be able to later */
|
||||
}
|
||||
|
||||
/* Retry reading the rtc until both read attempts give the same sec value.
|
||||
This way the race condition is prevented that the RTC has updated itself
|
||||
during the first read operation. */
|
||||
do {
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw);
|
||||
if (status >= 0) {
|
||||
status = ioctl(fd, RTC_RD_TIME, &rtc_raw_retry);
|
||||
}
|
||||
} while (status >= 0 && rtc_raw.tm_sec != rtc_raw_retry.tm_sec);
|
||||
|
||||
/* Read system clock */
|
||||
LCL_ReadCookedTime(&old_sys_time, NULL);
|
||||
rtc_t = RTC_Linux_ReadTimeNow(fd, rtc_on_utc, &old_sys_time, NULL);
|
||||
|
||||
close(fd);
|
||||
|
||||
if (status >= 0) {
|
||||
/* Convert to seconds since 1970 */
|
||||
rtc_tm.tm_sec = rtc_raw.tm_sec;
|
||||
rtc_tm.tm_min = rtc_raw.tm_min;
|
||||
rtc_tm.tm_hour = rtc_raw.tm_hour;
|
||||
rtc_tm.tm_mday = rtc_raw.tm_mday;
|
||||
rtc_tm.tm_mon = rtc_raw.tm_mon;
|
||||
rtc_tm.tm_year = rtc_raw.tm_year;
|
||||
|
||||
rtc_t = t_from_rtc(&rtc_tm);
|
||||
if (rtc_t != (time_t)(-1)) {
|
||||
|
||||
if (rtc_t != (time_t)(-1)) {
|
||||
|
||||
/* Work out approximatation to correct time (to about the
|
||||
nearest second) */
|
||||
if (valid_coefs_from_file) {
|
||||
accumulated_error = file_ref_offset +
|
||||
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
|
||||
} else {
|
||||
accumulated_error = 0.0;
|
||||
}
|
||||
|
||||
/* Correct time */
|
||||
|
||||
new_sys_time.tv_sec = rtc_t;
|
||||
/* Average error in the RTC reading */
|
||||
new_sys_time.tv_nsec = 500000000;
|
||||
|
||||
UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
|
||||
|
||||
if (new_sys_time.tv_sec < driftfile_time) {
|
||||
LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sys_offset = UTI_DiffTimespecsToDouble(&old_sys_time, &new_sys_time);
|
||||
|
||||
/* Set system time only if the step is larger than 1 second */
|
||||
if (fabs(sys_offset) >= 1.0) {
|
||||
if (LCL_ApplyStepOffset(sys_offset))
|
||||
LOG(LOGS_INFO, "System time set from RTC");
|
||||
}
|
||||
/* Work out approximation to correct time (to about the
|
||||
nearest second) */
|
||||
if (valid_coefs_from_file) {
|
||||
accumulated_error = file_ref_offset +
|
||||
(rtc_t - file_ref_time) * 1.0e-6 * file_rate_ppm;
|
||||
} else {
|
||||
accumulated_error = 0.0;
|
||||
}
|
||||
|
||||
/* Correct time */
|
||||
|
||||
new_sys_time.tv_sec = rtc_t;
|
||||
/* Average error in the RTC reading */
|
||||
new_sys_time.tv_nsec = 500000000;
|
||||
|
||||
UTI_AddDoubleToTimespec(&new_sys_time, -accumulated_error, &new_sys_time);
|
||||
|
||||
if (new_sys_time.tv_sec < driftfile_time) {
|
||||
LOG(LOGS_WARN, "RTC time before last driftfile modification (ignored)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
sys_offset = UTI_DiffTimespecsToDouble(&old_sys_time, &new_sys_time);
|
||||
|
||||
/* Set system time only if the step is larger than 1 second */
|
||||
if (fabs(sys_offset) >= 1.0) {
|
||||
if (LCL_ApplyStepOffset(sys_offset))
|
||||
LOG(LOGS_INFO, "System time set from RTC");
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -1065,7 +1085,7 @@ RTC_Linux_Trim(void)
|
||||
/* And start rapid sampling, interrupts on now */
|
||||
SCH_RemoveTimeout(timeout_id);
|
||||
timeout_id = 0;
|
||||
switch_interrupts(1);
|
||||
RTC_Linux_SwitchInterrupt(fd, 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -42,4 +42,13 @@ extern int RTC_Linux_Trim(void);
|
||||
|
||||
extern void RTC_Linux_CycleLogFile(void);
|
||||
|
||||
extern int RTC_Linux_SwitchInterrupt(int fd, int on_off);
|
||||
extern int RTC_Linux_CheckInterrupt(int fd);
|
||||
extern time_t RTC_Linux_ReadTimeAfterInterrupt(int fd, int utc,
|
||||
struct timespec *sys_time_cooked,
|
||||
struct timespec *sys_time_raw);
|
||||
extern time_t RTC_Linux_ReadTimeNow(int fd, int utc,
|
||||
struct timespec *sys_time_cooked,
|
||||
struct timespec *sys_time_raw);
|
||||
|
||||
#endif /* _GOT_RTC_LINUX_H */
|
||||
|
||||
1
siv.h
1
siv.h
@@ -36,6 +36,7 @@
|
||||
|
||||
/* Identifiers of SIV algorithms following the IANA AEAD registry */
|
||||
typedef enum {
|
||||
AEAD_SIV_INVALID = 0,
|
||||
AEAD_AES_SIV_CMAC_256 = 15,
|
||||
AEAD_AES_SIV_CMAC_384 = 16,
|
||||
AEAD_AES_SIV_CMAC_512 = 17,
|
||||
|
||||
@@ -28,18 +28,14 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#ifdef HAVE_NETTLE_SIV_CMAC
|
||||
#include <nettle/siv-cmac.h>
|
||||
#else
|
||||
#include "siv_nettle_int.c"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETTLE_SIV_GCM
|
||||
#include <nettle/siv-gcm.h>
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "siv.h"
|
||||
#include "util.h"
|
||||
|
||||
struct SIV_Instance_Record {
|
||||
SIV_Algorithm algorithm;
|
||||
@@ -163,8 +159,7 @@ SIV_GetMaxNonceLength(SIV_Instance instance)
|
||||
int
|
||||
SIV_GetTagLength(SIV_Instance instance)
|
||||
{
|
||||
if (instance->tag_length < 1 || instance->tag_length > SIV_MAX_TAG_LENGTH)
|
||||
assert(0);
|
||||
BRIEF_ASSERT(instance->tag_length >= 1 && instance->tag_length <= SIV_MAX_TAG_LENGTH);
|
||||
return instance->tag_length;
|
||||
}
|
||||
|
||||
|
||||
452
siv_nettle_int.c
452
siv_nettle_int.c
@@ -1,452 +0,0 @@
|
||||
/* This is a single-file implementation of AES-SIV-CMAC-256 based on
|
||||
a patch for GNU Nettle by Nikos Mavrogiannopoulos */
|
||||
|
||||
/*
|
||||
AES-CMAC-128 (rfc 4493)
|
||||
Copyright (C) Stefan Metzmacher 2012
|
||||
Copyright (C) Jeremy Allison 2012
|
||||
Copyright (C) Michael Adam 2012
|
||||
Copyright (C) 2017, Red Hat Inc.
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle 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 copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* siv-aes128.c, siv-cmac.c, siv.h
|
||||
|
||||
AES-SIV, RFC5297
|
||||
SIV-CMAC, RFC5297
|
||||
|
||||
Copyright (C) 2017 Nikos Mavrogiannopoulos
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle 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 copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* cmac.h, siv-cmac.h, cmac-aes128.c
|
||||
|
||||
CMAC mode, as specified in RFC4493
|
||||
SIV-CMAC mode, as specified in RFC5297
|
||||
CMAC using AES128 as the underlying cipher.
|
||||
|
||||
Copyright (C) 2017 Red Hat, Inc.
|
||||
|
||||
Contributed by Nikos Mavrogiannopoulos
|
||||
|
||||
This file is part of GNU Nettle.
|
||||
|
||||
GNU Nettle is free software: you can redistribute it and/or
|
||||
modify it under the terms of either:
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
GNU Nettle 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 copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nettle/aes.h"
|
||||
#include "nettle/ctr.h"
|
||||
#include "nettle/macros.h"
|
||||
#include "nettle/memxor.h"
|
||||
#include "nettle/memops.h"
|
||||
|
||||
#include "nettle/nettle-types.h"
|
||||
|
||||
/* For SIV, the block size of the block cipher shall be 128 bits. */
|
||||
#define SIV_BLOCK_SIZE 16
|
||||
#define SIV_DIGEST_SIZE 16
|
||||
#define SIV_MIN_NONCE_SIZE 1
|
||||
|
||||
/*
|
||||
* SIV mode requires the aad and plaintext when building the IV, which
|
||||
* prevents streaming processing and it incompatible with the AEAD API.
|
||||
*/
|
||||
|
||||
/* AES_SIV_CMAC_256 */
|
||||
struct siv_cmac_aes128_ctx {
|
||||
struct aes128_ctx cipher;
|
||||
uint8_t s2vk[AES128_KEY_SIZE];
|
||||
};
|
||||
|
||||
struct cmac128_ctx
|
||||
{
|
||||
/* Key */
|
||||
union nettle_block16 K1;
|
||||
union nettle_block16 K2;
|
||||
|
||||
/* MAC state */
|
||||
union nettle_block16 X;
|
||||
|
||||
/* Block buffer */
|
||||
union nettle_block16 block;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
/* shift one and XOR with 0x87. */
|
||||
static void
|
||||
_cmac128_block_mulx(union nettle_block16 *dst,
|
||||
const union nettle_block16 *src)
|
||||
{
|
||||
uint64_t b1 = READ_UINT64(src->b);
|
||||
uint64_t b2 = READ_UINT64(src->b+8);
|
||||
|
||||
b1 = (b1 << 1) | (b2 >> 63);
|
||||
b2 <<= 1;
|
||||
|
||||
if (src->b[0] & 0x80)
|
||||
b2 ^= 0x87;
|
||||
|
||||
WRITE_UINT64(dst->b, b1);
|
||||
WRITE_UINT64(dst->b+8, b2);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac128_set_key(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt)
|
||||
{
|
||||
static const uint8_t const_zero[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
union nettle_block16 *L = &ctx->block;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
/* step 1 - generate subkeys k1 and k2 */
|
||||
encrypt(cipher, 16, L->b, const_zero);
|
||||
|
||||
_cmac128_block_mulx(&ctx->K1, L);
|
||||
_cmac128_block_mulx(&ctx->K2, &ctx->K1);
|
||||
}
|
||||
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
static void
|
||||
cmac128_update(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt,
|
||||
size_t msg_len, const uint8_t *msg)
|
||||
{
|
||||
union nettle_block16 Y;
|
||||
/*
|
||||
* check if we expand the block
|
||||
*/
|
||||
if (ctx->index < 16)
|
||||
{
|
||||
size_t len = MIN(16 - ctx->index, msg_len);
|
||||
memcpy(&ctx->block.b[ctx->index], msg, len);
|
||||
msg += len;
|
||||
msg_len -= len;
|
||||
ctx->index += len;
|
||||
}
|
||||
|
||||
if (msg_len == 0) {
|
||||
/* if it is still the last block, we are done */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* now checksum everything but the last block
|
||||
*/
|
||||
memxor3(Y.b, ctx->X.b, ctx->block.b, 16);
|
||||
encrypt(cipher, 16, ctx->X.b, Y.b);
|
||||
|
||||
while (msg_len > 16)
|
||||
{
|
||||
memxor3(Y.b, ctx->X.b, msg, 16);
|
||||
encrypt(cipher, 16, ctx->X.b, Y.b);
|
||||
msg += 16;
|
||||
msg_len -= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy the last block, it will be processed in
|
||||
* cmac128_digest().
|
||||
*/
|
||||
memcpy(ctx->block.b, msg, msg_len);
|
||||
ctx->index = msg_len;
|
||||
}
|
||||
|
||||
static void
|
||||
cmac128_digest(struct cmac128_ctx *ctx, const void *cipher,
|
||||
nettle_cipher_func *encrypt,
|
||||
unsigned length,
|
||||
uint8_t *dst)
|
||||
{
|
||||
union nettle_block16 Y;
|
||||
|
||||
memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index);
|
||||
|
||||
/* re-use ctx->block for memxor output */
|
||||
if (ctx->index < 16)
|
||||
{
|
||||
ctx->block.b[ctx->index] = 0x80;
|
||||
memxor(ctx->block.b, ctx->K2.b, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
memxor(ctx->block.b, ctx->K1.b, 16);
|
||||
}
|
||||
|
||||
memxor3(Y.b, ctx->block.b, ctx->X.b, 16);
|
||||
|
||||
assert(length <= 16);
|
||||
if (length == 16)
|
||||
{
|
||||
encrypt(cipher, 16, dst, Y.b);
|
||||
}
|
||||
else
|
||||
{
|
||||
encrypt(cipher, 16, ctx->block.b, Y.b);
|
||||
memcpy(dst, ctx->block.b, length);
|
||||
}
|
||||
|
||||
/* reset state for re-use */
|
||||
memset(&ctx->X, 0, sizeof(ctx->X));
|
||||
ctx->index = 0;
|
||||
}
|
||||
|
||||
|
||||
#define CMAC128_CTX(type) \
|
||||
{ struct cmac128_ctx ctx; type cipher; }
|
||||
|
||||
/* NOTE: Avoid using NULL, as we don't include anything defining it. */
|
||||
#define CMAC128_SET_KEY(self, set_key, encrypt, cmac_key) \
|
||||
do { \
|
||||
(set_key)(&(self)->cipher, (cmac_key)); \
|
||||
if (0) (encrypt)(&(self)->cipher, ~(size_t) 0, \
|
||||
(uint8_t *) 0, (const uint8_t *) 0); \
|
||||
cmac128_set_key(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *) (encrypt)); \
|
||||
} while (0)
|
||||
|
||||
#define CMAC128_UPDATE(self, encrypt, length, src) \
|
||||
cmac128_update(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *)encrypt, (length), (src))
|
||||
|
||||
#define CMAC128_DIGEST(self, encrypt, length, digest) \
|
||||
(0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \
|
||||
(uint8_t *) 0, (const uint8_t *) 0) \
|
||||
: cmac128_digest(&(self)->ctx, &(self)->cipher, \
|
||||
(nettle_cipher_func *) (encrypt), \
|
||||
(length), (digest)))
|
||||
|
||||
struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
|
||||
|
||||
static void
|
||||
cmac_aes128_set_key(struct cmac_aes128_ctx *ctx, const uint8_t *key)
|
||||
{
|
||||
CMAC128_SET_KEY(ctx, aes128_set_encrypt_key, aes128_encrypt, key);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac_aes128_update (struct cmac_aes128_ctx *ctx,
|
||||
size_t length, const uint8_t *data)
|
||||
{
|
||||
CMAC128_UPDATE (ctx, aes128_encrypt, length, data);
|
||||
}
|
||||
|
||||
static void
|
||||
cmac_aes128_digest(struct cmac_aes128_ctx *ctx,
|
||||
size_t length, uint8_t *digest)
|
||||
{
|
||||
CMAC128_DIGEST(ctx, aes128_encrypt, length, digest);
|
||||
}
|
||||
|
||||
static const uint8_t const_one[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
static const uint8_t const_zero[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static
|
||||
void _siv_s2v(nettle_set_key_func *cmac_set_key,
|
||||
nettle_hash_update_func *cmac_update,
|
||||
nettle_hash_digest_func *cmac_digest,
|
||||
size_t cmac_ctx_size,
|
||||
const uint8_t *s2vk, size_t alength, const uint8_t *adata,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t plength, const uint8_t *pdata,
|
||||
uint8_t *v)
|
||||
{
|
||||
uint8_t ctx[sizeof(struct cmac128_ctx)+sizeof(struct aes_ctx)];
|
||||
union nettle_block16 D, S, T;
|
||||
|
||||
assert(cmac_ctx_size <= sizeof (ctx));
|
||||
|
||||
cmac_set_key(ctx, s2vk);
|
||||
|
||||
if (nlength == 0 && alength == 0) {
|
||||
cmac_update(ctx, 16, const_one);
|
||||
cmac_digest(ctx, 16, v);
|
||||
return;
|
||||
}
|
||||
|
||||
cmac_update(ctx, 16, const_zero);
|
||||
cmac_digest(ctx, 16, D.b);
|
||||
|
||||
if (1) {
|
||||
_cmac128_block_mulx(&D, &D);
|
||||
cmac_update(ctx, alength, adata);
|
||||
cmac_digest(ctx, 16, S.b);
|
||||
|
||||
memxor(D.b, S.b, 16);
|
||||
}
|
||||
|
||||
if (nlength > 0) {
|
||||
_cmac128_block_mulx(&D, &D);
|
||||
cmac_update(ctx, nlength, nonce);
|
||||
cmac_digest(ctx, 16, S.b);
|
||||
|
||||
memxor(D.b, S.b, 16);
|
||||
}
|
||||
|
||||
/* Sn */
|
||||
if (plength >= 16) {
|
||||
cmac_update(ctx, plength-16, pdata);
|
||||
|
||||
pdata += plength-16;
|
||||
|
||||
memxor3(T.b, pdata, D.b, 16);
|
||||
} else {
|
||||
union nettle_block16 pad;
|
||||
|
||||
_cmac128_block_mulx(&T, &D);
|
||||
memcpy(pad.b, pdata, plength);
|
||||
pad.b[plength] = 0x80;
|
||||
if (plength+1 < 16)
|
||||
memset(&pad.b[plength+1], 0, 16-plength-1);
|
||||
|
||||
memxor(T.b, pad.b, 16);
|
||||
}
|
||||
|
||||
cmac_update(ctx, 16, T.b);
|
||||
cmac_digest(ctx, 16, v);
|
||||
}
|
||||
|
||||
static void
|
||||
siv_cmac_aes128_set_key(struct siv_cmac_aes128_ctx *ctx, const uint8_t *key)
|
||||
{
|
||||
memcpy(ctx->s2vk, key, 16);
|
||||
aes128_set_encrypt_key(&ctx->cipher, key+16);
|
||||
}
|
||||
|
||||
static void
|
||||
siv_cmac_aes128_encrypt_message(struct siv_cmac_aes128_ctx *ctx,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t alength, const uint8_t *adata,
|
||||
size_t clength, uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
union nettle_block16 siv;
|
||||
size_t slength;
|
||||
|
||||
assert (clength >= SIV_DIGEST_SIZE);
|
||||
slength = clength - SIV_DIGEST_SIZE;
|
||||
|
||||
/* create CTR nonce */
|
||||
_siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
|
||||
(nettle_hash_update_func*)cmac_aes128_update,
|
||||
(nettle_hash_digest_func*)cmac_aes128_digest,
|
||||
sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
|
||||
nlength, nonce, slength, src, siv.b);
|
||||
memcpy(dst, siv.b, SIV_DIGEST_SIZE);
|
||||
siv.b[8] &= ~0x80;
|
||||
siv.b[12] &= ~0x80;
|
||||
|
||||
ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
|
||||
siv.b, slength, dst+SIV_DIGEST_SIZE, src);
|
||||
}
|
||||
|
||||
static int
|
||||
siv_cmac_aes128_decrypt_message(struct siv_cmac_aes128_ctx *ctx,
|
||||
size_t nlength, const uint8_t *nonce,
|
||||
size_t alength, const uint8_t *adata,
|
||||
size_t mlength, uint8_t *dst, const uint8_t *src)
|
||||
{
|
||||
union nettle_block16 siv;
|
||||
union nettle_block16 ctr;
|
||||
|
||||
memcpy(ctr.b, src, SIV_DIGEST_SIZE);
|
||||
ctr.b[8] &= ~0x80;
|
||||
ctr.b[12] &= ~0x80;
|
||||
|
||||
ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE,
|
||||
ctr.b, mlength, dst, src+SIV_DIGEST_SIZE);
|
||||
|
||||
/* create CTR nonce */
|
||||
_siv_s2v((nettle_set_key_func*)cmac_aes128_set_key,
|
||||
(nettle_hash_update_func*)cmac_aes128_update,
|
||||
(nettle_hash_digest_func*)cmac_aes128_digest,
|
||||
sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata,
|
||||
nlength, nonce, mlength, dst, siv.b);
|
||||
|
||||
return memeql_sec(siv.b, src, SIV_DIGEST_SIZE);
|
||||
}
|
||||
|
||||
89
socket.c
89
socket.c
@@ -213,12 +213,25 @@ get_reusable_socket(int type, IPSockAddr *spec)
|
||||
/* ================================================== */
|
||||
|
||||
#if defined(SOCK_CLOEXEC) || defined(SOCK_NONBLOCK)
|
||||
|
||||
static int
|
||||
get_default_inet_domain(void)
|
||||
{
|
||||
#ifdef FEAT_IPV6
|
||||
if (!ip4_enabled && ip6_enabled)
|
||||
return AF_INET6;
|
||||
#endif
|
||||
return AF_INET;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
check_socket_flag(int sock_flag, int fd_flag, int fs_flag)
|
||||
{
|
||||
int sock_fd, fd_flags, fs_flags;
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM | sock_flag, 0);
|
||||
sock_fd = socket(get_default_inet_domain(), SOCK_DGRAM | sock_flag, 0);
|
||||
if (sock_fd < 0)
|
||||
return 0;
|
||||
|
||||
@@ -526,7 +539,7 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *ifac
|
||||
else if (remote_addr)
|
||||
family = remote_addr->ip_addr.family;
|
||||
else
|
||||
family = IPADDR_INET4;
|
||||
family = !ip4_enabled && ip6_enabled ? IPADDR_INET6 : IPADDR_INET4;
|
||||
|
||||
switch (family) {
|
||||
case IPADDR_INET4:
|
||||
@@ -590,25 +603,40 @@ error:
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static socklen_t
|
||||
set_unix_sockaddr(struct sockaddr_un *sun, const char *addr)
|
||||
{
|
||||
size_t len = strlen(addr);
|
||||
|
||||
if (len + 1 > sizeof (sun->sun_path)) {
|
||||
DEBUG_LOG("Unix socket path %s too long", addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(sun, 0, sizeof (*sun));
|
||||
sun->sun_family = AF_UNIX;
|
||||
memcpy(sun->sun_path, addr, len);
|
||||
|
||||
return offsetof(struct sockaddr_un, sun_path) + len + 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
bind_unix_address(int sock_fd, const char *addr, int flags)
|
||||
{
|
||||
union sockaddr_all saddr;
|
||||
socklen_t saddr_len;
|
||||
|
||||
memset(&saddr, 0, sizeof (saddr));
|
||||
|
||||
if (snprintf(saddr.un.sun_path, sizeof (saddr.un.sun_path), "%s", addr) >=
|
||||
sizeof (saddr.un.sun_path)) {
|
||||
DEBUG_LOG("Unix socket path %s too long", addr);
|
||||
saddr_len = set_unix_sockaddr(&saddr.un, addr);
|
||||
if (saddr_len == 0)
|
||||
return 0;
|
||||
}
|
||||
saddr.un.sun_family = AF_UNIX;
|
||||
|
||||
if (unlink(addr) < 0)
|
||||
DEBUG_LOG("Could not remove %s : %s", addr, strerror(errno));
|
||||
|
||||
/* PRV_BindSocket() doesn't support Unix sockets yet */
|
||||
if (bind(sock_fd, &saddr.sa, sizeof (saddr.un)) < 0) {
|
||||
if (bind(sock_fd, &saddr.sa, saddr_len) < 0) {
|
||||
DEBUG_LOG("Could not bind Unix socket to %s : %s", addr, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
@@ -628,17 +656,13 @@ static int
|
||||
connect_unix_address(int sock_fd, const char *addr)
|
||||
{
|
||||
union sockaddr_all saddr;
|
||||
socklen_t saddr_len;
|
||||
|
||||
memset(&saddr, 0, sizeof (saddr));
|
||||
|
||||
if (snprintf(saddr.un.sun_path, sizeof (saddr.un.sun_path), "%s", addr) >=
|
||||
sizeof (saddr.un.sun_path)) {
|
||||
DEBUG_LOG("Unix socket path %s too long", addr);
|
||||
saddr_len = set_unix_sockaddr(&saddr.un, addr);
|
||||
if (saddr_len == 0)
|
||||
return 0;
|
||||
}
|
||||
saddr.un.sun_family = AF_UNIX;
|
||||
|
||||
if (connect(sock_fd, &saddr.sa, sizeof (saddr.un)) < 0) {
|
||||
if (connect(sock_fd, &saddr.sa, saddr_len) < 0) {
|
||||
DEBUG_LOG("Could not connect Unix socket to %s : %s", addr, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
@@ -853,8 +877,10 @@ static int
|
||||
process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
|
||||
SCK_Message *message)
|
||||
{
|
||||
int r = 1, path_len, max_path_len;
|
||||
struct cmsghdr *cmsg;
|
||||
int r = 1;
|
||||
|
||||
init_message_addresses(message, SCK_ADDR_UNSPEC);
|
||||
|
||||
if (msg->msg_namelen <= sizeof (union sockaddr_all) &&
|
||||
msg->msg_namelen > sizeof (((struct sockaddr *)msg->msg_name)->sa_family)) {
|
||||
@@ -867,18 +893,23 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
|
||||
SCK_SockaddrToIPSockAddr(msg->msg_name, msg->msg_namelen, &message->remote_addr.ip);
|
||||
break;
|
||||
case AF_UNIX:
|
||||
/* Make sure the path is terminated by '\0' */
|
||||
max_path_len = sizeof (((struct sockaddr_un *)msg->msg_name)->sun_path);
|
||||
path_len = strnlen(((struct sockaddr_un *)msg->msg_name)->sun_path, max_path_len);
|
||||
if (path_len >= max_path_len) {
|
||||
DEBUG_LOG("Unterminated path");
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
init_message_addresses(message, SCK_ADDR_UNIX);
|
||||
message->remote_addr.path = ((struct sockaddr_un *)msg->msg_name)->sun_path;
|
||||
break;
|
||||
default:
|
||||
init_message_addresses(message, SCK_ADDR_UNSPEC);
|
||||
DEBUG_LOG("Unexpected address");
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
init_message_addresses(message, SCK_ADDR_UNSPEC);
|
||||
|
||||
if (msg->msg_namelen > sizeof (union sockaddr_all)) {
|
||||
DEBUG_LOG("Truncated source address");
|
||||
r = 0;
|
||||
@@ -1050,9 +1081,8 @@ receive_messages(int sock_fd, int flags, int max_messages, int *num_messages)
|
||||
n = ARR_GetSize(recv_headers);
|
||||
n = MIN(n, max_messages);
|
||||
|
||||
if (n < 1 || n > MAX_RECV_MESSAGES ||
|
||||
n > ARR_GetSize(recv_messages) || n > ARR_GetSize(recv_sck_messages))
|
||||
assert(0);
|
||||
BRIEF_ASSERT(n >= 1 && n <= MAX_RECV_MESSAGES &&
|
||||
n <= ARR_GetSize(recv_messages) && n <= ARR_GetSize(recv_sck_messages));
|
||||
|
||||
recv_flags = get_recv_flags(flags);
|
||||
|
||||
@@ -1142,14 +1172,9 @@ send_message(int sock_fd, SCK_Message *message, int flags)
|
||||
(struct sockaddr *)&saddr, sizeof (saddr));
|
||||
break;
|
||||
case SCK_ADDR_UNIX:
|
||||
memset(&saddr, 0, sizeof (saddr));
|
||||
if (snprintf(saddr.un.sun_path, sizeof (saddr.un.sun_path), "%s",
|
||||
message->remote_addr.path) >= sizeof (saddr.un.sun_path)) {
|
||||
DEBUG_LOG("Unix socket path %s too long", message->remote_addr.path);
|
||||
saddr_len = set_unix_sockaddr(&saddr.un, message->remote_addr.path);
|
||||
if (saddr_len == 0)
|
||||
return 0;
|
||||
}
|
||||
saddr.un.sun_family = AF_UNIX;
|
||||
saddr_len = sizeof (saddr.un);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
||||
153
sources.c
153
sources.c
@@ -66,7 +66,7 @@ struct SelectInfo {
|
||||
/* This enum contains the flag values that are used to label
|
||||
each source */
|
||||
typedef enum {
|
||||
SRC_OK, /* OK so far, not a final status! */
|
||||
SRC_OK = 0, /* OK so far, not a final status! */
|
||||
SRC_UNSELECTABLE, /* Has noselect option set */
|
||||
SRC_BAD_STATS, /* Doesn't have valid stats data */
|
||||
SRC_UNSYNCHRONISED, /* Provides samples, but not synchronised */
|
||||
@@ -144,9 +144,9 @@ struct SRC_Instance_Record {
|
||||
/* Flag indicating the source has a leap second vote */
|
||||
int leap_vote;
|
||||
|
||||
/* Flag indicating the source was already reported as
|
||||
a falseticker since the last selection change */
|
||||
int reported_falseticker;
|
||||
/* Flags indicating which status was already reported for
|
||||
the source since the last change of the system peer */
|
||||
char reported_status[SRC_SELECTED + 1];
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
@@ -206,8 +206,7 @@ static LOG_FileID logfileid;
|
||||
/* Forward prototype */
|
||||
|
||||
static void update_sel_options(void);
|
||||
static void unselect_selected_source(LOG_Severity severity, const char *format,
|
||||
const char *arg);
|
||||
static void unselect_selected_source(LOG_Severity severity, const char *format, ...);
|
||||
static void slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
|
||||
double doffset, LCL_ChangeType change_type, void *anything);
|
||||
static void add_dispersion(double dispersion, void *anything);
|
||||
@@ -322,9 +321,8 @@ void SRC_DestroyInstance(SRC_Instance instance)
|
||||
last_updated_inst = NULL;
|
||||
|
||||
assert(initialised);
|
||||
if (instance->index < 0 || instance->index >= n_sources ||
|
||||
instance != sources[instance->index])
|
||||
assert(0);
|
||||
BRIEF_ASSERT(instance->index >= 0 && instance->index < n_sources &&
|
||||
instance == sources[instance->index]);
|
||||
|
||||
SST_DeleteInstance(instance->stats);
|
||||
dead_index = instance->index;
|
||||
@@ -340,7 +338,7 @@ void SRC_DestroyInstance(SRC_Instance instance)
|
||||
if (selected_source_index > dead_index)
|
||||
--selected_source_index;
|
||||
else if (selected_source_index == dead_index)
|
||||
unselect_selected_source(LOGS_INFO, NULL, NULL);
|
||||
unselect_selected_source(LOGS_INFO, NULL);
|
||||
|
||||
SRC_SelectSource(NULL);
|
||||
}
|
||||
@@ -360,8 +358,8 @@ SRC_ResetInstance(SRC_Instance instance)
|
||||
instance->stratum = 0;
|
||||
instance->leap = LEAP_Unsynchronised;
|
||||
instance->leap_vote = 0;
|
||||
instance->reported_falseticker = 0;
|
||||
|
||||
memset(instance->reported_status, 0, sizeof (instance->reported_status));
|
||||
memset(&instance->sel_info, 0, sizeof (instance->sel_info));
|
||||
|
||||
SST_ResetInstance(instance->stats);
|
||||
@@ -620,20 +618,45 @@ update_sel_options(void)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
static void
|
||||
log_selection_message(LOG_Severity severity, const char *format, const char *arg)
|
||||
log_selection_message(LOG_Severity severity, const char *format, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
if (REF_GetMode() != REF_ModeNormal)
|
||||
return;
|
||||
LOG(severity, format, arg);
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof (buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
LOG(severity, "%s", buf);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
FORMAT_ATTRIBUTE_PRINTF(3, 4)
|
||||
static void
|
||||
log_selection_source(LOG_Severity severity, const char *format, SRC_Instance inst)
|
||||
log_selection_source(LOG_Severity severity, SRC_Instance inst, const char *format, ...)
|
||||
{
|
||||
char buf[320], *name, *ntp_name;
|
||||
char buf[320], buf2[256], *name, *ntp_name, *s;
|
||||
va_list ap;
|
||||
|
||||
if (REF_GetMode() != REF_ModeNormal)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf2, sizeof (buf2), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Replace ## with %s in the formatted string to be the source name */
|
||||
s = strstr(buf2, "##");
|
||||
if (!s || strchr(buf2, '%'))
|
||||
return;
|
||||
s[0] = '%';
|
||||
s[1] = 's';
|
||||
|
||||
name = source_to_string(inst);
|
||||
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
|
||||
@@ -643,7 +666,9 @@ log_selection_source(LOG_Severity severity, const char *format, SRC_Instance ins
|
||||
else
|
||||
snprintf(buf, sizeof (buf), "%s", name);
|
||||
|
||||
log_selection_message(severity, format, buf);
|
||||
LOG(severity, buf2, buf);
|
||||
|
||||
inst->reported_status[inst->status] = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
@@ -686,7 +711,7 @@ source_to_string(SRC_Instance inst)
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
mark_source(SRC_Instance inst, SRC_Status status)
|
||||
set_source_status(SRC_Instance inst, SRC_Status status)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
@@ -731,6 +756,43 @@ mark_source(SRC_Instance inst, SRC_Status status)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
mark_source(SRC_Instance inst, SRC_Status status)
|
||||
{
|
||||
set_source_status(inst, status);
|
||||
|
||||
BRIEF_ASSERT(status >= SRC_OK && status < sizeof (inst->reported_status));
|
||||
|
||||
if (!inst->reported_status[status]) {
|
||||
switch (status) {
|
||||
case SRC_BAD_DISTANCE:
|
||||
if (inst->bad < BAD_HANDLE_THRESHOLD)
|
||||
break;
|
||||
log_selection_source(LOGS_WARN, inst,
|
||||
"Root distance of ## exceeds maxdistance of %.3f seconds",
|
||||
max_distance);
|
||||
break;
|
||||
case SRC_JITTERY:
|
||||
if (inst->bad < BAD_HANDLE_THRESHOLD)
|
||||
break;
|
||||
log_selection_source(LOGS_WARN, inst,
|
||||
"Jitter of ## exceeds maxjitter of %.3f seconds",
|
||||
max_jitter);
|
||||
break;
|
||||
case SRC_FALSETICKER:
|
||||
log_selection_source(LOGS_WARN, inst, "Detected falseticker ##");
|
||||
break;
|
||||
case SRC_SELECTED:
|
||||
log_selection_source(LOGS_INFO, inst, "Selected source ##");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
mark_ok_sources(SRC_Status status)
|
||||
{
|
||||
@@ -739,7 +801,8 @@ mark_ok_sources(SRC_Status status)
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
if (sources[i]->status != SRC_OK)
|
||||
continue;
|
||||
mark_source(sources[i], status);
|
||||
/* Don't log the status in this case (multiple sources at once) */
|
||||
set_source_status(sources[i], status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,16 +812,24 @@ mark_ok_sources(SRC_Status status)
|
||||
call providing a message or selection of another source, which resets the
|
||||
report_selection_loss flag. */
|
||||
|
||||
FORMAT_ATTRIBUTE_PRINTF(2, 3)
|
||||
static void
|
||||
unselect_selected_source(LOG_Severity severity, const char *format, const char *arg)
|
||||
unselect_selected_source(LOG_Severity severity, const char *format, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
if (selected_source_index != INVALID_SOURCE) {
|
||||
selected_source_index = INVALID_SOURCE;
|
||||
report_selection_loss = 1;
|
||||
}
|
||||
|
||||
if (report_selection_loss && format) {
|
||||
log_selection_message(severity, format, arg);
|
||||
va_start(ap, format);
|
||||
vsnprintf(buf, sizeof (buf), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
log_selection_message(severity, "%s", buf);
|
||||
report_selection_loss = 0;
|
||||
}
|
||||
}
|
||||
@@ -864,7 +935,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
struct timespec now, ref_time;
|
||||
int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources, sel_req_source;
|
||||
int max_badstat_reach, max_badstat_reach_size, n_badstats_sources;
|
||||
int max_sel_reach, max_sel_reach_size;
|
||||
int max_sel_reach, max_sel_reach_size, n_unreach_sources;
|
||||
int depth, best_depth, trust_depth, best_trust_depth, n_sel_trust_sources;
|
||||
int combined, stratum, min_stratum, max_score_index;
|
||||
int orphan_stratum, orphan_source;
|
||||
@@ -881,7 +952,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
}
|
||||
|
||||
if (n_sources == 0) {
|
||||
unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources", NULL);
|
||||
unselect_selected_source(LOGS_WARN, "Can't synchronise: no sources");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -893,6 +964,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
n_endpoints = 0;
|
||||
n_sel_sources = n_sel_trust_sources = 0;
|
||||
n_badstats_sources = 0;
|
||||
n_unreach_sources = 0;
|
||||
sel_req_source = 0;
|
||||
max_sel_reach = max_badstat_reach = 0;
|
||||
max_sel_reach_size = max_badstat_reach_size = 0;
|
||||
@@ -915,6 +987,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Count unreachable sources for a warning message */
|
||||
if (sources[i]->reachability == 0)
|
||||
n_unreach_sources++;
|
||||
|
||||
si = &sources[i]->sel_info;
|
||||
SST_GetSelectionData(sources[i]->stats, &now,
|
||||
&si->lo_limit, &si->hi_limit, &si->root_distance,
|
||||
@@ -1068,7 +1144,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
if (n_badstats_sources && n_sel_sources && selected_source_index == INVALID_SOURCE &&
|
||||
max_sel_reach_size < SOURCE_REACH_BITS && max_sel_reach >> 1 == max_badstat_reach) {
|
||||
mark_ok_sources(SRC_WAITS_STATS);
|
||||
unselect_selected_source(LOGS_INFO, NULL, NULL);
|
||||
unselect_selected_source(LOGS_INFO, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1082,7 +1158,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
|
||||
if (n_endpoints == 0) {
|
||||
/* No sources provided valid endpoints */
|
||||
unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources", NULL);
|
||||
unselect_selected_source(LOGS_WARN, "Can't synchronise: no selectable sources"
|
||||
" (%d unreachable sources)", n_unreach_sources);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1156,12 +1233,23 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
assert(depth == 0 && trust_depth == 0);
|
||||
assert(2 * n_sel_sources == n_endpoints);
|
||||
|
||||
if ((best_trust_depth == 0 && best_depth <= n_sel_sources / 2) ||
|
||||
(best_trust_depth > 0 && best_trust_depth <= n_sel_trust_sources / 2)) {
|
||||
if (best_trust_depth > 0) {
|
||||
best_depth = best_trust_depth;
|
||||
n_sel_sources = n_sel_trust_sources;
|
||||
}
|
||||
|
||||
if (best_depth <= n_sel_sources / 2) {
|
||||
/* Could not even get half the reachable (trusted) sources to agree */
|
||||
|
||||
if (!reported_no_majority) {
|
||||
log_selection_message(LOGS_WARN, "Can't synchronise: no majority", NULL);
|
||||
if (best_depth < 2)
|
||||
log_selection_message(LOGS_WARN, "%s (no agreement among %d %ssources)",
|
||||
"Can't synchronise: no majority", n_sel_sources,
|
||||
best_trust_depth > 0 ? "trusted " : "");
|
||||
else
|
||||
log_selection_message(LOGS_WARN, "%s (only %d of %d %ssources agree)",
|
||||
"Can't synchronise: no majority", best_depth,
|
||||
n_sel_sources, best_trust_depth > 0 ? "trusted " : "");
|
||||
reported_no_majority = 1;
|
||||
report_selection_loss = 0;
|
||||
}
|
||||
@@ -1212,15 +1300,11 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
sel_req_source = 0;
|
||||
} else {
|
||||
mark_source(sources[i], SRC_FALSETICKER);
|
||||
if (!sources[i]->reported_falseticker) {
|
||||
log_selection_source(LOGS_WARN, "Detected falseticker %s", sources[i]);
|
||||
sources[i]->reported_falseticker = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
|
||||
unselect_selected_source(LOGS_INFO, "Can't synchronise: %s selectable sources",
|
||||
unselect_selected_source(LOGS_WARN, "Can't synchronise: %s selectable sources",
|
||||
!n_sel_sources ? "no" :
|
||||
sel_req_source ? "no required source in" : "not enough");
|
||||
mark_ok_sources(SRC_WAITS_SOURCES);
|
||||
@@ -1329,19 +1413,18 @@ SRC_SelectSource(SRC_Instance updated_inst)
|
||||
/* Before selecting the new synchronisation source wait until the reference
|
||||
can be updated */
|
||||
if (sources[max_score_index]->updates == 0) {
|
||||
unselect_selected_source(LOGS_INFO, NULL, NULL);
|
||||
unselect_selected_source(LOGS_INFO, NULL);
|
||||
mark_ok_sources(SRC_WAITS_UPDATE);
|
||||
return;
|
||||
}
|
||||
|
||||
selected_source_index = max_score_index;
|
||||
log_selection_source(LOGS_INFO, "Selected source %s", sources[selected_source_index]);
|
||||
|
||||
/* New source has been selected, reset all scores */
|
||||
for (i = 0; i < n_sources; i++) {
|
||||
sources[i]->sel_score = 1.0;
|
||||
sources[i]->distant = 0;
|
||||
sources[i]->reported_falseticker = 0;
|
||||
memset(sources[i]->reported_status, 0, sizeof (sources[i]->reported_status));
|
||||
}
|
||||
|
||||
reported_no_majority = 0;
|
||||
|
||||
313
stubs.c
313
stubs.c
@@ -49,66 +49,6 @@
|
||||
#include "sched.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(FEAT_NTP) && !defined(FEAT_ASYNCDNS)
|
||||
|
||||
/* This is a blocking implementation used when asynchronous resolving is not available */
|
||||
|
||||
struct DNS_Async_Instance {
|
||||
const char *name;
|
||||
DNS_NameResolveHandler handler;
|
||||
void *arg;
|
||||
int pipe[2];
|
||||
};
|
||||
|
||||
static void
|
||||
resolve_name(int fd, int event, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
IPAddr addrs[DNS_MAX_ADDRESSES];
|
||||
DNS_Status status;
|
||||
int i;
|
||||
|
||||
inst = (struct DNS_Async_Instance *)anything;
|
||||
|
||||
SCH_RemoveFileHandler(inst->pipe[0]);
|
||||
close(inst->pipe[0]);
|
||||
close(inst->pipe[1]);
|
||||
|
||||
status = PRV_Name2IPAddress(inst->name, addrs, DNS_MAX_ADDRESSES);
|
||||
|
||||
for (i = 0; status == DNS_Success && i < DNS_MAX_ADDRESSES &&
|
||||
addrs[i].family != IPADDR_UNSPEC; i++)
|
||||
;
|
||||
|
||||
(inst->handler)(status, i, addrs, inst->arg);
|
||||
|
||||
Free(inst);
|
||||
}
|
||||
|
||||
void
|
||||
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
|
||||
{
|
||||
struct DNS_Async_Instance *inst;
|
||||
|
||||
inst = MallocNew(struct DNS_Async_Instance);
|
||||
inst->name = name;
|
||||
inst->handler = handler;
|
||||
inst->arg = anything;
|
||||
|
||||
if (pipe(inst->pipe))
|
||||
LOG_FATAL("pipe() failed");
|
||||
|
||||
UTI_FdSetCloexec(inst->pipe[0]);
|
||||
UTI_FdSetCloexec(inst->pipe[1]);
|
||||
|
||||
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, resolve_name, inst);
|
||||
|
||||
if (write(inst->pipe[1], "", 1) < 0)
|
||||
;
|
||||
}
|
||||
|
||||
#endif /* !FEAT_ASYNCDNS */
|
||||
|
||||
#ifndef FEAT_CMDMON
|
||||
|
||||
void
|
||||
@@ -144,259 +84,6 @@ MNL_Finalise(void)
|
||||
|
||||
#endif /* !FEAT_CMDMON */
|
||||
|
||||
#ifndef FEAT_NTP
|
||||
|
||||
void
|
||||
NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NCR_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NCR_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
NCR_CheckAccessRestriction(IPAddr *ip_addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
NIO_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NIO_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id)
|
||||
{
|
||||
return NSR_TooManySources;
|
||||
}
|
||||
|
||||
NSR_Status
|
||||
NSR_AddSourceByName(char *name, int family, int port, int pool, NTP_Source_Type type,
|
||||
SourceParameters *params, uint32_t *conf_id)
|
||||
{
|
||||
return NSR_TooManySources;
|
||||
}
|
||||
|
||||
const char *
|
||||
NSR_StatusToString(NSR_Status status)
|
||||
{
|
||||
return "NTP not supported";
|
||||
}
|
||||
|
||||
NSR_Status
|
||||
NSR_RemoveSource(IPAddr *address)
|
||||
{
|
||||
return NSR_NoSuchSource;
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RemoveSourcesById(uint32_t conf_id)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RemoveAllSources(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_HandleBadSource(IPAddr *address)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NSR_RefreshAddresses(void)
|
||||
{
|
||||
}
|
||||
|
||||
char *
|
||||
NSR_GetName(IPAddr *address)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
|
||||
{
|
||||
if (handler)
|
||||
(handler)();
|
||||
}
|
||||
|
||||
void
|
||||
NSR_ResolveSources(void)
|
||||
{
|
||||
}
|
||||
|
||||
void NSR_StartSources(void)
|
||||
{
|
||||
}
|
||||
|
||||
void NSR_AutoStartSources(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples,
|
||||
IPAddr *mask, IPAddr *address)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
NSR_GetLocalRefid(IPAddr *address)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMinpoll(IPAddr *address, int new_minpoll)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyOffset(IPAddr *address, double new_offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_ModifyPolltarget(IPAddr *address, int new_poll_target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
NSR_ReportSource(RPT_SourceReport *report, struct timespec *now)
|
||||
{
|
||||
memset(report, 0, sizeof (*report));
|
||||
}
|
||||
|
||||
int
|
||||
NSR_GetAuthReport(IPAddr *address, RPT_AuthReport *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
NSR_GetNTPReport(RPT_NTPReport *report)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
NSR_GetActivityReport(RPT_ActivityReport *report)
|
||||
{
|
||||
memset(report, 0, sizeof (*report));
|
||||
}
|
||||
|
||||
void
|
||||
NSR_DumpAuthData(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef FEAT_CMDMON
|
||||
|
||||
void
|
||||
CLG_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CLG_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DNS_SetAddressFamily(int family)
|
||||
{
|
||||
}
|
||||
|
||||
DNS_Status
|
||||
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
|
||||
{
|
||||
return DNS_Failure;
|
||||
}
|
||||
|
||||
void
|
||||
KEY_Initialise(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
KEY_Finalise(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !FEAT_CMDMON */
|
||||
#endif /* !FEAT_NTP */
|
||||
|
||||
#ifndef FEAT_REFCLOCK
|
||||
void
|
||||
RCL_Initialise(void)
|
||||
|
||||
113
sys_linux.c
113
sys_linux.c
@@ -38,6 +38,12 @@
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SCFILTER
|
||||
#include <sys/prctl.h>
|
||||
#include <seccomp.h>
|
||||
@@ -48,9 +54,6 @@
|
||||
#ifdef FEAT_RTC
|
||||
#include <linux/rtc.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
#include <linux/sockios.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_PRIVDROP
|
||||
@@ -64,6 +67,7 @@
|
||||
#include "local.h"
|
||||
#include "logging.h"
|
||||
#include "privops.h"
|
||||
#include "socket.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Frequency scale to convert from ppm to the timex freq */
|
||||
@@ -902,33 +906,100 @@ get_precise_phc_readings(int phc_fd, int max_samples, struct timespec ts[][3])
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *path, int phc_index)
|
||||
/* Make sure an FD is a PHC. Return the FD if it is, or close the FD
|
||||
and return -1 if it is not. */
|
||||
|
||||
static int
|
||||
verify_fd_is_phc(int phc_fd)
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
char phc_path[64];
|
||||
int phc_fd;
|
||||
|
||||
if (!path) {
|
||||
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
|
||||
return -1;
|
||||
path = phc_path;
|
||||
}
|
||||
|
||||
phc_fd = open(path, O_RDONLY);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open %s : %s", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure it is a PHC */
|
||||
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
LOG(LOGS_ERR, "ioctl(%s) failed : %s", "PTP_CLOCK_GETCAPS", strerror(errno));
|
||||
close(phc_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
open_phc_by_iface_name(const char *iface)
|
||||
{
|
||||
#ifdef HAVE_LINUX_TIMESTAMPING
|
||||
struct ethtool_ts_info ts_info;
|
||||
char phc_device[PATH_MAX];
|
||||
struct ifreq req;
|
||||
int sock_fd;
|
||||
|
||||
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
|
||||
if (sock_fd < 0)
|
||||
return -1;
|
||||
|
||||
memset(&req, 0, sizeof (req));
|
||||
memset(&ts_info, 0, sizeof (ts_info));
|
||||
|
||||
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", iface) >=
|
||||
sizeof (req.ifr_name)) {
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ts_info.cmd = ETHTOOL_GET_TS_INFO;
|
||||
req.ifr_data = (char *)&ts_info;
|
||||
|
||||
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
|
||||
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
|
||||
SCK_CloseSocket(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Simplify failure paths by closing the socket as early as possible */
|
||||
SCK_CloseSocket(sock_fd);
|
||||
sock_fd = -1;
|
||||
|
||||
if (ts_info.phc_index < 0) {
|
||||
DEBUG_LOG("PHC missing on %s", req.ifr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (snprintf(phc_device, sizeof (phc_device),
|
||||
"/dev/ptp%d", ts_info.phc_index) >= sizeof (phc_device))
|
||||
return -1;
|
||||
|
||||
return open(phc_device, O_RDONLY);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
SYS_Linux_OpenPHC(const char *device)
|
||||
{
|
||||
int phc_fd = -1;
|
||||
|
||||
if (device[0] == '/') {
|
||||
phc_fd = open(device, O_RDONLY);
|
||||
if (phc_fd >= 0)
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
}
|
||||
|
||||
if (phc_fd < 0) {
|
||||
phc_fd = open_phc_by_iface_name(device);
|
||||
if (phc_fd < 0) {
|
||||
LOG(LOGS_ERR, "Could not open PHC of iface %s : %s",
|
||||
device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
phc_fd = verify_fd_is_phc(phc_fd);
|
||||
}
|
||||
|
||||
if (phc_fd >= 0)
|
||||
UTI_FdSetCloexec(phc_fd);
|
||||
|
||||
return phc_fd;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ extern void SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext conte
|
||||
|
||||
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);
|
||||
|
||||
extern int SYS_Linux_OpenPHC(const char *path, int phc_index);
|
||||
extern int SYS_Linux_OpenPHC(const char *device);
|
||||
|
||||
extern int SYS_Linux_GetPHCReadings(int fd, int nocrossts, int *reading_mode, int max_readings,
|
||||
struct timespec tss[][3]);
|
||||
|
||||
19
sys_timex.c
19
sys_timex.c
@@ -257,6 +257,8 @@ SYS_Timex_Finalise(void)
|
||||
int
|
||||
SYS_Timex_Adjust(struct timex *txc, int ignore_error)
|
||||
{
|
||||
static long last_constant, last_freq;
|
||||
static int last_status = -1;
|
||||
int state;
|
||||
|
||||
#ifdef SOLARIS
|
||||
@@ -270,7 +272,24 @@ SYS_Timex_Adjust(struct timex *txc, int ignore_error)
|
||||
if (state < 0) {
|
||||
LOG(ignore_error ? LOGS_DEBUG : LOGS_FATAL,
|
||||
NTP_ADJTIME_NAME"(0x%x) failed : %s", txc->modes, strerror(errno));
|
||||
return state;
|
||||
}
|
||||
|
||||
/* This a good place to verify that nothing else is touching the clock,
|
||||
without making an additional timex call. A clock update is normally
|
||||
expected to have four driver calls:
|
||||
- set_sync_status - primarily updating leap status
|
||||
- set_frequency - correcting frequency error
|
||||
- set_frequency - correcting phase error
|
||||
- set_sync_status - updating leap and estimated/maximum error */
|
||||
if (last_status != -1 &&
|
||||
(((last_status ^ txc->status) & STA_PLL && !(txc->modes & MOD_STATUS)) ||
|
||||
(last_constant != txc->constant && !(txc->modes & MOD_TIMECONST)) ||
|
||||
(last_freq != txc->freq && !(txc->modes & MOD_FREQUENCY))))
|
||||
LOG(LOGS_WARN, "System clock interference detected (another NTP client?)");
|
||||
last_status = txc->status;
|
||||
last_constant = txc->constant;
|
||||
last_freq = txc->freq;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ for opts in \
|
||||
"--enable-debug" \
|
||||
"--enable-ntp-signd" \
|
||||
"--enable-scfilter" \
|
||||
"--disable-asyncdns" \
|
||||
"--disable-ipv6" \
|
||||
"--disable-privdrop" \
|
||||
"--disable-readline" \
|
||||
@@ -18,19 +17,13 @@ for opts in \
|
||||
"--disable-sechash" \
|
||||
"--disable-cmdmon" \
|
||||
"--disable-cmdmon --enable-scfilter" \
|
||||
"--disable-ntp" \
|
||||
"--disable-ntp --enable-scfilter" \
|
||||
"--disable-nts" \
|
||||
"--disable-refclock" \
|
||||
"--disable-timestamping" \
|
||||
"--disable-timestamping --disable-ntp" \
|
||||
"--disable-cmdmon --disable-ntp" \
|
||||
"--disable-cmdmon --disable-ntp --enable-scfilter" \
|
||||
"--disable-cmdmon --disable-refclock" \
|
||||
"--disable-cmdmon --disable-ntp --disable-refclock"
|
||||
"--disable-cmdmon --disable-refclock"
|
||||
do
|
||||
./configure $opts || exit 1
|
||||
make clean
|
||||
make "$@" || exit 1
|
||||
make -C test/unit check || exit 1
|
||||
make -C test/unit "$@" check || exit 1
|
||||
done
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Run the unit and simulation tests with different compiler sanitizers
|
||||
# and under valgrind
|
||||
|
||||
valgrind_opts="--leak-check=full --errors-for-leak-kinds=definite"
|
||||
valgrind_opts="--leak-check=full --errors-for-leak-kinds=definite --track-fds=yes"
|
||||
|
||||
cd ../..
|
||||
|
||||
|
||||
@@ -24,6 +24,12 @@ for falsetickers in 3 4; do
|
||||
# These check are expected to fail
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
|
||||
if [ $falsetickers = 3 ]; then
|
||||
check_log_messages "Can't synchronise: no majority (only 2 of 5 sources agree)" 1 1 || test_fail
|
||||
else
|
||||
check_log_messages "Can't synchronise: no majority (no agreement among 5 sources)" 1 1 || test_fail
|
||||
fi
|
||||
done
|
||||
|
||||
# Sources with large asymmetric delay should be excluded
|
||||
|
||||
49
test/simulation/014-intermittent
Executable file
49
test/simulation/014-intermittent
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "intermittent connection"
|
||||
|
||||
# Pass packets only for 1200 seconds every 10000 seconds
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1
|
||||
(equal 0.1 (min (% time 10000) 1200) 1200)))
|
||||
EOF
|
||||
)
|
||||
|
||||
time_max_limit=1e-1
|
||||
freq_max_limit=1e-2
|
||||
time_rms_limit=2e-3
|
||||
freq_rms_limit=2e-5
|
||||
limit=100000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_log_messages "Can't.*no selectable sources (1 unreachable" 9 10 || test_fail
|
||||
check_log_messages "Selected source 192.168.123.1" 9 10 || test_fail
|
||||
|
||||
# Pass every 20th request
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1
|
||||
(equal 0.1 from 2)
|
||||
(equal 0.1 (min (% (sum 1) 20) 1) 1)))
|
||||
EOF
|
||||
)
|
||||
|
||||
time_max_limit=1e-2
|
||||
freq_max_limit=1e-4
|
||||
time_rms_limit=5e-3
|
||||
max_sync_time=22000
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_log_messages "Can't.*no selectable sources (1 unreachable" 5 15 || test_fail
|
||||
check_log_messages "Selected source 192.168.123.1" 5 15 || test_fail
|
||||
|
||||
test_pass
|
||||
15
test/simulation/015-ipv6
Executable file
15
test/simulation/015-ipv6
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
. ./test.common
|
||||
|
||||
test_start "IPv6 addressing"
|
||||
|
||||
ip_family=6
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
test_pass
|
||||
@@ -35,11 +35,7 @@ Root delay : 0.001000000 seconds
|
||||
Update interval : 16\.. seconds
|
||||
.*$" || test_fail
|
||||
|
||||
if echo "$refclock" | grep -q 'PHC.*nocrossts'; then
|
||||
check_file_messages "20.* GPS.*[0-9] N " 620 750 refclocks.log || test_fail
|
||||
else
|
||||
check_file_messages "20.* GPS.*[0-9] N " 997 1001 refclocks.log || test_fail
|
||||
fi
|
||||
check_file_messages "20.* GPS.*[0-9] N " 997 1001 refclocks.log || test_fail
|
||||
check_file_messages "20.* GPS.*- N " 61 63 refclocks.log || test_fail
|
||||
rm -f tmp/refclocks.log
|
||||
done
|
||||
@@ -89,9 +85,9 @@ Root delay : 0\.000000001 seconds
|
||||
check_file_messages "20.* PPS1.*- N " 60 63 refclocks.log || test_fail
|
||||
rm -f tmp/refclocks.log
|
||||
|
||||
min_sync_time=80
|
||||
max_sync_time=180
|
||||
chronyc_start=220
|
||||
min_sync_time=180
|
||||
max_sync_time=260
|
||||
chronyc_start=270
|
||||
client_conf="
|
||||
refclock SHM 0 refid NMEA offset 0.35 delay 0.1
|
||||
refclock PPS /dev/pps0
|
||||
@@ -112,8 +108,60 @@ Root delay : 0\.000000001 seconds
|
||||
check_file_messages "20.* PPS1.*[0-9] N " 800 960 refclocks.log || test_fail
|
||||
check_file_messages "20.* PPS1.*- N " 50 63 refclocks.log || test_fail
|
||||
rm -f tmp/refclocks.log
|
||||
|
||||
min_sync_time=80
|
||||
max_sync_time=180
|
||||
chronyc_start=220
|
||||
# Swapped order of SHM and PPS impacts first accepted sample
|
||||
client_conf="
|
||||
refclock PPS /dev/pps0
|
||||
refclock SHM 0 refid NMEA offset 0.35 delay 0.1
|
||||
logdir tmp
|
||||
log refclocks
|
||||
maxupdateskew 10000"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^Reference ID.*50505330 \(PPS0\)
|
||||
Stratum.*: 1
|
||||
.*
|
||||
Root delay : 0\.000000001 seconds
|
||||
.*$" || test_fail
|
||||
|
||||
check_file_messages "20.* PPS0.*[0-9] N " 800 960 refclocks.log || test_fail
|
||||
check_file_messages "20.* PPS0.*- N " 50 63 refclocks.log || test_fail
|
||||
rm -f tmp/refclocks.log
|
||||
fi
|
||||
|
||||
export CLKNETSIM_PHC_JITTER_OFF=$[2 * 25 * 492]
|
||||
export CLKNETSIM_PHC_JITTER_ON=$[2 * 25 * 8]
|
||||
export CLKNETSIM_PHC_JITTER=1e-6
|
||||
refclock_offset=0.0
|
||||
refclock_jitter=1e-9
|
||||
min_sync_time=5
|
||||
max_sync_time=7
|
||||
time_max_limit=1e-7
|
||||
time_rms_limit=1e-8
|
||||
client_conf="refclock PHC /dev/ptp0:nocrossts poll 0
|
||||
logdir tmp
|
||||
log refclocks"
|
||||
chronyc_start=500
|
||||
chronyc_conf="sources"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^MS.*
|
||||
=*
|
||||
#\* PHC0 0 0 377 8 .*$" || test_fail
|
||||
rm -f tmp/refclocks.log
|
||||
|
||||
unset CLKNETSIM_PHC_JITTER_OFF
|
||||
unset CLKNETSIM_PHC_JITTER_ON
|
||||
export CLKNETSIM_PHC_JITTER=1e-7
|
||||
refclock_offset="(+ 0.399 (sum 1e-3))"
|
||||
refclock_jitter=1e-6
|
||||
servers=1
|
||||
|
||||
@@ -31,6 +31,17 @@ check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
if check_config_h 'FEAT_IPV6 1'; then
|
||||
ip_family=6
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
ip_family=$default_ip_family
|
||||
fi
|
||||
|
||||
freq_max_limit=$default_freq_max_limit
|
||||
base_delay="(+ 1e-4 (* -1 (equal 0.1 from 3) (equal 0.1 to 1)))"
|
||||
client_peer_options=""
|
||||
|
||||
@@ -145,7 +145,7 @@ for chronyc_conf in \
|
||||
"dfreq 1.0e-3" \
|
||||
"doffset -1.0" \
|
||||
"dump" \
|
||||
"local stratum 5 distance 1.0 activate 0.5 orphan" \
|
||||
"local stratum 5 distance 1.0 activate 0.5 orphan waitsynced 100 waitunsynced 20" \
|
||||
"local off" \
|
||||
"makestep 10.0 3" \
|
||||
"makestep" \
|
||||
@@ -195,6 +195,33 @@ do
|
||||
check_chronyc_output "501 Not authorised$" || test_fail
|
||||
done
|
||||
|
||||
for chronyc_conf in \
|
||||
"activity" \
|
||||
"authdata" \
|
||||
"clients" \
|
||||
"manual list" \
|
||||
"ntpdata" \
|
||||
"rtcdata" \
|
||||
"selectdata" \
|
||||
"serverstats" \
|
||||
"smoothing" \
|
||||
"sourcename 192.168.123.1" \
|
||||
"sources" \
|
||||
"sourcestats" \
|
||||
"tracking"
|
||||
do
|
||||
server_conf="opencommands ${chronyc_conf% *}"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_chronyc_output "501 Not authorised$" && test_fail
|
||||
|
||||
server_conf="opencommands"
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_chronyc_output "501 Not authorised$" || test_fail
|
||||
done
|
||||
|
||||
server_conf="server 192.168.123.1"
|
||||
cmdmon_unix=1
|
||||
|
||||
chronyc_conf="
|
||||
@@ -242,14 +269,14 @@ Jitter asymmetry: \+0\.00
|
||||
NTP tests : 111 111 1110
|
||||
Interleaved : No
|
||||
Authenticated : No
|
||||
TX timestamping : Kernel
|
||||
RX timestamping : Kernel
|
||||
TX timestamping : (Daemon|Kernel)
|
||||
RX timestamping : (Daemon|Kernel)
|
||||
Total TX : 1
|
||||
Total RX : 1
|
||||
Total valid RX : 1
|
||||
Total good RX : 0
|
||||
Total kernel TX : [01]
|
||||
Total kernel RX : 1
|
||||
Total kernel RX : [01]
|
||||
Total HW TX : 0
|
||||
Total HW RX : 0
|
||||
S Name/IP Address Auth COpts EOpts Last Score Interval Leap
|
||||
@@ -266,9 +293,9 @@ Authenticated NTP packets : 0
|
||||
Interleaved NTP packets : 0
|
||||
NTP timestamps held : 0
|
||||
NTP timestamp span : 0
|
||||
NTP daemon RX timestamps : 0
|
||||
NTP daemon RX timestamps : [01]
|
||||
NTP daemon TX timestamps : 1
|
||||
NTP kernel RX timestamps : 1
|
||||
NTP kernel RX timestamps : [01]
|
||||
NTP kernel TX timestamps : 0
|
||||
NTP hardware RX timestamps : 0
|
||||
NTP hardware TX timestamps : 0$" || test_fail
|
||||
@@ -392,7 +419,7 @@ cyclelogs
|
||||
dump
|
||||
dfreq 1.0e-3
|
||||
doffset -0.01
|
||||
local stratum 5 distance 1.0 orphan
|
||||
local stratum 5 distance 1.0 orphan waitsynced 100 waitunsynced 10
|
||||
local off
|
||||
makestep 10.0 3
|
||||
makestep
|
||||
|
||||
@@ -7,7 +7,7 @@ test_start "local options"
|
||||
check_config_h 'FEAT_CMDMON 1' || test_skip
|
||||
|
||||
server_strata=3
|
||||
server_conf="local stratum 5 orphan
|
||||
server_conf="local stratum 5 orphan waitunsynced 0
|
||||
server 192.168.123.1
|
||||
server 192.168.123.2
|
||||
server 192.168.123.3"
|
||||
@@ -23,11 +23,62 @@ check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^.*Stratum *: 7.*$" || test_fail
|
||||
|
||||
limit=1000
|
||||
server_conf="local stratum 5 orphan
|
||||
server 192.168.123.1 minpoll 6 maxpoll 6
|
||||
server 192.168.123.2 minpoll 6 maxpoll 6
|
||||
server 192.168.123.3 minpoll 6 maxpoll 6"
|
||||
server_server_options="minpoll 6 maxpoll 6"
|
||||
client_start=0
|
||||
client_server_conf="
|
||||
server 192.168.123.1 minpoll 6 maxpoll 6
|
||||
server 192.168.123.2 minpoll 6 maxpoll 6
|
||||
server 192.168.123.3 minpoll 6 maxpoll 6"
|
||||
client_conf="logdir tmp
|
||||
log measurements"
|
||||
chronyc_start=700
|
||||
chronyc_conf=""
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
check_file_messages "20.*123\.1.* 5 111 " 10 11 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.1.* [6-9] 111 " 0 0 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.2.* 5 111 " 2 4 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.2.* 6 111 " 7 9 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.2.* [7-9] 111 " 0 0 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.3.* 5 111 " 2 4 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.3.* 6 111 " 7 9 measurements.log || test_fail
|
||||
check_file_messages "20.*123\.3.* [7-9] 111 " 0 0 measurements.log || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
server_conf="local stratum 5 orphan distance 0.0 waitsynced 150 waitunsynced 0"
|
||||
base_delay=$(cat <<-EOF | tr -d '\n'
|
||||
(+ 1e-4
|
||||
(* -1
|
||||
(equal 0.1 from 1)
|
||||
(equal 0.1 to 2)
|
||||
(equal 0.1 (min time 500) 500)))
|
||||
EOF
|
||||
)
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_sync || test_fail
|
||||
check_file_messages "20.*:1.:.*123\.1.* 5 111 " 6 6 measurements.log || test_fail
|
||||
check_file_messages "20.*:0.:.*123\.2.* 5 111 " 2 3 measurements.log || test_fail
|
||||
check_file_messages "20.*:1.:.*123\.2.* 5 111 " 6 7 measurements.log || test_fail
|
||||
check_file_messages "20.*:0.:.*123\.3.* 5 111 " 7 10 measurements.log || test_fail
|
||||
check_file_messages "20.*:1.:.*123\.3.* 5 111 " 0 1 measurements.log || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
limit=4000
|
||||
wander=0.0
|
||||
jitter=0.0
|
||||
server_strata=1
|
||||
server_conf=""
|
||||
server_server_options=""
|
||||
client_server_conf=""
|
||||
client_server_options="minpoll 6 maxpoll 6 minsamples 64"
|
||||
chronyc_start=1
|
||||
chronyc_conf="timeout 1000000
|
||||
|
||||
@@ -22,6 +22,24 @@ check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^.*Stratum *: 2.*$" || test_fail
|
||||
check_chronyc_output "^.*Stratum *: 2
|
||||
Ref time.*
|
||||
System time *: 0.000.*
|
||||
Last offset *: [+-]0.000.*$" || test_fail
|
||||
check_log_messages "Could not step" 0 0 || test_fail
|
||||
|
||||
client_conf="makestep 0.01 -1"
|
||||
client_server_options="offset 5.0005"
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
check_chronyc_output "^.*Stratum *: 2
|
||||
Ref time.*
|
||||
System time *: 5.000.*
|
||||
Last offset *: [+-]0.000.*$" || test_fail
|
||||
check_log_messages "Could not step" 20 60 || test_fail
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -58,6 +58,21 @@ for client_conf in \
|
||||
fi
|
||||
done
|
||||
|
||||
if check_config_h 'FEAT_IPV6 1'; then
|
||||
server_chronyd_options="-6"
|
||||
client_chronyd_options="-6"
|
||||
ip_family=6
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
server_chronyd_options=$default_server_chronyd_options
|
||||
client_chronyd_options="-d"
|
||||
ip_family=$default_ip_family
|
||||
fi
|
||||
|
||||
server_conf+="
|
||||
server 192.168.123.2 minpoll 1 maxpoll 1 noselect"
|
||||
|
||||
|
||||
@@ -56,6 +56,20 @@ check_file_messages " 2 1 .* 4460 " 260 300 log.packets || test_fail
|
||||
check_file_messages "." 6 6 ntskeys || test_fail
|
||||
rm -f tmp/measurements.log
|
||||
|
||||
if check_config_h 'FEAT_IPV6 1'; then
|
||||
ip_family=6
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_file_messages " 2 1 .* 4460 " 260 300 log.packets || test_fail
|
||||
check_file_messages "." 6 6 ntskeys || test_fail
|
||||
|
||||
ip_family=$default_ip_family
|
||||
fi
|
||||
|
||||
client_conf+="
|
||||
ntsrefresh 120
|
||||
ntsdumpdir tmp"
|
||||
@@ -313,4 +327,31 @@ check_sync && test_fail
|
||||
check_file_messages " 3 1 .* 123 " 0 0 log.packets || test_fail
|
||||
check_file_messages " 3 2 .* 123 " 0 0 log.packets || test_fail
|
||||
|
||||
for server_aead in "" "15" "30"; do
|
||||
for client_aead in "" "15" "30"; do
|
||||
server_conf="
|
||||
ntsaeads $server_aead
|
||||
ntsserverkey tmp/server1.key
|
||||
ntsservercert tmp/server1.crt
|
||||
ntsprocesses 0"
|
||||
client_conf="
|
||||
nosystemcert
|
||||
ntsaeads $client_aead
|
||||
ntstrustedcerts tmp/server1.crt
|
||||
ntstrustedcerts tmp/server2.crt"
|
||||
client_server_conf=""
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
if [ -n "$server_aead" ] && [ "$server_aead" == "$client_aead" ] &&
|
||||
( [ "$server_aead" != "30" ] || check_config_h '.*_SIV_GCM 1' ); then
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
else
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
||||
@@ -68,7 +68,7 @@ check_source_selection && test_fail
|
||||
check_packet_interval || test_fail
|
||||
check_sync || test_fail
|
||||
|
||||
check_log_messages "Can't synchronise: no majority" 1 1 || test_fail
|
||||
check_log_messages "Can't synchronise: no majority (no agreement among 2 sources)" 1 1 || test_fail
|
||||
check_log_messages "Detected falseticker" 0 2 || test_fail
|
||||
check_log_messages "Source 192.168.123.. replaced with" 3 60 || test_fail
|
||||
check_log_messages "Source 192.168.123.1 replaced with" 1 25 || test_fail
|
||||
|
||||
@@ -78,6 +78,7 @@ default_max_sync_time=210
|
||||
default_client_min_mean_out_interval=0.0
|
||||
default_client_max_min_out_interval=inf
|
||||
|
||||
default_ip_family=4
|
||||
default_cmdmon_unix=1
|
||||
default_pcap_dumps=0
|
||||
default_dns=0
|
||||
@@ -91,8 +92,6 @@ done
|
||||
test_start() {
|
||||
rm -rf tmp/*
|
||||
echo "Testing $@:"
|
||||
|
||||
check_config_h 'FEAT_NTP 1' || test_skip
|
||||
}
|
||||
|
||||
test_pass() {
|
||||
@@ -192,6 +191,8 @@ get_node_name() {
|
||||
|
||||
if [ $dns -ne 0 ]; then
|
||||
echo "node$index.net1.clk"
|
||||
elif [ $ip_family -eq 6 ]; then
|
||||
printf "fc00::123:%x" $index
|
||||
else
|
||||
echo "192.168.123.$index"
|
||||
fi
|
||||
@@ -239,7 +240,7 @@ check_config_h() {
|
||||
|
||||
# Check if the clock was well synchronized
|
||||
check_sync() {
|
||||
local i sync_time max_time_error max_freq_error ret=0
|
||||
local i msg sync_time max_time_error max_freq_error r ret=0
|
||||
local rms_time_error rms_freq_error
|
||||
|
||||
test_message 2 1 "checking clock sync time, max/rms time/freq error:"
|
||||
@@ -254,17 +255,37 @@ check_sync() {
|
||||
rms_time_error=$(get_stat 'RMS offset' $i)
|
||||
rms_freq_error=$(get_stat 'RMS frequency' $i)
|
||||
|
||||
test_message 3 0 "node $i: $sync_time $(printf '%.2e %.2e %.2e %.2e' \
|
||||
$max_time_error $max_freq_error $rms_time_error $rms_freq_error)"
|
||||
r=0
|
||||
msg="$sync_time"
|
||||
if ! check_stat $sync_time $min_sync_time $max_sync_time; then
|
||||
msg+="!"
|
||||
r=1
|
||||
fi
|
||||
msg+="$(printf ' %.2e' $max_time_error)"
|
||||
if ! check_stat $max_time_error 0.0 $time_max_limit; then
|
||||
msg+="!"
|
||||
r=1
|
||||
fi
|
||||
msg+="$(printf ' %.2e' $max_freq_error)"
|
||||
if ! check_stat $max_freq_error 0.0 $freq_max_limit; then
|
||||
msg+="!"
|
||||
r=1
|
||||
fi
|
||||
msg+="$(printf ' %.2e' $rms_time_error)"
|
||||
if ! check_stat $rms_time_error 0.0 $time_rms_limit; then
|
||||
msg+="!"
|
||||
r=1
|
||||
fi
|
||||
msg+="$(printf ' %.2e' $rms_freq_error)"
|
||||
if ! check_stat $rms_freq_error 0.0 $freq_rms_limit; then
|
||||
msg+="!"
|
||||
r=1
|
||||
fi
|
||||
|
||||
check_stat $sync_time $min_sync_time $max_sync_time && \
|
||||
check_stat $max_time_error 0.0 $time_max_limit && \
|
||||
check_stat $max_freq_error 0.0 $freq_max_limit && \
|
||||
check_stat $rms_time_error 0.0 $time_rms_limit && \
|
||||
check_stat $rms_freq_error 0.0 $freq_rms_limit && \
|
||||
test_ok || test_bad
|
||||
test_message 3 0 "node $i: $msg"
|
||||
|
||||
[ $? -eq 0 ] || ret=1
|
||||
[ $r -eq 0 ] || ret=1
|
||||
[ $r -eq 0 ] && test_ok || test_bad
|
||||
done
|
||||
|
||||
return $ret
|
||||
@@ -454,6 +475,7 @@ run_test() {
|
||||
nodes=$(get_chronyd_nodes)
|
||||
[ -n "$chronyc_conf" ] && nodes=$[$nodes + $clients]
|
||||
|
||||
export CLKNETSIM_IP_FAMILY=$ip_family
|
||||
export CLKNETSIM_UNIX_SUBNET=$[$cmdmon_unix != 0 ? 2 : 0]
|
||||
|
||||
for i in $(seq 1 $nodes); do
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
check_chronyd_features PRIVDROP || test_skip "PRIVDROP support disabled"
|
||||
|
||||
user="nobody"
|
||||
priv_drop=1
|
||||
|
||||
test_start "dropping of root privileges"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ certtool --generate-privkey --key-type=ed25519 --outfile $TEST_DIR/server.key \
|
||||
&> $TEST_DIR/certtool.log
|
||||
certtool --generate-self-signed --load-privkey $TEST_DIR/server.key \
|
||||
--template $TEST_DIR/cert.cfg --outfile $TEST_DIR/server.crt &>> $TEST_DIR/certtool.log
|
||||
chown $user $TEST_DIR/server.*
|
||||
chown "$(get_user)" $TEST_DIR/server.*
|
||||
|
||||
ntpport=$(get_free_port)
|
||||
ntsport=$(get_free_port)
|
||||
|
||||
@@ -26,7 +26,7 @@ certtool --generate-privkey --key-type=ed25519 --outfile $TEST_DIR/server.key \
|
||||
&> $TEST_DIR/certtool.log
|
||||
certtool --generate-self-signed --load-privkey $TEST_DIR/server.key \
|
||||
--template $TEST_DIR/cert.cfg --outfile $TEST_DIR/server.crt &>> $TEST_DIR/certtool.log
|
||||
chown $user $TEST_DIR/server.*
|
||||
chown "$(get_user)" $TEST_DIR/server.*
|
||||
|
||||
ntpport=$(get_free_port)
|
||||
ntsport=$(get_free_port)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
check_chronyd_features SCFILTER || test_skip "SCFILTER support disabled"
|
||||
|
||||
[[ $CHRONYD_WRAPPER == *valgrind* ]] && test_skip "SCFILTER breaks valgrind"
|
||||
|
||||
test_start "system call filter in non-destructive tests"
|
||||
|
||||
for level in 1 2 -1 -2; do
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
TEST_LIBDIR=${CHRONY_LIBDIR:-/var/lib/chrony}
|
||||
TEST_LOGDIR=${CHRONY_LOGDIR:-/var/log/chrony}
|
||||
TEST_RUNDIR=${CHRONY_RUNDIR:-/var/run/chrony}
|
||||
TEST_PRIVDROP_USER=$(ls -ld "$TEST_RUNDIR" 2> /dev/null | awk '{print $3}')
|
||||
|
||||
. ./test.common
|
||||
|
||||
user=$(ls -ld "$TEST_RUNDIR" 2> /dev/null | awk '{print $3}')
|
||||
priv_drop=1
|
||||
|
||||
test_start "system directories"
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
check_chronyd_features SCFILTER || test_skip "SCFILTER support disabled"
|
||||
|
||||
[[ $CHRONYD_WRAPPER == *valgrind* ]] && test_skip "SCFILTER breaks valgrind"
|
||||
|
||||
test_start "system call filter in destructive tests"
|
||||
|
||||
for level in 1 2 -1 -2; do
|
||||
|
||||
@@ -21,9 +21,13 @@ TEST_LIBDIR=${TEST_LIBDIR:-$TEST_DIR}
|
||||
TEST_LOGDIR=${TEST_LOGDIR:-$TEST_DIR}
|
||||
TEST_RUNDIR=${TEST_RUNDIR:-$TEST_DIR}
|
||||
TEST_SCFILTER=${TEST_SCFILTER:-0}
|
||||
TEST_ROOT_USER=${TEST_ROOT_USER:-root}
|
||||
TEST_PRIVDROP_USER=${TEST_PRIVDROP_USER:-nobody}
|
||||
|
||||
test_start() {
|
||||
check_chronyd_features NTP CMDMON || test_skip "NTP/CMDMON support disabled"
|
||||
local user=$(get_user)
|
||||
|
||||
check_chronyd_features CMDMON || test_skip "CMDMON support disabled"
|
||||
|
||||
[ "${#TEST_DIR}" -ge 5 ] || test_skip "invalid TEST_DIR"
|
||||
|
||||
@@ -36,7 +40,7 @@ test_start() {
|
||||
|
||||
rm -f "$TEST_LIBDIR"/* "$TEST_LOGDIR"/* "$TEST_RUNDIR"/*
|
||||
|
||||
if [ "$user" != "root" ]; then
|
||||
if [ "$user" != "$TEST_ROOT_USER" ]; then
|
||||
id -u "$user" > /dev/null 2> /dev/null || test_skip "missing user $user"
|
||||
chown "$user:$(id -g "$user")" "$TEST_DIR" || test_skip "could not chown $TEST_DIR"
|
||||
su "$user" -s /bin/sh -c "touch $TEST_DIR/test" 2> /dev/null || \
|
||||
@@ -108,7 +112,7 @@ default_clock_control=0
|
||||
default_server=127.0.0.1
|
||||
default_server_name=127.0.0.1
|
||||
default_server_options=""
|
||||
default_user=root
|
||||
default_priv_drop=0
|
||||
|
||||
# Initialize test settings from their defaults
|
||||
for defoptname in ${!default_*}; do
|
||||
@@ -183,6 +187,14 @@ get_cmdsocket() {
|
||||
echo "$TEST_RUNDIR/chronyd.sock"
|
||||
}
|
||||
|
||||
get_user() {
|
||||
if [ "$priv_drop" -ne 0 ]; then
|
||||
echo "$TEST_PRIVDROP_USER"
|
||||
else
|
||||
echo "$TEST_ROOT_USER"
|
||||
fi
|
||||
}
|
||||
|
||||
# Find a free port in the 10000-20000 range (their use is racy)
|
||||
get_free_port() {
|
||||
local port
|
||||
@@ -197,8 +209,9 @@ get_free_port() {
|
||||
}
|
||||
|
||||
generate_chrony_conf() {
|
||||
local ntpport cmdport
|
||||
local user ntpport cmdport
|
||||
|
||||
user=$(get_user)
|
||||
ntpport=$(get_free_port)
|
||||
cmdport=$(get_free_port)
|
||||
|
||||
@@ -246,14 +259,14 @@ get_chronyd_options() {
|
||||
[ "$clock_control" -eq 0 ] && echo "-x"
|
||||
echo "-l $(get_logfile)"
|
||||
echo "-f $(get_conffile)"
|
||||
echo "-u $user"
|
||||
echo "-u $(get_user)"
|
||||
echo "-F $TEST_SCFILTER"
|
||||
echo "$extra_chronyd_options"
|
||||
}
|
||||
|
||||
# Start a chronyd instance
|
||||
start_chronyd() {
|
||||
local pid pidfile=$(get_pidfile)
|
||||
local pid pidfile=$(get_pidfile) wrapper_options=""
|
||||
|
||||
print_nondefaults
|
||||
test_message 1 0 "starting chronyd"
|
||||
@@ -264,7 +277,12 @@ start_chronyd() {
|
||||
|
||||
rm -f "$TEST_LOGDIR"/*.log
|
||||
|
||||
$CHRONYD_WRAPPER "$chronyd" $(get_chronyd_options) > "$TEST_DIR/chronyd.out" 2>&1
|
||||
if [[ $CHRONYD_WRAPPER == *valgrind* ]]; then
|
||||
wrapper_options="--log-file=$TEST_DIR/chronyd.valgrind --enable-debuginfod=no"
|
||||
fi
|
||||
|
||||
$CHRONYD_WRAPPER $wrapper_options \
|
||||
"$chronyd" $(get_chronyd_options) > "$TEST_DIR/chronyd.out" 2>&1
|
||||
|
||||
[ $? -eq 0 ] && [ -f "$pidfile" ] && ps -p "$(cat "$pidfile")" > /dev/null && test_ok || test_error
|
||||
}
|
||||
@@ -311,6 +329,12 @@ stop_chronyd() {
|
||||
done
|
||||
|
||||
test_ok
|
||||
|
||||
if [ -f "$TEST_DIR/chronyd.valgrind" ]; then
|
||||
test_message 2 0 "checking valgrind report"
|
||||
! grep -q 'ERROR SUMMARY: [^0]' "$TEST_DIR/chronyd.valgrind" && \
|
||||
test_ok || test_bad
|
||||
fi
|
||||
}
|
||||
|
||||
# Check chronyd log for expected and unexpected messages
|
||||
@@ -351,7 +375,7 @@ check_chronyd_files() {
|
||||
|
||||
# Run a chronyc command
|
||||
run_chronyc() {
|
||||
local host=$chronyc_host options="-n -m"
|
||||
local host=$chronyc_host options="-n -m" wrapper_options="" ret=0
|
||||
|
||||
test_message 1 0 "running chronyc $([ -n "$host" ] && echo "@$host ")$*"
|
||||
|
||||
@@ -361,8 +385,23 @@ run_chronyc() {
|
||||
options="$options -p $(grep cmdport "$(get_conffile)" | awk '{print $2}')"
|
||||
fi
|
||||
|
||||
$CHRONYC_WRAPPER "$chronyc" -h "$host" $options "$@" > "$TEST_DIR/chronyc.out" && \
|
||||
test_ok || test_error
|
||||
if [[ $CHRONYC_WRAPPER == *valgrind* ]]; then
|
||||
wrapper_options="--log-file=$TEST_DIR/chronyc.valgrind --enable-debuginfod=no"
|
||||
fi
|
||||
|
||||
$CHRONYC_WRAPPER $wrapper_options \
|
||||
"$chronyc" -h "$host" $options "$@" > "$TEST_DIR/chronyc.out" && \
|
||||
test_ok || test_error
|
||||
[ $? -ne 0 ] && ret=1
|
||||
|
||||
if [ -f "$TEST_DIR/chronyc.valgrind" ]; then
|
||||
test_message 2 0 "checking valgrind report"
|
||||
! grep -q 'ERROR SUMMARY: [^0]' "$TEST_DIR/chronyc.valgrind" && \
|
||||
test_ok || test_bad
|
||||
[ $? -ne 0 ] && ret=1
|
||||
fi
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
# Compare chronyc output with specified pattern
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <config.h>
|
||||
#include "test.h"
|
||||
|
||||
#if defined(FEAT_NTP) || defined(FEAT_CMDMON)
|
||||
|
||||
#include <clientlog.c>
|
||||
|
||||
static uint64_t
|
||||
@@ -321,10 +319,3 @@ test_unit(void)
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
}
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <local.h>
|
||||
#include "test.h"
|
||||
|
||||
#if defined(FEAT_NTP) || defined(FEAT_CMDMON)
|
||||
|
||||
#include <keys.c>
|
||||
|
||||
#define KEYS 100
|
||||
#define KEYFILE "keys.test-keys"
|
||||
#define MIN_TIMING_INTERVAL 1.0e-3
|
||||
|
||||
static
|
||||
uint32_t write_random_key(FILE *f)
|
||||
@@ -99,9 +99,11 @@ generate_key_file(const char *name, uint32_t *keys)
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, j, data_len, auth_len, type, bits;
|
||||
int i, j, data_len, auth_len, type, bits, s, timing_fails, timing_iters;
|
||||
uint32_t keys[KEYS], key;
|
||||
unsigned char data[100], auth[MAX_HASH_LENGTH];
|
||||
unsigned char data[100], auth[MAX_HASH_LENGTH], auth2[MAX_HASH_LENGTH];
|
||||
struct timespec ts1, ts2;
|
||||
double diff1, diff2;
|
||||
char conf[][100] = {
|
||||
"keyfile "KEYFILE
|
||||
};
|
||||
@@ -109,6 +111,7 @@ test_unit(void)
|
||||
CNF_Initialise(0, 0);
|
||||
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
|
||||
CNF_ParseLine(NULL, i + 1, conf[i]);
|
||||
LCL_Initialise();
|
||||
|
||||
generate_key_file(KEYFILE, keys);
|
||||
KEY_Initialise();
|
||||
@@ -158,16 +161,63 @@ test_unit(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (!getenv("NO_TIMING_TESTS") &&
|
||||
LCL_GetSysPrecisionAsQuantum() < MIN_TIMING_INTERVAL / 100.0) {
|
||||
auth_len = sizeof (auth);
|
||||
UTI_GetRandomBytes(auth, auth_len);
|
||||
memcpy(auth2, auth, auth_len);
|
||||
|
||||
timing_fails = 0;
|
||||
timing_iters = 1000;
|
||||
|
||||
i = 0;
|
||||
for (i = 0; i < 100; i++) {
|
||||
int d = random() % 2;
|
||||
|
||||
auth2[0] = auth[0] + d;
|
||||
|
||||
for (j = s = 0; j < timing_iters; j++) {
|
||||
if (j == 100)
|
||||
LCL_ReadRawTime(&ts1);
|
||||
s += UTI_IsMemoryEqual(auth, auth2, auth_len);
|
||||
}
|
||||
LCL_ReadRawTime(&ts2);
|
||||
TEST_CHECK(s == (d + 1) % 2 * timing_iters);
|
||||
diff1 = UTI_DiffTimespecsToDouble(&ts2, &ts1);
|
||||
|
||||
auth2[0] = auth[0] + (d + 1) % 2;
|
||||
|
||||
for (j = s = 0; j < timing_iters; j++) {
|
||||
if (j == 100)
|
||||
LCL_ReadRawTime(&ts1);
|
||||
s += UTI_IsMemoryEqual(auth, auth2, auth_len);
|
||||
}
|
||||
LCL_ReadRawTime(&ts2);
|
||||
TEST_CHECK(s == d * timing_iters);
|
||||
diff2 = UTI_DiffTimespecsToDouble(&ts2, &ts1);
|
||||
|
||||
DEBUG_LOG("d=%d diff1=%e diff2=%e iters=%d", d, diff1, diff2, timing_iters);
|
||||
|
||||
if (diff1 < MIN_TIMING_INTERVAL && diff2 < MIN_TIMING_INTERVAL) {
|
||||
if (timing_iters >= INT_MAX / 2)
|
||||
break;
|
||||
timing_iters *= 2;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((d == 0 && 0.8 * diff1 > diff2) || (d == 1 && diff1 < 0.8 * diff2))
|
||||
timing_fails++;
|
||||
}
|
||||
|
||||
DEBUG_LOG("timing fails %d/%d", timing_fails, i);
|
||||
TEST_CHECK(timing_fails < i / 2);
|
||||
}
|
||||
|
||||
unlink(KEYFILE);
|
||||
|
||||
KEY_Finalise();
|
||||
LCL_Finalise();
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <socket.h>
|
||||
#include "test.h"
|
||||
|
||||
#ifdef FEAT_NTP
|
||||
|
||||
#include <ntp_auth.c>
|
||||
|
||||
static void
|
||||
@@ -279,11 +277,3 @@ test_unit(void)
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <local.h>
|
||||
#include "test.h"
|
||||
|
||||
#ifdef FEAT_NTP
|
||||
|
||||
static struct timespec current_time;
|
||||
static NTP_Packet req_buffer, res_buffer;
|
||||
static int req_length, res_length;
|
||||
@@ -638,11 +636,3 @@ test_unit(void)
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <config.h>
|
||||
#include "test.h"
|
||||
|
||||
#ifdef FEAT_NTP
|
||||
|
||||
#include <util.h>
|
||||
#include <logging.h>
|
||||
|
||||
@@ -157,11 +155,3 @@ test_unit(void)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <config.h>
|
||||
#include "test.h"
|
||||
|
||||
#ifdef FEAT_NTP
|
||||
|
||||
#include <conf.h>
|
||||
#include <cmdparse.h>
|
||||
#include <nameserv_async.h>
|
||||
@@ -372,11 +370,3 @@ test_unit(void)
|
||||
CNF_Finalise();
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
TEST_REQUIRE(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
* Copyright (C) Miroslav Lichvar 2020, 2024
|
||||
*
|
||||
* 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
|
||||
@@ -23,8 +23,24 @@
|
||||
|
||||
#ifdef FEAT_NTS
|
||||
|
||||
#include <nts_ke_client.c>
|
||||
#include <local.h>
|
||||
#include <nts_ke_session.h>
|
||||
#include <util.h>
|
||||
|
||||
#define NKSN_GetKeys get_keys
|
||||
|
||||
static int
|
||||
get_keys(NKSN_Instance session, SIV_Algorithm algorithm, SIV_Algorithm exporter_algorithm,
|
||||
int next_protocol, NKE_Key *c2s, NKE_Key *s2c)
|
||||
{
|
||||
c2s->length = SIV_GetKeyLength(algorithm);
|
||||
UTI_GetRandomBytes(c2s->key, c2s->length);
|
||||
s2c->length = SIV_GetKeyLength(algorithm);
|
||||
UTI_GetRandomBytes(s2c->key, s2c->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include <nts_ke_client.c>
|
||||
|
||||
static void
|
||||
prepare_response(NKSN_Instance session, int valid)
|
||||
@@ -88,12 +104,17 @@ prepare_response(NKSN_Instance session, int valid)
|
||||
|
||||
if (random() % 2) {
|
||||
length = random() % (sizeof (data) + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, 1000 + random() % 1000, data, length));
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, 2000 + random() % 1000, data, length));
|
||||
}
|
||||
|
||||
if (random() % 2)
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0));
|
||||
|
||||
if (index != 8) {
|
||||
for (i = 0; i < NKE_MAX_COOKIES; i++) {
|
||||
for (i = random() % NKE_MAX_COOKIES; i >= 0; i--) {
|
||||
length = (random() % sizeof (data) + 1) / 4 * 4;
|
||||
if (i == 0 && length == 0)
|
||||
length = 4;
|
||||
if (index == 9)
|
||||
length += (length < sizeof (data) ? 1 : -1) * (random() % 3 + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COOKIE, data, length));
|
||||
@@ -103,12 +124,16 @@ prepare_response(NKSN_Instance session, int valid)
|
||||
TEST_CHECK(NKSN_EndMessage(session));
|
||||
}
|
||||
|
||||
#define MAX_COOKIES (2 * NKE_MAX_COOKIES)
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
NKE_Context context, alt_context;
|
||||
NKE_Cookie cookies[MAX_COOKIES];
|
||||
int i, j, r, valid, num_cookies;
|
||||
NKC_Instance inst;
|
||||
IPSockAddr addr;
|
||||
int i, r, valid;
|
||||
|
||||
char conf[][100] = {
|
||||
"nosystemcert",
|
||||
@@ -127,10 +152,33 @@ test_unit(void)
|
||||
TEST_CHECK(inst);
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
inst->got_response = 0;
|
||||
valid = random() % 2;
|
||||
prepare_response(inst->session, valid);
|
||||
r = process_response(inst);
|
||||
r = handle_message(inst);
|
||||
TEST_CHECK(r == valid);
|
||||
|
||||
memset(&context, 0, sizeof (context));
|
||||
memset(&alt_context, 0, sizeof (alt_context));
|
||||
num_cookies = 0;
|
||||
|
||||
r = NKC_GetNtsData(inst, &context, &alt_context,
|
||||
cookies, &num_cookies, random() % MAX_COOKIES + 1, &addr);
|
||||
TEST_CHECK(r == valid);
|
||||
if (r) {
|
||||
TEST_CHECK(context.algorithm != AEAD_SIV_INVALID);
|
||||
TEST_CHECK(context.c2s.length > 0);
|
||||
TEST_CHECK(context.c2s.length == SIV_GetKeyLength(context.algorithm));
|
||||
TEST_CHECK(context.s2c.length == SIV_GetKeyLength(context.algorithm));
|
||||
if (alt_context.algorithm != AEAD_SIV_INVALID) {
|
||||
TEST_CHECK(context.c2s.length > 0);
|
||||
TEST_CHECK(alt_context.c2s.length == SIV_GetKeyLength(alt_context.algorithm));
|
||||
TEST_CHECK(alt_context.s2c.length == SIV_GetKeyLength(alt_context.algorithm));
|
||||
}
|
||||
TEST_CHECK(num_cookies > 0 && num_cookies <= NKE_MAX_COOKIES);
|
||||
for (j = 0; j < num_cookies; j++)
|
||||
TEST_CHECK(cookies[j].length > 0 && cookies[j].length % 4 == 0);
|
||||
}
|
||||
}
|
||||
|
||||
NKC_DestroyInstance(inst);
|
||||
|
||||
@@ -30,11 +30,12 @@
|
||||
#define NKSN_GetKeys get_keys
|
||||
|
||||
static int
|
||||
get_keys(NKSN_Instance session, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c)
|
||||
get_keys(NKSN_Instance session, SIV_Algorithm algorithm, SIV_Algorithm exporter_algorithm,
|
||||
int next_protocol, NKE_Key *c2s, NKE_Key *s2c)
|
||||
{
|
||||
c2s->length = SIV_GetKeyLength(siv);
|
||||
c2s->length = SIV_GetKeyLength(algorithm);
|
||||
UTI_GetRandomBytes(c2s->key, c2s->length);
|
||||
s2c->length = SIV_GetKeyLength(siv);
|
||||
s2c->length = SIV_GetKeyLength(algorithm);
|
||||
UTI_GetRandomBytes(s2c->key, s2c->length);
|
||||
return 1;
|
||||
}
|
||||
@@ -91,7 +92,7 @@ prepare_request(NKSN_Instance session, int valid)
|
||||
|
||||
if (index == 8) {
|
||||
length = random() % (sizeof (data) + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, 1000 + random() % 1000, data, length));
|
||||
TEST_CHECK(NKSN_AddRecord(session, 1, 2000 + random() % 1000, data, length));
|
||||
}
|
||||
|
||||
if (random() % 2) {
|
||||
@@ -105,9 +106,12 @@ prepare_request(NKSN_Instance session, int valid)
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_NTPV4_PORT_NEGOTIATION, data, length));
|
||||
}
|
||||
|
||||
if (random() % 2)
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0));
|
||||
|
||||
if (random() % 2) {
|
||||
length = random() % (sizeof (data) + 1);
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, 1000 + random() % 1000, data, length));
|
||||
TEST_CHECK(NKSN_AddRecord(session, 0, 2000 + random() % 1000, data, length));
|
||||
}
|
||||
|
||||
TEST_CHECK(NKSN_EndMessage(session));
|
||||
@@ -174,7 +178,8 @@ test_unit(void)
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
context.algorithm = AEAD_AES_SIV_CMAC_256;
|
||||
get_keys(session, context.algorithm, &context.c2s, &context.s2c);
|
||||
get_keys(session, context.algorithm, random() % 100, NKE_NEXT_PROTOCOL_NTPV4,
|
||||
&context.c2s, &context.s2c);
|
||||
memset(&cookie, 0, sizeof (cookie));
|
||||
TEST_CHECK(NKS_GenerateCookie(&context, &cookie));
|
||||
TEST_CHECK(NKS_DecodeCookie(&cookie, &context2));
|
||||
|
||||
@@ -116,9 +116,19 @@ verify_message(NKSN_Instance inst)
|
||||
|
||||
TEST_CHECK(!NKSN_GetRecord(inst, &critical, &t, &length, buffer, sizeof (buffer)));
|
||||
|
||||
TEST_CHECK(NKSN_GetKeys(inst, AEAD_AES_SIV_CMAC_256, &c2s, &s2c));
|
||||
TEST_CHECK(c2s.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256));
|
||||
TEST_CHECK(s2c.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256));
|
||||
for (i = 0; i < 10; i++) {
|
||||
TEST_CHECK(NKSN_GetKeys(inst, AEAD_AES_SIV_CMAC_256, random(), random(), &c2s, &s2c));
|
||||
TEST_CHECK(c2s.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256));
|
||||
TEST_CHECK(s2c.length == SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256));
|
||||
|
||||
if (SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0) {
|
||||
TEST_CHECK(NKSN_GetKeys(inst, AEAD_AES_128_GCM_SIV, random(), random(), &c2s, &s2c));
|
||||
TEST_CHECK(c2s.length == SIV_GetKeyLength(AEAD_AES_128_GCM_SIV));
|
||||
TEST_CHECK(s2c.length == SIV_GetKeyLength(AEAD_AES_128_GCM_SIV));
|
||||
} else {
|
||||
TEST_CHECK(!NKSN_GetKeys(inst, AEAD_AES_128_GCM_SIV, random(), random(), &c2s, &s2c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -166,6 +176,7 @@ test_unit(void)
|
||||
const char *cert, *key;
|
||||
int sock_fds[2], i;
|
||||
uint32_t cert_id;
|
||||
NKE_Key c2s, s2c;
|
||||
|
||||
LCL_Initialise();
|
||||
TST_RegisterDummyDrivers();
|
||||
@@ -190,6 +201,9 @@ test_unit(void)
|
||||
TEST_CHECK(NKSN_StartSession(server, sock_fds[0], "client", server_cred, 4.0));
|
||||
TEST_CHECK(NKSN_StartSession(client, sock_fds[1], "server", client_cred, 4.0));
|
||||
|
||||
TEST_CHECK(!NKSN_GetKeys(server, AEAD_AES_SIV_CMAC_256, 0, 0, &c2s, &s2c));
|
||||
TEST_CHECK(!NKSN_GetKeys(client, AEAD_AES_SIV_CMAC_256, 0, 0, &c2s, &s2c));
|
||||
|
||||
send_message(client);
|
||||
|
||||
request_received = response_received = 0;
|
||||
@@ -201,6 +215,9 @@ test_unit(void)
|
||||
TEST_CHECK(NKSN_IsStopped(server));
|
||||
TEST_CHECK(NKSN_IsStopped(client));
|
||||
|
||||
TEST_CHECK(!NKSN_GetKeys(server, AEAD_AES_SIV_CMAC_256, 0, 0, &c2s, &s2c));
|
||||
TEST_CHECK(!NKSN_GetKeys(client, AEAD_AES_SIV_CMAC_256, 0, 0, &c2s, &s2c));
|
||||
|
||||
TEST_CHECK(request_received);
|
||||
TEST_CHECK(response_received);
|
||||
|
||||
|
||||
@@ -39,6 +39,18 @@ test_unit(void)
|
||||
int i, j, r, packet_length, nonce_length, key_length;
|
||||
int plaintext_length, plaintext2_length, min_ef_length;
|
||||
|
||||
TEST_CHECK(get_padding_length(0) == 0);
|
||||
TEST_CHECK(get_padding_length(1) == 3);
|
||||
TEST_CHECK(get_padding_length(2) == 2);
|
||||
TEST_CHECK(get_padding_length(3) == 1);
|
||||
TEST_CHECK(get_padding_length(4) == 0);
|
||||
TEST_CHECK(get_padded_length(0) == 0);
|
||||
TEST_CHECK(get_padded_length(1) == 4);
|
||||
TEST_CHECK(get_padded_length(2) == 4);
|
||||
TEST_CHECK(get_padded_length(3) == 4);
|
||||
TEST_CHECK(get_padded_length(4) == 4);
|
||||
TEST_CHECK(get_padded_length(5) == 8);
|
||||
|
||||
for (algo = 1; algo < 100; algo++) {
|
||||
siv = SIV_CreateInstance(algo);
|
||||
if (!siv) {
|
||||
@@ -102,20 +114,37 @@ test_unit(void)
|
||||
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
||||
plaintext_length, min_ef_length);
|
||||
TEST_CHECK(r);
|
||||
TEST_CHECK(info.ext_fields == 1);
|
||||
TEST_CHECK(info.length - packet_length >= min_ef_length);
|
||||
TEST_CHECK(info.length - packet_length == get_padded_length(min_ef_length) ||
|
||||
info.length - packet_length == 4 + 4 +
|
||||
get_padded_length(MAX(MIN(16, SIV_GetMaxNonceLength(siv)), nonce_length)) +
|
||||
get_padded_length(plaintext_length) + SIV_GetTagLength(siv));
|
||||
|
||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||
-1, &plaintext2_length);
|
||||
TEST_CHECK(!r);
|
||||
|
||||
if (random() % 2) {
|
||||
for (j = 0; j < get_padding_length(nonce_length); j++)
|
||||
((unsigned char *)&packet)[packet_length + 4 + 4 + nonce_length + j]++;
|
||||
for (j = packet_length + 4 + 4 + get_padded_length(nonce_length) +
|
||||
plaintext_length + SIV_GetTagLength(siv); j < sizeof (packet); j++)
|
||||
((unsigned char *)&packet)[j]++;
|
||||
}
|
||||
|
||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||
sizeof (plaintext2), &plaintext2_length);
|
||||
TEST_CHECK(r);
|
||||
TEST_CHECK(plaintext_length == plaintext2_length);
|
||||
TEST_CHECK(memcmp(plaintext, plaintext2, plaintext_length) == 0);
|
||||
|
||||
j = random() % (packet_length + plaintext_length +
|
||||
nonce_length + SIV_GetTagLength(siv) + 8) / 4 * 4;
|
||||
if (random() % 2) {
|
||||
j = random() % (packet_length + 4 + 4 + nonce_length);
|
||||
} else {
|
||||
j = packet_length + 4 + 4 + get_padded_length(nonce_length);
|
||||
j += random() % (plaintext_length + SIV_GetTagLength(siv));
|
||||
}
|
||||
((unsigned char *)&packet)[j]++;
|
||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||
sizeof (plaintext2), &plaintext2_length);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#define NKC_IsActive(inst) (random() % 2)
|
||||
#define NKC_GetRetryFactor(inst) (1)
|
||||
|
||||
static int get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
static int get_nts_data(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address);
|
||||
#define NKC_GetNtsData get_nts_data
|
||||
@@ -41,7 +41,7 @@ static int get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
#include <nts_ntp_client.c>
|
||||
|
||||
static int
|
||||
get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
get_nts_data(NKC_Instance inst, NKE_Context *context, NKE_Context *alt_context,
|
||||
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
|
||||
IPSockAddr *ntp_address)
|
||||
{
|
||||
@@ -60,6 +60,14 @@ get_nts_data(NKC_Instance inst, NKE_Context *context,
|
||||
context->s2c.length = SIV_GetKeyLength(context->algorithm);
|
||||
UTI_GetRandomBytes(context->s2c.key, context->s2c.length);
|
||||
|
||||
if (random() % 2) {
|
||||
*alt_context = *context;
|
||||
UTI_GetRandomBytes(alt_context->c2s.key, alt_context->c2s.length);
|
||||
UTI_GetRandomBytes(alt_context->s2c.key, alt_context->s2c.length);
|
||||
} else {
|
||||
alt_context->algorithm = AEAD_SIV_INVALID;
|
||||
}
|
||||
|
||||
*num_cookies = random() % max_cookies + 1;
|
||||
for (i = 0; i < *num_cookies; i++) {
|
||||
cookies[i].length = random() % (sizeof (cookies[i].cookie) + 1);
|
||||
|
||||
@@ -28,7 +28,7 @@ test_unit(void)
|
||||
{
|
||||
int i, j, k, min_k, max_k, q, r, in_order, out_order;
|
||||
QNT_Instance inst;
|
||||
double x;
|
||||
double x, x2;
|
||||
|
||||
in_order = out_order = 0;
|
||||
|
||||
@@ -40,9 +40,11 @@ test_unit(void)
|
||||
max_k = random() % (q - 1) + 1;
|
||||
} while (min_k > max_k);
|
||||
|
||||
inst = QNT_CreateInstance(min_k, max_k, q, r, 1e-9);
|
||||
inst = QNT_CreateInstance(min_k, max_k, q, r, 900, 1e-9);
|
||||
|
||||
TEST_CHECK(min_k == QNT_GetMinK(inst));
|
||||
TEST_CHECK(max_k == QNT_GetMaxK(inst));
|
||||
TEST_CHECK(fabs(QNT_GetMinStep(inst) - 1e-9) < 1e-12);
|
||||
|
||||
for (j = 0; j < 3000; j++) {
|
||||
x = TST_GetRandomDouble(0.0, 2e-6);
|
||||
@@ -61,6 +63,32 @@ test_unit(void)
|
||||
QNT_Reset(inst);
|
||||
TEST_CHECK(inst->n_set == 0);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
QNT_Reset(inst);
|
||||
x = (i + 950) / 1e9;
|
||||
if (random() % 10)
|
||||
x2 = (i + 951) / 1e9;
|
||||
else
|
||||
x2 = x;
|
||||
for (k = 0; k < 1000; k++)
|
||||
QNT_Accumulate(inst, random() % 2 ? x : x2);
|
||||
for (k = 0; k < inst->n_quants; k++) {
|
||||
TEST_CHECK(inst->quants[k].est > x - 0.4e-9);
|
||||
TEST_CHECK(inst->quants[k].est < x2 + 0.4e-9);
|
||||
TEST_CHECK(inst->quants[k].step < -15e-9);
|
||||
TEST_CHECK(inst->quants[k].step > -901e-9);
|
||||
if (min_k * 2 == q && k < inst->repeat) {
|
||||
if (x == x2) {
|
||||
TEST_CHECK(inst->quants[k].step < -750e-9);
|
||||
TEST_CHECK(inst->quants[k].step > -901e-9);
|
||||
} else {
|
||||
TEST_CHECK(inst->quants[k].step < -350e-9);
|
||||
TEST_CHECK(inst->quants[k].step > -600e-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QNT_DestroyInstance(inst);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,199 @@ test_preinitialise(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
send_and_recv(int type, int is_stream, int is_client_bound, int server_fd, int client_fd)
|
||||
{
|
||||
SCK_Message *msg1, msg2;
|
||||
char buf1[16], buf2[16];
|
||||
|
||||
TEST_CHECK(!SCK_IsReusable(server_fd));
|
||||
TEST_CHECK(!SCK_IsReusable(client_fd));
|
||||
|
||||
if (random() % 2 && !SCK_EnableKernelRxTimestamping(client_fd))
|
||||
;
|
||||
|
||||
UTI_GetRandomBytes(buf1, sizeof (buf1));
|
||||
|
||||
TEST_CHECK(SCK_Send(client_fd, buf1, sizeof (buf1), 0) == sizeof (buf1));
|
||||
msg1 = SCK_ReceiveMessage(server_fd, 0);
|
||||
|
||||
TEST_CHECK(msg1);
|
||||
TEST_CHECK(msg1->data);
|
||||
TEST_CHECK(msg1->length == sizeof (buf1));
|
||||
if (is_stream) {
|
||||
TEST_CHECK(msg1->addr_type == type || msg1->addr_type == SCK_ADDR_UNSPEC);
|
||||
} else if (is_client_bound) {
|
||||
TEST_CHECK(msg1->addr_type == type);
|
||||
TEST_CHECK(msg1->remote_addr.ip.ip_addr.family != IPADDR_UNSPEC);
|
||||
} else {
|
||||
TEST_CHECK(msg1->addr_type == SCK_ADDR_UNSPEC);
|
||||
}
|
||||
|
||||
TEST_CHECK(memcmp(buf1, msg1->data, sizeof (buf1)) == 0);
|
||||
|
||||
UTI_GetRandomBytes(buf2, sizeof (buf2));
|
||||
SCK_InitMessage(&msg2, is_stream ? SCK_ADDR_UNSPEC : type);
|
||||
if (!is_stream)
|
||||
msg2.remote_addr = msg1->remote_addr;
|
||||
msg2.data = buf2;
|
||||
msg2.length = sizeof (buf1);
|
||||
|
||||
TEST_CHECK(SCK_SendMessage(server_fd, &msg2, 0));
|
||||
TEST_CHECK(SCK_Receive(client_fd, buf1, sizeof (buf1), 0) == sizeof (buf1));
|
||||
TEST_CHECK(memcmp(buf1, buf2, sizeof (buf1)) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
int i, family, s1, s2, s3;
|
||||
IPSockAddr sa1, sa2;
|
||||
IPAddr ip1, ip2;
|
||||
|
||||
test_preinitialise();
|
||||
|
||||
SCK_PreInitialise();
|
||||
|
||||
SCK_Initialise(IPADDR_INET4);
|
||||
TEST_CHECK(SCK_IsIpFamilyEnabled(IPADDR_INET4));
|
||||
TEST_CHECK(!SCK_IsIpFamilyEnabled(IPADDR_INET6));
|
||||
SCK_Finalise();
|
||||
|
||||
SCK_Initialise(IPADDR_INET6);
|
||||
TEST_CHECK(!SCK_IsIpFamilyEnabled(IPADDR_INET4));
|
||||
#ifdef FEAT_IPV6
|
||||
TEST_CHECK(SCK_IsIpFamilyEnabled(IPADDR_INET6));
|
||||
#else
|
||||
TEST_CHECK(!SCK_IsIpFamilyEnabled(IPADDR_INET6));
|
||||
#endif
|
||||
SCK_Finalise();
|
||||
|
||||
SCK_Initialise(IPADDR_UNSPEC);
|
||||
TEST_CHECK(SCK_IsIpFamilyEnabled(IPADDR_INET4));
|
||||
#ifdef FEAT_IPV6
|
||||
TEST_CHECK(SCK_IsIpFamilyEnabled(IPADDR_INET6));
|
||||
#else
|
||||
TEST_CHECK(!SCK_IsIpFamilyEnabled(IPADDR_INET6));
|
||||
#endif
|
||||
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET4, &ip1);
|
||||
if (UTI_StringToIP("0.0.0.0", &ip2))
|
||||
TEST_CHECK(UTI_CompareIPs(&ip1, &ip2, NULL) == 0);
|
||||
SCK_GetAnyLocalIPAddress(IPADDR_INET6, &ip1);
|
||||
if (UTI_StringToIP("::", &ip2))
|
||||
TEST_CHECK(UTI_CompareIPs(&ip1, &ip2, NULL) == 0);
|
||||
|
||||
SCK_GetLoopbackIPAddress(IPADDR_INET4, &ip1);
|
||||
if (UTI_StringToIP("127.0.0.1", &ip2))
|
||||
TEST_CHECK(UTI_CompareIPs(&ip1, &ip2, NULL) == 0);
|
||||
SCK_GetLoopbackIPAddress(IPADDR_INET6, &ip1);
|
||||
if (UTI_StringToIP("::1", &ip2))
|
||||
TEST_CHECK(UTI_CompareIPs(&ip1, &ip2, NULL) == 0);
|
||||
|
||||
if (UTI_StringToIP("169.254.100.100", &ip1))
|
||||
TEST_CHECK(SCK_IsLinkLocalIPAddress(&ip1));
|
||||
if (UTI_StringToIP("169.255.100.100", &ip1))
|
||||
TEST_CHECK(!SCK_IsLinkLocalIPAddress(&ip2));
|
||||
if (UTI_StringToIP("fe80::", &ip1))
|
||||
TEST_CHECK(SCK_IsLinkLocalIPAddress(&ip1));
|
||||
if (UTI_StringToIP("fe81::", &ip1))
|
||||
TEST_CHECK(!SCK_IsLinkLocalIPAddress(&ip2));
|
||||
|
||||
for (family = IPADDR_INET4; family <= IPADDR_INET6; family++) {
|
||||
SCK_GetLoopbackIPAddress(family, &sa1.ip_addr);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
sa1.port = 1024 + random() % 60000;
|
||||
s1 = SCK_OpenUdpSocket(NULL, &sa1, NULL, SCK_FLAG_BLOCK);
|
||||
if (s1 >= 0) {
|
||||
s2 = SCK_OpenUdpSocket(&sa1, NULL, NULL, SCK_FLAG_BLOCK);
|
||||
TEST_CHECK(s2 >= 0);
|
||||
|
||||
send_and_recv(SCK_ADDR_IP, 0, 1, s1, s2);
|
||||
|
||||
SCK_CloseSocket(s1);
|
||||
SCK_CloseSocket(s2);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
sa1.port = 1024 + random() % 60000;
|
||||
s1 = SCK_OpenTcpSocket(NULL, &sa1, NULL, SCK_FLAG_BLOCK);
|
||||
if (s1 >= 0) {
|
||||
TEST_CHECK(SCK_ListenOnSocket(s1, 1));
|
||||
if (i % 2) {
|
||||
sa2 = sa1;
|
||||
sa2.port = 1024 + random() % 60000;
|
||||
s2 = SCK_OpenTcpSocket(&sa1, &sa2, NULL, SCK_FLAG_BLOCK);
|
||||
if (s2 < 0) {
|
||||
SCK_CloseSocket(s1);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
s2 = SCK_OpenTcpSocket(&sa1, NULL, NULL, SCK_FLAG_BLOCK);
|
||||
}
|
||||
TEST_CHECK(s2 >= 0);
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(UTI_CompareIPs(&sa1.ip_addr, &sa2.ip_addr, NULL) == 0);
|
||||
|
||||
send_and_recv(SCK_ADDR_IP, 1, 1, s3, s2);
|
||||
|
||||
SCK_ShutdownConnection(s2);
|
||||
SCK_ShutdownConnection(s3);
|
||||
SCK_CloseSocket(s1);
|
||||
SCK_CloseSocket(s2);
|
||||
SCK_CloseSocket(s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
s1 = SCK_OpenUnixDatagramSocket(NULL, "testsocket1", SCK_FLAG_BLOCK);
|
||||
TEST_CHECK(s1 >= 0);
|
||||
s2 = SCK_OpenUnixDatagramSocket("testsocket1", "testsocket2", SCK_FLAG_BLOCK);
|
||||
TEST_CHECK(s2 >= 0);
|
||||
|
||||
send_and_recv(SCK_ADDR_UNIX, 0, 1, s1, s2);
|
||||
|
||||
if (i % 2)
|
||||
TEST_CHECK(SCK_RemoveSocket(s1));
|
||||
if (i % 2)
|
||||
TEST_CHECK(SCK_RemoveSocket(s2));
|
||||
SCK_CloseSocket(s1);
|
||||
SCK_CloseSocket(s2);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
s1 = SCK_OpenUnixStreamSocket(NULL, "testsocket1", SCK_FLAG_BLOCK);
|
||||
TEST_CHECK(s1 >= 0);
|
||||
TEST_CHECK(SCK_ListenOnSocket(s1, 1));
|
||||
s2 = SCK_OpenUnixStreamSocket("testsocket1", i % 2 ? "testsocket2" : NULL, SCK_FLAG_BLOCK);
|
||||
TEST_CHECK(s2 >= 0);
|
||||
s3 = SCK_AcceptConnection(s1, &sa2);
|
||||
TEST_CHECK(sa2.ip_addr.family == IPADDR_UNSPEC);
|
||||
|
||||
send_and_recv(SCK_ADDR_UNIX, 1, i % 2, s3, s2);
|
||||
|
||||
if (i % 4)
|
||||
TEST_CHECK(SCK_RemoveSocket(s1));
|
||||
SCK_ShutdownConnection(s2);
|
||||
SCK_ShutdownConnection(s3);
|
||||
SCK_CloseSocket(s1);
|
||||
SCK_CloseSocket(s2);
|
||||
SCK_CloseSocket(s3);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
s1 = SCK_OpenUnixSocketPair(SCK_FLAG_BLOCK, &s2);
|
||||
TEST_CHECK(s1 >= 0);
|
||||
TEST_CHECK(s2 >= 0);
|
||||
|
||||
send_and_recv(SCK_ADDR_UNIX, 1, 0, s1, s2);
|
||||
|
||||
SCK_CloseSocket(s1);
|
||||
SCK_CloseSocket(s2);
|
||||
}
|
||||
|
||||
SCK_Finalise();
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ handle_signal(int signal)
|
||||
void
|
||||
test_unit(void)
|
||||
{
|
||||
char buf[16], buf2[16], *s, *s2, *words[3];
|
||||
struct timespec ts, ts2, ts3, ts4;
|
||||
char buf[16], *s, *s2, *words[3];
|
||||
NTP_int64 ntp_ts, ntp_ts2, ntp_fuzz;
|
||||
NTP_int32 ntp32_ts;
|
||||
struct timeval tv;
|
||||
@@ -797,5 +797,19 @@ test_unit(void)
|
||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||
TEST_CHECK(strcmp(words[1], "b") == 0);
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
UTI_GetRandomBytes(buf, sizeof (buf));
|
||||
memcpy(buf2, buf, sizeof (buf));
|
||||
for (j = 0; j < sizeof (buf); j++)
|
||||
TEST_CHECK(UTI_IsMemoryEqual(buf, buf2, j));
|
||||
|
||||
for (j = 0; j < 8 * sizeof (buf); j++) {
|
||||
buf2[j / 8] ^= 1U << j % 8;
|
||||
TEST_CHECK(!UTI_IsMemoryEqual(buf, buf2, sizeof (buf)));
|
||||
buf2[j / 8] ^= 1U << j % 8;
|
||||
TEST_CHECK(UTI_IsMemoryEqual(buf, buf2, sizeof (buf)));
|
||||
}
|
||||
}
|
||||
|
||||
HSH_Finalise();
|
||||
}
|
||||
|
||||
25
util.c
25
util.c
@@ -29,6 +29,12 @@
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#if defined(HAVE_NETTLE_MEMEQL)
|
||||
#include <nettle/memops.h>
|
||||
#elif defined(HAVE_GNUTLS)
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
@@ -1648,3 +1654,22 @@ UTI_SplitString(char *string, char **words, int max_saved_words)
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
UTI_IsMemoryEqual(const void *s1, const void *s2, unsigned int len)
|
||||
{
|
||||
#if defined(HAVE_NETTLE_MEMEQL)
|
||||
return nettle_memeql_sec(s1, s2, len);
|
||||
#elif defined(HAVE_GNUTLS)
|
||||
return gnutls_memcmp(s1, s2, len) == 0;
|
||||
#else
|
||||
unsigned int i, x;
|
||||
|
||||
for (i = 0, x = 0; i < len; i++)
|
||||
x |= ((const unsigned char *)s1)[i] ^ ((const unsigned char *)s2)[i];
|
||||
|
||||
return x == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
13
util.h
13
util.h
@@ -257,6 +257,11 @@ extern unsigned int UTI_HexToBytes(const char *hex, void *buf, unsigned int len)
|
||||
number of pointers to the words. */
|
||||
extern int UTI_SplitString(char *string, char **words, int max_saved_words);
|
||||
|
||||
/* Check if two buffers of the same length contain the same data, but do the
|
||||
comparison in constant time with respect to the returned value to avoid
|
||||
creating a timing side channel */
|
||||
extern int UTI_IsMemoryEqual(const void *s1, const void *s2, unsigned int len);
|
||||
|
||||
/* Macros to get maximum and minimum of two values */
|
||||
#ifdef MAX
|
||||
#undef MAX
|
||||
@@ -272,4 +277,12 @@ extern int UTI_SplitString(char *string, char **words, int max_saved_words);
|
||||
|
||||
#define SQUARE(x) ((x) * (x))
|
||||
|
||||
/* Macro to make an assertion with the text of a long argument replaced
|
||||
with "0" to avoid bloating the compiled binary */
|
||||
#ifdef NDEBUG
|
||||
#define BRIEF_ASSERT(a)
|
||||
#else
|
||||
#define BRIEF_ASSERT(a) if (!(a)) assert(0)
|
||||
#endif
|
||||
|
||||
#endif /* GOT_UTIL_H */
|
||||
|
||||
Reference in New Issue
Block a user